diff --git a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag index 6bd575cb2424d020b5ad12ce170e64eca288d3f6..4695a2fe3e3723a4ecfcc6185be7cbc5e91bea5b 100644 --- a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag +++ b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag @@ -9,6 +9,7 @@ aspect ProgramToScopeTree { /** a relational nta collection attribute to compute a special scope containing visible fields and subtypes */ coll TypeDeclScope ClassDecl.protectedScope() [asProtectedScope()] with addElement root Program; + coll TypeDeclScope ClassDecl.packageScope() [asPackageScope()] with addElement root Program; // collect all scopes TypeDecl contributes scope() when !isClassDecl() to ASTNode.scope() for containingScope(); @@ -17,16 +18,23 @@ aspect ProgramToScopeTree { to ASTNode.scope() for containingScope(); ClassDecl contributes protectedScope() - when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() + when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() && !accessibleFromPackage(superclass().hostPackage()) to ClassDecl.protectedScope() for superclass(); + ClassDecl contributes protectedScope() + when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() && accessibleFromPackage(superclass().hostPackage()) + to ClassDecl.packageScope() + for superclass(); Block contributes scope() to ASTNode.scope() for containingScope(); ForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope(); EnhancedForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope(); // collect all elements Declarator contributes asDeclaration() when !isField() || isPrivate() to ASTNode.scope() for containingScope(); - Declarator contributes asDeclaration() when isField() && !isPrivate() to ClassDecl.protectedScope() for containingScope(); + // field which is neither private, protected, nor public -> package-private scope + Declarator contributes asDeclaration() when isField() && !isPrivate() && !(isProtected() || isPublic()) to ClassDecl.packageScope() for containingScope(); + // field which is either protected or public -> protected scope + Declarator contributes asDeclaration() when isField() && !isPrivate() && (isProtected() || isPublic()) to ClassDecl.protectedScope() for containingScope(); ParameterDeclaration contributes asDeclaration() to ASTNode.scope() for containingScope(); } @@ -57,7 +65,7 @@ aspect ScopeTreeConstructors { syn lazy TypeDeclScope ClassDecl.asProtectedScope() { TypeDeclScope scope = new TypeDeclScope(); scope.setTypeDecl(this); - scope.addElement(scope()); // this irregular statement is necessary because of either a bug or a limitation in JastAdd collections + scope.addElement(packageScope()); // this irregular statement is necessary because of either a bug or a limitation in JastAdd collections return scope; } // the following commented statement unfortunately does not work, because during the contribution phase, the information @@ -65,6 +73,13 @@ aspect ScopeTreeConstructors { // and JastAdd always wants to also add the contribution made in line 17ff to this target as well. // ClassDecl contributes scope() to ClassDecl.protectedScope() for this; + syn lazy TypeDeclScope ClassDecl.asPackageScope() { + TypeDeclScope scope = new TypeDeclScope(); + scope.setTypeDecl(this); + scope.addElement(scope()); + return scope; + } + syn lazy BlockScope Block.asScope() { BlockScope scope = new BlockScope(); scope.setBlock(this); diff --git a/scope4j/src/test/java/org/extendj/ProtectedTest.java b/scope4j/src/test/java/org/extendj/ProtectedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2ed5d96afd5aea830ebea2dc1d645725018138de --- /dev/null +++ b/scope4j/src/test/java/org/extendj/ProtectedTest.java @@ -0,0 +1,113 @@ +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 ProtectedTest extends ScopeAnalysisTest { + + @Test + void test() { + + ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); + Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/protected_", true, true); + + System.out.println(findings); + + final String classA = "src/test/resources/protected_/one/ClassA.java"; + final String classB = "src/test/resources/protected_/one/ClassB.java"; + final String classC = "src/test/resources/protected_/one/ClassC.java"; + final String classD = "src/test/resources/protected_/two/ClassD.java"; + final String classE = "src/test/resources/protected_/two/ClassE.java"; + + // within class A + // A.A() + assertShadow(findings, "fPrivate", classA, 19, classA, 9); + assertShadow(findings, "fPackage", classA, 20, classA, 10); + assertShadow(findings, "fProtected", classA, 21, classA, 11); + assertShadow(findings, "fPublic", classA, 22, classA, 12); + // A.foo() + assertShadow(findings, "fPrivate", classA, 26, classA, 9); + assertShadow(findings, "fPackage", classA, 27, classA, 10); + assertShadow(findings, "fProtected", classA, 28, classA, 11); + assertShadow(findings, "fPublic", classA, 29, classA, 12); + // A.bar() + assertShadow(findings, "fPrivate", classA, 32, classA, 9); + assertShadow(findings, "fPackage", classA, 33, classA, 10); + assertShadow(findings, "fProtected", classA, 34, classA, 11); + assertShadow(findings, "fPublic", classA, 35, classA, 12); + + // within class B + assertShadow(findings, "fPackage", classB, 14, classA, 10); + assertShadow(findings, "fProtected", classB, 15, classA, 11); + assertShadow(findings, "fPublic", classB, 16, classA, 12); + // B.B() + assertShadow(findings, "fPrivate", classB, 19, classB, 13); + assertShadow(findings, "fPackage", classB, 20, classB, 14); + assertShadow(findings, "fProtected", classB, 21, classB, 15); + assertShadow(findings, "fPublic", classB, 22, classB, 16); + // B.foo() + assertShadow(findings, "fPrivate", classB, 26, classB, 13); + assertShadow(findings, "fPackage", classB, 27, classB, 14); + assertShadow(findings, "fProtected", classB, 28, classB, 15); + assertShadow(findings, "fPublic", classB, 29, classB, 16); + // B.bar() + assertShadow(findings, "fPrivate", classB, 32, classB, 13); + assertShadow(findings, "fPackage", classB, 33, classB, 14); + assertShadow(findings, "fProtected", classB, 34, classB, 15); + assertShadow(findings, "fPublic", classB, 35, classB, 16); + + // within class C + // C.C() + assertShadow(findings, "fPackage", classC, 20, classA, 10); + assertShadow(findings, "fProtected", classC, 21, classA, 11); + assertShadow(findings, "fPublic", classC, 22, classA, 12); + // C.foo() + assertShadow(findings, "fPackage", classC, 27, classA, 10); + assertShadow(findings, "fProtected", classC, 28, classA, 11); + assertShadow(findings, "fPublic", classC, 29, classA, 12); + // C.bar() + assertShadow(findings, "fPackage", classC, 33, classA, 10); + assertShadow(findings, "fProtected", classC, 34, classA, 11); + assertShadow(findings, "fPublic", classC, 35, classA, 12); + + // within class D + assertNotShadow(findings, "fPackage", classD, 20, classA, 10); + assertShadow(findings, "fProtected", classD, 15, classA, 11); + assertShadow(findings, "fPublic", classD, 16, classA, 12); + // D.D() + assertShadow(findings, "fPrivate", classD, 19, classA, 13); + assertShadow(findings, "fPackage", classD, 20, classA, 14); + assertShadow(findings, "fProtected", classD, 21, classA, 15); + assertShadow(findings, "fPublic", classD, 22, classA, 16); + // D.foo() + assertShadow(findings, "fPrivate", classD, 26, classA, 13); + assertShadow(findings, "fPackage", classD, 27, classA, 14); + assertShadow(findings, "fProtected", classD, 28, classA, 15); + assertShadow(findings, "fPublic", classD, 29, classA, 16); + // D.bar() + assertShadow(findings, "fPrivate", classD, 32, classA, 13); + assertShadow(findings, "fPackage", classD, 33, classA, 14); + assertShadow(findings, "fProtected", classD, 34, classA, 15); + assertShadow(findings, "fPublic", classD, 35, classA, 16); + + // within class E + // E.E() + assertNotShadow(findings, "fPackage", classE, 20, classA, 10); + assertShadow(findings, "fProtected", classE, 21, classA, 11); + assertShadow(findings, "fPublic", classE, 22, classA, 12); + // E.foo() + assertNotShadow(findings, "fPackage", classE, 27, classA, 10); + assertShadow(findings, "fProtected", classE, 28, classA, 11); + assertShadow(findings, "fPublic", classE, 29, classA, 12); + // E.bar() + assertNotShadow(findings, "fPackage", classE, 33, classA, 14); + assertShadow(findings, "fProtected", classE, 34, classA, 11); + assertShadow(findings, "fPublic", classE, 35, classA, 12); + + Assertions.assertEquals(56, findings.size()); + } + +} diff --git a/scope4j/src/test/resources/protected_/one/ClassA.java b/scope4j/src/test/resources/protected_/one/ClassA.java new file mode 100644 index 0000000000000000000000000000000000000000..9929229498cee9696281fb62d9f28de648b53023 --- /dev/null +++ b/scope4j/src/test/resources/protected_/one/ClassA.java @@ -0,0 +1,38 @@ +/* + As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to + avoid conflicts with Java keywords. +*/ +package protected_.one; + +public class ClassA { + + private int fPrivate = 0; + int fPackage = 0; + protected int fProtected = 0; + public int fPublic = 0; + + + + + + protected ClassA() { + int fPrivate = 1; + int fPackage = 1; + int fProtected = 1; + int fPublic = 1; + } + + void foo() { + int fPrivate = 2; + int fPackage = 2; + int fProtected = 2; + int fPublic = 2; + } + + void bar(int fPrivate, + int fPackage, + int fProtected, + int fPublic) { + // empty + } +} diff --git a/scope4j/src/test/resources/protected_/one/ClassB.java b/scope4j/src/test/resources/protected_/one/ClassB.java new file mode 100644 index 0000000000000000000000000000000000000000..bde099846c3ce8b8fb4c17b60ba1b07c0c8ddde8 --- /dev/null +++ b/scope4j/src/test/resources/protected_/one/ClassB.java @@ -0,0 +1,38 @@ +/* + As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to + avoid conflicts with Java keywords. +*/ +package protected_.one; + +class ClassB extends ClassA { + + + + + + private int fPrivate = 0; + int fPackage = 0; + protected int fProtected = 0; + public int fPublic = 0; + + ClassB() { + int fPrivate = 1; + int fPackage = 1; + int fProtected = 1; + int fPublic = 1; + } + + void foo() { + int fPrivate = 2; + int fPackage = 2; + int fProtected = 2; + int fPublic = 2; + } + + void bar(int fPrivate, + int fPackage, + int fProtected, + int fPublic) { + // empty + } +} diff --git a/scope4j/src/test/resources/protected_/one/ClassC.java b/scope4j/src/test/resources/protected_/one/ClassC.java new file mode 100644 index 0000000000000000000000000000000000000000..5fc85fdd3e7390f533f3111ff9149c9e44299d70 --- /dev/null +++ b/scope4j/src/test/resources/protected_/one/ClassC.java @@ -0,0 +1,38 @@ +/* + As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to + avoid conflicts with Java keywords. +*/ +package protected_.one; + +class ClassC extends ClassA { + + + + + + + + + + + ClassC() { + int fPrivate = 1; + int fPackage = 1; + int fProtected = 1; + int fPublic = 1; + } + + void foo() { + int fPrivate = 2; + int fPackage = 2; + int fProtected = 2; + int fPublic = 2; + } + + void bar(int fPrivate, + int fPackage, + int fProtected, + int fPublic) { + // empty + } +} diff --git a/scope4j/src/test/resources/protected_/two/ClassD.java b/scope4j/src/test/resources/protected_/two/ClassD.java new file mode 100644 index 0000000000000000000000000000000000000000..b5fe8e114e989e3b165f6cc77f95f5aa77c52cd7 --- /dev/null +++ b/scope4j/src/test/resources/protected_/two/ClassD.java @@ -0,0 +1,38 @@ +/* + As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to + avoid conflicts with Java keywords. +*/ +package protected_.two; +import protected_.one.ClassA; +class ClassD extends ClassA { + + + + + + int fPrivate = 0; + int fPackage = 0; + int fProtected = 0; + int fPublic = 0; + + ClassD() { + int fPrivate = 1; + int fPackage = 1; + int fProtected = 1; + int fPublic = 1; + } + + void foo() { + int fPrivate = 2; + int fPackage = 2; + int fProtected = 2; + int fPublic = 2; + } + + void bar(int fPrivate, + int fPackage, + int fProtected, + int fPublic) { + // empty + } +} diff --git a/scope4j/src/test/resources/protected_/two/ClassE.java b/scope4j/src/test/resources/protected_/two/ClassE.java new file mode 100644 index 0000000000000000000000000000000000000000..84c0d0aba6f92f0b086edf9c76c491f2f7b7da90 --- /dev/null +++ b/scope4j/src/test/resources/protected_/two/ClassE.java @@ -0,0 +1,38 @@ +/* + As of https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html, an underscore shall be added to + avoid conflicts with Java keywords. +*/ +package protected_.two; + +class ClassE extends protected_.one.ClassA { + + + + + + + + + + + ClassE() { + int fPrivate = 1; + int fPackage = 1; + int fProtected = 1; + int fPublic = 1; + } + + void foo() { + int fPrivate = 2; + int fPackage = 2; + int fProtected = 2; + int fPublic = 2; + } + + void bar(int fPrivate, + int fPackage, + int fProtected, + int fPublic) { + // empty + } +}