[java] Fix class scopes for anon inner classes
- A new ClassScope was being created for each annon inner class method / field, which is incorrect. - I reworked the AccessorMethodGeneration to compare scopes directly, since I was missing anonymous classes completely. - Fixes #274
This commit is contained in:

committed by
Andreas Dangel

parent
9291125bd0
commit
7a1eb4f26e
@ -16,9 +16,17 @@ public class ASTClassOrInterfaceBody extends AbstractJavaNode {
|
||||
|
||||
|
||||
/**
|
||||
* Accept the visitor. *
|
||||
* Accept the visitor.
|
||||
*/
|
||||
public Object jjtAccept(JavaParserVisitor visitor, Object data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
public boolean isAnonymousInnerClass() {
|
||||
return jjtGetParent() instanceof ASTAllocationExpression;
|
||||
}
|
||||
|
||||
public boolean isEnumChild() {
|
||||
return jjtGetParent() instanceof ASTEnumConstant;
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,7 @@ package net.sourceforge.pmd.lang.java.rule.design;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode;
|
||||
@ -60,13 +57,10 @@ public class AccessorMethodGenerationRule extends AbstractJavaRule {
|
||||
}
|
||||
|
||||
for (final NameOccurrence no : occurrences) {
|
||||
Node n = no.getLocation();
|
||||
while (n != null && !(n instanceof ASTClassOrInterfaceDeclaration) && !(n instanceof ASTEnumDeclaration)) {
|
||||
n = n.jjtGetParent();
|
||||
}
|
||||
ClassScope usedAtScope = no.getLocation().getScope().getEnclosingScope(ClassScope.class);
|
||||
|
||||
// Are we within the same class that defines the field / method?
|
||||
if (!n.getImage().equals(classScope.getClassName())) {
|
||||
if (!classScope.equals(usedAtScope)) {
|
||||
addViolation(data, no.getLocation());
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCatchStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
|
||||
@ -124,7 +124,7 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
|
||||
ClassNameDeclaration classNameDeclaration = new ClassNameDeclaration(node);
|
||||
s.addDeclaration(classNameDeclaration);
|
||||
|
||||
if (node instanceof ASTClassOrInterfaceBodyDeclaration) {
|
||||
if (node instanceof ASTClassOrInterfaceBody) {
|
||||
addScope(new ClassScope(classNameDeclaration), node);
|
||||
} else {
|
||||
addScope(new ClassScope(node.getImage(), classNameDeclaration), node);
|
||||
@ -183,14 +183,14 @@ public class ScopeAndDeclarationFinder extends JavaParserVisitorAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTClassOrInterfaceBodyDeclaration node, Object data) {
|
||||
if (node.isAnonymousInnerClass() || node.isEnumChild()) {
|
||||
createClassScope(node);
|
||||
cont(node);
|
||||
} else {
|
||||
super.visit(node, data);
|
||||
}
|
||||
return data;
|
||||
public Object visit(ASTClassOrInterfaceBody node, Object data) {
|
||||
if (node.isAnonymousInnerClass() || node.isEnumChild()) {
|
||||
createClassScope(node);
|
||||
cont(node);
|
||||
} else {
|
||||
super.visit(node, data);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,14 +6,17 @@ package net.sourceforge.pmd.lang.java.symboltable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
|
||||
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
|
||||
|
||||
public class ScopeAndDeclarationFinderTest extends STBBaseTst {
|
||||
|
||||
/**
|
||||
@ -44,4 +47,28 @@ public class ScopeAndDeclarationFinderTest extends STBBaseTst {
|
||||
Assert.assertEquals(1, scope.getVariableDeclarations().get(decl).size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnonInnerClassScoping() {
|
||||
String source = "public class Foo {" + PMD.EOL
|
||||
+ " public static final Creator<Foo> CREATOR = new Creator<Foo>() {" + PMD.EOL
|
||||
+ " @Override public Foo createFromParcel(Parcel source) {" + PMD.EOL
|
||||
+ " return new Foo();" + PMD.EOL
|
||||
+ " }" + PMD.EOL
|
||||
+ " @Override public Foo[] newArray(int size) {" + PMD.EOL
|
||||
+ " return new Foo[size];" + PMD.EOL
|
||||
+ " }" + PMD.EOL
|
||||
+ " };" + PMD.EOL
|
||||
+ "}" + PMD.EOL;
|
||||
parseCode(source, LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.6"));
|
||||
|
||||
ClassScope cs = (ClassScope) acu.getFirstDescendantOfType(ASTClassOrInterfaceDeclaration.class).getScope();
|
||||
Assert.assertEquals(1, cs.getClassDeclarations().size()); // There should be 1 anonymous class
|
||||
|
||||
List<ASTMethodDeclarator> methods = acu.findDescendantsOfType(ASTMethodDeclarator.class);
|
||||
Assert.assertEquals(2, methods.size());
|
||||
ClassScope scope1 = methods.get(0).getScope().getEnclosingScope(ClassScope.class);
|
||||
ClassScope scope2 = methods.get(1).getScope().getEnclosingScope(ClassScope.class);
|
||||
Assert.assertSame(scope1, scope2);
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +163,33 @@ public class Foo {
|
||||
|
||||
/* package */ void outerPackage() {
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description><![CDATA[
|
||||
#274 - Method inside static inner class incorrectly reported as generating accessor methods
|
||||
]]></description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo implements Parcelable {
|
||||
public static final Creator<Foo> CREATOR = new Creator<Foo>() {
|
||||
@Override
|
||||
public Foo createFromParcel(Parcel source) {
|
||||
return new Foo(source.readString(),
|
||||
getBooleanForInt(source.readInt()),
|
||||
source.readLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Foo[] newArray(int size) {
|
||||
return new Foo[size];
|
||||
}
|
||||
|
||||
private boolean getBooleanForInt(int value) {
|
||||
return value == 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
Reference in New Issue
Block a user