Skip to content
Snippets Groups Projects
Commit c31c3c87 authored by Johannes Mey's avatar Johannes Mey
Browse files

added proper support for (multiple) inheritance, but broke visibility again,...

added proper support for (multiple) inheritance, but broke visibility again, should be easily fixable.
parent ffbd4c9c
Branches
Tags
No related merge requests found
...@@ -2,3 +2,5 @@ ScopeTree : Scope; ...@@ -2,3 +2,5 @@ ScopeTree : Scope;
abstract Element; abstract Element;
Declaration:Element ::= <Name:String>; Declaration:Element ::= <Name:String>;
Scope:Element ::= Element*; Scope:Element ::= Element*;
rel Scope.inheritedScope* -> Scope;
...@@ -4,25 +4,26 @@ aspect Shadowing { ...@@ -4,25 +4,26 @@ aspect Shadowing {
Declaration contributes new VariableShadowFinding(shadowed(), this) when isShadowing() to ScopeTree.variableShadowings(); Declaration contributes new VariableShadowFinding(shadowed(), this) when isShadowing() to ScopeTree.variableShadowings();
Declaration contributes new MultipleDeclarationFinding(this) when isShadowingInSameScope() to ScopeTree.variableShadowings(); Declaration contributes new MultipleDeclarationFinding(this) when isShadowingInSameScope() to ScopeTree.variableShadowings();
inh Declaration Declaration.shadowed(); syn Declaration Declaration.shadowed()= shadowed(asDeclaration());
eq Scope.getElement(int i).shadowed() = shadowed(getElement(i).asDeclaration());
inh Declaration Element.shadowed(Declaration shadower); inh Declaration Element.shadowed(Declaration shadower);
eq ScopeTree.getElement().shadowed(Declaration shadower) { eq Scope.getElement().shadowed(Declaration shadower) = shadowedLocally(shadower);
syn Declaration Scope.shadowedLocally(Declaration shadower) {
// first look in the current scope
for (Declaration declaration : declarations()) { for (Declaration declaration : declarations()) {
if (declaration != shadower && declaration.getName().equals(shadower.getName())) { if (declaration != shadower && declaration.getName().equals(shadower.getName())) {
return declaration; return declaration;
} }
} }
return null; // the look in the inherited scopes
} for (Scope inherited : getInheritedScopeList()) {
eq Scope.getElement().shadowed(Declaration shadower) { Declaration shadowed = inherited.shadowedLocally(shadower);
for (Declaration declaration : declarations()) { if (shadowed != null) {
if (declaration != shadower && declaration.getName().equals(shadower.getName())) { return shadowed;
return declaration;
} }
} }
return shadowed(shadower); return (this instanceof ScopeTree) ? null : shadowed(shadower);
} }
inh Declaration Declaration.shadowedInSameScope(); inh Declaration Declaration.shadowedInSameScope();
...@@ -39,8 +40,6 @@ aspect Shadowing { ...@@ -39,8 +40,6 @@ aspect Shadowing {
syn boolean Declaration.isShadowing() = shadowed() != null; syn boolean Declaration.isShadowing() = shadowed() != null;
syn boolean Declaration.isShadowingInSameScope() = shadowedInSameScope() != null; syn boolean Declaration.isShadowingInSameScope() = shadowedInSameScope() != null;
} }
aspect Statictics { aspect Statictics {
......
aspect ProgramToScopeTree { aspect ProgramToScopeTree {
/** a relational nta collection attribute to compute the scope tree */ /** a relational nta collection attribute to compute the scope tree */
coll ScopeTree Program.scopeTree() [asScopeTree()] with addElement root Program; syn lazy ScopeTree Program.scopeTree() {
TypeDecl contributes scope() when !isClassDecl() to Program.scopeTree(); ScopeTree tree = asScopeTree();
ClassDecl contributes protectedScope() when !isInnerType() && !superclass().compilationUnit().fromSource() to Program.scopeTree();
// add all classes
for (CompilationUnit cu : getCompilationUnitList()) {
for (TypeDecl typeDecl : cu.getTypeDeclList()) {
tree.addElement(typeDecl.isClassDecl() ? ((ClassDecl)typeDecl).protectedScope() : typeDecl.scope());
}
}
tree.updateInheritance(); // traverse the tree and add all inheritance relations
return tree;
}
/** helper method to add inheritance relations */
public void Scope.updateInheritance() {
for (Element element : getElementList()) {
if (element.isScope()) {
element.asScope().updateInheritance();
}
}
}
public void ProtectedClassDeclScope.updateInheritance() {
if (getTypeDecl().isClassDecl()) {
ClassDecl classDecl = (ClassDecl)getTypeDecl();
if(classDecl.superclass().isClassDecl() && classDecl.superclass().compilationUnit().fromSource()) {
addInheritedScope(((ClassDecl)classDecl.superclass()).asPackageScope());
}
}
super.updateInheritance();
}
/** a relational nta collection attribute to compute scopes */ /** a relational nta collection attribute to compute scopes */
coll Scope ASTNode.scope() [asScope()] with addElement root Program; coll Scope ASTNode.scope() [asScope()] with addElement root Program;
...@@ -12,19 +42,8 @@ aspect ProgramToScopeTree { ...@@ -12,19 +42,8 @@ aspect ProgramToScopeTree {
coll TypeDeclScope ClassDecl.packageScope() [asPackageScope()] with addElement root Program; coll TypeDeclScope ClassDecl.packageScope() [asPackageScope()] with addElement root Program;
// collect all scopes // collect all scopes
TypeDecl contributes scope() when !isClassDecl() to ASTNode.scope() for containingScope(); TypeDecl contributes scope() when !isNestedType() && !isClassDecl() to ASTNode.scope() for containingScope();
ClassDecl contributes protectedScope() ClassDecl contributes protectedScope() when isNestedType() to ASTNode.scope() for containingScope();
when !(!isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource())
to ASTNode.scope()
for containingScope();
ClassDecl contributes protectedScope()
when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() && !hostPackage().equals(superclass().hostPackage())
to ClassDecl.protectedScope()
for superclass();
ClassDecl contributes protectedScope()
when !isInnerClass() && superclass().isClassDecl() && superclass().compilationUnit().fromSource() && hostPackage().equals(superclass().hostPackage())
to ClassDecl.packageScope()
for superclass();
Block contributes scope() to ASTNode.scope() for containingScope(); Block contributes scope() to ASTNode.scope() for containingScope();
ForStmt contributes scope() when !(getStmt() instanceof Block) 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(); EnhancedForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope();
...@@ -39,9 +58,8 @@ aspect ProgramToScopeTree { ...@@ -39,9 +58,8 @@ aspect ProgramToScopeTree {
} }
/** /**
* ascpect containing helper methods to construct (mostly empty) AST nodes of the scope tree * aspect containing helper methods to construct (mostly empty) AST nodes of the scope tree
* If it was not for the single line in asProtectedScope(), the rest of this aspect could have been generated * There are few parts added manually, but stubs could easily be generated from the mapping grammar
* automatically, which would have been much nicer!
*/ */
aspect ScopeTreeConstructors { aspect ScopeTreeConstructors {
...@@ -62,19 +80,21 @@ aspect ScopeTreeConstructors { ...@@ -62,19 +80,21 @@ aspect ScopeTreeConstructors {
return scope; return scope;
} }
syn lazy TypeDeclScope ClassDecl.asScope() {
TypeDeclScope scope = new PrivateClassDeclScope();
scope.setTypeDecl(this);
return scope;
}
syn lazy TypeDeclScope ClassDecl.asProtectedScope() { syn lazy TypeDeclScope ClassDecl.asProtectedScope() {
TypeDeclScope scope = new TypeDeclScope(); TypeDeclScope scope = new ProtectedClassDeclScope();
scope.setTypeDecl(this); scope.setTypeDecl(this);
scope.addElement(packageScope()); // this irregular statement is necessary because of either a bug or a limitation in JastAdd collections scope.addElement(packageScope());
return scope; return scope;
} }
// the following commented statement unfortunately does not work, because during the contribution phase, the information
// which target should be contributed to is lost if there are multiple targets. Maybe I got it wrong, but I tried many things
// 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() { syn lazy TypeDeclScope ClassDecl.asPackageScope() {
TypeDeclScope scope = new TypeDeclScope(); TypeDeclScope scope = new PackageClassDeclScope();
scope.setTypeDecl(this); scope.setTypeDecl(this);
scope.addElement(scope()); scope.addElement(scope());
return scope; return scope;
......
...@@ -5,6 +5,10 @@ abstract JavaScope : Scope; ...@@ -5,6 +5,10 @@ abstract JavaScope : Scope;
TypeDeclScope : JavaScope; TypeDeclScope : JavaScope;
rel TypeDeclScope.typeDecl -> TypeDecl; rel TypeDeclScope.typeDecl -> TypeDecl;
ProtectedClassDeclScope : TypeDeclScope;
PackageClassDeclScope : TypeDeclScope;
PrivateClassDeclScope : TypeDeclScope;
BlockScope : JavaScope; BlockScope : JavaScope;
rel BlockScope.block -> Block; rel BlockScope.block -> Block;
......
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 InnerInheritanceTest extends ScopeAnalysisTest {
@Test
void test() {
ScopeAnalysis scopeAnalysis = new ScopeAnalysis();
Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/innerInheritance", true, true);
assertShadow(findings, "fieldA", "ClassB", 6, "ClassA", 3);
assertShadow(findings, "fieldB", "ClassB", 7, "ClassB", 3);
Assertions.assertEquals(2, findings.size());
}
}
...@@ -35,10 +35,12 @@ public class InnerTest extends ScopeAnalysisTest { ...@@ -35,10 +35,12 @@ public class InnerTest extends ScopeAnalysisTest {
// anonymous class defined in other class // anonymous class defined in other class
assertShadow(findings, "fieldB", "ClassB", 5, "ClassB", 10); assertShadow(findings, "fieldB", "ClassB", 5, "ClassB", 10);
// this finding is currently not found
// assertShadow(findings, "fieldB", 10, 4);
Assertions.assertEquals(10, findings.size()); // the anonymous class inherited a field
assertShadow(findings, "fieldB", "ClassB", 10, "ClassA", 4);
Assertions.assertEquals(11, findings.size());
} }
} }
public class ClassA {
public int fieldA;
}
public class ClassB {
int fieldB;
class ClassC extends ClassA {
int fieldA;
int fieldB;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment