From 92b22994479b5eefc33d0eb1da4f4c4ac1d821c7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Dec 2023 22:56:35 -0500 Subject: [PATCH 01/14] codes and tests --- .../specimin/JavaTypeCorrect.java | 1 + .../specimin/SpeciminRunner.java | 2 ++ .../specimin/TargetMethodFinderVisitor.java | 12 ++++++++++ .../specimin/UnsolvedSymbolVisitor.java | 15 ++++++++++--- .../specimin/LocalVarInExceptionTest.java | 18 +++++++++++++++ .../specimin/UnionTypeTest.java | 16 ++++++++++++++ .../specimin/VarTypeTest.java | 15 +++++++++++++ .../expected/com/example/Simple.java | 16 ++++++++++++++ .../expected/javalanguage/Method.java | 12 ++++++++++ .../javalanguage/SolveReturnType.java | 4 ++++ .../input/com/example/Simple.java | 16 ++++++++++++++ .../expected/com/example/Simple.java | 18 +++++++++++++++ .../resolution/UnsolvedSymbolException.java | 8 +++++++ .../expected/javalanguage/Method.java | 12 ++++++++++ .../javalanguage/SolveReturnType.java | 4 ++++ .../uniontype/input/com/example/Simple.java | 22 +++++++++++++++++++ .../vartype/expected/com/example/Simple.java | 15 +++++++++++++ .../expected/com/mathematic/Calculator.java | 8 +++++++ .../vartype/input/com/example/Simple.java | 14 ++++++++++++ 19 files changed, 225 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/checkerframework/specimin/LocalVarInExceptionTest.java create mode 100644 src/test/java/org/checkerframework/specimin/UnionTypeTest.java create mode 100644 src/test/java/org/checkerframework/specimin/VarTypeTest.java create mode 100644 src/test/resources/localvarinexception/expected/com/example/Simple.java create mode 100644 src/test/resources/localvarinexception/expected/javalanguage/Method.java create mode 100644 src/test/resources/localvarinexception/expected/javalanguage/SolveReturnType.java create mode 100644 src/test/resources/localvarinexception/input/com/example/Simple.java create mode 100644 src/test/resources/uniontype/expected/com/example/Simple.java create mode 100644 src/test/resources/uniontype/expected/com/github/javaparser/resolution/UnsolvedSymbolException.java create mode 100644 src/test/resources/uniontype/expected/javalanguage/Method.java create mode 100644 src/test/resources/uniontype/expected/javalanguage/SolveReturnType.java create mode 100644 src/test/resources/uniontype/input/com/example/Simple.java create mode 100644 src/test/resources/vartype/expected/com/example/Simple.java create mode 100644 src/test/resources/vartype/expected/com/mathematic/Calculator.java create mode 100644 src/test/resources/vartype/input/com/example/Simple.java diff --git a/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java b/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java index 86845b213..abcdfe9d4 100644 --- a/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java +++ b/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java @@ -94,6 +94,7 @@ public void runJavacAndUpdateTypes(String filePath) { new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); String line; while ((line = reader.readLine()) != null) { + System.out.println(line); if (line.contains("error: incompatible types")) { updateTypeToChange(line, filePath); } diff --git a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java index b9230a29f..306966240 100644 --- a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java +++ b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java @@ -205,6 +205,8 @@ public static void performMinimization( // return type of some synthetic methods, but later javac has found the correct return type // for that method. if (typesToChange.containsKey(simpleName)) { + System.out.println(typesToChange); + System.out.println("A: " + target.getValue()); continue; } if (!finder.getUsedClass().contains(classFullyQualfiedName)) { diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index a86963085..a18a71278 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -14,6 +14,7 @@ import com.github.javaparser.ast.expr.SuperExpr; import com.github.javaparser.ast.stmt.CatchClause; import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt; +import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.type.UnionType; @@ -278,6 +279,17 @@ public Visitable visit(MethodCallExpr call, Void p) { return super.visit(call, p); } + @Override + public Visitable visit(ClassOrInterfaceType type, Void p) { + try { + usedClass.add(type.resolve().getQualifiedName()); + System.out.println(type.resolve().getQualifiedName()); + } catch (UnsolvedSymbolException e) { + return super.visit(type, p); + } + return super.visit(type, p); + } + @Override public Visitable visit(ObjectCreationExpr newExpr, Void p) { if (insideTargetMethod) { diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 5664e2a13..c4bd15157 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -400,6 +400,7 @@ public Visitable visit(TryStmt node, Void p) { @Override public Visitable visit(CatchClause node, Void p) { HashSet currentLocalVariables = new HashSet<>(); + currentLocalVariables.add(node.getParameter().getNameAsString()); localVariables.addFirst(currentLocalVariables); Visitable result = super.visit(node, p); localVariables.removeFirst(); @@ -430,7 +431,12 @@ public Visitable visit(VariableDeclarator decl, Void p) { Type declType = decl.getType(); try { declType.resolve(); - } catch (UnsolvedSymbolException | UnsupportedOperationException e) { + } catch (RuntimeException e) { + // nothing to do here. This type is a var type. It is not unsolved. + if (!(e instanceof UnsolvedSymbolException) + && !(e instanceof UnsupportedOperationException)) { + return super.visit(decl, p); + } String typeAsString = declType.asString(); List elements = Splitter.onPattern("\\.").splitToList(typeAsString); // There could be three cases here: a type variable, a fully-qualified class name, or a simple @@ -769,11 +775,14 @@ private void handleParameterResolveFailure(@NonNull Parameter parameter) { * @param parameter unionType parameter from visitor class */ private void resolveUnionType(@NonNull Parameter parameter) { - for (var param : parameter.getType().asUnionType().getElements()) { + for (ReferenceType param : parameter.getType().asUnionType().getElements()) { try { param.resolve(); } catch (UnsolvedSymbolException | UnsupportedOperationException e) { - handleParameterResolveFailure(parameter); + // since this type is unsolved, it could not be a primitive type + @ClassGetSimpleName String typeName = param.getElementType().asClassOrInterfaceType().getName().asString(); + UnsolvedClass newClass = updateUnsolvedClassWithClassName(typeName, true); + updateMissingClass(newClass); } } } diff --git a/src/test/java/org/checkerframework/specimin/LocalVarInExceptionTest.java b/src/test/java/org/checkerframework/specimin/LocalVarInExceptionTest.java new file mode 100644 index 000000000..9a3819468 --- /dev/null +++ b/src/test/java/org/checkerframework/specimin/LocalVarInExceptionTest.java @@ -0,0 +1,18 @@ +package org.checkerframework.specimin; + +import java.io.IOException; +import org.junit.Test; + +/** + * This test checks if Specimin can work when the parameter of the catch clause is used in the + * associating block statement. + */ +public class LocalVarInExceptionTest { + @Test + public void runTest() throws IOException { + SpeciminTestExecutor.runTestWithoutJarPaths( + "localvarinexception", + new String[] {"com/example/Simple.java"}, + new String[] {"com.example.Simple#bar()"}); + } +} diff --git a/src/test/java/org/checkerframework/specimin/UnionTypeTest.java b/src/test/java/org/checkerframework/specimin/UnionTypeTest.java new file mode 100644 index 000000000..beb508e09 --- /dev/null +++ b/src/test/java/org/checkerframework/specimin/UnionTypeTest.java @@ -0,0 +1,16 @@ +package org.checkerframework.specimin; + +import org.junit.Test; + +import java.io.IOException; + +/** This test checks if Specimin can work when there is an unsolved union type. */ +public class UnionTypeTest { + @Test + public void runTest() throws IOException { + SpeciminTestExecutor.runTestWithoutJarPaths( + "uniontype", + new String[] {"com/example/Simple.java"}, + new String[] {"com.example.Simple#bar()"}); + } +} diff --git a/src/test/java/org/checkerframework/specimin/VarTypeTest.java b/src/test/java/org/checkerframework/specimin/VarTypeTest.java new file mode 100644 index 000000000..64f6db3bc --- /dev/null +++ b/src/test/java/org/checkerframework/specimin/VarTypeTest.java @@ -0,0 +1,15 @@ +package org.checkerframework.specimin; + +import java.io.IOException; +import org.junit.Test; + +/** This test checks if Specimin can work when there is the var keyword in the input test. */ +public class VarTypeTest { + @Test + public void runTest() throws IOException { + SpeciminTestExecutor.runTestWithoutJarPaths( + "vartype", + new String[] {"com/example/Simple.java"}, + new String[] {"com.example.Simple#bar()"}); + } +} diff --git a/src/test/resources/localvarinexception/expected/com/example/Simple.java b/src/test/resources/localvarinexception/expected/com/example/Simple.java new file mode 100644 index 000000000..efbf9c17d --- /dev/null +++ b/src/test/resources/localvarinexception/expected/com/example/Simple.java @@ -0,0 +1,16 @@ +package com.example; + +import javalanguage.Method; + +class Simple { + + void bar() { + String x = ""; + Method method = new Method(); + try { + method.solve(); + } catch (UnsupportedOperationException e) { + x = e.toString(); + } + } +} diff --git a/src/test/resources/localvarinexception/expected/javalanguage/Method.java b/src/test/resources/localvarinexception/expected/javalanguage/Method.java new file mode 100644 index 000000000..5e6f2456f --- /dev/null +++ b/src/test/resources/localvarinexception/expected/javalanguage/Method.java @@ -0,0 +1,12 @@ +package javalanguage; + +public class Method { + + public Method() { + throw new Error(); + } + + public SolveReturnType solve() { + throw new Error(); + } +} diff --git a/src/test/resources/localvarinexception/expected/javalanguage/SolveReturnType.java b/src/test/resources/localvarinexception/expected/javalanguage/SolveReturnType.java new file mode 100644 index 000000000..2ecef265a --- /dev/null +++ b/src/test/resources/localvarinexception/expected/javalanguage/SolveReturnType.java @@ -0,0 +1,4 @@ +package javalanguage; + +public class SolveReturnType { +} diff --git a/src/test/resources/localvarinexception/input/com/example/Simple.java b/src/test/resources/localvarinexception/input/com/example/Simple.java new file mode 100644 index 000000000..50297aa1a --- /dev/null +++ b/src/test/resources/localvarinexception/input/com/example/Simple.java @@ -0,0 +1,16 @@ +package com.example; + +import javalanguage.Method; +class Simple { + // Target method. + void bar() { + String x = ""; + Method method = new Method(); + try { + method.solve(); + } + catch (UnsupportedOperationException e) { + x = e.toString(); + } + } +} diff --git a/src/test/resources/uniontype/expected/com/example/Simple.java b/src/test/resources/uniontype/expected/com/example/Simple.java new file mode 100644 index 000000000..f424bbc15 --- /dev/null +++ b/src/test/resources/uniontype/expected/com/example/Simple.java @@ -0,0 +1,18 @@ +package com.example; + +import com.github.javaparser.resolution.UnsolvedSymbolException; +import javalanguage.Method; + +class Simple { + + void bar() { + String x = ""; + Method method = new Method(); + try { + method.solve(); + throw new UnsolvedSymbolException(); + } catch (UnsupportedOperationException | UnsolvedSymbolException e) { + x = e.toString(); + } + } +} diff --git a/src/test/resources/uniontype/expected/com/github/javaparser/resolution/UnsolvedSymbolException.java b/src/test/resources/uniontype/expected/com/github/javaparser/resolution/UnsolvedSymbolException.java new file mode 100644 index 000000000..7abea364e --- /dev/null +++ b/src/test/resources/uniontype/expected/com/github/javaparser/resolution/UnsolvedSymbolException.java @@ -0,0 +1,8 @@ +package com.github.javaparser.resolution; + +public class UnsolvedSymbolException extends Exception { + + public UnsolvedSymbolException() { + throw new Error(); + } +} diff --git a/src/test/resources/uniontype/expected/javalanguage/Method.java b/src/test/resources/uniontype/expected/javalanguage/Method.java new file mode 100644 index 000000000..5e6f2456f --- /dev/null +++ b/src/test/resources/uniontype/expected/javalanguage/Method.java @@ -0,0 +1,12 @@ +package javalanguage; + +public class Method { + + public Method() { + throw new Error(); + } + + public SolveReturnType solve() { + throw new Error(); + } +} diff --git a/src/test/resources/uniontype/expected/javalanguage/SolveReturnType.java b/src/test/resources/uniontype/expected/javalanguage/SolveReturnType.java new file mode 100644 index 000000000..2ecef265a --- /dev/null +++ b/src/test/resources/uniontype/expected/javalanguage/SolveReturnType.java @@ -0,0 +1,4 @@ +package javalanguage; + +public class SolveReturnType { +} diff --git a/src/test/resources/uniontype/input/com/example/Simple.java b/src/test/resources/uniontype/input/com/example/Simple.java new file mode 100644 index 000000000..7560f8db6 --- /dev/null +++ b/src/test/resources/uniontype/input/com/example/Simple.java @@ -0,0 +1,22 @@ +package com.example; + +import com.github.javaparser.resolution.UnsolvedSymbolException; +import javalanguage.Method; + +import java.io.IOException; + +class Simple { + // Target method. + void bar() { + String x = ""; + Method method = new Method(); + try { + method.solve(); + // this line is to avoid the compilation error when an exception is never thrown + throw new UnsolvedSymbolException(); + } + catch (UnsupportedOperationException | UnsolvedSymbolException e) { + x = e.toString(); + } + } +} diff --git a/src/test/resources/vartype/expected/com/example/Simple.java b/src/test/resources/vartype/expected/com/example/Simple.java new file mode 100644 index 000000000..8a6974d36 --- /dev/null +++ b/src/test/resources/vartype/expected/com/example/Simple.java @@ -0,0 +1,15 @@ +package com.example; + +import com.mathematic.Calculator; + +class Simple { + + void bar() { + var myCal = new Calculator(); + baz(myCal); + } + + Object baz(Calculator obj) { + throw new Error(); + } +} diff --git a/src/test/resources/vartype/expected/com/mathematic/Calculator.java b/src/test/resources/vartype/expected/com/mathematic/Calculator.java new file mode 100644 index 000000000..325bd5920 --- /dev/null +++ b/src/test/resources/vartype/expected/com/mathematic/Calculator.java @@ -0,0 +1,8 @@ +package com.mathematic; + +public class Calculator { + + public Calculator() { + throw new Error(); + } +} diff --git a/src/test/resources/vartype/input/com/example/Simple.java b/src/test/resources/vartype/input/com/example/Simple.java new file mode 100644 index 000000000..73e1ee4e6 --- /dev/null +++ b/src/test/resources/vartype/input/com/example/Simple.java @@ -0,0 +1,14 @@ +package com.example; +import com.mathematic.Calculator; + +class Simple { + // Target method. + void bar() { + var myCal = new Calculator(); + baz(myCal); + } + + Object baz(Calculator obj) { + throw new RuntimeException(); + } +} From 5b0329d645fe606a5302d615151607fa57958104 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Dec 2023 23:11:44 -0500 Subject: [PATCH 02/14] beautify the codes --- .../org/checkerframework/specimin/JavaTypeCorrect.java | 1 - .../java/org/checkerframework/specimin/SpeciminRunner.java | 2 -- .../specimin/TargetMethodFinderVisitor.java | 7 +++++-- .../java/org/checkerframework/specimin/UnionTypeTest.java | 3 +-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java b/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java index abcdfe9d4..86845b213 100644 --- a/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java +++ b/src/main/java/org/checkerframework/specimin/JavaTypeCorrect.java @@ -94,7 +94,6 @@ public void runJavacAndUpdateTypes(String filePath) { new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); String line; while ((line = reader.readLine()) != null) { - System.out.println(line); if (line.contains("error: incompatible types")) { updateTypeToChange(line, filePath); } diff --git a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java index 306966240..b9230a29f 100644 --- a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java +++ b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java @@ -205,8 +205,6 @@ public static void performMinimization( // return type of some synthetic methods, but later javac has found the correct return type // for that method. if (typesToChange.containsKey(simpleName)) { - System.out.println(typesToChange); - System.out.println("A: " + target.getValue()); continue; } if (!finder.getUsedClass().contains(classFullyQualfiedName)) { diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index a18a71278..dea43f0e5 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -283,8 +283,11 @@ public Visitable visit(MethodCallExpr call, Void p) { public Visitable visit(ClassOrInterfaceType type, Void p) { try { usedClass.add(type.resolve().getQualifiedName()); - System.out.println(type.resolve().getQualifiedName()); - } catch (UnsolvedSymbolException e) { + } + // if the type has a fully-qualified form, JavaParser also consider other components rather than + // the class name as ClassOrInterfaceType. For example, if the type is org.A.B, then JavaParser + // will also consider org and org.A as ClassOrInterfaceType + catch (UnsolvedSymbolException e) { return super.visit(type, p); } return super.visit(type, p); diff --git a/src/test/java/org/checkerframework/specimin/UnionTypeTest.java b/src/test/java/org/checkerframework/specimin/UnionTypeTest.java index beb508e09..0e0a3128e 100644 --- a/src/test/java/org/checkerframework/specimin/UnionTypeTest.java +++ b/src/test/java/org/checkerframework/specimin/UnionTypeTest.java @@ -1,8 +1,7 @@ package org.checkerframework.specimin; -import org.junit.Test; - import java.io.IOException; +import org.junit.Test; /** This test checks if Specimin can work when there is an unsolved union type. */ public class UnionTypeTest { From 9348ea0fe1de71206d1f71bf51be5de1516101a8 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Dec 2023 23:56:38 -0500 Subject: [PATCH 03/14] temporary progress --- .../checkerframework/specimin/SpeciminRunner.java | 8 ++++++++ .../specimin/UnsolvedSymbolVisitor.java | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java index b9230a29f..0de429197 100644 --- a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java +++ b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java @@ -11,6 +11,7 @@ import com.github.javaparser.symbolsolver.resolution.typesolvers.JarTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver; import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; +import com.github.javaparser.utils.SourceRoot; import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -104,6 +105,13 @@ public static void performMinimization( parsedTargetFiles.put(targetFile, parseJavaFile(root, targetFile)); } + // the set of Java files already exist in the input codebase + Set existingFiles = new HashSet<>(); + SourceRoot sourceRoot = new SourceRoot(Path.of(root)); + for (CompilationUnit compilationUnit : sourceRoot.getCompilationUnits()) { + existingFiles.add(compilationUnit.getStorage().get().getPath()); + } + System.out.println(existingFiles); UnsolvedSymbolVisitor addMissingClass = new UnsolvedSymbolVisitor(root); addMissingClass.setClassesFromJar(jarPaths); /** diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index c4bd15157..44fea8842 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -586,7 +586,14 @@ public Visitable visit(FieldAccessExpr node, Void p) { // if the symbol that called this field is solvable yet this field is unsolved, then the type of // the calling symbol is a synthetic class that needs to have a synthetic field updated else if (canBeSolved(node.getScope())) { - updateSyntheticClassWithNonStaticFields(node); + Expression nodeSccope = node.getScope(); + String filePath = + rootDirectory + nodeSccope.calculateResolvedType().describe().replace(".", "/") + ".java"; + System.out.println(filePath); + // this condition checks if the class is a synthetic class. + if (createdClass.contains(Path.of(filePath))) { + updateSyntheticClassWithNonStaticFields(node); + } } try { @@ -1344,6 +1351,9 @@ public static boolean calledByAnIncompleteSyntheticClass(MethodCallExpr method) * @param missedClass the class to be updated */ public void updateMissingClass(UnsolvedClass missedClass) { + if (missedClass.getClassName().equals("Avro2Confluent")) { + throw new RuntimeException("Toi ru em ngu. Mot som mua thu"); + } Iterator iterator = missingClass.iterator(); while (iterator.hasNext()) { UnsolvedClass e = iterator.next(); @@ -1427,7 +1437,6 @@ public void createMissingClass(UnsolvedClass missedClass) { String filePathStr = this.rootDirectory + classDirectory + "/" + missedClass.getClassName() + ".java"; Path filePath = Paths.get(filePathStr); - createdClass.add(filePath); try { Path parentPath = filePath.getParent(); From bea74fc20c2b6b74ba3f0a18d8aa5ed54a5b013a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 00:35:45 -0500 Subject: [PATCH 04/14] check existing files --- .../specimin/SpeciminRunner.java | 6 +++--- .../specimin/TargetMethodFinderVisitor.java | 4 +++- .../specimin/UnsolvedSymbolVisitor.java | 9 ++++++--- .../specimin/UnsolvedFieldInExistingFile.java | 18 ++++++++++++++++++ .../expected/com/example/Simple.java | 12 ++++++++++++ .../expected/com/school/Department.java | 4 ++++ .../input/com/example/Simple.java | 12 ++++++++++++ 7 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/checkerframework/specimin/UnsolvedFieldInExistingFile.java create mode 100644 src/test/resources/unsolvedFieldInExistingFile/expected/com/example/Simple.java create mode 100644 src/test/resources/unsolvedFieldInExistingFile/expected/com/school/Department.java create mode 100644 src/test/resources/unsolvedFieldInExistingFile/input/com/example/Simple.java diff --git a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java index 0de429197..2aa6af85c 100644 --- a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java +++ b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java @@ -108,11 +108,11 @@ public static void performMinimization( // the set of Java files already exist in the input codebase Set existingFiles = new HashSet<>(); SourceRoot sourceRoot = new SourceRoot(Path.of(root)); + sourceRoot.tryToParse(); for (CompilationUnit compilationUnit : sourceRoot.getCompilationUnits()) { - existingFiles.add(compilationUnit.getStorage().get().getPath()); + existingFiles.add(compilationUnit.getStorage().get().getPath().normalize()); } - System.out.println(existingFiles); - UnsolvedSymbolVisitor addMissingClass = new UnsolvedSymbolVisitor(root); + UnsolvedSymbolVisitor addMissingClass = new UnsolvedSymbolVisitor(root, existingFiles); addMissingClass.setClassesFromJar(jarPaths); /** * The set of path of files that have been created by addMissingClass. We will delete all those diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index dea43f0e5..d2c2eec9a 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -322,7 +322,9 @@ public Visitable visit(FieldAccessExpr expr, Void p) { usedMembers.add(fullNameOfClass + "#" + expr.getName().asString()); usedClass.add(fullNameOfClass); usedClass.add(expr.resolve().getType().describe()); - } catch (UnsolvedSymbolException e) { + } + // when the type is a primitive array, we will have an UnsupportedOperationException + catch (UnsolvedSymbolException | UnsupportedOperationException e) { // if the a field is accessed in the form of a fully-qualified path, such as // org.example.A.b, then other components in the path apart from the class name and field // name, such as org and org.example, will also be considered as FieldAccessExpr. diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 44fea8842..84a7a03d8 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -164,14 +164,18 @@ public class UnsolvedSymbolVisitor extends ModifierVisitor { */ private Map fieldNameToClassNameMap = new HashMap<>(); + /** The list of existing files in the input codebase. */ + private Set setOfExistingFiles; + /** * Create a new UnsolvedSymbolVisitor instance * * @param rootDirectory the root directory of the input files */ - public UnsolvedSymbolVisitor(String rootDirectory) { + public UnsolvedSymbolVisitor(String rootDirectory, Set setOfExistingFiles) { this.rootDirectory = rootDirectory; this.gotException = true; + this.setOfExistingFiles = setOfExistingFiles; } /** @@ -589,9 +593,8 @@ else if (canBeSolved(node.getScope())) { Expression nodeSccope = node.getScope(); String filePath = rootDirectory + nodeSccope.calculateResolvedType().describe().replace(".", "/") + ".java"; - System.out.println(filePath); // this condition checks if the class is a synthetic class. - if (createdClass.contains(Path.of(filePath))) { + if (setOfExistingFiles.contains(Path.of(filePath).normalize())) { updateSyntheticClassWithNonStaticFields(node); } } diff --git a/src/test/java/org/checkerframework/specimin/UnsolvedFieldInExistingFile.java b/src/test/java/org/checkerframework/specimin/UnsolvedFieldInExistingFile.java new file mode 100644 index 000000000..32f7ab8fe --- /dev/null +++ b/src/test/java/org/checkerframework/specimin/UnsolvedFieldInExistingFile.java @@ -0,0 +1,18 @@ +package org.checkerframework.specimin; + +import java.io.IOException; +import org.junit.Test; + +/** + * This test checks if Specimin will not create a synthetic file for a class that already exist in + * the input codebase. + */ +public class UnsolvedFieldInExistingFile { + @Test + public void runTest() throws IOException { + SpeciminTestExecutor.runTestWithoutJarPaths( + "unsolvedFieldInExistingFile", + new String[] {"com/example/Simple.java"}, + new String[] {"com.example.Simple#bar()"}); + } +} diff --git a/src/test/resources/unsolvedFieldInExistingFile/expected/com/example/Simple.java b/src/test/resources/unsolvedFieldInExistingFile/expected/com/example/Simple.java new file mode 100644 index 000000000..371915a97 --- /dev/null +++ b/src/test/resources/unsolvedFieldInExistingFile/expected/com/example/Simple.java @@ -0,0 +1,12 @@ +package com.example; + +import com.school.Department; + +class Simple { + + Department math; + + Department bar() { + return this.math; + } +} diff --git a/src/test/resources/unsolvedFieldInExistingFile/expected/com/school/Department.java b/src/test/resources/unsolvedFieldInExistingFile/expected/com/school/Department.java new file mode 100644 index 000000000..1762648eb --- /dev/null +++ b/src/test/resources/unsolvedFieldInExistingFile/expected/com/school/Department.java @@ -0,0 +1,4 @@ +package com.school; + +public class Department { +} diff --git a/src/test/resources/unsolvedFieldInExistingFile/input/com/example/Simple.java b/src/test/resources/unsolvedFieldInExistingFile/input/com/example/Simple.java new file mode 100644 index 000000000..ae64675ad --- /dev/null +++ b/src/test/resources/unsolvedFieldInExistingFile/input/com/example/Simple.java @@ -0,0 +1,12 @@ +package com.example; + +import com.school.Department; + +class Simple { + Department math; + Department bar() { + // math is unsolved, but Specimin should not create a synthetic class for class Simple + return this.math; + } + +} From 9856f85b43b774a99dff27ae77754fb06a2fd51d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 00:37:23 -0500 Subject: [PATCH 05/14] delete debug lines --- .../org/checkerframework/specimin/UnsolvedSymbolVisitor.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 84a7a03d8..88306cdd4 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -1354,9 +1354,6 @@ public static boolean calledByAnIncompleteSyntheticClass(MethodCallExpr method) * @param missedClass the class to be updated */ public void updateMissingClass(UnsolvedClass missedClass) { - if (missedClass.getClassName().equals("Avro2Confluent")) { - throw new RuntimeException("Toi ru em ngu. Mot som mua thu"); - } Iterator iterator = missingClass.iterator(); while (iterator.hasNext()) { UnsolvedClass e = iterator.next(); From c14ebdafa2761f6070d7191af219f0628d89c5ce Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 01:22:59 -0500 Subject: [PATCH 06/14] use absolute path --- src/main/java/org/checkerframework/specimin/SpeciminRunner.java | 2 +- .../org/checkerframework/specimin/UnsolvedSymbolVisitor.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java index 2aa6af85c..82c8f7a6e 100644 --- a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java +++ b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java @@ -110,7 +110,7 @@ public static void performMinimization( SourceRoot sourceRoot = new SourceRoot(Path.of(root)); sourceRoot.tryToParse(); for (CompilationUnit compilationUnit : sourceRoot.getCompilationUnits()) { - existingFiles.add(compilationUnit.getStorage().get().getPath().normalize()); + existingFiles.add(compilationUnit.getStorage().get().getPath().toAbsolutePath().normalize()); } UnsolvedSymbolVisitor addMissingClass = new UnsolvedSymbolVisitor(root, existingFiles); addMissingClass.setClassesFromJar(jarPaths); diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 88306cdd4..d78084157 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -594,7 +594,7 @@ else if (canBeSolved(node.getScope())) { String filePath = rootDirectory + nodeSccope.calculateResolvedType().describe().replace(".", "/") + ".java"; // this condition checks if the class is a synthetic class. - if (setOfExistingFiles.contains(Path.of(filePath).normalize())) { + if (!setOfExistingFiles.contains(Path.of(filePath).toAbsolutePath().normalize())) { updateSyntheticClassWithNonStaticFields(node); } } From 2f522d6f0c9a2aca7cfbdceedd5fb04fea0c6dba Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 01:32:32 -0500 Subject: [PATCH 07/14] ignore outside types --- .../checkerframework/specimin/TargetMethodFinderVisitor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index d2c2eec9a..3d79c1142 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -281,6 +281,9 @@ public Visitable visit(MethodCallExpr call, Void p) { @Override public Visitable visit(ClassOrInterfaceType type, Void p) { + if (!insideTargetMethod) { + return super.visit(type, p); + } try { usedClass.add(type.resolve().getQualifiedName()); } From e19ad181d8dcd19dcd681097a564508cc7538298 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 01:33:56 -0500 Subject: [PATCH 08/14] add param in javadoc --- .../org/checkerframework/specimin/UnsolvedSymbolVisitor.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index d78084157..63afd3f5a 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -171,6 +171,7 @@ public class UnsolvedSymbolVisitor extends ModifierVisitor { * Create a new UnsolvedSymbolVisitor instance * * @param rootDirectory the root directory of the input files + * @param setOfExistingFiles the set of existing files in the input codebase */ public UnsolvedSymbolVisitor(String rootDirectory, Set setOfExistingFiles) { this.rootDirectory = rootDirectory; From 16b85a7ffc70c4a8237f5fb1cce080eb418c519d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 01:35:40 -0500 Subject: [PATCH 09/14] add exception --- .../checkerframework/specimin/TargetMethodFinderVisitor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index 3d79c1142..cf266f574 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -289,8 +289,9 @@ public Visitable visit(ClassOrInterfaceType type, Void p) { } // if the type has a fully-qualified form, JavaParser also consider other components rather than // the class name as ClassOrInterfaceType. For example, if the type is org.A.B, then JavaParser - // will also consider org and org.A as ClassOrInterfaceType - catch (UnsolvedSymbolException e) { + // will also consider org and org.A as ClassOrInterfaceType. + // if type is a type variable, we will get an UnsupportedOperation Exception. + catch (UnsolvedSymbolException | UnsupportedOperationException e) { return super.visit(type, p); } return super.visit(type, p); From 170236d71a6deb55df305aa71ff5f6cbdb95680a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Dec 2023 18:27:09 -0500 Subject: [PATCH 10/14] throw exception with wildcard imports --- .../checkerframework/specimin/UnsolvedSymbolVisitor.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 63afd3f5a..66f9d5b57 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -276,6 +276,15 @@ public void setExceptionToFalse() { gotException = false; } + @Override + public Node visit(ImportDeclaration decl, Void arg) { + if (decl.isAsterisk()) { + throw new RuntimeException( + "A wildcard import statement found. Please use explicit import" + " statements."); + } + return super.visit(decl, arg); + } + @Override public Visitable visit(PackageDeclaration node, Void arg) { this.currentPackage = node.getNameAsString(); From 2b03137f6ab2e272864bd6faea99736b378a3638 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Dec 2023 18:53:24 -0500 Subject: [PATCH 11/14] update codes and fix some bugs --- .../specimin/PrunerVisitor.java | 29 +++++++++++++++++++ .../specimin/SpeciminRunner.java | 1 - .../specimin/TargetMethodFinderVisitor.java | 20 +++++++++++-- .../specimin/UnsolvedSymbolVisitor.java | 13 ++++----- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/PrunerVisitor.java b/src/main/java/org/checkerframework/specimin/PrunerVisitor.java index ac1571a76..dac12ebbd 100644 --- a/src/main/java/org/checkerframework/specimin/PrunerVisitor.java +++ b/src/main/java/org/checkerframework/specimin/PrunerVisitor.java @@ -18,6 +18,7 @@ import com.github.javaparser.ast.type.Type; import com.github.javaparser.ast.visitor.ModifierVisitor; import com.github.javaparser.ast.visitor.Visitable; +import com.github.javaparser.resolution.UnsolvedSymbolException; import com.github.javaparser.resolution.declarations.ResolvedConstructorDeclaration; import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; import java.util.Iterator; @@ -91,6 +92,16 @@ public Node visit(ImportDeclaration decl, Void p) { @Override public Visitable visit(MethodDeclaration methodDecl, Void p) { + try { + // resolved() will only check if the return type is solvable + // getQualifiedSignature() will also check if the parameters are solvable + methodDecl.resolve().getQualifiedSignature(); + } catch (UnsolvedSymbolException e) { + // The current class is employed by the target methods, although not all of its members are + // utilized. It's not surprising for unused members to remain unresolved. + methodDecl.remove(); + return methodDecl; + } ResolvedMethodDeclaration resolved = methodDecl.resolve(); if (methodsToLeaveUnchanged.contains(resolved.getQualifiedSignature())) { insideTargetMethod = true; @@ -112,6 +123,16 @@ public Visitable visit(MethodDeclaration methodDecl, Void p) { @Override public Visitable visit(ConstructorDeclaration constructorDecl, Void p) { + try { + // resolved() will only check if the return type is solvable + // getQualifiedSignature() will also check if the parameters are solvable + constructorDecl.resolve().getQualifiedSignature(); + } catch (UnsolvedSymbolException e) { + // The current class is employed by the target methods, although not all of its members are + // utilized. It's not surprising for unused members to remain unresolved. + constructorDecl.remove(); + return constructorDecl; + } ResolvedConstructorDeclaration resolved = constructorDecl.resolve(); if (methodsToLeaveUnchanged.contains(resolved.getQualifiedSignature())) { return super.visit(constructorDecl, p); @@ -126,6 +147,14 @@ public Visitable visit(ConstructorDeclaration constructorDecl, Void p) { @Override public Visitable visit(FieldDeclaration fieldDecl, Void p) { + try { + fieldDecl.resolve(); + } catch (UnsolvedSymbolException e) { + // The current class is employed by the target methods, although not all of its members are + // utilized. It's not surprising for unused members to remain unresolved. + fieldDecl.remove(); + return fieldDecl; + } String classFullName = fieldDecl.resolve().declaringType().getQualifiedName(); boolean isFinal = fieldDecl.isFinal(); Iterator iterator = fieldDecl.getVariables().iterator(); diff --git a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java index 82c8f7a6e..f6cc789e3 100644 --- a/src/main/java/org/checkerframework/specimin/SpeciminRunner.java +++ b/src/main/java/org/checkerframework/specimin/SpeciminRunner.java @@ -161,7 +161,6 @@ public static void performMinimization( } Set relatedClass = new HashSet<>(parsedTargetFiles.keySet()); - // add all files related to the targeted methods for (String classFullName : finder.getUsedClass()) { String directoryOfFile = classFullName.replace(".", "/") + ".java"; diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index cf266f574..329602d13 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -26,6 +26,7 @@ import com.github.javaparser.resolution.declarations.ResolvedValueDeclaration; import com.github.javaparser.resolution.types.ResolvedReferenceType; import com.github.javaparser.resolution.types.ResolvedType; +import com.google.common.base.Splitter; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -185,8 +186,7 @@ public Visitable visit(MethodDeclaration method, Void p) { String methodDeclAsString = method.getDeclarationAsString(false, false, false); // The substring here is to remove the method's return type. Return types cannot contain spaces. // TODO: test this with annotations - String methodName = - this.classFQName + "#" + methodDeclAsString.substring(methodDeclAsString.indexOf(' ') + 1); + String methodName = this.classFQName + "#" + removeMethodReturnType(methodDeclAsString); // this method belongs to an anonymous class inside the target method if (insideTargetMethod) { ObjectCreationExpr parentExpression = (ObjectCreationExpr) method.getParentNode().get(); @@ -354,6 +354,22 @@ public Visitable visit(NameExpr expr, Void p) { return super.visit(expr, p); } + /** + * Given a method declaration, this method return the declaration of that method without the + * return type. + * + * @param methodDeclaration the method declaration to be used as input + * @return methodDeclaration without the return type + */ + public static String removeMethodReturnType(String methodDeclaration) { + String methodDeclarationWithoutParen = + methodDeclaration.substring(0, methodDeclaration.indexOf("(")); + List methodParts = Splitter.onPattern(" ").splitToList(methodDeclarationWithoutParen); + String methodName = methodParts.get(methodParts.size() - 1); + String methodReturnType = methodDeclaration.substring(0, methodDeclaration.indexOf(methodName)); + return methodDeclaration.replace(methodReturnType, ""); + } + /** * Resolves unionType parameters one by one and adds them in the usedClass set. * diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 66f9d5b57..793b327b4 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -173,7 +173,7 @@ public class UnsolvedSymbolVisitor extends ModifierVisitor { * @param rootDirectory the root directory of the input files * @param setOfExistingFiles the set of existing files in the input codebase */ - public UnsolvedSymbolVisitor(String rootDirectory, Set setOfExistingFiles) { + public UnsolvedSymbolVisitor(String rootDirectory, Set setOfExistingFiles) { this.rootDirectory = rootDirectory; this.gotException = true; this.setOfExistingFiles = setOfExistingFiles; @@ -443,14 +443,13 @@ public Visitable visit(VariableDeclarator decl, Void p) { // This part is to create synthetic class for the type of decl if needed. Type declType = decl.getType(); + if (declType.isVarType()) { + // nothing to do here. A var type could never be solved. + return super.visit(decl, p); + } try { declType.resolve(); - } catch (RuntimeException e) { - // nothing to do here. This type is a var type. It is not unsolved. - if (!(e instanceof UnsolvedSymbolException) - && !(e instanceof UnsupportedOperationException)) { - return super.visit(decl, p); - } + } catch (UnsolvedSymbolException | UnsupportedOperationException e) { String typeAsString = declType.asString(); List elements = Splitter.onPattern("\\.").splitToList(typeAsString); // There could be three cases here: a type variable, a fully-qualified class name, or a simple From ba1431eba9f308234356ddbe518e73a7c7f89a85 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Dec 2023 19:33:05 -0500 Subject: [PATCH 12/14] make a separate method --- .../specimin/UnsolvedSymbolVisitor.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 793b327b4..c949c5a3b 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -596,16 +596,9 @@ public Visitable visit(FieldAccessExpr node, Void p) { classAndPackageMap.getOrDefault(simpleClassName, currentPackage) + "." + node; updateClassSetWithQualifiedFieldSignature(fullyQualifiedCall, true); } - // if the symbol that called this field is solvable yet this field is unsolved, then the type of - // the calling symbol is a synthetic class that needs to have a synthetic field updated - else if (canBeSolved(node.getScope())) { - Expression nodeSccope = node.getScope(); - String filePath = - rootDirectory + nodeSccope.calculateResolvedType().describe().replace(".", "/") + ".java"; - // this condition checks if the class is a synthetic class. - if (!setOfExistingFiles.contains(Path.of(filePath).toAbsolutePath().normalize())) { - updateSyntheticClassWithNonStaticFields(node); - } + // check if this unsolved field belongs to a synthetic class. + else if (canBeSolved(node.getScope()) && !belongsToARealClassFile(node)) { + updateSyntheticClassWithNonStaticFields(node); } try { @@ -763,6 +756,20 @@ public Visitable visit(ObjectCreationExpr newExpr, Void p) { return newExpr; } + /** + * Given a field access expression, this method determines whether the field is declared in one of + * the original class file in the codebase (instead of a synthetic class). + * + * @param node a FieldAccessExpr instance + * @return true if the field is inside an original class file + */ + public boolean belongsToARealClassFile(FieldAccessExpr node) { + Expression nodeScope = node.getScope(); + String filePath = + rootDirectory + nodeScope.calculateResolvedType().describe().replace(".", "/") + ".java"; + return setOfExistingFiles.contains(Path.of(filePath).toAbsolutePath().normalize()); + } + /** * @param parameter parameter from visitor method which is unsolvable. */ From 864fc8c80d8031fd1acfba2b1737fbc1eb987c22 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Dec 2023 19:50:38 -0500 Subject: [PATCH 13/14] return type can contain space --- .../checkerframework/specimin/TargetMethodFinderVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index 329602d13..05933bf23 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -184,7 +184,7 @@ public Visitable visit(VariableDeclarator node, Void arg) { @Override public Visitable visit(MethodDeclaration method, Void p) { String methodDeclAsString = method.getDeclarationAsString(false, false, false); - // The substring here is to remove the method's return type. Return types cannot contain spaces. + // The substring here is to remove the method's return type. // TODO: test this with annotations String methodName = this.classFQName + "#" + removeMethodReturnType(methodDeclAsString); // this method belongs to an anonymous class inside the target method From b4ea9c50ab9c97d8fece4846fbb90a044d347b27 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Dec 2023 14:36:55 -0500 Subject: [PATCH 14/14] remove unrelated comments --- .../org/checkerframework/specimin/TargetMethodFinderVisitor.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java index 05933bf23..7d31a084a 100644 --- a/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java +++ b/src/main/java/org/checkerframework/specimin/TargetMethodFinderVisitor.java @@ -184,7 +184,6 @@ public Visitable visit(VariableDeclarator node, Void arg) { @Override public Visitable visit(MethodDeclaration method, Void p) { String methodDeclAsString = method.getDeclarationAsString(false, false, false); - // The substring here is to remove the method's return type. // TODO: test this with annotations String methodName = this.classFQName + "#" + removeMethodReturnType(methodDeclAsString); // this method belongs to an anonymous class inside the target method