From a8d7b594ab8ee3afbcf3390be2aa5c8dee1f06c7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sat, 15 Nov 2014 12:55:15 +0100 Subject: [PATCH] #1276 False positive in UnusedPrivateMethod with inner enum --- .../symboltable/ClassNameDeclaration.java | 15 ++++++++- .../pmd/lang/java/symboltable/ClassScope.java | 31 ++++++++++++++++--- .../ScopeAndDeclarationFinder.java | 2 ++ .../java/symboltable/SourceFileScope.java | 25 +++++++++++++++ .../unusedcode/xml/UnusedPrivateMethod.xml | 27 ++++++++++++++++ src/site/markdown/overview/changelog.md | 1 + 6 files changed, 95 insertions(+), 6 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java index 327dbbbd73..62316a43ed 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassNameDeclaration.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.java.symboltable; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.symboltable.AbstractNameDeclaration; public class ClassNameDeclaration extends AbstractNameDeclaration implements TypedNameDeclaration { @@ -13,8 +14,20 @@ public class ClassNameDeclaration extends AbstractNameDeclaration implements Typ super(node); } + public ClassNameDeclaration(ASTEnumDeclaration node) { + super(node); + } + public String toString() { - return "Class " + node.getImage(); + if (node instanceof ASTClassOrInterfaceDeclaration) { + if (((ASTClassOrInterfaceDeclaration) node).isInterface()) { + return "Interface " + node.getImage(); + } else { + return "Class " + node.getImage(); + } + } else { + return "Enum " + node.getImage(); + } } public Node getAccessNodeParent() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java index 4d9afb7485..95164ea13c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ClassScope.java @@ -221,15 +221,33 @@ public class ClassScope extends AbstractJavaScope { List parameterTypes = new ArrayList(); List parameters = mnd.getMethodNameDeclaratorNode().findDescendantsOfType(ASTFormalParameter.class); for (ASTFormalParameter p : parameters) { - Class resolvedType = this.getEnclosingScope(SourceFileScope.class).resolveType(p.getTypeNode().getTypeImage()); + String typeImage = p.getTypeNode().getTypeImage(); + // typeImage might be qualified/unqualified. If it refers to a type, defined in the same toplevel class, + // we should normalize the name here. + typeImage = qualifyTypeName(typeImage); + Class resolvedType = this.getEnclosingScope(SourceFileScope.class).resolveType(typeImage); if (resolvedType == null) { - resolvedType = resolveGenericType(p, p.getTypeNode().getTypeImage()); + resolvedType = resolveGenericType(p, typeImage); } - parameterTypes.add(new SimpleTypedNameDeclaration(p.getTypeNode().getTypeImage(), resolvedType)); + parameterTypes.add(new SimpleTypedNameDeclaration(typeImage, resolvedType)); } return parameterTypes; } + private String qualifyTypeName(String typeImage) { + String result = typeImage; + for (String qualified : this.getEnclosingScope(SourceFileScope.class).getQualifiedTypeNames()) { + int fullLength = qualified.length(); + int nameLength = typeImage.length(); + if (qualified.endsWith(typeImage) + && (fullLength == nameLength || qualified.substring(0, fullLength - nameLength).endsWith("."))) { + result = qualified; + break; + } + } + return result; + } + /** * Provide a list of types of the arguments of the given method call. * The types are simple type images. If the argument type cannot be determined (e.g. because it is itself @@ -274,8 +292,10 @@ public class ClassScope extends AbstractJavaScope { Map> vars = s.getDeclarations(VariableNameDeclaration.class); for (VariableNameDeclaration d : vars.keySet()) { if (d.getImage().equals(name.getImage())) { - type = new SimpleTypedNameDeclaration(d.getTypeImage(), - this.getEnclosingScope(SourceFileScope.class).resolveType(d.getTypeImage())); + String typeName = d.getTypeImage(); + typeName = qualifyTypeName(typeName); + type = new SimpleTypedNameDeclaration(typeName, + this.getEnclosingScope(SourceFileScope.class).resolveType(typeName)); break; } } @@ -298,6 +318,7 @@ public class ClassScope extends AbstractJavaScope { } else if (child instanceof ASTAllocationExpression && child.jjtGetChild(0) instanceof ASTClassOrInterfaceType) { ASTClassOrInterfaceType classInterface = (ASTClassOrInterfaceType)child.jjtGetChild(0); String typeImage = classInterface.getImage(); + typeImage = qualifyTypeName(typeImage); type = new SimpleTypedNameDeclaration(typeImage, this.getEnclosingScope(SourceFileScope.class).resolveType(typeImage)); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java index 8cd0bedd5a..f57fe1212e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/ScopeAndDeclarationFinder.java @@ -165,6 +165,8 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter { @Override public Object visit(ASTEnumDeclaration node, Object data) { createClassScope(node); + Scope s = ((JavaNode)node.jjtGetParent()).getScope(); + s.addDeclaration(new ClassNameDeclaration(node)); cont(node); return data; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/SourceFileScope.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/SourceFileScope.java index f4b5808cd6..632e6c060f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/SourceFileScope.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symboltable/SourceFileScope.java @@ -4,12 +4,15 @@ package net.sourceforge.pmd.lang.java.symboltable; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; +import net.sourceforge.pmd.lang.symboltable.Scope; /** * This scope is the outer most scope of a Java file. @@ -103,4 +106,26 @@ public class SourceFileScope extends AbstractJavaScope { Applier.apply(finder, getDeclarations().keySet().iterator()); return finder.getDecl(); } + + /** + * Returns a set of all types defined within this source file. + * This includes all top-level types and nested types. + * @return set of all types in this source file. + */ + public Set getQualifiedTypeNames() { + return getSubTypes(null, this); + } + + private Set getSubTypes(String qualifyingName, Scope subType) { + Set types = new HashSet(); + for (ClassNameDeclaration c : subType.getDeclarations(ClassNameDeclaration.class).keySet()) { + String typeName = c.getName(); + if (qualifyingName != null) { + typeName = qualifyingName + "." + typeName; + } + types.add(typeName); + types.addAll(getSubTypes(typeName, c.getScope())); + } + return types; + } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/unusedcode/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/unusedcode/xml/UnusedPrivateMethod.xml index fd3c2128f6..6d9e035fcc 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/unusedcode/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/unusedcode/xml/UnusedPrivateMethod.xml @@ -1242,6 +1242,33 @@ public class TestPrivate { private void setTotals(X ledgerable) throws ServiceException { // do stuff } +} + ]]> + + + #1276 False positive in UnusedPrivateMethod when method arg is Object and not called with plain Object + 0 + diff --git a/src/site/markdown/overview/changelog.md b/src/site/markdown/overview/changelog.md index ce8497a202..b0dadb17f9 100644 --- a/src/site/markdown/overview/changelog.md +++ b/src/site/markdown/overview/changelog.md @@ -10,3 +10,4 @@ **Bugfixes:** +* [#1276](https://sourceforge.net/p/pmd/bugs/1276/): False positive in UnusedPrivateMethod with inner enum