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

add inheritance support for modelica, prevent recursive scope analysis

parent 8b85b75b
No related branches found
No related tags found
No related merge requests found
......@@ -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 {
......
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();
}
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);
}
}
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);
}
}
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;
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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment