#1276 False positive in UnusedPrivateMethod with inner enum
This commit is contained in:
@ -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() {
|
||||
|
@ -221,15 +221,33 @@ public class ClassScope extends AbstractJavaScope {
|
||||
List<TypedNameDeclaration> parameterTypes = new ArrayList<TypedNameDeclaration>();
|
||||
List<ASTFormalParameter> 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<VariableNameDeclaration, List<NameOccurrence>> 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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<String> getQualifiedTypeNames() {
|
||||
return getSubTypes(null, this);
|
||||
}
|
||||
|
||||
private Set<String> getSubTypes(String qualifyingName, Scope subType) {
|
||||
Set<String> types = new HashSet<String>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1242,6 +1242,33 @@ public class TestPrivate {
|
||||
private <X extends Map> void setTotals(X ledgerable) throws ServiceException {
|
||||
// do stuff
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>#1276 False positive in UnusedPrivateMethod when method arg is Object and not called with plain Object</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Parent {
|
||||
enum A {
|
||||
someEnum;
|
||||
}
|
||||
|
||||
public void doSomethingUnqualified(A a) {
|
||||
doSomethingPrivateWithQualified(a);
|
||||
}
|
||||
|
||||
private void doSomethingPrivateWithQualified(Parent.A a) {
|
||||
// PMD error because it doesn't equate Parent.A as the same type as A.
|
||||
}
|
||||
|
||||
public void doSomethingQualified(Parent.A a) {
|
||||
doSomethingPrivateUnqualified(a);
|
||||
}
|
||||
|
||||
private void doSomethingPrivateUnqualified(A a) {
|
||||
// PMD error because it doesn't equate Parent.A as the same type as A.
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
Reference in New Issue
Block a user