diff --git a/scope/src/main/jastadd/Shadowing.jrag b/scope/src/main/jastadd/Shadowing.jrag index 5c37ee81a752b76949c42dc1184f4c896509bad7..56a1a218138b579846dbab4cb04d0a7616aa1d11 100644 --- a/scope/src/main/jastadd/Shadowing.jrag +++ b/scope/src/main/jastadd/Shadowing.jrag @@ -4,7 +4,7 @@ aspect Shadowing { Declaration contributes new VariableShadowFinding(shadowed(), this) when isShadowing() to ScopeTree.variableShadowings(); Declaration contributes new MultipleDeclarationFinding(this) when isShadowingInSameScope() to ScopeTree.variableShadowings(); - syn Declaration Declaration.shadowed() = shadowed(asDeclaration()); + syn Declaration Declaration.shadowed()= shadowed(asDeclaration()); inh Declaration Element.shadowed(Declaration shadower); eq Scope.getElement().shadowed(Declaration shadower) = shadowedLocally(shadower); @@ -18,9 +18,11 @@ aspect Shadowing { } // then look in the inherited scopes for (Scope inherited : getInheritedScopeList()) { - Declaration shadowed = inherited.shadowedLocally(shadower); - if (shadowed != null) { - return shadowed; + if (!inherited.isSuperScopeOf(this)) { + Declaration shadowed = inherited.shadowedLocally(shadower); + if (shadowed != null) { + return shadowed; + } } } return (this instanceof ScopeTree) ? null : shadowed(shadower); @@ -40,6 +42,11 @@ aspect Shadowing { syn boolean Declaration.isShadowing() = shadowed() != null; syn boolean Declaration.isShadowingInSameScope() = shadowedInSameScope() != null; + syn boolean Scope.isSuperScopeOf(Scope subScope) = (this==subScope) || isSuperScopeInh(subScope); + eq ScopeTree.isSuperScopeOf(Scope subScope) = this==subScope; + inh boolean Scope.isSuperScopeInh(Scope subScope); + eq Scope.getElement().isSuperScopeInh(Scope subScope) = isSuperScopeOf(subScope); + } aspect Statictics { diff --git a/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag b/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag index d9a6b42e29d38bf56201f0a6ff451605197f1b6c..7c8954aca3882b62b4cbe3d4d7ee8c68d490eda6 100644 --- a/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag +++ b/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag @@ -1,15 +1,44 @@ aspect ModelicaToScopeTree { - /** a relational nta collection attribute to compute the scope tree */ - syn lazy ScopeTree SourceRoot.scopeTree() = (ScopeTree) scope(); + /** a relational nta attribute to compute the scope tree */ + syn lazy ScopeTree SourceRoot.scopeTree() { + ScopeTree tree = (ScopeTree) scope(); + + // add all top-level classes + for (SrcClassDecl classDecl : topLevelClasses()) { + tree.addElement(classDecl.scope()); + } + + tree.updateInheritance(); // traverse the tree and add all inheritance relations + + return tree; + } + + coll HashSet<SrcClassDecl> SourceRoot.topLevelClasses() root SourceRoot; + SrcClassDecl contributes this when !isInnerClass() to SourceRoot.topLevelClasses(); + + /** helper method to add inheritance relations */ + public void Scope.updateInheritance() { + for (Element element : getElementList()) { + if (element.isScope()) { + element.asScope().updateInheritance(); + } + } + } + + public void ClassDeclScope.updateInheritance() { + for (SrcExtendsClause extendsClause : getClassDecl().superClasses()) { + SrcClassDecl superClass = extendsClause.getSuper().findClassDecl(); + if (superClass != null && superClass != superClass.program().getSrcUnknownClassDecl()) { + addInheritedScope(superClass.asScope()); + } + } + } /** a relational nta collection attribute to compute scopes */ coll Scope ASTNode.scope() [asScope()] with addElement root SourceRoot; - // collect all scopes - SrcClassDecl contributes scope() when !isEncapsulated() to ASTNode.scope() for containingScope(); - // if a scope is encapsulated, it is added to the top-level, because the inner - SrcClassDecl contributes scope() when isEncapsulated() to ASTNode.scope() for srcRoot(); - + // collect all scopes (except the top-level ones) + SrcClassDecl contributes scope() when isInnerClass() to ASTNode.scope() for containingScope(); SrcForStmt contributes scope() to ASTNode.scope() for containingScope(); // collect all elements @@ -68,4 +97,13 @@ aspect ScopeGenerationAttributes { inh SourceRoot SrcBaseNode.srcRoot(); eq SourceRoot.getChild().srcRoot() = this; + inh boolean SrcClassDecl.isInnerClass(); + eq SourceRoot.getChild().isInnerClass() = false; + eq SrcClassDecl.getChild().isInnerClass() = true; + + syn Program ASTNode.program() = programInh(); + eq SourceRoot.program() = getProgram(); + inh Program ASTNode.programInh(); + eq SourceRoot.getChild().programInh() = getProgram(); + } diff --git a/scope4m/src/test/java/org/jmodelica/ForbiddenShadowTest.java b/scope4m/src/test/java/org/jmodelica/ForbiddenShadowTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6de2d107302da49664d2da3575bd58d533842255 --- /dev/null +++ b/scope4m/src/test/java/org/jmodelica/ForbiddenShadowTest.java @@ -0,0 +1,19 @@ +package org.jmodelica; + +import org.jmodelica.compiler.AbstractFinding; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +public class ForbiddenShadowTest extends ScopeAnalysisTest { + + @Test + void test() { + + ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); + Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/forbiddenshadowing/", true, false); + + + } + +} diff --git a/scope4m/src/test/java/org/jmodelica/MultipleInheritanceTest.java b/scope4m/src/test/java/org/jmodelica/MultipleInheritanceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b8db94c3a792c43a2fe52299cdc8b1c733b54756 --- /dev/null +++ b/scope4m/src/test/java/org/jmodelica/MultipleInheritanceTest.java @@ -0,0 +1,19 @@ +package org.jmodelica; + +import org.jmodelica.compiler.AbstractFinding; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +public class MultipleInheritanceTest extends ScopeAnalysisTest { + + @Test + void test() { + + ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); + Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/forbiddenshadowing/", true, false); + + + } + +} diff --git a/scope4m/src/test/resources/forbiddenshadowing/shadowing.mo b/scope4m/src/test/resources/forbiddenshadowing/shadowing.mo new file mode 100644 index 0000000000000000000000000000000000000000..66dd99a31814df16393a3db7a11a98352d392f74 --- /dev/null +++ b/scope4m/src/test/resources/forbiddenshadowing/shadowing.mo @@ -0,0 +1,27 @@ +within ModelicaCompliance.Scoping.NameLookup.Simple; + + +model EnclosingClassLookupShadowedConstant + extends Icons.TestCase; + + constant Real x = 4.0; + + model A + Real x = 3.0; + + model B + Real y = x; + end B; + + B b; + end A; + + A a; + + annotation ( + __ModelicaAssociation(TestCase(shouldPass = false, section = {"5.3.1"})), + experiment(StopTime = 0.01), + Documentation( + info = "<html>Tests that variables found in an enclosing scope must be + declared constant, even if there is a constant in a more outer scope.</html>")); +end EnclosingClassLookupShadowedConstant; diff --git a/scope4m/src/test/resources/multipleInheritance/inheritance.mo b/scope4m/src/test/resources/multipleInheritance/inheritance.mo new file mode 100644 index 0000000000000000000000000000000000000000..412c20cbe53c27d27eba8958b95dafd3a9f043d3 --- /dev/null +++ b/scope4m/src/test/resources/multipleInheritance/inheritance.mo @@ -0,0 +1,24 @@ +within ModelicaCompliance.Inheritance.Flattening; + +model MultipleInheritance + extends Icons.TestCase; + + model A + Real x = 2; + end A; + + model B + Real y = 3; + end B; + + extends A; + extends B; + + Real z = x + y; +equation + annotation ( + __ModelicaAssociation(TestCase(shouldPass = true, section = {"7.1.1"})), + experiment(StopTime = 0.01), + Documentation( + info = "<html>Tests that multiple inheritance works.</html>")); +end MultipleInheritance;