Merge branch 'pr-1198'
This commit is contained in:
commit
2d6a599bb1
10 files changed
+650
-236
No files matched your search
@@ -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>*/</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>*/</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>*/</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", " ");
|
||||
|
||||
+25
-115
@@ -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);
|
||||
}
|
||||
}
|
||||
+18
@@ -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")
|
||||
|
||||
Reference in new issue
Block a user