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();