From 3bb558293798395146d94346043c4afa4c80fbf4 Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Tue, 31 Dec 2019 16:11:45 +0100 Subject: [PATCH] add inherited fields to class scope. split findings in re-definitons and shadowings/hidings. quite unhappy with this approach, second one is coming up. --- scope/src/main/jastadd/Shadowing.jadd | 20 +++++++++++- scope/src/main/jastadd/Shadowing.jrag | 18 +++++++++-- .../src/main/jastadd/ProgramToScopeTree.jrag | 25 +++++++++++++++ .../main/java/org/extendj/ScopeAnalysis.java | 8 ++--- .../java/org/extendj/ScopeAnalysisTest.java | 31 ++++++++++++++----- .../java/org/extendj/SimpleScopeTest.java | 4 +-- .../org/extendj/SuperclassFieldsTest.java | 10 +++--- 7 files changed, 95 insertions(+), 21 deletions(-) diff --git a/scope/src/main/jastadd/Shadowing.jadd b/scope/src/main/jastadd/Shadowing.jadd index 7f05f3e..08b0f58 100644 --- a/scope/src/main/jastadd/Shadowing.jadd +++ b/scope/src/main/jastadd/Shadowing.jadd @@ -1,5 +1,7 @@ aspect Shadowing { - public class VariableShadowFinding { + public abstract class AbstractFinding {} + + public class VariableShadowFinding extends AbstractFinding { private Declaration shadower, shadowed; @@ -24,4 +26,20 @@ aspect Shadowing { } } } +public class MultipleDeclarationFinding extends AbstractFinding { + + private Declaration declaration; + + public MultipleDeclarationFinding(Declaration declaration) { + this.declaration = declaration; + } + + public Declaration getDeclaration() { + return declaration; + } + + public String toString() { + return declaration.sourceFile() + ": declaration '" + declaration + "' (l." + declaration.lineNumber() + ") is not unique in its scope!"; + } + } } diff --git a/scope/src/main/jastadd/Shadowing.jrag b/scope/src/main/jastadd/Shadowing.jrag index 4d20158..3ca6452 100644 --- a/scope/src/main/jastadd/Shadowing.jrag +++ b/scope/src/main/jastadd/Shadowing.jrag @@ -1,9 +1,11 @@ aspect Shadowing { - coll Set<VariableShadowFinding> ScopeTree.variableShadowings() [new HashSet<>()] with add root ScopeTree; + coll Set<AbstractFinding> ScopeTree.variableShadowings() [new HashSet<>()] with add root ScopeTree; 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(this); + inh Declaration Declaration.shadowed(); + eq Scope.getElement(int i).shadowed() = shadowed(getElement(i).asDeclaration()); inh Declaration Element.shadowed(Declaration shadower); eq ScopeTree.getElement().shadowed(Declaration shadower) { @@ -23,7 +25,19 @@ aspect Shadowing { return shadowed(shadower); } + inh Declaration Declaration.shadowedInSameScope(); + eq Scope.getElement(int i).shadowedInSameScope() { + Declaration declaration = getElement(i).asDeclaration(); + for (Element otherElement : getElementList()) { + if (otherElement != declaration && otherElement.isDeclaration() && otherElement.asDeclaration().getName().equals(declaration.getName())) { + return otherElement.asDeclaration(); + } + } + return null; + } + syn boolean Declaration.isShadowing() = shadowed() != null; + syn boolean Declaration.isShadowingInSameScope() = shadowedInSameScope() != null; diff --git a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag index 6a155b9..c0aa607 100644 --- a/scope4j/src/main/jastadd/ProgramToScopeTree.jrag +++ b/scope4j/src/main/jastadd/ProgramToScopeTree.jrag @@ -23,6 +23,26 @@ aspect ProgramToScopeTree { Declarator contributes asDeclaration() to ASTNode.scope() for containingScope(); ParameterDeclaration contributes asDeclaration() to ASTNode.scope() for containingScope(); + Collection<Declaration> ClassDecl.createSuperClassFieldDeclarators() { + ArrayList<Declaration> result = new ArrayList<>(); + TypeDecl supertype = superclass(); + + System.out.println("supertype " + supertype.getID()); + while (supertype.isClassDecl() && supertype != unknownType()) { + for (BodyDecl bodyDecl : supertype.getBodyDeclList()) { + if (bodyDecl instanceof FieldDecl) { + for (FieldDeclarator declarator : ((FieldDecl)bodyDecl).getDeclaratorList()) { + JavaDeclaration declaration = new JavaDeclaration(declarator.getID()); + declaration.setDeclarator(declarator); + result.add(declaration); + } + } + } + supertype = ((ClassDecl)supertype).superclass(); + } + return result; + } + /** 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()); @@ -31,6 +51,11 @@ aspect ProgramToScopeTree { syn lazy TypeDeclScope TypeDecl.asScope() { TypeDeclScope scope = new TypeDeclScope(); scope.setTypeDecl(this); + if (isClassDecl()) { + for (Declaration declaration : ((ClassDecl)this).createSuperClassFieldDeclarators()) { + scope.addElement(declaration); + } + } return scope; } diff --git a/scope4j/src/main/java/org/extendj/ScopeAnalysis.java b/scope4j/src/main/java/org/extendj/ScopeAnalysis.java index 333ad33..4409ba3 100644 --- a/scope4j/src/main/java/org/extendj/ScopeAnalysis.java +++ b/scope4j/src/main/java/org/extendj/ScopeAnalysis.java @@ -69,7 +69,7 @@ public class ScopeAnalysis extends Frontend { long startAnalysisTime = System.nanoTime(); - Set<VariableShadowFinding> findings = scopeTree.variableShadowings(); + Set<AbstractFinding> findings = scopeTree.variableShadowings(); // measure the time until here long endTime = System.nanoTime(); @@ -98,7 +98,7 @@ public class ScopeAnalysis extends Frontend { } - public Set<VariableShadowFinding> analyze(String path, boolean tree, boolean warnings) { + public Set<AbstractFinding> analyze(String path, boolean tree, boolean warnings) { try { List<String> files = Files.walk(Paths.get(path)) .filter(Files::isRegularFile) @@ -122,10 +122,10 @@ public class ScopeAnalysis extends Frontend { System.out.println(); } - Set<VariableShadowFinding> findings = scopeTree.variableShadowings(); + Set<AbstractFinding> findings = scopeTree.variableShadowings(); System.out.println("\nScope4J found the following problems:"); - for (VariableShadowFinding finding : findings) { + for (AbstractFinding finding : findings) { System.out.println(finding); } System.out.println(); diff --git a/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java b/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java index 10bdd1e..95d479c 100644 --- a/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java +++ b/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java @@ -1,21 +1,36 @@ package org.extendj; +import org.extendj.ast.AbstractFinding; import org.extendj.ast.Declaration; +import org.extendj.ast.MultipleDeclarationFinding; import org.extendj.ast.VariableShadowFinding; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; import java.util.Set; public abstract class ScopeAnalysisTest { - static void assertShadow(Set<VariableShadowFinding> findings, String name, int shadowerLine, int shadowedLine) { - for (VariableShadowFinding finding : findings) { - Declaration shadower = finding.getShadower(); - Declaration shadowed = finding.getShadowed(); - if (shadowed.getName().equals(name) && shadowed.lineNumber() == shadowedLine && shadower.lineNumber() == shadowerLine) { - return; + 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 finding found for name '" + name + "' in lines " + shadowerLine + " > " + shadowedLine); + 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/scope4j/src/test/java/org/extendj/SimpleScopeTest.java b/scope4j/src/test/java/org/extendj/SimpleScopeTest.java index c11b502..2bb7111 100644 --- a/scope4j/src/test/java/org/extendj/SimpleScopeTest.java +++ b/scope4j/src/test/java/org/extendj/SimpleScopeTest.java @@ -1,6 +1,6 @@ package org.extendj; -import org.extendj.ast.VariableShadowFinding; +import org.extendj.ast.AbstractFinding; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -12,7 +12,7 @@ public class SimpleScopeTest extends ScopeAnalysisTest { void test() { ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); - Set<VariableShadowFinding> findings = scopeAnalysis.analyze("src/test/resources/simple", false, false); + Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/simple", false, false); Assertions.assertEquals(5, findings.size()); diff --git a/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java b/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java index 3dd2b9e..e32199d 100644 --- a/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java +++ b/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java @@ -1,5 +1,6 @@ package org.extendj; +import org.extendj.ast.AbstractFinding; import org.extendj.ast.VariableShadowFinding; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -12,14 +13,15 @@ public class SuperclassFieldsTest extends ScopeAnalysisTest { void test() { ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); - Set<VariableShadowFinding> findings = scopeAnalysis.analyze("src/test/resources/superclassFields", false, false); + Set<AbstractFinding> findings = scopeAnalysis.analyze("src/test/resources/superclassFields", true, false); assertShadow(findings, "fieldC", 19, 3); - assertShadow(findings, "fieldB", 21, 2); - assertShadow(findings, "fieldB", 2, 4); + assertShadow(findings, "fieldB", 21, 4); + assertRedefinition(findings, "fieldB", 2); + assertRedefinition(findings, "fieldB", 4); - Assertions.assertEquals(3, findings.size()); + Assertions.assertEquals(4, findings.size()); } -- GitLab