Fixed false positive in UnusedImports: javadoc comments are parsed to check @see and other tags
git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/branches/pmd/4.2.x@6018 51baf565-9d33-0410-a72c-fc3788e3496d
This commit is contained in:
@ -1,3 +1,7 @@
|
||||
???? - 4.2.2:
|
||||
|
||||
Fixed false positive in UnusedImports: javadoc comments are parsed to check @see and other tags
|
||||
|
||||
April 11, 2008 - 4.2.1:
|
||||
|
||||
'41' and '42' shortcuts for rulesets added
|
||||
|
@ -163,6 +163,8 @@ public class JavaParser {
|
||||
}
|
||||
PARSER_END(JavaParser)
|
||||
TOKEN_MGR_DECLS : {
|
||||
protected List<Token> formalComments = new ArrayList<Token>();
|
||||
|
||||
private Map<Integer, String> excludeMap = new HashMap<Integer, String>();
|
||||
private String excludeMarker = PMD.EXCLUDE_MARKER;
|
||||
|
||||
@ -204,7 +206,7 @@ MORE :
|
||||
<IN_FORMAL_COMMENT>
|
||||
SPECIAL_TOKEN :
|
||||
{
|
||||
<FORMAL_COMMENT: "*/" > : DEFAULT
|
||||
<FORMAL_COMMENT: "*/" > { formalComments.add(matchedToken); } : DEFAULT
|
||||
}
|
||||
|
||||
<IN_MULTI_LINE_COMMENT>
|
||||
@ -1077,6 +1079,7 @@ ASTCompilationUnit CompilationUnit() :
|
||||
( < "~[]" > )?
|
||||
<EOF>
|
||||
{
|
||||
jjtThis.setFormalComments(token_source.formalComments);
|
||||
return jjtThis;
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,27 @@ On demand import
|
||||
import java.util.*;
|
||||
public class Foo {
|
||||
List list = new ArrayList();
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
imports used in javadoc comment
|
||||
]]></description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.File;
|
||||
public class Foo {
|
||||
/**
|
||||
* {@linkplain List list}
|
||||
* {@link ArrayList arraylist}
|
||||
* {@value Calendar#DATE}
|
||||
* @see File
|
||||
*/
|
||||
public void test() {}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
@ -154,4 +154,25 @@ public class Foo {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
imports used in javadoc comment
|
||||
]]></description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.File;
|
||||
public class Foo {
|
||||
/**
|
||||
* {@linkplain List list}
|
||||
* {@link ArrayList arraylist}
|
||||
* {@value Calendar#DATE}
|
||||
* @see File
|
||||
*/
|
||||
public void test() {}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
package net.sourceforge.pmd.ast;
|
||||
|
||||
import java.util.List;
|
||||
import net.sourceforge.pmd.typeresolution.ClassTypeResolver;
|
||||
|
||||
// FUTURE Change this class to extend from SimpleJavaNode, as TypeNode is not appropriate (unless I'm wrong)
|
||||
@ -17,6 +18,15 @@ public class ASTCompilationUnit extends SimpleJavaTypeNode implements Compilatio
|
||||
super(p, id);
|
||||
}
|
||||
|
||||
private List<Token> formalComments;
|
||||
|
||||
public List<Token> getFormalComments() {
|
||||
return formalComments;
|
||||
}
|
||||
|
||||
public void setFormalComments(List<Token> formalComments) {
|
||||
this.formalComments = formalComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept the visitor. *
|
||||
|
@ -169,6 +169,7 @@ public class JavaParser/*@bgen(jjtree)*/implements JavaParserTreeConstants, Java
|
||||
jj_consume_token(0);
|
||||
jjtree.closeNodeScope(jjtn000, true);
|
||||
jjtc000 = false;
|
||||
jjtn000.setFormalComments(token_source.formalComments);
|
||||
{if (true) return jjtn000;}
|
||||
} catch (Throwable jjte000) {
|
||||
if (jjtc000) {
|
||||
@ -8001,6 +8002,15 @@ jjtn000.setModifiers(modifiers);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean jj_3R_188() {
|
||||
if (jj_scan_token(WHILE)) return true;
|
||||
if (jj_scan_token(LPAREN)) return true;
|
||||
if (jj_3R_88()) return true;
|
||||
if (jj_scan_token(RPAREN)) return true;
|
||||
if (jj_3R_91()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean jj_3_1() {
|
||||
Token xsp;
|
||||
while (true) {
|
||||
@ -8011,15 +8021,6 @@ jjtn000.setModifiers(modifiers);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean jj_3R_188() {
|
||||
if (jj_scan_token(WHILE)) return true;
|
||||
if (jj_scan_token(LPAREN)) return true;
|
||||
if (jj_3R_88()) return true;
|
||||
if (jj_scan_token(RPAREN)) return true;
|
||||
if (jj_3R_91()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean jj_3_44() {
|
||||
if (jj_3R_74()) return true;
|
||||
return false;
|
||||
|
@ -6,6 +6,8 @@ import net.sourceforge.pmd.PMD;
|
||||
/** Token Manager. */
|
||||
public class JavaParserTokenManager implements JavaParserConstants
|
||||
{
|
||||
protected List<Token> formalComments = new ArrayList<Token>();
|
||||
|
||||
private Map<Integer, String> excludeMap = new HashMap<Integer, String>();
|
||||
private String excludeMarker = PMD.EXCLUDE_MARKER;
|
||||
|
||||
@ -2051,6 +2053,10 @@ void SkipLexicalActions(Token matchedToken)
|
||||
excludeMap.put(matchedToken.beginLine, matchedToken.image.substring(startOfNOPMD + excludeMarker.length()));
|
||||
}
|
||||
break;
|
||||
case 9 :
|
||||
image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
|
||||
formalComments.add(matchedToken);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
@ -10,10 +10,14 @@ import net.sourceforge.pmd.ast.ASTImportDeclaration;
|
||||
import net.sourceforge.pmd.ast.ASTName;
|
||||
import net.sourceforge.pmd.ast.SimpleJavaNode;
|
||||
import net.sourceforge.pmd.ast.SimpleNode;
|
||||
import net.sourceforge.pmd.ast.Token;
|
||||
import net.sourceforge.pmd.rules.ImportWrapper;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class UnusedImportsRule extends AbstractRule {
|
||||
|
||||
@ -22,12 +26,55 @@ public class UnusedImportsRule extends AbstractRule {
|
||||
public Object visit(ASTCompilationUnit node, Object data) {
|
||||
imports.clear();
|
||||
super.visit(node, data);
|
||||
visitFormalComments(node);
|
||||
for (ImportWrapper wrapper : imports) {
|
||||
addViolation(data, wrapper.getNode(), wrapper.getFullName());
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Patterns to match the following constructs:
|
||||
*
|
||||
* @see package.class#member label
|
||||
* {@linkplain package.class#member label}
|
||||
* {@link package.class#member label}
|
||||
* {@value package.class#field}
|
||||
*/
|
||||
private static final Pattern SEE_PATTERN = Pattern.compile(
|
||||
"@see\\s+(\\p{Alpha}\\p{Alnum}*)[\\s#]");
|
||||
|
||||
private static final Pattern LINK_PATTERNS = Pattern.compile(
|
||||
"\\{@link(?:plain)?\\s+(\\p{Alpha}\\p{Alnum}*)[\\s#]");
|
||||
|
||||
private static final Pattern VALUE_PATTERN = Pattern.compile(
|
||||
"\\{@value\\s+(\\p{Alpha}\\p{Alnum}*)[\\s#]");
|
||||
|
||||
private static final Pattern[] PATTERNS = { SEE_PATTERN, LINK_PATTERNS, VALUE_PATTERN };
|
||||
|
||||
private void visitFormalComments(ASTCompilationUnit node) {
|
||||
if (imports.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Token> formals = node.getFormalComments();
|
||||
for (Token formal: formals) {
|
||||
for (Pattern p: PATTERNS) {
|
||||
Matcher m = p.matcher(formal.image);
|
||||
while (m.find()) {
|
||||
String s = m.group(1);
|
||||
ImportWrapper candidate = new ImportWrapper(s, s, new SimpleJavaNode(-1));
|
||||
|
||||
if (imports.contains(candidate)) {
|
||||
imports.remove(candidate);
|
||||
if (imports.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object visit(ASTImportDeclaration node, Object data) {
|
||||
if (!node.isImportOnDemand()) {
|
||||
ASTName importedType = (ASTName) node.jjtGetChild(0);
|
||||
|
Reference in New Issue
Block a user