From 41afe7e7a394fc10b70da274fffe5463e30b90f0 Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Tue, 24 Dec 2019 15:16:43 +0100 Subject: [PATCH] add two very simple tests (one fails, because inheritance is not yet considered) --- scope4j/build.gradle | 8 ++ .../main/java/org/extendj/ScopeAnalysis.java | 80 ++++++++++++++----- .../java/org/extendj/ScopeAnalysisTest.java | 21 +++++ .../java/org/extendj/SimpleScopeTest.java | 29 +++++++ .../org/extendj/SuperclassFieldsTest.java | 26 ++++++ scope4j/src/test/resources/simple/ClassA.java | 42 ++++++++++ .../resources/superclassFields/ClassA.java | 12 +++ .../resources/superclassFields/ClassB.java | 26 ++++++ 8 files changed, 222 insertions(+), 22 deletions(-) create mode 100644 scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java create mode 100644 scope4j/src/test/java/org/extendj/SimpleScopeTest.java create mode 100644 scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java create mode 100644 scope4j/src/test/resources/simple/ClassA.java create mode 100644 scope4j/src/test/resources/superclassFields/ClassA.java create mode 100644 scope4j/src/test/resources/superclassFields/ClassB.java diff --git a/scope4j/build.gradle b/scope4j/build.gradle index 74c3ca8..cf6e3a0 100644 --- a/scope4j/build.gradle +++ b/scope4j/build.gradle @@ -23,6 +23,10 @@ idea { } } +test { + useJUnitPlatform {} +} + sourceSets.main { java { @@ -37,6 +41,10 @@ sourceSets.main { } dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' + testCompile 'org.junit.platform:junit-platform-runner:1.4.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' } jastadd { diff --git a/scope4j/src/main/java/org/extendj/ScopeAnalysis.java b/scope4j/src/main/java/org/extendj/ScopeAnalysis.java index 9ac9889..333ad33 100644 --- a/scope4j/src/main/java/org/extendj/ScopeAnalysis.java +++ b/scope4j/src/main/java/org/extendj/ScopeAnalysis.java @@ -18,6 +18,12 @@ public class ScopeAnalysis extends Frontend { } + public Program getProgram() { + return program; + } + + private Program program; + /** * Entry point for the Java checker. * @@ -28,13 +34,24 @@ public class ScopeAnalysis extends Frontend { List<String> arguments = new ArrayList<>(Arrays.asList(args)); boolean debug = arguments.isEmpty() || arguments.remove("--debug"); + boolean tree = arguments.remove("--tree"); + boolean warnings = arguments.remove("--warnings"); if (arguments.size() > 1) { - System.out.println("usage: ScopeAnalysis [--debug] <directory with java files>"); + System.out.println("usage: ScopeAnalysis [--debug] [--tree] [--warnings] <directory with java files>"); System.exit(-1); } String path = arguments.isEmpty() ? "../testprograms/simpleScope" : arguments.get(arguments.size() - 1); + if (debug) { + new ScopeAnalysis().analyze(path, tree, warnings); + } else { + new ScopeAnalysis().analyzeTimed(path); + } + + } + + public void analyzeTimed(String path) { try { List<String> files = Files.walk(Paths.get(path)) .filter(Files::isRegularFile) @@ -43,37 +60,17 @@ public class ScopeAnalysis extends Frontend { // measure the time (with parsing) from here long startMeasurementTime = System.nanoTime(); - Program program = new ScopeAnalysis().readProgram(files); + program = readProgram(files); // measure the time (without parsing) from here long startGenerationTime = System.nanoTime(); ScopeTree scopeTree = program.scopeTree(); - if (debug) { - scopeTree.printAST(); - - System.out.println("\nExtendJ found the following problems:"); - for (CompilationUnit unit : program.getCompilationUnitList()) { - for (Problem problem : unit.problems()) { - System.out.println(problem); - } - } - System.out.println(); - } - long startAnalysisTime = System.nanoTime(); Set<VariableShadowFinding> findings = scopeTree.variableShadowings(); - if (debug) { - System.out.println("\nScope4J found the following problems:"); - for (VariableShadowFinding finding : findings) { - System.out.println(finding); - } - System.out.println(); - } - // measure the time until here long endTime = System.nanoTime(); @@ -100,6 +97,45 @@ public class ScopeAnalysis extends Frontend { } } + + public Set<VariableShadowFinding> analyze(String path, boolean tree, boolean warnings) { + try { + List<String> files = Files.walk(Paths.get(path)) + .filter(Files::isRegularFile) + .filter(x -> x.getFileName().toString().endsWith(".java")).map(Path::toString).collect(Collectors.toList()); + + program = readProgram(files); + + ScopeTree scopeTree = program.scopeTree(); + + if (tree) { + scopeTree.printAST(); + } + + if (warnings) { + System.out.println("\nExtendJ found the following problems:"); + for (CompilationUnit unit : program.getCompilationUnitList()) { + for (Problem problem : unit.problems()) { + System.out.println(problem); + } + } + System.out.println(); + } + + Set<VariableShadowFinding> findings = scopeTree.variableShadowings(); + + System.out.println("\nScope4J found the following problems:"); + for (VariableShadowFinding finding : findings) { + System.out.println(finding); + } + System.out.println(); + + return findings; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + private Program readProgram(Collection<String> files) throws IOException { diff --git a/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java b/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java new file mode 100644 index 0000000..10bdd1e --- /dev/null +++ b/scope4j/src/test/java/org/extendj/ScopeAnalysisTest.java @@ -0,0 +1,21 @@ +package org.extendj; + +import org.extendj.ast.Declaration; +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; + } + } + Assertions.fail("No finding found for name '" + name + "' in lines " + shadowerLine + " > " + shadowedLine); + } +} diff --git a/scope4j/src/test/java/org/extendj/SimpleScopeTest.java b/scope4j/src/test/java/org/extendj/SimpleScopeTest.java new file mode 100644 index 0000000..c11b502 --- /dev/null +++ b/scope4j/src/test/java/org/extendj/SimpleScopeTest.java @@ -0,0 +1,29 @@ +package org.extendj; + +import org.extendj.ast.VariableShadowFinding; +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<VariableShadowFinding> findings = scopeAnalysis.analyze("src/test/resources/simple", false, false); + + + Assertions.assertEquals(5, findings.size()); + + assertShadow(findings, "localVarA", 19, 11); + assertShadow(findings, "localVarB", 33, 12); + assertShadow(findings, "localVarC", 24, 13); + assertShadow(findings, "fieldA", 29, 3); + assertShadow(findings, "fieldB", 36, 4); + + + } + +} diff --git a/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java b/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java new file mode 100644 index 0000000..3dd2b9e --- /dev/null +++ b/scope4j/src/test/java/org/extendj/SuperclassFieldsTest.java @@ -0,0 +1,26 @@ +package org.extendj; + +import org.extendj.ast.VariableShadowFinding; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +public class SuperclassFieldsTest extends ScopeAnalysisTest { + + @Test + void test() { + + ScopeAnalysis scopeAnalysis = new ScopeAnalysis(); + Set<VariableShadowFinding> findings = scopeAnalysis.analyze("src/test/resources/superclassFields", false, false); + + + assertShadow(findings, "fieldC", 19, 3); + assertShadow(findings, "fieldB", 21, 2); + assertShadow(findings, "fieldB", 2, 4); + + Assertions.assertEquals(3, findings.size()); + + } + +} diff --git a/scope4j/src/test/resources/simple/ClassA.java b/scope4j/src/test/resources/simple/ClassA.java new file mode 100644 index 0000000..a066a2a --- /dev/null +++ b/scope4j/src/test/resources/simple/ClassA.java @@ -0,0 +1,42 @@ +public abstract class ClassA { + + int fieldA; + int fieldB; + + public ClassA(int constructorParameterA) { + int localConstructorVarA = 0; + } + + public void methodNameA(int parameterA) { + int localVarA = 1; + int localVarB = 1; + int localVarC = 1; + + { + int localVarInBlockA = 2; + + // this is shadowing (and forbidden) + int localVarA = 3; + } + + class Local { + { + for (int localVarC = 0; localVarC < 10; localVarC++) System.out.println(localVarC); + } + } + + // this is shadowing (over two levels, not forbidden) + int fieldA; + + try ( + // this is forbidden + java.util.zip.ZipFile localVarB = new java.util.zip.ZipFile("zipFileName"); + + // this is okay + java.io.BufferedWriter fieldB = java.nio.file.Files.newBufferedWriter(null) + ) { /* do stuff */ } catch (java.io.IOException e) {/* do stuff */} + } + + // this does not appear as a scope (and, more importantly, the parameters are not added anywhere else) + public abstract void methodNameB(int parameterForAbstractMethodB); +} diff --git a/scope4j/src/test/resources/superclassFields/ClassA.java b/scope4j/src/test/resources/superclassFields/ClassA.java new file mode 100644 index 0000000..675b936 --- /dev/null +++ b/scope4j/src/test/resources/superclassFields/ClassA.java @@ -0,0 +1,12 @@ +public abstract class ClassA { + + int fieldA; + int fieldB; + + void m(); + + void n() { + //... + } + +} diff --git a/scope4j/src/test/resources/superclassFields/ClassB.java b/scope4j/src/test/resources/superclassFields/ClassB.java new file mode 100644 index 0000000..dbd482e --- /dev/null +++ b/scope4j/src/test/resources/superclassFields/ClassB.java @@ -0,0 +1,26 @@ +public class ClassB extends ClassA { + int fieldB; + int fieldC; + + @Override + void m() { + //Overridden.. + } + + void n() { + //not overriden + } + + void n(int value) { + //polymorphic + } + + class ClassC { + int fieldC; + + public ClassC(int fieldB) { + fieldC = fieldB; + } + } + +} -- GitLab