Merge branch 'pr-1198'

This commit is contained in:
Juan Martín Sotuyo Dodero committed 2018-06-24 19:09:30 -03:00
commit 2d6a599bb1
10 files changed
+650 -236

No files matched your search

+15
View File
@@ -42,6 +42,8 @@ This is a minor release.
* [#1193](https://github.com/pmd/pmd/issues/1193): \[core] Designer doesn't start with run.sh
* ecmascript
* [#861](https://github.com/pmd/pmd/issues/861): \[ecmascript] InnaccurateNumericLiteral false positive with hex literals
* java
* [#1174](https://github.com/pmd/pmd/issues/1174): \[java] CommentUtil.multiLinesIn() could lead to StringIndexOutOfBoundsException
* java-bestpractices
* [#651](https://github.com/pmd/pmd/issues/651): \[java] SwitchStmtsShouldHaveDefault should be aware of enum types
* [#869](https://github.com/pmd/pmd/issues/869): \[java] GuardLogStatement false positive on return statements and Math.log
@@ -55,6 +57,19 @@ This is a minor release.
### API Changes
* The utility class `net.sourceforge.pmd.lang.java.ast.CommentUtil` has been deprecated and will be removed
with PMD 7.0.0. Its methods have been intended to parse javadoc tags. A more useful solution will be added
around the AST node `FormalComment`, which contains as children `JavadocElement` nodes, which in
turn provide access to the `JavadocTag`.
All comment AST nodes (`FormalComment`, `MultiLineComment`, `SingleLineComment`) have a new method
`getFilteredComment()` which provide access to the comment text without the leading `/*` markers.
* The method `AbstractCommentRule.tagsIndicesIn()` has been deprecated and will be removed with
PMD 7.0.0. It is not very useful, since it doesn't extract the information
in a useful way. You would still need check, which tags have been found, and with which
data they might be accompanied.
### External Contributions
* [#836](https://github.com/pmd/pmd/pull/836): \[apex] Add a rule to prevent use of non-existent annotations - [anand13s](https://github.com/anand13s)
@@ -5,22 +5,28 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.lang.ast.AbstractNode;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.javadoc.JavadocTag;
public abstract class Comment extends AbstractNode {
// single regex, that captures: the start of a multi-line comment (/**|/*), the start of a single line comment (//)
// or the start of line within a multine comment (*). It removes the end of the comment (*/) if existing.
private static final Pattern COMMENT_LINE_COMBINED = Pattern.compile("^(?://|/\\*\\*?|\\*)?(.*?)(?:\\*/|/)?$");
// Same as "\\R" - but \\R is only available with java8+
static final Pattern NEWLINES_PATTERN = Pattern.compile("\\u000D\\u000A|[\\u000A\\u000B\\u000C\\u000D\\u0085\\u2028\\u2029]");
protected Comment(Token t) {
super(-1, t.beginLine, t.endLine, t.beginColumn, t.endColumn);
setImage(t.image);
if (t.image.startsWith("/**")) {
findJavadocs(t.image);
}
}
@Override
@@ -28,22 +34,76 @@ public abstract class Comment extends AbstractNode {
return getImage();
}
private void findJavadocs(String commentText) {
Collection<JavadocElement> kids = new ArrayList<>();
Map<String, Integer> tags = CommentUtil.javadocTagsIn(commentText);
for (Map.Entry<String, Integer> entry : tags.entrySet()) {
JavadocTag tag = JavadocTag.tagFor(entry.getKey());
if (tag == null) {
continue;
}
kids.add(new JavadocElement(getBeginLine(), getBeginLine(),
// TODO valid?
entry.getValue() + 1, entry.getValue() + tag.label.length() + 1, tag));
}
children = kids.toArray(new Node[0]);
/**
* Filters the comment by removing the leading comment marker (like {@code *}) of each line
* as well as the start markers ({@code //}, {@code /*} or {@code /**}
* and the end markers (<code>&#x2a;/</code>).
* Also leading and trailing empty lines are removed.
*
* @return the filtered comment
*/
public String getFilteredComment() {
List<String> lines = multiLinesIn();
lines = trim(lines);
return StringUtils.join(lines, PMD.EOL);
}
/**
* Removes the leading comment marker (like {@code *}) of each line
* of the comment as well as the start marker ({@code //}, {@code /*} or {@code /**}
* and the end markers (<code>&#x2a;/</code>).
*
* @param comment the raw comment
* @return List of lines of the comments
*/
private List<String> multiLinesIn() {
String[] lines = NEWLINES_PATTERN.split(getImage());
List<String> filteredLines = new ArrayList<>(lines.length);
for (String rawLine : lines) {
String line = rawLine.trim();
Matcher allMatcher = COMMENT_LINE_COMBINED.matcher(line);
if (allMatcher.matches()) {
filteredLines.add(allMatcher.group(1).trim());
}
}
return filteredLines;
}
/**
* Similar to the String.trim() function, this one removes the leading and
* trailing empty/blank lines from the line list.
*
* @param lines the list of lines, which might contain empty lines
* @return the lines without leading or trailing blank lines.
*/
// note: this is only package private, since it is used by CommentUtil. Once CommentUtil is gone, this
// can be private
static List<String> trim(List<String> lines) {
if (lines == null) {
return Collections.emptyList();
}
List<String> result = new ArrayList<>(lines.size());
List<String> tempList = new ArrayList<>();
boolean foundFirstNonEmptyLine = false;
for (String line : lines) {
if (StringUtils.isNotBlank(line)) {
// new non-empty line: add all previous empty lines occurred before
result.addAll(tempList);
tempList.clear();
result.add(line);
foundFirstNonEmptyLine = true;
} else {
if (foundFirstNonEmptyLine) {
// add the empty line to a temporary list first
tempList.add(line);
}
}
}
return result;
}
}
@@ -4,9 +4,7 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -15,18 +13,41 @@ import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import net.sourceforge.pmd.lang.java.javadoc.JavadocTag;
/**
*
* @deprecated This utility class is deprecated and will be removed with PMD 7.0.0.
* Its methods have been intended to parse javadoc tags.
* A more useful solution will be added around the AST node {@link FormalComment},
* which contains as children {@link JavadocElement} nodes, which in
* turn provide access to the {@link JavadocTag}.
*/
@Deprecated // will be remove with PMD 7.0.0
public final class CommentUtil {
private static final String CR = "\n";
private static final Pattern JAVADOC_TAG = Pattern.compile("@[A-Za-z0-9]+");
private static final Map<String, String> JAVADOC_CACHE = new HashMap<>();
private CommentUtil() {
}
/**
* Gets the next word (characters until next whitespace, punctuation,
* or anything that is not a letter or digit) at the given position.
*
* @param text the complete text
* @param position the position, at which the word starts
* @return the word
*
* @deprecated This method is deprecated and will be removed with PMD 7.0.0.
* This method has been intended to parse javadoc tags.
* A more useful solution will be added around the AST node {@link FormalComment},
* which contains as children {@link JavadocElement} nodes, which in
* turn provide access to the {@link JavadocTag}.
*/
@Deprecated // will be removed with PMD 7.0.0
public static String wordAfter(String text, int position) {
if (position >= text.length()) {
if (text == null || position >= text.length()) {
return null;
}
int newposition = position + 1;
@@ -40,11 +61,28 @@ public final class CommentUtil {
return text.substring(newposition, end);
}
/**
* Gets the remaining line after a specific position.
*
* @param text the complete text
* @param position the position from which the comment should be returned
* @return the part of the text
*
* @deprecated This method is deprecated and will be removed with PMD 7.0.0.
* This method has been intended to parse javadoc tags.
* A more useful solution will be added around the AST node {@link FormalComment},
* which contains as children {@link JavadocElement} nodes, which in
* turn provide access to the {@link JavadocTag}.
*/
@Deprecated // will be removed with PMD 7.0.0
public static String javadocContentAfter(String text, int position) {
if (text == null || position > text.length()) {
return null;
}
int endPos = text.indexOf('\n', position);
if (endPos < 0) {
return null;
endPos = text.length();
}
if (StringUtils.isNotBlank(text.substring(position, endPos))) {
@@ -65,108 +103,69 @@ public final class CommentUtil {
return null;
}
/**
* Finds all the javadoc tags in the (formal) comment.
* Returns a map from javadoc tag to index position.
*
* <p>Note: If a tag is used multiple times, the last occurrence is returned.
*
* @param comment the raw comment
* @return mapping of javadoc tag to index position
*
* @deprecated This method is deprecated and will be removed with PMD 7.0.0.
* This method has been intended to parse javadoc tags.
* A more useful solution will be added around the AST node {@link FormalComment},
* which contains as children {@link JavadocElement} nodes, which in
* turn provide access to the {@link JavadocTag}.
*/
@Deprecated // will be removed with PMD 7.0.0
public static Map<String, Integer> javadocTagsIn(String comment) {
Matcher m = JAVADOC_TAG.matcher(comment);
Map<String, Integer> tags = null;
while (m.find()) {
if (tags == null) {
tags = new HashMap<>();
Map<String, Integer> tags = new HashMap<>();
if (comment != null) {
Matcher m = JAVADOC_TAG.matcher(comment);
while (m.find()) {
String match = comment.substring(m.start() + 1, m.end());
tags.put(match, m.start());
}
String match = comment.substring(m.start() + 1, m.end());
String tag = JAVADOC_CACHE.get(match);
if (tag == null) {
JAVADOC_CACHE.put(match, match);
}
tags.put(tag, m.start());
}
if (tags == null) {
return Collections.emptyMap();
}
return tags;
}
/**
* Removes the leading comment marker (like {@code *}) of each line
* of the comment as well as the start marker ({@code //}, {@code /*} or {@code /**}
* and the end markers (<code>&#x2a;/</code>).
*
* @param comment the raw comment
* @return List of lines of the comments
*
* @deprecated This method will be removed with PMD 7.0.0.
* It has been replaced by {@link Comment#getFilteredComment()}.
*/
@Deprecated // will be removed with PMD 7.0.0
public static List<String> multiLinesIn(String comment) {
String[] lines = comment.split(CR);
List<String> filteredLines = new ArrayList<>(lines.length);
for (String rawLine : lines) {
String line = rawLine.trim();
if (line.startsWith("//")) {
filteredLines.add(line.substring(2));
continue;
}
if (line.endsWith("*/")) {
int end = line.length() - 2;
int start = line.startsWith("/**") ? 3 : line.startsWith("/*") ? 2 : 0;
filteredLines.add(line.substring(start, end));
continue;
}
if (line.charAt(0) == '*') {
filteredLines.add(line.substring(1));
continue;
}
if (line.startsWith("/**")) {
filteredLines.add(line.substring(3));
continue;
}
if (line.startsWith("/*")) {
filteredLines.add(line.substring(2));
continue;
}
filteredLines.add(line);
}
return filteredLines;
// temporary createa a Multiline Comment Node
Token t = new Token();
t.image = comment;
MultiLineComment node = new MultiLineComment(t);
return Arrays.asList(Comment.NEWLINES_PATTERN.split(node.getFilteredComment()));
}
/**
* Similar to the String.trim() function, this one removes the leading and
* trailing empty/blank lines from the line list.
*
* @param lines
* @param lines the list of lines, which might contain empty lines
* @return the lines without leading or trailing blank lines.
*
* @deprecated This method will be removed with PMD 7.0.0.
* It is not needed anymore, since {@link Comment#getFilteredComment()}
* returns already the filtered and trimmed comment text.
*/
@Deprecated // will be removed with PMD 7.0.0
public static List<String> trim(List<String> lines) {
int firstNonEmpty = 0;
for (; firstNonEmpty < lines.size(); firstNonEmpty++) {
if (StringUtils.isNotBlank(lines.get(firstNonEmpty))) {
break;
}
}
// all of them empty?
if (firstNonEmpty == lines.size()) {
return Collections.emptyList();
}
int lastNonEmpty = lines.size() - 1;
for (; lastNonEmpty > 0; lastNonEmpty--) {
if (StringUtils.isNotBlank(lines.get(lastNonEmpty))) {
break;
}
}
List<String> filtered = new ArrayList<>();
for (int i = firstNonEmpty; i < lastNonEmpty; i++) {
filtered.add(lines.get(i));
}
return filtered;
}
public static void main(String[] args) {
Collection<String> tags = javadocTagsIn(args[0]).keySet();
for (String tag : tags) {
System.out.println(tag);
}
return Comment.trim(lines);
}
}
@@ -4,15 +4,43 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.javadoc.JavadocTag;
public class FormalComment extends Comment {
private static final Pattern JAVADOC_TAG = Pattern.compile("@([A-Za-z0-9]+)");
public FormalComment(Token t) {
super(t);
}
findJavadocs();
}
@Override
public String getXPathNodeName() {
return "FormalComment";
}
private void findJavadocs() {
Collection<JavadocElement> kids = new ArrayList<>();
Matcher javadocTagMatcher = JAVADOC_TAG.matcher(getFilteredComment());
while (javadocTagMatcher.find()) {
JavadocTag tag = JavadocTag.tagFor(javadocTagMatcher.group(1));
int tagStartIndex = javadocTagMatcher.start(1);
if (tag != null) {
kids.add(new JavadocElement(getBeginLine(), getBeginLine(),
// TODO valid?
tagStartIndex, tagStartIndex + tag.label.length() + 1, tag));
}
}
children = kids.toArray(new Node[0]);
}
}
@@ -24,7 +24,7 @@ public final class JavadocTag {
"Indicates that an item is a member of the deprecated API");
public static final JavadocTag PARAM = new JavadocTag("param", " ");
public static final JavadocTag THROWS = new JavadocTag("throws", " ");
public static final JavadocTag RETURN = new JavadocTag("returns", " ");
public static final JavadocTag RETURN = new JavadocTag("return", " ");
public static final JavadocTag SEE = new JavadocTag("see", " ");
/* public static final JavadocTag POST = new JavadocTag("post", " ");
@@ -5,14 +5,12 @@
package net.sourceforge.pmd.lang.java.rule.documentation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.commons.lang3.StringUtils;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
@@ -24,130 +22,42 @@ import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;
import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessTypeNode;
import net.sourceforge.pmd.lang.java.ast.Comment;
import net.sourceforge.pmd.lang.java.ast.CommentUtil;
import net.sourceforge.pmd.lang.java.ast.FormalComment;
import net.sourceforge.pmd.lang.java.ast.MultiLineComment;
import net.sourceforge.pmd.lang.java.ast.SingleLineComment;
import net.sourceforge.pmd.lang.java.ast.JavadocElement;
import net.sourceforge.pmd.lang.java.javadoc.JavadocTag;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
/**
*
*
* @author Brian Remedios
*/
public abstract class AbstractCommentRule extends AbstractJavaRule {
/**
* Returns a list of indices of javadoc tag occurrences in the comment.
*
* <p>Note: if the same tag occurs multiple times, only the last occurrence is returned.
*
* @param comments the complete comment text
* @return list of indices.
*
* @deprecated This method is deprecated and will be removed with PMD 7.0.0.
* It is not very useful, since it doesn't extract the information
* in a useful way. You would still need check, which tags have been found, and with which
* data they might be accompanied.
* A more useful solution will be added around the AST node {@link FormalComment},
* which contains as children {@link JavadocElement} nodes, which in
* turn provide access to the {@link JavadocTag}.
*/
@Deprecated // the method will be removed with PMD 7.0.0
protected List<Integer> tagsIndicesIn(String comments) {
int atPos = comments.indexOf('@');
if (atPos < 0) {
return Collections.emptyList();
}
List<Integer> ints = new ArrayList<>();
ints.add(atPos);
atPos = comments.indexOf('@', atPos + 1);
while (atPos >= 0) {
ints.add(atPos);
atPos = comments.indexOf('@', atPos + 1);
}
return ints;
Map<String, Integer> tags = CommentUtil.javadocTagsIn(comments);
return new ArrayList<>(tags.values());
}
protected String filteredCommentIn(Comment comment) {
String trimmed = comment.getImage().trim();
if (comment instanceof SingleLineComment) {
return singleLineIn(trimmed);
}
if (comment instanceof MultiLineComment) {
return multiLinesIn(trimmed);
}
if (comment instanceof FormalComment) {
return formalLinesIn(trimmed);
}
return trimmed; // should never reach here
}
private String singleLineIn(String comment) {
if (comment.startsWith("//")) {
return comment.substring(2);
}
return comment;
}
private static String asSingleString(List<String> lines) {
StringBuilder sb = new StringBuilder();
for (String line : lines) {
if (StringUtils.isBlank(line)) {
continue;
}
sb.append(line).append('\n');
}
return sb.toString().trim();
}
private static String multiLinesIn(String comment) {
String[] lines = comment.split("\n");
List<String> filteredLines = new ArrayList<>(lines.length);
for (String rawLine : lines) {
String line = rawLine.trim();
if (line.endsWith("*/")) {
int end = line.length() - 2;
int start = line.startsWith("/*") ? 2 : 0;
filteredLines.add(line.substring(start, end));
continue;
}
if (line.length() > 0 && line.charAt(0) == '*') {
filteredLines.add(line.substring(1));
continue;
}
if (line.startsWith("/*")) {
filteredLines.add(line.substring(2));
continue;
}
}
return asSingleString(filteredLines);
}
private String formalLinesIn(String comment) {
String[] lines = comment.split("\n");
List<String> filteredLines = new ArrayList<>(lines.length);
for (String origLine : lines) {
String line = origLine.trim();
if (line.endsWith("*/")) {
filteredLines.add(line.substring(0, line.length() - 2));
continue;
}
if (line.length() > 0 && line.charAt(0) == '*') {
filteredLines.add(line.substring(1));
continue;
}
if (line.startsWith("/**")) {
filteredLines.add(line.substring(3));
continue;
}
}
return asSingleString(filteredLines);
return comment.getFilteredComment();
}
protected void assignCommentsToDeclarations(ASTCompilationUnit cUnit) {
@@ -0,0 +1,110 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Test;
import net.sourceforge.pmd.PMD;
public class CommentTest {
@Test
public void testMultiLinesInSingleLine() {
String comment = "/* single line. */";
String filtered = filter(comment);
Assert.assertEquals(1, lineCount(filtered));
Assert.assertEquals("single line.", filtered);
}
@Test
public void testMultiLinesInSingleLineSimple() {
String comment = "// single line.";
String filtered = filter(comment);
Assert.assertEquals(1, lineCount(filtered));
Assert.assertEquals("single line.", filtered);
}
@Test
public void testMultiLinesInSingleLineFormal() {
String comment = "/** single line. */";
String filtered = filter(comment);
Assert.assertEquals(1, lineCount(filtered));
Assert.assertEquals("single line.", filtered);
}
@Test
public void testMultiLinesInMultiLine() {
String comment =
"/*\n"
+ " * line 1\n"
+ " * line 2\n"
+ " */\n";
String filtered = filter(comment);
Assert.assertEquals(2, lineCount(filtered));
Assert.assertEquals("line 1" + PMD.EOL + "line 2", filtered);
}
@Test
public void testMultiLinesInMultiLineCrLf() {
String comment =
"/*\r\n"
+ " * line 1\r\n"
+ " * line 2\r\n"
+ " */\r\n";
String filtered = filter(comment);
Assert.assertEquals(2, lineCount(filtered));
Assert.assertEquals("line 1" + PMD.EOL + "line 2", filtered);
}
@Test
public void testMultiLinesInMultiLineFormal() {
String comment =
"/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " */\n";
String filtered = filter(comment);
Assert.assertEquals(2, lineCount(filtered));
Assert.assertEquals("line 1" + PMD.EOL + "line 2", filtered);
}
@Test
public void testMultiLinesInMultiLineFormalCrLf() {
String comment =
"/**\r\n"
+ " * line 1\r\n"
+ " * line 2\r\n"
+ " */\r\n";
String filtered = filter(comment);
Assert.assertEquals(2, lineCount(filtered));
Assert.assertEquals("line 1" + PMD.EOL + "line 2", filtered);
}
@Test
public void testMultiLinesInMultiLineNoAsteriskEmpty() {
String comment =
"/**\n"
+ " * line 1\n"
+ "line 2\n"
+ "\n"
+ " */\n";
String filtered = filter(comment);
Assert.assertEquals(2, lineCount(filtered));
Assert.assertEquals("line 1" + PMD.EOL + "line 2", filtered);
}
private String filter(String comment) {
Token t = new Token();
t.image = comment;
Comment node = new Comment(t) {
};
return node.getFilteredComment();
}
private int lineCount(String filtered) {
return StringUtils.countMatches(filtered, PMD.EOL) + 1;
}
}
@@ -0,0 +1,238 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
public class CommentUtilTest {
@Test
public void testFindJavaDocTags() {
String formalComment =
"/**\n"
+ " * @see something\n"
+ " * @author Author1\n"
+ " * @author Author2\n"
+ " * @param parm1 description\n"
+ " */\n";
Map<String, Integer> javadocTagsIn = CommentUtil.javadocTagsIn(formalComment);
Assert.assertEquals(3, javadocTagsIn.size());
Assert.assertEquals(7, javadocTagsIn.get("see").intValue());
Assert.assertEquals("@see", formalComment.substring(7, 7 + 4));
Assert.assertEquals("@author", formalComment.substring(javadocTagsIn.get("author"),
javadocTagsIn.get("author") + "author".length() + 1));
}
@Test
public void testFindJavaDocTagsEmpty() {
Map<String, Integer> javadocTagsIn = CommentUtil.javadocTagsIn("");
Assert.assertEquals(0, javadocTagsIn.size());
}
@Test
public void testFindJavaDocTagsNull() {
Map<String, Integer> javadocTagsIn = CommentUtil.javadocTagsIn(null);
Assert.assertEquals(0, javadocTagsIn.size());
}
@Test
public void testMultiLinesInSingleLine() {
String comment = "/* single line. */";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(1, lines.size());
Assert.assertEquals("single line.", lines.get(0));
}
@Test
public void testMultiLinesInSingleLineSimple() {
String comment = "// single line.";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(1, lines.size());
Assert.assertEquals("single line.", lines.get(0));
}
@Test
public void testMultiLinesInSingleLineFormal() {
String comment = "/** single line. */";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(1, lines.size());
Assert.assertEquals("single line.", lines.get(0));
}
@Test
public void testMultiLinesInMultiLine() {
String comment =
"/*\n"
+ " * line 1\n"
+ " * line 2\n"
+ " */\n";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(2, lines.size());
Assert.assertEquals("line 1", lines.get(0));
Assert.assertEquals("line 2", lines.get(1));
}
@Test
public void testMultiLinesInMultiLineCrLf() {
String comment =
"/*\r\n"
+ " * line 1\r\n"
+ " * line 2\r\n"
+ " */\r\n";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(2, lines.size());
Assert.assertEquals("line 1", lines.get(0));
Assert.assertEquals("line 2", lines.get(1));
}
@Test
public void testMultiLinesInMultiLineFormal() {
String comment =
"/**\n"
+ " * line 1\n"
+ " * line 2\n"
+ " */\n";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(2, lines.size());
Assert.assertEquals("line 1", lines.get(0));
Assert.assertEquals("line 2", lines.get(1));
}
@Test
public void testMultiLinesInMultiLineFormalCrLf() {
String comment =
"/**\r\n"
+ " * line 1\r\n"
+ " * line 2\r\n"
+ " */\r\n";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(2, lines.size());
Assert.assertEquals("line 1", lines.get(0));
Assert.assertEquals("line 2", lines.get(1));
}
@Test
public void testMultiLinesInMultiLineNoAsteriskEmpty() {
String comment =
"/**\n"
+ " * line 1\n"
+ "line 2\n"
+ "\n"
+ " */\n";
List<String> lines = CommentUtil.multiLinesIn(comment);
Assert.assertEquals(2, lines.size());
Assert.assertEquals("line 1", lines.get(0));
Assert.assertEquals("line 2", lines.get(1));
}
@Test
public void testTrim() {
List<String> lines = Arrays.asList("", "a", "", "");
List<String> trimmed = CommentUtil.trim(lines);
Assert.assertEquals(1, trimmed.size());
Assert.assertEquals("a", trimmed.get(0));
}
@Test
public void testTrimNotMiddle() {
List<String> lines = Arrays.asList("a", "b", "", "c");
List<String> trimmed = CommentUtil.trim(lines);
Assert.assertEquals(4, trimmed.size());
Assert.assertEquals("a", trimmed.get(0));
Assert.assertEquals("b", trimmed.get(1));
Assert.assertEquals("", trimmed.get(2));
Assert.assertEquals("c", trimmed.get(3));
}
@Test
public void testTrimEmpty() {
List<String> trimmed = CommentUtil.trim(new ArrayList<String>());
Assert.assertEquals(0, trimmed.size());
}
@Test
public void testTrimNull() {
List<String> trimmed = CommentUtil.trim(null);
Assert.assertEquals(0, trimmed.size());
}
@Test
public void testWordAfter() {
String wordAfter = CommentUtil.wordAfter("@param param1 Description", "@param".length());
Assert.assertEquals("param1", wordAfter);
}
@Test
public void testWordAfterPositionOutOfBounds() {
String wordAfter = CommentUtil.wordAfter("@param param1 Description", Integer.MAX_VALUE);
Assert.assertNull(wordAfter);
}
@Test
public void testWordAfterNull() {
String wordAfter = CommentUtil.wordAfter(null, 0);
Assert.assertNull(wordAfter);
}
@Test
public void testJavadocAfter() {
String javadocContentAfter = CommentUtil.javadocContentAfter("@param param1 The Description\n",
"@param param1".length());
Assert.assertEquals("The Description", javadocContentAfter);
}
@Test
public void testJavadocAfterOutOfBounds() {
String javadocContentAfter = CommentUtil.javadocContentAfter("@param param1 The Description\n",
Integer.MAX_VALUE);
Assert.assertNull(javadocContentAfter);
}
@Test
public void testJavadocAfterNull() {
String javadocContentAfter = CommentUtil.javadocContentAfter(null, 0);
Assert.assertNull(javadocContentAfter);
}
@Test
public void testJavadoc() {
String comment = " /**\n"
+ " * Checks if the metric can be computed on the node.\n"
+ " *\n"
+ " * @param node The node to check\n"
+ " *\n"
+ " * @return True if the metric can be computed\n"
+ " */\n"
+ " boolean supports(N node);\n"
+ "";
List<String> lines = CommentUtil.multiLinesIn(comment);
lines = CommentUtil.trim(lines);
for (String line : lines) {
Map<String, Integer> tags = CommentUtil.javadocTagsIn(line);
for (String tag : tags.keySet()) {
int pos = tags.get(tag) + tag.length() + 1;
String wordAfter = CommentUtil.wordAfter(line, pos);
pos = pos + wordAfter.length() + 1;
String description = CommentUtil.javadocContentAfter(line, pos);
if ("param".equals(tag)) {
Assert.assertEquals("node", wordAfter); // the parameter name
Assert.assertEquals("The node to check", description);
} else if ("return".equals(tag)) {
Assert.assertEquals("True", wordAfter);
Assert.assertEquals("if the metric can be computed", description);
}
}
}
}
}
@@ -0,0 +1,36 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import org.junit.Assert;
import org.junit.Test;
public class FormalCommentTest {
@Test
public void testJavadocTagsAsChildren() {
String comment = " /**\n"
+ " * Checks if the metric can be computed on the node.\n"
+ " *\n"
+ " * @param node The node to check\n"
+ " *\n"
+ " * @return True if the metric can be computed\n"
+ " */\n"
+ " boolean supports(N node);\n"
+ "";
Token token = new Token();
token.image = comment;
FormalComment commentNode = new FormalComment(token);
Assert.assertEquals(2, commentNode.jjtGetNumChildren());
JavadocElement paramTag = (JavadocElement) commentNode.jjtGetChild(0);
Assert.assertEquals("param", paramTag.tag().label);
JavadocElement returnTag = (JavadocElement) commentNode.jjtGetChild(1);
Assert.assertEquals("return", returnTag.tag().label);
}
}
@@ -44,6 +44,24 @@ public class AbstractCommentRuleTest {
assertEquals("a formal comment with blank lines", filtered);
}
@Test
public void testTagsIndicesIn() {
String comment = " /**\n"
+ " * Checks if the metric can be computed on the node.\n"
+ " *\n"
+ " * @param node The node to check\n"
+ " *\n"
+ " * @return True if the metric can be computed\n"
+ " */\n"
+ " boolean supports(N node);\n"
+ "";
List<Integer> indices = testSubject.tagsIndicesIn(comment);
Assert.assertEquals(2, indices.size());
Assert.assertEquals(79, indices.get(0).intValue());
Assert.assertEquals(123, indices.get(1).intValue());
}
@Test
public void testCommentAssignments() {
LanguageVersionHandler handler = LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.8")