iterator = match.iterator(); iterator.hasNext();) {
mark = iterator.next();
- Element file = doc.createElement("file");
+ final Element file = doc.createElement("file");
file.setAttribute("line", String.valueOf(mark.getBeginLine()));
file.setAttribute("path", mark.getFilename());
+ file.setAttribute("endline", String.valueOf(mark.getEndLine()));
+ final int beginCol = mark.getBeginColumn();
+ final int endCol = mark.getEndColumn();
+ if (beginCol != -1) {
+ file.setAttribute("column", String.valueOf(beginCol));
+ }
+ if (endCol != -1) {
+ file.setAttribute("endcolumn", String.valueOf(endCol));
+ }
duplication.appendChild(file);
}
return duplication;
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java
index 3310732cb0..4dc054e38a 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java
@@ -58,7 +58,7 @@ public abstract class AntlrTokenizer implements Tokenizer {
}
private void processToken(final Tokens tokenEntries, final String fileName, final AntlrToken token) {
- final TokenEntry tokenEntry = new TokenEntry(token.getImage(), fileName, token.getBeginLine());
+ final TokenEntry tokenEntry = new TokenEntry(token.getImage(), fileName, token.getBeginLine(), token.getBeginColumn() + 1, token.getEndColumn() + 1);
tokenEntries.add(tokenEntry);
}
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java
index 03adab05c5..0672b655f0 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/JavaCCTokenizer.java
@@ -24,7 +24,7 @@ public abstract class JavaCCTokenizer implements Tokenizer {
}
protected TokenEntry processToken(Tokens tokenEntries, GenericToken currentToken, String filename) {
- return new TokenEntry(currentToken.getImage(), filename, currentToken.getBeginLine());
+ return new TokenEntry(currentToken.getImage(), filename, currentToken.getBeginLine(), currentToken.getBeginColumn(), currentToken.getEndColumn());
}
@Override
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java
index aebe05551f..4dcce59fbf 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java
@@ -43,14 +43,14 @@ import net.sourceforge.pmd.lang.dfa.DataFlowNode;
* method return an instance of this sub-interface. For example,
* no JSP node should have a Java node as its child. Embedding nodes from
* different languages will not be done via these methods, and conforming
- * implementations should ensure, that every node returned by these methods
+ * implementations should ensure that every node returned by these methods
* are indeed of the same type. Possibly, a type parameter will be added to
* the Node interface in 7.0.0 to enforce it at compile-time.
*
* A number of methods are deprecated and will be removed in 7.0.0.
* Most of them are implementation details that clutter this API and
* make implementation more difficult. Some methods prefixed with {@code jjt}
- * have a more conventional counterpart (e.g. {@link #getParent()} and
+ * have a more conventional counterpart (e.g. {@link #jjtGetParent()} and
* {@link #getParent()}) that should be preferred.
*/
public interface Node {
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java
index 5f2e1c6915..5e0b0ed42c 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java
@@ -29,6 +29,34 @@ public class MarkTest {
assertEquals(beginLine, mark.getBeginLine());
assertEquals(lineCount, mark.getLineCount());
assertEquals(beginLine + lineCount - 1, mark.getEndLine());
+ assertEquals(-1, mark.getBeginColumn());
+ assertEquals(-1, mark.getEndColumn());
+ assertEquals(codeFragment, mark.getSourceCodeSlice());
+ }
+
+ @Test
+ public void testColumns() {
+ final String filename = "/var/Foo.java";
+ final int beginLine = 1;
+ final int beginColumn = 2;
+ final int endColumn = 3;
+ final TokenEntry token = new TokenEntry("public", "/var/Foo.java", 1, beginColumn, 0);
+ final TokenEntry endToken = new TokenEntry("}", "/var/Foo.java", 5, 0, endColumn);
+
+ final Mark mark = new Mark(token);
+ final int lineCount = 10;
+ mark.setLineCount(lineCount);
+ mark.setEndToken(endToken);
+ final String codeFragment = "code fragment";
+ mark.setSourceCode(new SourceCode(new StringCodeLoader(codeFragment)));
+
+ assertEquals(token, mark.getToken());
+ assertEquals(filename, mark.getFilename());
+ assertEquals(beginLine, mark.getBeginLine());
+ assertEquals(lineCount, mark.getLineCount());
+ assertEquals(beginLine + lineCount - 1, mark.getEndLine());
+ assertEquals(beginColumn, mark.getBeginColumn());
+ assertEquals(endColumn, mark.getEndColumn());
assertEquals(codeFragment, mark.getSourceCodeSlice());
}
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java
index d3e1042ae8..e66a27fb1e 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java
@@ -17,6 +17,19 @@ public class TokenEntryTest {
assertEquals(1, mark.getBeginLine());
assertEquals("/var/Foo.java", mark.getTokenSrcID());
assertEquals(0, mark.getIndex());
+ assertEquals(-1, mark.getBeginColumn());
+ assertEquals(-1, mark.getEndColumn());
+ }
+
+ @Test
+ public void testColumns() {
+ TokenEntry.clearImages();
+ TokenEntry mark = new TokenEntry("public", "/var/Foo.java", 1, 2, 3);
+ assertEquals(1, mark.getBeginLine());
+ assertEquals("/var/Foo.java", mark.getTokenSrcID());
+ assertEquals(0, mark.getIndex());
+ assertEquals(2, mark.getBeginColumn());
+ assertEquals(3, mark.getEndColumn());
}
public static junit.framework.Test suite() {
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 c6307b735a..22eca255a7 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
@@ -78,6 +78,9 @@ public class XMLRendererTest {
if (file != null) {
assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue());
assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue());
+ assertEquals("6", file.getAttributes().getNamedItem("endline").getNodeValue());
+ assertEquals(null, file.getAttributes().getNamedItem("column"));
+ assertEquals(null, file.getAttributes().getNamedItem("endcolumn"));
file = file.getNextSibling();
while (file != null && file.getNodeType() != Node.ELEMENT_NODE) {
file = file.getNextSibling();
@@ -85,6 +88,9 @@ public class XMLRendererTest {
}
if (file != null) {
assertEquals("73", file.getAttributes().getNamedItem("line").getNodeValue());
+ assertEquals("78", file.getAttributes().getNamedItem("endline").getNodeValue());
+ assertEquals(null, file.getAttributes().getNamedItem("column"));
+ assertEquals(null, file.getAttributes().getNamedItem("endcolumn"));
}
assertEquals(1, doc.getElementsByTagName("codefragment").getLength());
assertEquals(codeFragment, doc.getElementsByTagName("codefragment").item(0).getTextContent());
@@ -126,6 +132,54 @@ public class XMLRendererTest {
}
}
+ @Test
+ public void testWithOneDuplicationWithColumns() throws IOException {
+ CPDRenderer renderer = new XMLRenderer();
+ List list = new ArrayList<>();
+ int lineCount = 6;
+ String codeFragment = "code\nfragment";
+ Mark mark1 = createMark("public", "/var/Foo.java", 1, lineCount, codeFragment, 2, 3);
+ Mark mark2 = createMark("stuff", "/var/Foo.java", 73, lineCount, codeFragment, 4, 5);
+ Match match = new Match(75, mark1, mark2);
+
+ list.add(match);
+ StringWriter sw = new StringWriter();
+ renderer.render(list.iterator(), sw);
+ String report = sw.toString();
+ try {
+ Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(new ByteArrayInputStream(report.getBytes(ENCODING)));
+ NodeList dupes = doc.getElementsByTagName("duplication");
+ assertEquals(1, dupes.getLength());
+ Node file = dupes.item(0).getFirstChild();
+ while (file != null && file.getNodeType() != Node.ELEMENT_NODE) {
+ file = file.getNextSibling();
+ }
+ if (file != null) {
+ assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue());
+ assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue());
+ assertEquals("6", file.getAttributes().getNamedItem("endline").getNodeValue());
+ assertEquals("2", file.getAttributes().getNamedItem("column").getNodeValue());
+ assertEquals("3", file.getAttributes().getNamedItem("endcolumn").getNodeValue());
+ file = file.getNextSibling();
+ while (file != null && file.getNodeType() != Node.ELEMENT_NODE) {
+ file = file.getNextSibling();
+ }
+ }
+ if (file != null) {
+ assertEquals("73", file.getAttributes().getNamedItem("line").getNodeValue());
+ assertEquals("78", file.getAttributes().getNamedItem("endline").getNodeValue());
+ assertEquals("4", file.getAttributes().getNamedItem("column").getNodeValue());
+ assertEquals("5", file.getAttributes().getNamedItem("endcolumn").getNodeValue());
+ }
+ assertEquals(1, doc.getElementsByTagName("codefragment").getLength());
+ assertEquals(codeFragment, doc.getElementsByTagName("codefragment").item(0).getTextContent());
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+
@Test
public void testRendererEncodedPath() throws IOException {
CPDRenderer renderer = new XMLRenderer();
@@ -135,7 +189,7 @@ public class XMLRendererTest {
Mark mark2 = createMark("void", "/var/F 0) {
tokenEntries.add(new TokenEntry(String.valueOf(currentToken.kind), sourceCode.getFileName(),
- currentToken.beginLine));
+ currentToken.beginLine, currentToken.beginColumn, currentToken.endColumn));
currentToken = (Token) tokenMgr.getNextToken();
}
} catch (IOException e) {
diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java
index b44122309b..40126ce624 100644
--- a/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java
+++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/cpd/PLSQLTokenizer.java
@@ -68,7 +68,8 @@ public class PLSQLTokenizer extends JavaCCTokenizer {
image = String.valueOf(plsqlToken.kind);
}
- return new TokenEntry(image, fileName, currentToken.getBeginLine());
+ return new TokenEntry(image, fileName, currentToken.getBeginLine(),
+ currentToken.getBeginColumn(), currentToken.getEndColumn());
}
@Override
diff --git a/pmd-scala/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenizer.java b/pmd-scala/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenizer.java
index 7706e48d31..94c48abdc2 100644
--- a/pmd-scala/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenizer.java
+++ b/pmd-scala/src/main/java/net/sourceforge/pmd/cpd/ScalaTokenizer.java
@@ -17,6 +17,7 @@ import net.sourceforge.pmd.lang.scala.ScalaLanguageModule;
import scala.collection.Iterator;
import scala.meta.Dialect;
import scala.meta.inputs.Input;
+import scala.meta.inputs.Position;
import scala.meta.internal.tokenizers.ScalametaTokenizer;
import scala.meta.tokens.Token;
@@ -74,7 +75,9 @@ public class ScalaTokenizer implements Tokenizer {
Token token;
while ((token = filter.getNextToken()) != null) {
String tokenText = token.text() != null ? token.text() : token.name();
- TokenEntry cpdToken = new TokenEntry(tokenText, filename, token.pos().startLine());
+ Position tokenPosition = token.pos();
+ TokenEntry cpdToken = new TokenEntry(tokenText, filename, tokenPosition.startLine(),
+ tokenPosition.startColumn(), tokenPosition.endColumn());
tokenEntries.add(cpdToken);
}
} finally {
diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java
index 9ddce331de..13febc7b90 100644
--- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java
+++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/cpd/VfTokenizer.java
@@ -34,7 +34,7 @@ public class VfTokenizer implements Tokenizer {
while (currentToken.image.length() > 0) {
tokenEntries.add(new TokenEntry(String.valueOf(currentToken.kind), sourceCode.getFileName(),
- currentToken.beginLine));
+ currentToken.beginLine, currentToken.beginColumn, currentToken.endColumn));
currentToken = (Token) tokenMgr.getNextToken();
}
} catch (IOException e) {