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
No related branches found
No related tags found
No related merge requests found
......@@ -2,3 +2,5 @@ ScopeTree : Scope;
abstract Element;
Declaration:Element ::= <Name:String>;
Scope:Element ::= Element*;
rel Scope.inheritedScope* -> Scope;
......@@ -4,25 +4,26 @@ aspect Shadowing {
Declaration contributes new VariableShadowFinding(shadowed(), this) when isShadowing() to ScopeTree.variableShadowings();
Declaration contributes new MultipleDeclarationFinding(this) when isShadowingInSameScope() to ScopeTree.variableShadowings();
inh Declaration Declaration.shadowed();
eq Scope.getElement(int i).shadowed() = shadowed(getElement(i).asDeclaration());
syn Declaration Declaration.shadowed()= shadowed(asDeclaration());
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()) {
if (declaration != shadower && declaration.getName().equals(shadower.getName())) {
return declaration;
}
}
return null;
}
eq Scope.getElement().shadowed(Declaration shadower) {
for (Declaration declaration : declarations()) {
if (declaration != shadower && declaration.getName().equals(shadower.getName())) {
return declaration;
// the look in the inherited scopes
for (Scope inherited : getInheritedScopeList()) {
Declaration shadowed = inherited.shadowedLocally(shadower);
if (shadowed != null) {
return shadowed;
}
}
return shadowed(shadower);
return (this instanceof ScopeTree) ? null : shadowed(shadower);
}
inh Declaration Declaration.shadowedInSameScope();
......@@ -39,8 +40,6 @@ aspect Shadowing {
syn boolean Declaration.isShadowing() = shadowed() != null;
syn boolean Declaration.isShadowingInSameScope() = shadowedInSameScope() != null;
}
aspect Statictics {
......
aspect ProgramToScopeTree {
/** a relational nta collection attribute to compute the scope tree */
coll ScopeTree Program.scopeTree() [asScopeTree()] with addElement root Program;
TypeDecl contributes scope() when !isClassDecl() to Program.scopeTree();
ClassDecl contributes protectedScope() when !isInnerType() && !superclass().compilationUnit().fromSource() to Program.scopeTree();
syn lazy ScopeTree Program.scopeTree() {
ScopeTree tree = asScopeTree();
// 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 */
coll Scope ASTNode.scope() [asScope()] with addElement root Program;
......@@ -12,19 +42,8 @@ aspect ProgramToScopeTree {
coll TypeDeclScope ClassDecl.packageScope() [asPackageScope()] with addElement root Program;
// collect all scopes
TypeDecl contributes scope() when !isClassDecl() to ASTNode.scope() for containingScope();
ClassDecl contributes protectedScope()
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();
TypeDecl contributes scope() when !isNestedType() && !isClassDecl() to ASTNode.scope() for containingScope();
ClassDecl contributes protectedScope() when isNestedType() 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();
EnhancedForStmt contributes scope() when !(getStmt() instanceof Block) to ASTNode.scope() for containingScope();
......@@ -39,9 +58,8 @@ aspect ProgramToScopeTree {
}
/**
* ascpect 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
* automatically, which would have been much nicer!
* aspect containing helper methods to construct (mostly empty) AST nodes of the scope tree
* There are few parts added manually, but stubs could easily be generated from the mapping grammar
*/
aspect ScopeTreeConstructors {
......@@ -62,19 +80,21 @@ aspect ScopeTreeConstructors {
return scope;
}
syn lazy TypeDeclScope ClassDecl.asScope() {
TypeDeclScope scope = new PrivateClassDeclScope();
scope.setTypeDecl(this);
return scope;
}
syn lazy TypeDeclScope ClassDecl.asProtectedScope() {
TypeDeclScope scope = new TypeDeclScope();
TypeDeclScope scope = new ProtectedClassDeclScope();
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;
}
// 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() {
TypeDeclScope scope = new TypeDeclScope();
TypeDeclScope scope = new PackageClassDeclScope();
scope.setTypeDecl(this);
scope.addElement(scope());
return scope;
......
......@@ -5,6 +5,10 @@ abstract JavaScope : Scope;
TypeDeclScope : JavaScope;
rel TypeDeclScope.typeDecl -> TypeDecl;
ProtectedClassDeclScope : TypeDeclScope;
PackageClassDeclScope : TypeDeclScope;
PrivateClassDeclScope : TypeDeclScope;
BlockScope : JavaScope;
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 {
// anonymous class defined in other class
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