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

add inherited fields to class scope. split findings in re-definitons and...

add inherited fields to class scope. split findings in re-definitons and shadowings/hidings. quite unhappy with this approach, second one is coming up.
parent 41afe7e7
No related branches found
No related tags found
No related merge requests found
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!";
}
}
}
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;
......
......@@ -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;
}
......
......@@ -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();
......
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);
}
}
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());
......
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());
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment