diff --git a/scope4j/src/main/java/org/extendj/ScopeAnalysis.java b/scope4j/src/main/java/org/extendj/ScopeAnalysis.java index 4409ba34b48dd9fc47d1c27aaafd82619ebe8d15..c6802fa0af437d36c7e77341d28f5ed219fa67c6 100644 --- a/scope4j/src/main/java/org/extendj/ScopeAnalysis.java +++ b/scope4j/src/main/java/org/extendj/ScopeAnalysis.java @@ -137,7 +137,7 @@ public class ScopeAnalysis extends Frontend { } private Program readProgram(Collection<String> files) throws IOException { - + System.out.println("Reading " + (files.size() > 10 ? files.size() + " files" : files.toString())); Program program = new Program(); program.resetStatistics(); diff --git a/scope4j/src/test/java/org/extendj/InnerTest.java b/scope4j/src/test/java/org/extendj/InnerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c5c187104159e7d1faa85bbb4a8e9437416b5a31 --- /dev/null +++ b/scope4j/src/test/java/org/extendj/InnerTest.java @@ -0,0 +1,44 @@ +package org.extendj; + +import org.extendj.ast.AbstractFinding; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +public class InnerTest extends ScopeAnalysisTest { + + @Test + void test() { + + ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); + Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/inner", true, true); + + System.out.println(findings); + + // anonymous class + assertShadow(findings, "fieldA", 11, 13); + assertShadow(findings, "fieldA", 13, 3); + + // local inner class + assertShadow(findings, "fieldA", 27, 29); + assertShadow(findings, "fieldA", 29, 3); + assertShadow(findings, "changingVar", 25, 19); + + // static member class + assertShadow(findings, "fieldA", 37, 35); + assertShadow(findings, "fieldA", 35, 3); + + // member class + assertShadow(findings, "fieldA", 44, 42); + assertShadow(findings, "fieldA", 42, 3); + + // anonymous class defined in other class + assertShadow(findings, "fieldB", 5, 10); + // this finding is currently not found +// assertShadow(findings, "fieldB", 10, 4); + + Assertions.assertEquals(10, findings.size()); + } + +} diff --git a/scope4j/src/test/resources/inner/ClassA.java b/scope4j/src/test/resources/inner/ClassA.java new file mode 100644 index 0000000000000000000000000000000000000000..c9dd1fa19fa804b33a9eb664ed58b6e400280727 --- /dev/null +++ b/scope4j/src/test/resources/inner/ClassA.java @@ -0,0 +1,47 @@ +public abstract class ClassA { + + int fieldA; + int fieldB; + + abstract void toBeDefined(); + + void method1() { + ClassA anonymous = new ClassA() { + void toBeDefined() { + int fieldA = 11; + } + int fieldA = 1; + }; + } + + void method2() { + final int finalVar = 1; + int changingVar = 0; + changingVar = 1; // changingVar is not-final and not-effective-final, thus can not be used in InnerA + class InnerA extends ClassA { + /* This variable shares the name, but actually could never reference the outer scope + We include it anyway, because a) it would obscure analysis for this edge-case, and b) warns for potentially + unwanted effects (as all shadowing-warnings do) */ + int changingVar = 4; + void toBeDefined() { + int fieldA = 21 + changingVar + finalVar; + } + int fieldA = 2; + } + ClassA inner = new InnerA(); + } + + static class StaticMemberClass extends ClassA { + int fieldA = 3; + void toBeDefined() { + int fieldA = 31; + } + } + + class MemberClass extends ClassA { + int fieldA = 4; + void toBeDefined() { + int fieldA = 41; + } + } +} diff --git a/scope4j/src/test/resources/inner/ClassB.java b/scope4j/src/test/resources/inner/ClassB.java new file mode 100644 index 0000000000000000000000000000000000000000..3213a0f7f5f67c18ce9a0385b94bfb08ca897b27 --- /dev/null +++ b/scope4j/src/test/resources/inner/ClassB.java @@ -0,0 +1,13 @@ +public class ClassB { + void anonymousClassFromOtherSourceFile() { + ClassA anonymous = new ClassA() { + void toBeDefined() { + int fieldB = 11; + } + + /* false-negative. there should be two scopes: ClassA and this method of ClassB + * But there is only the method, thus, not shadowing of ClassA.fieldB is detected. */ + int fieldB = 1; + } + } +} diff --git a/scope4j/src/test/resources/simple/ClassA.java b/scope4j/src/test/resources/simple/ClassA.java index a066a2aa6bdf14ea306e3c0c077723250ced13fb..4cd7ec11b7fb1f8f21cb133aec2ce25501ea5f4c 100644 --- a/scope4j/src/test/resources/simple/ClassA.java +++ b/scope4j/src/test/resources/simple/ClassA.java @@ -37,6 +37,7 @@ public abstract class ClassA { ) { /* do stuff */ } catch (java.io.IOException e) {/* do stuff */} } - // this does not appear as a scope (and, more importantly, the parameters are not added anywhere else) + // these do not appear as a scope (and, more importantly, the parameters are not added anywhere else) public abstract void methodNameB(int parameterForAbstractMethodB); + public abstract void methodNameC(int fieldA); } diff --git a/scope4j/src/test/resources/superclassFields/ClassA.java b/scope4j/src/test/resources/superclassFields/ClassA.java index 675b9360cbfcb0764893486d7dcc1946b2c10085..1bd25cd71c600406dc7af4bf5040a3def7753497 100644 --- a/scope4j/src/test/resources/superclassFields/ClassA.java +++ b/scope4j/src/test/resources/superclassFields/ClassA.java @@ -1,12 +1,12 @@ public abstract class ClassA { - + int fieldA; int fieldB; - void m(); + abstract void m(); void n() { //... } - + }