Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues #368, #370, #361 #371

Merged
merged 5 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/main/java/org/checkerframework/specimin/JavaParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import com.google.common.base.Splitter;
Expand Down Expand Up @@ -271,6 +272,18 @@ public static List<String> getReferenceTypesFromCommaSeparatedString(String comm
return types;
}

/**
* Returns a package prefix that can be prepended to a class name, for a given method or
* constructor declaration.
*
* @param decl declaration to extract a package prefix from(using getPackageName)
* @return empty string if default package, otherwise package name followed by "."
*/
public static String packagePrefix(ResolvedMethodLikeDeclaration decl) {
String packageName = decl.getPackageName();
return packageName.isEmpty() ? "" : packageName + ".";
}

/**
* Returns true iff the innermost enclosing class/interface is an enum.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.checkerframework.specimin;

import com.github.javaparser.ParseProblemException;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
Expand Down Expand Up @@ -236,7 +237,10 @@ private static void performMinimizationImpl(
Map<String, String> nonPrimaryClassesToPrimaryClass = new HashMap<>();
SourceRoot sourceRoot = new SourceRoot(Path.of(root));
sourceRoot.tryToParse();
for (CompilationUnit compilationUnit : sourceRoot.getCompilationUnits()) {
//getCompilationUnits does not seem to include all files, causing some to be deleted
for (ParseResult<CompilationUnit> res : sourceRoot.getCache()) {
CompilationUnit compilationUnit =
res.getResult().orElseThrow(() -> new RuntimeException("" + res.getProblems()));
kelloggm marked this conversation as resolved.
Show resolved Hide resolved
Path pathOfCurrentJavaFile =
compilationUnit.getStorage().get().getPath().toAbsolutePath().normalize();
String primaryTypeQualifiedName = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ public Visitable visit(ConstructorDeclaration method, Void p) {
targetMethods.add(resolvedMethod.getQualifiedSignature());
unfoundMethods.remove(methodName);
updateUsedClassWithQualifiedClassName(
resolvedMethod.getPackageName() + "." + resolvedMethod.getClassName(),
JavaParserUtil.packagePrefix(resolvedMethod) + resolvedMethod.getClassName(),
usedTypeElements,
nonPrimaryClassesToPrimaryClass);
if (modularityModel.preserveAllFieldsIfTargetIsConstructor()) {
Expand Down Expand Up @@ -341,19 +341,19 @@ public Visitable visit(MethodDeclaration method, Void p) {
if (parentNode instanceof ObjectCreationExpr) {
ObjectCreationExpr parentExpression = (ObjectCreationExpr) parentNode;
ResolvedConstructorDeclaration resolved = parentExpression.resolve();
String methodPackage = resolved.getPackageName();
String methodPackagePrefix = JavaParserUtil.packagePrefix(resolved);
String methodClass = resolved.getClassName();
usedMembers.add(methodPackage + "." + methodClass + "." + method.getNameAsString() + "()");
usedMembers.add(methodPackagePrefix + methodClass + "." + method.getNameAsString() + "()");
updateUsedClassWithQualifiedClassName(
methodPackage + "." + methodClass, usedTypeElements, nonPrimaryClassesToPrimaryClass);
methodPackagePrefix + methodClass, usedTypeElements, nonPrimaryClassesToPrimaryClass);
}
}
String methodWithoutAnySpace = methodName.replaceAll("\\s", "");
if (this.targetMethodNames.contains(methodWithoutAnySpace)) {
ResolvedMethodDeclaration resolvedMethod = method.resolve();
updateUsedClassesForInterface(resolvedMethod);
updateUsedClassWithQualifiedClassName(
resolvedMethod.getPackageName() + "." + resolvedMethod.getClassName(),
JavaParserUtil.packagePrefix(resolvedMethod) + resolvedMethod.getClassName(),
usedTypeElements,
nonPrimaryClassesToPrimaryClass);

Expand Down Expand Up @@ -518,9 +518,11 @@ public Visitable visit(MethodCallExpr call, Void p) {
resolvedYetStuckMethodCall.add(scopeAsString + "." + call.getNameAsString());
usedTypeElements.add(scopeAsString);
} else {
String packagePrefix =
getCurrentPackage().isEmpty() ? "" : getCurrentPackage() + ".";
resolvedYetStuckMethodCall.add(
getCurrentPackage() + "." + scopeAsString + "." + call.getNameAsString());
usedTypeElements.add(getCurrentPackage() + "." + scopeAsString);
packagePrefix + scopeAsString + "." + call.getNameAsString());
usedTypeElements.add(packagePrefix + scopeAsString);
}
}
}
Expand Down Expand Up @@ -564,7 +566,7 @@ public Visitable visit(MethodCallExpr call, Void p) {
private void preserveMethodDecl(ResolvedMethodDeclaration decl) {
usedMembers.add(decl.getQualifiedSignature());
updateUsedClassWithQualifiedClassName(
decl.getPackageName() + "." + decl.getClassName(),
JavaParserUtil.packagePrefix(decl) + decl.getClassName(),
usedTypeElements,
nonPrimaryClassesToPrimaryClass);
try {
Expand Down Expand Up @@ -624,7 +626,7 @@ public Visitable visit(ObjectCreationExpr newExpr, Void p) {
ResolvedConstructorDeclaration resolved = newExpr.resolve();
usedMembers.add(resolved.getQualifiedSignature());
updateUsedClassWithQualifiedClassName(
resolved.getPackageName() + "." + resolved.getClassName(),
JavaParserUtil.packagePrefix(resolved) + resolved.getClassName(),
usedTypeElements,
nonPrimaryClassesToPrimaryClass);
for (int i = 0; i < resolved.getNumberOfParams(); ++i) {
Expand All @@ -646,7 +648,7 @@ public Visitable visit(ExplicitConstructorInvocationStmt expr, Void p) {
ResolvedConstructorDeclaration resolved = expr.resolve();
usedMembers.add(resolved.getQualifiedSignature());
updateUsedClassWithQualifiedClassName(
resolved.getPackageName() + "." + resolved.getClassName(),
JavaParserUtil.packagePrefix(resolved) + resolved.getClassName(),
usedTypeElements,
nonPrimaryClassesToPrimaryClass);
}
Expand Down Expand Up @@ -850,10 +852,6 @@ public static void updateUsedClassWithQualifiedClassName(
Set<String> usedTypeElement,
Map<String, String> nonPrimaryClassesToPrimaryClass) {

// in case of type variables
if (!qualifiedClassName.contains(".")) {
return;
}
// strip type variables, if they're present
if (qualifiedClassName.contains("<")) {
qualifiedClassName = qualifiedClassName.substring(0, qualifiedClassName.indexOf("<"));
Expand All @@ -867,6 +865,10 @@ public static void updateUsedClassWithQualifiedClassName(
nonPrimaryClassesToPrimaryClass);
}

// in case of type variables TODO:investigate side effects of having moved this from earlier
if (!qualifiedClassName.contains(".")) {
return;
}
String potentialOuterClass =
qualifiedClassName.substring(0, qualifiedClassName.lastIndexOf("."));
if (JavaParserUtil.isAClassPath(potentialOuterClass)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1588,6 +1588,9 @@ public boolean updatedAddedTargetFilesForPotentialEnum(FieldAccessExpr expr) {
return false;
}
if (resolved.isEnumConstant()) {
if (JavaLangUtils.inJdkPackage(resolved.getType().describe())) {
return true;
kelloggm marked this conversation as resolved.
Show resolved Hide resolved
}
String filePathName = qualifiedNameToFilePath(resolved.getType().describe());
if (!addedTargetFiles.contains(filePathName)) {
gotException();
Expand Down Expand Up @@ -3257,7 +3260,8 @@ public static UnsolvedClassOrInterface getSimpleSyntheticClassFromFullyQualified
+ fullyName);
}
String className = fullyQualifiedToSimple(fullyName);
String packageName = fullyName.replace("." + className, "");
String packageName =
fullyName.contains("." + className) ? fullyName.replace("." + className, "") : "";
return new UnsolvedClassOrInterface(className, packageName);
}

Expand Down
15 changes: 15 additions & 0 deletions src/test/java/org/checkerframework/specimin/BuiltinEnumTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.checkerframework.specimin;

import java.io.IOException;
import org.junit.Test;

/** This test checks if Specimin is able to process Java builtin enum classes. Issue #361 */
public class BuiltinEnumTest {
@Test
public void runTest() throws IOException {
SpeciminTestExecutor.runTestWithoutJarPaths(
"enumbuiltin",
new String[] {"com/example/Scheduler.java"},
new String[] {"com.example.Scheduler#schedule(Runnable, int)"});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.checkerframework.specimin;

import java.io.IOException;
import org.junit.Test;

/**
* This test checks if Specimin correctly preserves things that are used as arguments to enum
* constants.
*/
public class DefaultPackageTest {
@Test
public void runTest() throws IOException {
SpeciminTestExecutor.runTestWithoutJarPaths(
"defaultpackage", new String[] {"A.java"}, new String[] {"A#schedule(Runnable, int)"});
}
}
32 changes: 32 additions & 0 deletions src/test/java/org/checkerframework/specimin/Issue368Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.checkerframework.specimin;

import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import org.junit.Test;

/**
* This test is the test described in <a
* href="https://github.com/njit-jerse/specimin/issues/368">...</a>. The issue caused the original
* source file A.java to be deleted, and in addition not appear in the output.
*/
public class Issue368Test {
@Test
public void runTest() throws IOException {
Path fileASource = Path.of("src/test/resources/issue368/A_code.java");
Path fileAPath = Path.of("src/test/resources/issue368/input/com/example/A.java");
Files.copy(fileASource, fileAPath, StandardCopyOption.REPLACE_EXISTING);
String fileACode = Files.readString(fileAPath);
SpeciminTestExecutor.runTestWithoutJarPaths(
"issue368", new String[] {"com/example/B.java"}, new String[] {"com.example.B#test()"});

try {
assertTrue(Files.exists(fileAPath));
} finally {
Files.writeString(fileAPath, fileACode);
}
}
}
6 changes: 6 additions & 0 deletions src/test/resources/defaultpackage/expected/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
public class A {

public static void schedule(Runnable task, int millis) {
System.out.println();
}
}
5 changes: 5 additions & 0 deletions src/test/resources/defaultpackage/input/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
public class A{//no package declaration
public static void schedule(Runnable task, int millis) {
System.out.println();
}
}
13 changes: 13 additions & 0 deletions src/test/resources/enumbuiltin/expected/com/example/Scheduler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Scheduler {

public static final ScheduledExecutorService ses = null;

public static void schedule(Runnable task, int millis) {
ses.schedule(task, millis, TimeUnit.MILLISECONDS);
}
}
14 changes: 14 additions & 0 deletions src/test/resources/enumbuiltin/input/com/example/Scheduler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example;
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class Scheduler{
private Scheduler() {}
public static final ScheduledExecutorService ses=newSingleThreadScheduledExecutor(r->new Thread(r,"Scheduler thread"));

public static void schedule(Runnable task, int millis) {
ses.schedule(task,millis,TimeUnit.MILLISECONDS);
}
}
21 changes: 21 additions & 0 deletions src/test/resources/issue368/A_code.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousSocketChannel;

public class A{
public AsynchronousSocketChannel client;
public A(AsynchronousSocketChannel client){
this.client=client;
}
public InetAddress test(){//target method
try {
if(client.getRemoteAddress() instanceof InetSocketAddress isa)
return isa.getAddress();
} catch (IOException e) {

}
return null;
}
}
10 changes: 10 additions & 0 deletions src/test/resources/issue368/expected/com/example/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example;

import java.net.InetAddress;

public class A {

public InetAddress test() {
throw new Error();
}
}
10 changes: 10 additions & 0 deletions src/test/resources/issue368/expected/com/example/B.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example;

import java.net.InetAddress;

public class B extends A {

public InetAddress test() {
return super.test();
}
}
21 changes: 21 additions & 0 deletions src/test/resources/issue368/input/com/example/A.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.example;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousSocketChannel;

public class A{
public AsynchronousSocketChannel client;
public A(AsynchronousSocketChannel client){
this.client=client;
}
public InetAddress test(){//target method
try {
if(client.getRemoteAddress() instanceof InetSocketAddress isa)
return isa.getAddress();
} catch (IOException e) {

}
return null;
}
}
11 changes: 11 additions & 0 deletions src/test/resources/issue368/input/com/example/B.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example;
import java.io.IOException;
import java.net.InetAddress;

public class B extends A {

@Override
public InetAddress test(){
return super.test();
}
}
Loading