forked from phoedos/pmd
[java] Improve symboltable for inner classes
This commit is contained in:
@ -226,17 +226,15 @@ public class ClassScope extends AbstractJavaScope {
|
||||
result.add(finder.getDecl());
|
||||
}
|
||||
|
||||
// search inner classes
|
||||
// search references to inner classes
|
||||
Map<ClassNameDeclaration, List<NameOccurrence>> classDeclarations = getClassDeclarations();
|
||||
if (result.isEmpty() && !classDeclarations.isEmpty()) {
|
||||
Applier.apply(finder, classDeclarations.keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
result.add(finder.getDecl());
|
||||
}
|
||||
for (ClassNameDeclaration innerClass : getClassDeclarations().keySet()) {
|
||||
ASTMethodDeclarator md = innerClass.getNode().getFirstDescendantOfType(ASTMethodDeclarator.class);
|
||||
if (md != null) {
|
||||
images.add(md.getImage());
|
||||
finder = new ImageFinderFunction(images);
|
||||
}
|
||||
Applier.apply(finder, innerClass.getScope().getDeclarations(VariableNameDeclaration.class).keySet().iterator());
|
||||
Applier.apply(finder, innerClass.getScope().getDeclarations(MethodNameDeclaration.class).keySet().iterator());
|
||||
if (finder.getDecl() != null) {
|
||||
result.add(finder.getDecl());
|
||||
}
|
||||
|
@ -650,6 +650,24 @@ import lombok.RequiredArgsConstructor;
|
||||
@RequiredArgsConstructor
|
||||
public class Foo {
|
||||
private String bar;
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False positive when referenced from within inner class</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
private static final String OUTER_CONSTANT = "";
|
||||
|
||||
private static final class Empty {
|
||||
private static final class Inner {
|
||||
public boolean isEmpty(String s) {
|
||||
return OUTER_CONSTANT.equals(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
@ -1734,14 +1734,13 @@ public class Outer {
|
||||
<code><![CDATA[
|
||||
public class OuterClass {
|
||||
|
||||
public void foo() {
|
||||
InnerClass.doSomething();
|
||||
}
|
||||
public void foo() {
|
||||
InnerClass.doSomething();
|
||||
}
|
||||
|
||||
static class InnerClass {
|
||||
private static void doSomething() {
|
||||
}
|
||||
}
|
||||
static class InnerClass {
|
||||
private static void doSomething() {}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
@ -278,4 +278,85 @@ public class Foo {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>False negatives for inner class references</description>
|
||||
<expected-problems>4</expected-problems>
|
||||
<expected-linenumbers>3,5,7,21</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
// from https://github.com/checkstyle/checkstyle/blob/checkstyle-9.1/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/grammar/antlr4/InputAntlr4AstRegressionUncommon.java#L185
|
||||
class OtherClass {
|
||||
Object x;
|
||||
class SuperClassA{
|
||||
protected SuperClassA bs;
|
||||
protected SuperClassA s; // this is actually a false negative
|
||||
Object s2;
|
||||
|
||||
private void method() {
|
||||
x = new Object();
|
||||
}
|
||||
}
|
||||
class SuperClassA2{}
|
||||
|
||||
|
||||
/*
|
||||
* Note: inherited fields of a nested class shadow outer scope variables
|
||||
* Note: only if they are accessible!
|
||||
*/
|
||||
public class FieldAccessSuper extends SuperClassA {
|
||||
private SuperClassA s;
|
||||
|
||||
public void foo() {
|
||||
// simple super field access
|
||||
// Primary[Prefix[Name[s]]]
|
||||
s = new SuperClassA();
|
||||
|
||||
// access inherited field through primary
|
||||
// Primary[ Prefix[Primary[(this)]], Suffix[s], Suffix[s2] ]
|
||||
(this).s.s2 = new SuperClassA2();
|
||||
this.s.s2 = new SuperClassA2();
|
||||
|
||||
// access inherited field, second 's' has inherited field 's2'
|
||||
// Primary[Prefix[Name[s.s.s2]]]
|
||||
s.s.s2 = new SuperClassA2();
|
||||
|
||||
// field access through super
|
||||
// Primary[Prefix["super"], Suffix["field"]]
|
||||
super.s = new SuperClassA();
|
||||
|
||||
// fully qualified case
|
||||
// Primary[Prefix[Name[net...FieldAccessSuper]], Suffix[this], Suffix[s]]
|
||||
FieldAccessSuper.this.s
|
||||
= new SuperClassA();
|
||||
}
|
||||
|
||||
public class Nested extends SuperClassA {
|
||||
SuperClassA a;
|
||||
class SubscriptionAdapter{}
|
||||
final /* synthetic */ SubscriptionAdapter this$0 = null;
|
||||
final /* synthetic */ Object val$argHolder = null;
|
||||
|
||||
public void foo() {
|
||||
// access enclosing super field
|
||||
// Primary[Prefix[Name[s]]]
|
||||
s = new SuperClassA();
|
||||
|
||||
// access Nested inherited field
|
||||
// Primary[Prefix[Name[bs]]]
|
||||
bs = new SuperClassA();
|
||||
|
||||
// access super field with fully qualified stuff
|
||||
// Primary[Prefix["FieldAccessSuper"], Suffix[Nested],
|
||||
// Suffix["super"], Suffix["bs"]]
|
||||
FieldAccessSuper.Nested.super.bs = new SuperClassA();
|
||||
|
||||
// refers to the enclosing class's immediate super class's field
|
||||
// Primary[Prefix["FieldAccessSuper"], Suffix["super"], Suffix["s"]]
|
||||
FieldAccessSuper.super.s = new SuperClassA();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
|
Reference in New Issue
Block a user