diff --git a/scope4m/src/main/jastadd/Helpers.jadd b/scope4m/src/main/jastadd/Helpers.jadd
index 3e171a6a2a637d32b77284caafb5f17d8ede8ad2..76a6d97efa1c53ff341fcce7516959d8a061686b 100644
--- a/scope4m/src/main/jastadd/Helpers.jadd
+++ b/scope4m/src/main/jastadd/Helpers.jadd
@@ -1,9 +1,7 @@
-/** copy of the extendj source location interface */
+/** helper methods to provide source locations */
 aspect SourceLocation {
 
-  protected String ASTNode.sourceFile() {
-    return retrieveFileName();
-  }
+  syn String ASTNode.sourceLocation() = sourceFile() + ":" + lineNumber();
 
   syn int ASTNode.lineNumber() {
     ASTNode n = this;
@@ -12,8 +10,18 @@ aspect SourceLocation {
     }
     return getLine(n.getStart());
   }
+  eq ClassDeclScope.lineNumber() = getClassDecl().lineNumber();
+  eq ForStmtScope.lineNumber() = getForStmt().lineNumber();
+  eq ComponentDeclaration.lineNumber() = getComponentDecl().lineNumber();
 
-  public String ASTNode.sourceLocation() {
-    return sourceFile() + ":" + lineNumber();
-  }
+  eq ClassDeclScope.toString() = "Class-" + getClassDecl().name() + "-Scope";
+  eq ForStmtScope.toString() = getForStmt().getClass().getSimpleName() + "-Scope";
+
+  eq ComponentDeclaration.toString() = getComponentDecl().getClass().getSimpleName() + ":" + super.toString();
+
+  syn String ASTNode.sourceFile() = "<unknown>";
+
+  eq ClassDeclScope.sourceFile() = getClassDecl().sourceFile();
+  eq ForStmtScope.sourceFile() = getForStmt().sourceFile();
+  eq ComponentDeclaration.sourceFile() =  getComponentDecl().sourceFile();
 }
diff --git a/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag b/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag
index b3c375dc727fbdddc15c810487d0fca7a35a6edd..d9a6b42e29d38bf56201f0a6ff451605197f1b6c 100644
--- a/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag
+++ b/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag
@@ -1,12 +1,71 @@
 aspect ModelicaToScopeTree {
-  syn lazy ScopeTree SourceRoot.scopeTree() {
+  /** a relational nta collection attribute to compute the scope tree */
+  syn lazy ScopeTree SourceRoot.scopeTree() = (ScopeTree) scope();
+
+  /** 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();
+
+  SrcForStmt contributes scope() to ASTNode.scope() for containingScope();
+
+  // collect all elements
+  SrcComponentDecl contributes asDeclaration() to ASTNode.scope() for containingScope();
+}
+
+/**
+ * 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 ScopeTreeConstructors {
+
+  syn lazy ScopeTree SourceRoot.asScope() {
     ScopeTree tree = new ScopeTree();
     tree.setSourceRoot(this);
-
     return tree;
   }
+
+  /** fallback attribute to ensure every AST element could pontentially be a scope */
+  syn Scope ASTNode.asScope() {
+    throw new RuntimeException("unable to create a scope for type " + getClass().getSimpleName());
+  }
+
+  syn lazy ClassDeclScope SrcClassDecl.asScope() {
+    ClassDeclScope scope = new ClassDeclScope();
+    scope.setClassDecl(this);
+    return scope;
+  }
+
+  syn lazy ForStmtScope SrcForStmt.asScope() {
+    ForStmtScope scope = new ForStmtScope();
+    scope.setForStmt(this);
+    return scope;
+  }
+
+  syn lazy ComponentDeclaration SrcComponentDecl.asDeclaration() {
+    ComponentDeclaration decl = new ComponentDeclaration(getName().getID());
+    decl.setComponentDecl(this);
+    return decl;
+  }
+
 }
 
 aspect ScopeGenerationAttributes {
 
+  /** determine the scope an AST element is contained in or belongs to.*/
+  inh lazy ASTNode SrcClassDecl.containingScope();
+  inh lazy ASTNode SrcForStmt.containingScope();
+  inh lazy ASTNode SrcComponentDecl.containingScope();
+  // contained in scope:
+  eq SourceRoot.getChild().containingScope() = this;
+  eq SrcClassDecl.getChild().containingScope() = this;
+  eq SrcForStmt.getChild().containingScope() = this;
+
+  inh SourceRoot SrcBaseNode.srcRoot();
+  eq SourceRoot.getChild().srcRoot() = this;
+
 }
diff --git a/scope4m/src/main/jastadd/ModelicaToScopeTree.relast b/scope4m/src/main/jastadd/ModelicaToScopeTree.relast
index 4c47dbc6b0ea111cf691919dba7bb0339e26dad7..082b97dcdbab81c65ce7836df9653a1821aa3537 100644
--- a/scope4m/src/main/jastadd/ModelicaToScopeTree.relast
+++ b/scope4m/src/main/jastadd/ModelicaToScopeTree.relast
@@ -1,2 +1,20 @@
 // glue relation for the Java-based variable shadowing analysis
 rel ScopeTree.SourceRoot -> SourceRoot;
+
+// scopes
+
+ClassDeclScope : Scope;
+rel ClassDeclScope.classDecl -> SrcClassDecl;
+
+ForStmtScope : Scope;
+rel ForStmtScope.forStmt -> SrcForStmt;
+
+// we do not need the for iter expression, because it cannot contains declarations
+// IterExpScope : Scope;
+// rel IterExpScope.iterExp -> SrcIterExp;
+
+// declarations
+
+ComponentDeclaration : Declaration;
+rel ComponentDeclaration.componentDecl -> SrcComponentDecl;
+
diff --git a/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java b/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java
index f7ce25d93bcc26f660f89f0887e8e6a537f9e5d1..a7dd42db699179a4d5e981856d9b49ff96fcaa69 100644
--- a/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java
+++ b/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java
@@ -37,10 +37,10 @@ public class ScopeAnalysis {
     boolean warnings = arguments.remove("--warnings");
 
     if (arguments.size() > 1) {
-      System.out.println("usage: ScopeAnalysis [--debug] [--tree] [--warnings] <directory with java files>");
+      System.out.println("usage: ScopeAnalysis [--debug] [--tree] [--warnings] <directory with modelica files>");
       System.exit(-1);
     }
-    String path = arguments.isEmpty() ? "../testprograms/modelica" : arguments.get(arguments.size() - 1);
+    String path = arguments.isEmpty() ? "../testprograms/modelica/simple" : arguments.get(arguments.size() - 1);
 
     if (debug) {
       new ScopeAnalysis().analyze(path, tree, warnings);
@@ -117,6 +117,7 @@ public class ScopeAnalysis {
 
       if (warnings) {
         // TODO find out if there are compiler warnings in JModelica
+        System.out.println("Currently, compiler warnings are not supported for jModelica.");
       }
 
       Set<AbstractFinding> findings = scopeTree.variableShadowings();
@@ -129,15 +130,13 @@ public class ScopeAnalysis {
 
       return findings;
     } catch (IOException | Parser.Exception | CompilerException e) {
+      System.out.println("Current relative path is: " + Paths.get("").toAbsolutePath());
       throw new RuntimeException(e);
     }
   }
 
   private static SourceRoot readProgram(Collection<String> files) throws IOException, beaver.Parser.Exception, CompilerException {
-
-
     ModelicaCompiler mc = new ModelicaCompiler(ModelicaCompiler.createOptions());
     return mc.getParserHandler().parseModel(UtilInterface.create(mc), (files.toArray(new String[]{})));
-
   }
 }
diff --git a/scope4m/src/test/java/org/jmodelica/ComplicatedScopeTest.java b/scope4m/src/test/java/org/jmodelica/ComplicatedScopeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..77496a1ab2c59bbf3e0de6e84246fb1182326a96
--- /dev/null
+++ b/scope4m/src/test/java/org/jmodelica/ComplicatedScopeTest.java
@@ -0,0 +1,20 @@
+package org.jmodelica;
+
+import org.jmodelica.compiler.AbstractFinding;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+public class ComplicatedScopeTest extends ScopeAnalysisTest {
+
+  @Test
+  void test() {
+
+    ScopeAnalysis scopeAnalysis = new ScopeAnalysis();
+    Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/complicated/", true, false);
+
+
+  }
+
+}
diff --git a/scope4m/src/test/java/org/jmodelica/EncapsulationTest.java b/scope4m/src/test/java/org/jmodelica/EncapsulationTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..065a38d3d2a4cbcfd584126d2712f65a41e6ea2c
--- /dev/null
+++ b/scope4m/src/test/java/org/jmodelica/EncapsulationTest.java
@@ -0,0 +1,16 @@
+package org.jmodelica;
+
+import org.jmodelica.compiler.AbstractFinding;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+public class EncapsulationTest extends ScopeAnalysisTest {
+
+  @Test
+  void test() {
+    ScopeAnalysis scopeAnalysis = new ScopeAnalysis();
+    Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/encapsulated", true, false);
+  }
+
+}
diff --git a/scope4m/src/test/java/org/jmodelica/ScopeAnalysisTest.java b/scope4m/src/test/java/org/jmodelica/ScopeAnalysisTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e097ec489e6d873de38a6ecc77158752b6f62ca9
--- /dev/null
+++ b/scope4m/src/test/java/org/jmodelica/ScopeAnalysisTest.java
@@ -0,0 +1,36 @@
+package org.jmodelica;
+
+import org.jmodelica.compiler.AbstractFinding;
+import org.jmodelica.compiler.Declaration;
+import org.jmodelica.compiler.MultipleDeclarationFinding;
+import org.jmodelica.compiler.VariableShadowFinding;
+import org.junit.jupiter.api.Assertions;
+
+import java.util.Set;
+
+public abstract class ScopeAnalysisTest {
+  static void assertShadow(Set<AbstractFinding> findings, String name, int shadowerLine, int shadowedLine) {
+    for (AbstractFinding finding : findings) {
+      if (finding instanceof VariableShadowFinding) {
+        Declaration shadower = ((VariableShadowFinding)finding).getShadower();
+        Declaration shadowed = ((VariableShadowFinding)finding).getShadowed();
+        if (shadowed.getName().equals(name) && shadowed.lineNumber() == shadowedLine && shadower.lineNumber() == shadowerLine) {
+          return;
+        }
+      }
+    }
+    Assertions.fail("No shadow finding found for name '" + name + "' in lines " + shadowerLine + " > " + shadowedLine);
+  }
+
+  static void assertRedefinition(Set<AbstractFinding> findings, String name, int declLine) {
+    for (AbstractFinding finding : findings) {
+      if (finding instanceof MultipleDeclarationFinding) {
+        Declaration declaration = ((MultipleDeclarationFinding)finding).getDeclaration();
+        if (declaration.getName().equals(name) && declaration.lineNumber() == declLine) {
+          return;
+        }
+      }
+    }
+    Assertions.fail("No multi-decl finding found for name '" + name + "' in line " + declLine);
+  }
+}
diff --git a/scope4m/src/test/java/org/jmodelica/SimpleScopeTest.java b/scope4m/src/test/java/org/jmodelica/SimpleScopeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..538bd3cdabf0098fb7e674d4f8ecb3430089bf6a
--- /dev/null
+++ b/scope4m/src/test/java/org/jmodelica/SimpleScopeTest.java
@@ -0,0 +1,20 @@
+package org.jmodelica;
+
+import org.jmodelica.compiler.AbstractFinding;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+public class SimpleScopeTest extends ScopeAnalysisTest {
+
+  @Test
+  void test() {
+
+    ScopeAnalysis scopeAnalysis = new ScopeAnalysis();
+    Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/simple", true, false);
+
+
+  }
+
+}
diff --git a/testprograms/modelica/ComplicatedNameLookup.mo b/scope4m/src/test/resources/complicated/complicated.mo
similarity index 100%
rename from testprograms/modelica/ComplicatedNameLookup.mo
rename to scope4m/src/test/resources/complicated/complicated.mo
diff --git a/scope4m/src/test/resources/encapsulated/encapsulation.mo b/scope4m/src/test/resources/encapsulated/encapsulation.mo
new file mode 100644
index 0000000000000000000000000000000000000000..d9877672c16dde105d17749aa34120e21f87985d
--- /dev/null
+++ b/scope4m/src/test/resources/encapsulated/encapsulation.mo
@@ -0,0 +1,19 @@
+within ModelicaCompliance.Scoping.NameLookup.Simple;
+
+model Encapsulation
+  extends Icons.TestCase;
+
+  encapsulated model A
+    constant Integer x = abs(-4);
+  equation
+    assert(x == 4, "x was not set correctly!");
+  end A;
+
+  A a;
+
+  annotation (
+    __ModelicaAssociation(TestCase(shouldPass = true, section = {"5.3.1"})),
+    experiment(StopTime = 0.01),
+    Documentation(
+    info = "<html>Tests that builtin functions can be found even if the scope is encapsulated.</html>"));
+end Encapsulation;
diff --git a/scope4m/src/test/resources/simple/simple.mo b/scope4m/src/test/resources/simple/simple.mo
new file mode 100644
index 0000000000000000000000000000000000000000..75b8e8a381d9290172f94b051b9e99a0d1e35f77
--- /dev/null
+++ b/scope4m/src/test/resources/simple/simple.mo
@@ -0,0 +1,17 @@
+within ModelicaCompliance.Scoping.InnerOuter;
+
+model SimpleNameLookup
+  extends Icons.TestCase;
+
+  class A
+    outer Integer T0;
+  end A;
+
+  class B
+    inner Integer T0 = 10;
+    A a1, a2; // B.T0, B.a1.T0 and B.a2.T0 is the same variable
+  end B;
+
+  B b;
+equation
+end SimpleNameLookup;
diff --git a/testprograms/modelica/simple/simple.mo b/testprograms/modelica/simple/simple.mo
new file mode 100644
index 0000000000000000000000000000000000000000..75b8e8a381d9290172f94b051b9e99a0d1e35f77
--- /dev/null
+++ b/testprograms/modelica/simple/simple.mo
@@ -0,0 +1,17 @@
+within ModelicaCompliance.Scoping.InnerOuter;
+
+model SimpleNameLookup
+  extends Icons.TestCase;
+
+  class A
+    outer Integer T0;
+  end A;
+
+  class B
+    inner Integer T0 = 10;
+    A a1, a2; // B.T0, B.a1.T0 and B.a2.T0 is the same variable
+  end B;
+
+  B b;
+equation
+end SimpleNameLookup;