From 8a8a818655f08fefff44cc66640a9591358e03d4 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Nov 2023 19:36:33 -0500 Subject: [PATCH 1/6] add codes and test --- .../specimin/UnsolvedSymbolVisitor.java | 44 ++++++++----------- .../UnsolvedClassInSamePackageTest.java | 18 ++++++++ .../expected/com/example/Baz.java | 8 ++++ .../expected/com/example/Simple.java | 8 ++++ .../input/com/example/Simple.java | 7 +++ 5 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 src/test/java/org/checkerframework/specimin/UnsolvedClassInSamePackageTest.java create mode 100644 src/test/resources/unsolvedclassinsamepackage/expected/com/example/Baz.java create mode 100644 src/test/resources/unsolvedclassinsamepackage/expected/com/example/Simple.java create mode 100644 src/test/resources/unsolvedclassinsamepackage/input/com/example/Simple.java diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index a843d0fd..f8b9952e 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -526,13 +526,11 @@ public Visitable visit(MethodDeclaration node, Void arg) { try { nodeType.resolve(); } catch (UnsolvedSymbolException | UnsupportedOperationException e) { - if (classAndPackageMap.containsKey(nodeTypeSimpleForm)) { - UnsolvedClass syntheticType = - new UnsolvedClass(nodeTypeSimpleForm, classAndPackageMap.get(nodeTypeSimpleForm)); - this.updateMissingClass(syntheticType); - } else { - throw new RuntimeException("Unexpected class: " + nodeTypeSimpleForm); - } + // if the class could not be found among import statements, we assume that the class must be + // in the same package as the current class. + String packageName = classAndPackageMap.getOrDefault(nodeTypeSimpleForm, currentPackage); + UnsolvedClass syntheticType = new UnsolvedClass(nodeTypeSimpleForm, packageName); + this.updateMissingClass(syntheticType); } } @@ -677,12 +675,11 @@ public Visitable visit(Parameter parameter, Void p) { } else { // since it is unsolved, it could not be a primitive type @ClassGetSimpleName String className = parameter.getType().asClassOrInterfaceType().getName().asString(); - if (classAndPackageMap.containsKey(className)) { - UnsolvedClass newClass = new UnsolvedClass(className, classAndPackageMap.get(className)); - updateMissingClass(newClass); - } else { - throw new RuntimeException("Unexpected class: " + className); - } + // we assume that an unsolved class not found among import statements should be in the same + // package as the current class + String packageName = classAndPackageMap.getOrDefault(className, currentPackage); + UnsolvedClass newClass = new UnsolvedClass(className, packageName); + updateMissingClass(newClass); } } gotException = true; @@ -706,14 +703,12 @@ public Visitable visit(ObjectCreationExpr newExpr, Void p) { try { List argumentsCreation = getArgumentsFromObjectCreation(newExpr); UnsolvedMethod creationMethod = new UnsolvedMethod("", type, argumentsCreation); - if (classAndPackageMap.containsKey(type)) { - UnsolvedClass newClass = new UnsolvedClass(type, classAndPackageMap.get(type)); - newClass.addMethod(creationMethod); - this.updateMissingClass(newClass); - } else { - throw new RuntimeException("Unexpected class: " + type); - } - + // we assume that an unsolved class not found among import statements should be in the same + // package as the current class + String packageName = classAndPackageMap.getOrDefault(type, currentPackage); + UnsolvedClass newClass = new UnsolvedClass(type, packageName); + newClass.addMethod(creationMethod); + this.updateMissingClass(newClass); } catch (Exception q) { // can not solve the parameters for this object creation in this current run } @@ -807,10 +802,9 @@ public void updateUnsolvedClassWithMethod( } else { returnType = desiredReturnType; } - if (!classAndPackageMap.containsKey(className)) { - throw new RuntimeException("Unexpected class: " + className); - } - UnsolvedClass missingClass = new UnsolvedClass(className, classAndPackageMap.get(className)); + // a class not found among import statements should be in the same package as the current class + UnsolvedClass missingClass = + new UnsolvedClass(className, classAndPackageMap.getOrDefault(className, currentPackage)); UnsolvedMethod thisMethod = new UnsolvedMethod(methodName, returnType, listOfParameters); missingClass.addMethod(thisMethod); syntheticMethodAndClass.put(methodName, missingClass); diff --git a/src/test/java/org/checkerframework/specimin/UnsolvedClassInSamePackageTest.java b/src/test/java/org/checkerframework/specimin/UnsolvedClassInSamePackageTest.java new file mode 100644 index 00000000..5e55d411 --- /dev/null +++ b/src/test/java/org/checkerframework/specimin/UnsolvedClassInSamePackageTest.java @@ -0,0 +1,18 @@ +package org.checkerframework.specimin; + +import java.io.IOException; +import org.junit.Test; + +/** + * This test checks that if there is an unsolved class not present among import statements, Specimin + * will assume that the class is in the same directory as the current class. + */ +public class UnsolvedClassInSamePackageTest { + @Test + public void runTest() throws IOException { + SpeciminTestExecutor.runTestWithoutJarPaths( + "unsolvedclassinsamepackage", + new String[] {"com/example/Simple.java"}, + new String[] {"com.example.Simple#bar()"}); + } +} diff --git a/src/test/resources/unsolvedclassinsamepackage/expected/com/example/Baz.java b/src/test/resources/unsolvedclassinsamepackage/expected/com/example/Baz.java new file mode 100644 index 00000000..88000d06 --- /dev/null +++ b/src/test/resources/unsolvedclassinsamepackage/expected/com/example/Baz.java @@ -0,0 +1,8 @@ +package com.example; + +public class Baz { + + public Baz(java.lang.String parameter0) { + throw new Error(); + } +} diff --git a/src/test/resources/unsolvedclassinsamepackage/expected/com/example/Simple.java b/src/test/resources/unsolvedclassinsamepackage/expected/com/example/Simple.java new file mode 100644 index 00000000..b97d5c86 --- /dev/null +++ b/src/test/resources/unsolvedclassinsamepackage/expected/com/example/Simple.java @@ -0,0 +1,8 @@ +package com.example; + +class Simple { + + void bar() { + Baz obj = new Baz("hello"); + } +} diff --git a/src/test/resources/unsolvedclassinsamepackage/input/com/example/Simple.java b/src/test/resources/unsolvedclassinsamepackage/input/com/example/Simple.java new file mode 100644 index 00000000..e2e0a5fb --- /dev/null +++ b/src/test/resources/unsolvedclassinsamepackage/input/com/example/Simple.java @@ -0,0 +1,7 @@ +package com.example; + +class Simple { + void bar() { + Baz obj = new Baz("hello"); + } +} From cc0748458068ec06b5fe2816f1d651b1023051d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 28 Nov 2023 10:55:39 -0500 Subject: [PATCH 2/6] create a method --- .../specimin/UnsolvedSymbolVisitor.java | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index f8b9952e..77d99675 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -528,9 +528,7 @@ public Visitable visit(MethodDeclaration node, Void arg) { } catch (UnsolvedSymbolException | UnsupportedOperationException e) { // if the class could not be found among import statements, we assume that the class must be // in the same package as the current class. - String packageName = classAndPackageMap.getOrDefault(nodeTypeSimpleForm, currentPackage); - UnsolvedClass syntheticType = new UnsolvedClass(nodeTypeSimpleForm, packageName); - this.updateMissingClass(syntheticType); + this.updateMissingClass(createUnsolvedClass(nodeTypeSimpleForm)); } } @@ -675,11 +673,7 @@ public Visitable visit(Parameter parameter, Void p) { } else { // since it is unsolved, it could not be a primitive type @ClassGetSimpleName String className = parameter.getType().asClassOrInterfaceType().getName().asString(); - // we assume that an unsolved class not found among import statements should be in the same - // package as the current class - String packageName = classAndPackageMap.getOrDefault(className, currentPackage); - UnsolvedClass newClass = new UnsolvedClass(className, packageName); - updateMissingClass(newClass); + updateMissingClass(createUnsolvedClass(className)); } } gotException = true; @@ -883,6 +877,20 @@ public void updateClassesFromJarSourcesForMethodCall(MethodCallExpr expr) { this.updateMissingClass(missingClass); } + /** + * Given the simple name of an unsolved class, this method will create an UnsolvedClass instance + * to represent that class. + * + * @param nameOfClass the name of an unsolved class + * @return an UnsolvedClass instance + */ + public UnsolvedClass createUnsolvedClass(@ClassGetSimpleName String nameOfClass) { + // if the name of the class is not present among import statements, we assume that this unsolved + // class is in the same directory as the current class + String packageName = classAndPackageMap.getOrDefault(nameOfClass, currentPackage); + return new UnsolvedClass(nameOfClass, packageName); + } + /** * This method updates a synthetic file based on a solvable expression. The input expression is * solvable because its data is in the jar files that Specimin taks as input. From fb95084b78a39ccdcb440d7f9f205778e2bd70af Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 28 Nov 2023 12:11:07 -0500 Subject: [PATCH 3/6] update method --- .../specimin/UnsolvedSymbolVisitor.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 77d99675..72e18ab9 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -526,9 +526,7 @@ public Visitable visit(MethodDeclaration node, Void arg) { try { nodeType.resolve(); } catch (UnsolvedSymbolException | UnsupportedOperationException e) { - // if the class could not be found among import statements, we assume that the class must be - // in the same package as the current class. - this.updateMissingClass(createUnsolvedClass(nodeTypeSimpleForm)); + updateUnsolvedClassWithClassName(nodeTypeSimpleForm); } } @@ -673,7 +671,7 @@ public Visitable visit(Parameter parameter, Void p) { } else { // since it is unsolved, it could not be a primitive type @ClassGetSimpleName String className = parameter.getType().asClassOrInterfaceType().getName().asString(); - updateMissingClass(createUnsolvedClass(className)); + updateUnsolvedClassWithClassName(className); } } gotException = true; @@ -879,16 +877,15 @@ public void updateClassesFromJarSourcesForMethodCall(MethodCallExpr expr) { /** * Given the simple name of an unsolved class, this method will create an UnsolvedClass instance - * to represent that class. + * to represent that class and update the list of missing class with that UnsolvedClass instance. * * @param nameOfClass the name of an unsolved class - * @return an UnsolvedClass instance */ - public UnsolvedClass createUnsolvedClass(@ClassGetSimpleName String nameOfClass) { + public void updateUnsolvedClassWithClassName(@ClassGetSimpleName String nameOfClass) { // if the name of the class is not present among import statements, we assume that this unsolved // class is in the same directory as the current class String packageName = classAndPackageMap.getOrDefault(nameOfClass, currentPackage); - return new UnsolvedClass(nameOfClass, packageName); + updateMissingClass(new UnsolvedClass(nameOfClass, packageName)); } /** From b5216e09decb910d6bbe200324290a57a6449d93 Mon Sep 17 00:00:00 2001 From: Martin Kellogg Date: Wed, 29 Nov 2023 07:49:40 -0500 Subject: [PATCH 4/6] use varargs --- .../specimin/UnsolvedSymbolVisitor.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index 72e18ab9..a32af0ca 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -695,12 +695,7 @@ public Visitable visit(ObjectCreationExpr newExpr, Void p) { try { List argumentsCreation = getArgumentsFromObjectCreation(newExpr); UnsolvedMethod creationMethod = new UnsolvedMethod("", type, argumentsCreation); - // we assume that an unsolved class not found among import statements should be in the same - // package as the current class - String packageName = classAndPackageMap.getOrDefault(type, currentPackage); - UnsolvedClass newClass = new UnsolvedClass(type, packageName); - newClass.addMethod(creationMethod); - this.updateMissingClass(newClass); + updateUnsolvedClassWithClassName(type, creationMethod); } catch (Exception q) { // can not solve the parameters for this object creation in this current run } @@ -880,12 +875,18 @@ public void updateClassesFromJarSourcesForMethodCall(MethodCallExpr expr) { * to represent that class and update the list of missing class with that UnsolvedClass instance. * * @param nameOfClass the name of an unsolved class + * @param unsolvedMethods unsolved methods to add to the class before updating this visitor's set + * missing classes (optional, may be omitted) */ - public void updateUnsolvedClassWithClassName(@ClassGetSimpleName String nameOfClass) { + public void updateUnsolvedClassWithClassName(@ClassGetSimpleName String nameOfClass, UnsolvedMethod... unsolvedMethods) { // if the name of the class is not present among import statements, we assume that this unsolved // class is in the same directory as the current class String packageName = classAndPackageMap.getOrDefault(nameOfClass, currentPackage); - updateMissingClass(new UnsolvedClass(nameOfClass, packageName)); + UnsolvedClass unsolvedClass = new UnsolvedClass(nameOfClass, packageName); + for (UnsolvedMethod unsolvedMethod : unsolvedMethods) { + unsolvedClass.addMethod(unsolvedMethod); + } + updateMissingClass(unsolvedClass); } /** From c388c0d80de7248f9daf24270210de8686af7b0e Mon Sep 17 00:00:00 2001 From: Martin Kellogg Date: Wed, 29 Nov 2023 07:55:07 -0500 Subject: [PATCH 5/6] another case --- .../specimin/UnsolvedSymbolVisitor.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index a32af0ca..f8382b7c 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -789,13 +789,9 @@ public void updateUnsolvedClassWithMethod( } else { returnType = desiredReturnType; } - // a class not found among import statements should be in the same package as the current class - UnsolvedClass missingClass = - new UnsolvedClass(className, classAndPackageMap.getOrDefault(className, currentPackage)); UnsolvedMethod thisMethod = new UnsolvedMethod(methodName, returnType, listOfParameters); - missingClass.addMethod(thisMethod); + UnsolvedClass missingClass = updateUnsolvedClassWithClassName(className, thisMethod); syntheticMethodAndClass.put(methodName, missingClass); - this.updateMissingClass(missingClass); // if the return type is not specified, a synthetic return type will be created. This part of // codes creates the corresponding class for that synthetic return type @@ -877,16 +873,18 @@ public void updateClassesFromJarSourcesForMethodCall(MethodCallExpr expr) { * @param nameOfClass the name of an unsolved class * @param unsolvedMethods unsolved methods to add to the class before updating this visitor's set * missing classes (optional, may be omitted) + * @return the newly-created UnsolvedClass method, for further processing. This output may be ignored. */ - public void updateUnsolvedClassWithClassName(@ClassGetSimpleName String nameOfClass, UnsolvedMethod... unsolvedMethods) { + public UnsolvedClass updateUnsolvedClassWithClassName(@ClassGetSimpleName String nameOfClass, UnsolvedMethod... unsolvedMethods) { // if the name of the class is not present among import statements, we assume that this unsolved // class is in the same directory as the current class String packageName = classAndPackageMap.getOrDefault(nameOfClass, currentPackage); - UnsolvedClass unsolvedClass = new UnsolvedClass(nameOfClass, packageName); + UnsolvedClass result = new UnsolvedClass(nameOfClass, packageName); for (UnsolvedMethod unsolvedMethod : unsolvedMethods) { - unsolvedClass.addMethod(unsolvedMethod); + result.addMethod(unsolvedMethod); } - updateMissingClass(unsolvedClass); + updateMissingClass(result); + return result; } /** From 2be3a832738a9bdec3028d2cf6c9d1ce28410c99 Mon Sep 17 00:00:00 2001 From: Martin Kellogg Date: Wed, 29 Nov 2023 07:56:04 -0500 Subject: [PATCH 6/6] formatting --- .../checkerframework/specimin/UnsolvedSymbolVisitor.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java index f8382b7c..64cef010 100644 --- a/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java +++ b/src/main/java/org/checkerframework/specimin/UnsolvedSymbolVisitor.java @@ -872,10 +872,12 @@ public void updateClassesFromJarSourcesForMethodCall(MethodCallExpr expr) { * * @param nameOfClass the name of an unsolved class * @param unsolvedMethods unsolved methods to add to the class before updating this visitor's set - * missing classes (optional, may be omitted) - * @return the newly-created UnsolvedClass method, for further processing. This output may be ignored. + * missing classes (optional, may be omitted) + * @return the newly-created UnsolvedClass method, for further processing. This output may be + * ignored. */ - public UnsolvedClass updateUnsolvedClassWithClassName(@ClassGetSimpleName String nameOfClass, UnsolvedMethod... unsolvedMethods) { + public UnsolvedClass updateUnsolvedClassWithClassName( + @ClassGetSimpleName String nameOfClass, UnsolvedMethod... unsolvedMethods) { // if the name of the class is not present among import statements, we assume that this unsolved // class is in the same directory as the current class String packageName = classAndPackageMap.getOrDefault(nameOfClass, currentPackage);