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:
|
April 11, 2008 - 4.2.1:
|
||||||
|
|
||||||
'41' and '42' shortcuts for rulesets added
|
'41' and '42' shortcuts for rulesets added
|
||||||
|
@ -163,6 +163,8 @@ public class JavaParser {
|
|||||||
}
|
}
|
||||||
PARSER_END(JavaParser)
|
PARSER_END(JavaParser)
|
||||||
TOKEN_MGR_DECLS : {
|
TOKEN_MGR_DECLS : {
|
||||||
|
protected List<Token> formalComments = new ArrayList<Token>();
|
||||||
|
|
||||||
private Map<Integer, String> excludeMap = new HashMap<Integer, String>();
|
private Map<Integer, String> excludeMap = new HashMap<Integer, String>();
|
||||||
private String excludeMarker = PMD.EXCLUDE_MARKER;
|
private String excludeMarker = PMD.EXCLUDE_MARKER;
|
||||||
|
|
||||||
@ -204,7 +206,7 @@ MORE :
|
|||||||
<IN_FORMAL_COMMENT>
|
<IN_FORMAL_COMMENT>
|
||||||
SPECIAL_TOKEN :
|
SPECIAL_TOKEN :
|
||||||
{
|
{
|
||||||
<FORMAL_COMMENT: "*/" > : DEFAULT
|
<FORMAL_COMMENT: "*/" > { formalComments.add(matchedToken); } : DEFAULT
|
||||||
}
|
}
|
||||||
|
|
||||||
<IN_MULTI_LINE_COMMENT>
|
<IN_MULTI_LINE_COMMENT>
|
||||||
@ -1077,6 +1079,7 @@ ASTCompilationUnit CompilationUnit() :
|
|||||||
( < "~[]" > )?
|
( < "~[]" > )?
|
||||||
<EOF>
|
<EOF>
|
||||||
{
|
{
|
||||||
|
jjtThis.setFormalComments(token_source.formalComments);
|
||||||
return jjtThis;
|
return jjtThis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,27 @@ On demand import
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
public class Foo {
|
public class Foo {
|
||||||
List list = new ArrayList();
|
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>
|
]]></code>
|
||||||
</test-code>
|
</test-code>
|
||||||
|
@ -154,4 +154,25 @@ public class Foo {
|
|||||||
}
|
}
|
||||||
]]></code>
|
]]></code>
|
||||||
</test-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>
|
</test-data>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package net.sourceforge.pmd.ast;
|
package net.sourceforge.pmd.ast;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import net.sourceforge.pmd.typeresolution.ClassTypeResolver;
|
import net.sourceforge.pmd.typeresolution.ClassTypeResolver;
|
||||||
|
|
||||||
// FUTURE Change this class to extend from SimpleJavaNode, as TypeNode is not appropriate (unless I'm wrong)
|
// 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);
|
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. *
|
* Accept the visitor. *
|
||||||
|
@ -169,6 +169,7 @@ public class JavaParser/*@bgen(jjtree)*/implements JavaParserTreeConstants, Java
|
|||||||
jj_consume_token(0);
|
jj_consume_token(0);
|
||||||
jjtree.closeNodeScope(jjtn000, true);
|
jjtree.closeNodeScope(jjtn000, true);
|
||||||
jjtc000 = false;
|
jjtc000 = false;
|
||||||
|
jjtn000.setFormalComments(token_source.formalComments);
|
||||||
{if (true) return jjtn000;}
|
{if (true) return jjtn000;}
|
||||||
} catch (Throwable jjte000) {
|
} catch (Throwable jjte000) {
|
||||||
if (jjtc000) {
|
if (jjtc000) {
|
||||||
@ -8001,6 +8002,15 @@ jjtn000.setModifiers(modifiers);
|
|||||||
return false;
|
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() {
|
private boolean jj_3_1() {
|
||||||
Token xsp;
|
Token xsp;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -8011,15 +8021,6 @@ jjtn000.setModifiers(modifiers);
|
|||||||
return false;
|
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() {
|
private boolean jj_3_44() {
|
||||||
if (jj_3R_74()) return true;
|
if (jj_3R_74()) return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -6,6 +6,8 @@ import net.sourceforge.pmd.PMD;
|
|||||||
/** Token Manager. */
|
/** Token Manager. */
|
||||||
public class JavaParserTokenManager implements JavaParserConstants
|
public class JavaParserTokenManager implements JavaParserConstants
|
||||||
{
|
{
|
||||||
|
protected List<Token> formalComments = new ArrayList<Token>();
|
||||||
|
|
||||||
private Map<Integer, String> excludeMap = new HashMap<Integer, String>();
|
private Map<Integer, String> excludeMap = new HashMap<Integer, String>();
|
||||||
private String excludeMarker = PMD.EXCLUDE_MARKER;
|
private String excludeMarker = PMD.EXCLUDE_MARKER;
|
||||||
|
|
||||||
@ -2051,6 +2053,10 @@ void SkipLexicalActions(Token matchedToken)
|
|||||||
excludeMap.put(matchedToken.beginLine, matchedToken.image.substring(startOfNOPMD + excludeMarker.length()));
|
excludeMap.put(matchedToken.beginLine, matchedToken.image.substring(startOfNOPMD + excludeMarker.length()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 9 :
|
||||||
|
image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
|
||||||
|
formalComments.add(matchedToken);
|
||||||
|
break;
|
||||||
default :
|
default :
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,14 @@ import net.sourceforge.pmd.ast.ASTImportDeclaration;
|
|||||||
import net.sourceforge.pmd.ast.ASTName;
|
import net.sourceforge.pmd.ast.ASTName;
|
||||||
import net.sourceforge.pmd.ast.SimpleJavaNode;
|
import net.sourceforge.pmd.ast.SimpleJavaNode;
|
||||||
import net.sourceforge.pmd.ast.SimpleNode;
|
import net.sourceforge.pmd.ast.SimpleNode;
|
||||||
|
import net.sourceforge.pmd.ast.Token;
|
||||||
import net.sourceforge.pmd.rules.ImportWrapper;
|
import net.sourceforge.pmd.rules.ImportWrapper;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class UnusedImportsRule extends AbstractRule {
|
public class UnusedImportsRule extends AbstractRule {
|
||||||
|
|
||||||
@ -22,12 +26,55 @@ public class UnusedImportsRule extends AbstractRule {
|
|||||||
public Object visit(ASTCompilationUnit node, Object data) {
|
public Object visit(ASTCompilationUnit node, Object data) {
|
||||||
imports.clear();
|
imports.clear();
|
||||||
super.visit(node, data);
|
super.visit(node, data);
|
||||||
|
visitFormalComments(node);
|
||||||
for (ImportWrapper wrapper : imports) {
|
for (ImportWrapper wrapper : imports) {
|
||||||
addViolation(data, wrapper.getNode(), wrapper.getFullName());
|
addViolation(data, wrapper.getNode(), wrapper.getFullName());
|
||||||
}
|
}
|
||||||
return data;
|
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) {
|
public Object visit(ASTImportDeclaration node, Object data) {
|
||||||
if (!node.isImportOnDemand()) {
|
if (!node.isImportOnDemand()) {
|
||||||
ASTName importedType = (ASTName) node.jjtGetChild(0);
|
ASTName importedType = (ASTName) node.jjtGetChild(0);
|
||||||
|
Reference in New Issue
Block a user