From 91fbcc804abf5cef726bb44eab1bd92703a5eb64 Mon Sep 17 00:00:00 2001
From: zon <>
Date: Wed, 17 Aug 2022 12:40:39 +0200
Subject: [PATCH] Added begin and end token attributes to XML output of CPD
---
.../pmd/userdocs/cpd/cpd_report_formats.md | 10 +++---
.../java/net/sourceforge/pmd/cpd/Mark.java | 8 +++++
.../net/sourceforge/pmd/cpd/XMLRenderer.java | 6 ++++
.../sourceforge/pmd/cpd/XMLRendererTest.java | 32 +++++++++++++++++++
4 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/docs/pages/pmd/userdocs/cpd/cpd_report_formats.md b/docs/pages/pmd/userdocs/cpd/cpd_report_formats.md
index 4e1a23a0d0..f21bd5b448 100644
--- a/docs/pages/pmd/userdocs/cpd/cpd_report_formats.md
+++ b/docs/pages/pmd/userdocs/cpd/cpd_report_formats.md
@@ -104,9 +104,9 @@ Example:
-
-
-
-
-
ruleChainVisits = query.getRuleChainVisits();
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/Mark.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/Mark.java
index c741a337ad..30e13c4b04 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/Mark.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/Mark.java
@@ -35,6 +35,10 @@ public class Mark implements Comparable {
return this.token.getBeginColumn(); // TODO Java 1.8 make optional
}
+ public int getBeginTokenIndex() {
+ return this.token.getIndex();
+ }
+
public int getEndLine() {
return getBeginLine() + getLineCount() - 1;
}
@@ -48,6 +52,10 @@ public class Mark implements Comparable {
return this.endToken == null ? -1 : this.endToken.getEndColumn(); // TODO Java 1.8 make optional
}
+ public int getEndTokenIndex() {
+ return this.endToken == null ? -1 : this.endToken.getIndex();
+ }
+
public int getLineCount() {
return this.lineCount;
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/XMLRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/XMLRenderer.java
index d7d69382e5..6b5d51a2cf 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/XMLRenderer.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/XMLRenderer.java
@@ -152,6 +152,12 @@ public final class XMLRenderer implements Renderer, CPDRenderer, CPDReportRender
if (endCol != -1) {
file.setAttribute("endcolumn", String.valueOf(endCol));
}
+ final int beginIndex = mark.getBeginTokenIndex();
+ final int endIndex = mark.getEndTokenIndex();
+ file.setAttribute("begintoken", String.valueOf(beginIndex));
+ if (endIndex != -1) {
+ file.setAttribute("endtoken", String.valueOf(endIndex));
+ }
duplication.appendChild(file);
}
return duplication;
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java
index 1e29e7961b..366733b088 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java
@@ -216,6 +216,38 @@ public class XMLRendererTest {
assertEquals("888", attributes.getNamedItem("totalNumberOfTokens").getNodeValue());
}
+ @Test
+ public void testGetDuplicationStartEnd() throws IOException, ParserConfigurationException, SAXException {
+ TokenEntry.clearImages();
+ final CPDReportRenderer renderer = new XMLRenderer();
+ final List matches = new ArrayList<>();
+ final String filename = "/var/Foo.java";
+ final int lineCount = 6;
+ final String codeFragment = "code\nfragment";
+ final Mark mark1 = createMark("public", filename, 1, lineCount, codeFragment, 2, 3);
+ final Mark mark2 = createMark("stuff", filename, 73, lineCount, codeFragment, 4, 5);
+ final Match match = new Match(75, mark1, mark2);
+ matches.add(match);
+ final Map numberOfTokensPerFile = new HashMap<>();
+ numberOfTokensPerFile.put(filename, 888);
+ final CPDReport report = new CPDReport(matches, numberOfTokensPerFile);
+ final StringWriter writer = new StringWriter();
+ renderer.render(report, writer);
+ final String xmlOutput = writer.toString();
+ final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(new ByteArrayInputStream(xmlOutput.getBytes(ENCODING)));
+ final NodeList files = doc.getElementsByTagName("file");
+ final Node dup_1 = files.item(1);
+ final NamedNodeMap attrs_1 = dup_1.getAttributes();
+ assertEquals("0", attrs_1.getNamedItem("begintoken").getNodeValue());
+ assertEquals("1", attrs_1.getNamedItem("endtoken").getNodeValue());
+
+ final Node dup_2 = files.item(2);
+ final NamedNodeMap attrs_2 = dup_2.getAttributes();
+ assertEquals("2", attrs_2.getNamedItem("begintoken").getNodeValue());
+ assertEquals("3", attrs_2.getNamedItem("endtoken").getNodeValue());
+ }
+
@Test
public void testRendererEncodedPath() throws IOException {
CPDRenderer renderer = new XMLRenderer();