Adopt Rewrite changes around JavaSourceSet

This commit is contained in:
aboyko
2023-04-17 12:39:43 -04:00
parent a6fcbd5326
commit 2cc2617516
4 changed files with 100 additions and 19 deletions

View File

@@ -40,8 +40,11 @@ import org.openrewrite.java.JavaParser.Builder;
import org.openrewrite.java.JavaParsingException;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.UpdateSourcePositions;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.java.tree.JavaSourceFile;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.marker.Range;
import org.openrewrite.tree.ParsingExecutionContextView;
import org.slf4j.Logger;
@@ -53,6 +56,8 @@ import org.springframework.ide.vscode.commons.rewrite.maven.MavenProjectParser;
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import javolution.util.function.Supplier;
public class ORAstUtils {
private static final Logger log = LoggerFactory.getLogger(ORAstUtils.class);
@@ -234,8 +239,12 @@ public class ORAstUtils {
// }
public static JavaParser createJavaParser(IJavaProject project) {
return createJavaParser(() -> createJavaParserBuilder(project));
}
public static JavaParser createJavaParser(Supplier<Builder<? extends JavaParser, ?>> f) {
try {
return createJavaParserBuilder(project).build();
return f.get().build();
} catch (Exception e) {
if (isExceptionFromInterrupedThread(e)) {
log.debug("", e);
@@ -458,4 +467,28 @@ public class ORAstUtils {
return MavenProjectParser.MAIN;
}
}
public static JavaSourceSet addJavaSourceSet(List<? extends SourceFile> sourceFiles, String sourceSetName, List<Path> classpath) {
JavaSourceSet sourceSet = JavaSourceSet.build(sourceSetName, classpath, null, false);
List<JavaType.FullyQualified> types = sourceSet.getClasspath();
for (SourceFile sourceFile : sourceFiles) {
if (!(sourceFile instanceof JavaSourceFile)) {
continue;
}
for (JavaType type : ((JavaSourceFile) sourceFile).getTypesInUse().getTypesInUse()) {
if (type instanceof JavaType.FullyQualified) {
types.add((JavaType.FullyQualified) type);
}
}
}
sourceSet = sourceSet.withClasspath(types);
for (int i = 0; i < sourceFiles.size(); i++) {
SourceFile sourceFile = sourceFiles.get(i);
sourceFiles.set(i, sourceFile
.withMarkers(sourceFile.getMarkers().computeByType(sourceSet, (original, updated) -> updated)));
}
return sourceSet;
}
}

View File

@@ -41,6 +41,7 @@ import org.openrewrite.java.JavaParser;
import org.openrewrite.java.marker.JavaProject;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.marker.JavaVersion;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.marker.BuildTool;
import org.openrewrite.marker.Marker;
import org.openrewrite.maven.MavenParser;
@@ -56,6 +57,7 @@ import org.openrewrite.xml.tree.Xml.Document;
import org.openrewrite.yaml.YamlParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.commons.rewrite.java.ORAstUtils;
/**
* Parse a Maven project on disk into a list of {@link org.openrewrite.SourceFile} including
@@ -126,20 +128,22 @@ public class MavenProjectParser {
sourceFiles.add(addProjectProvenance(maven, projectProvenance));
// List<Path> dependencies = downloadArtifacts(getResolvedPom(maven).getDependencies().get(Scope.Compile));
javaParser.setSourceSet(MAIN);
javaParser.setClasspath(dependencies);
sourceFiles.addAll(ListUtils.map(javaParser.parseInputs(
getJavaSources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, ctx), addProvenance(projectProvenance)));
List<CompilationUnit> mainJavaSources = ListUtils.map(javaParser.parseInputs(
getJavaSources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, ctx), addProvenance(projectProvenance));
JavaSourceSet mainSourceSet = ORAstUtils.addJavaSourceSet(mainJavaSources, MAIN, dependencies);
sourceFiles.addAll(mainJavaSources);
//Resources in the src/main should also have the main source set attached to them.
parseResources(getResources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, sourceFiles, projectProvenance, javaParser.getSourceSet(ctx));
parseResources(getResources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, sourceFiles, projectProvenance, mainSourceSet);
// List<Path> testDependencies = downloadArtifacts(maven.getModel().getDependencies(Scope.Test));
javaParser.setSourceSet(TEST);
// javaParser.setClasspath(testDependencies);
sourceFiles.addAll(ListUtils.map(javaParser.parseInputs(
getTestJavaSources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, ctx), addProvenance(projectProvenance)));
List<CompilationUnit> testJavaSources = ListUtils.map(javaParser.parseInputs(
getTestJavaSources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, ctx), addProvenance(projectProvenance));
JavaSourceSet testSourceSet = ORAstUtils.addJavaSourceSet(testJavaSources, TEST, dependencies);
sourceFiles.addAll(testJavaSources);
//Resources in the src/test should also have the test source set attached to them.
parseResources(getTestResources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, sourceFiles, projectProvenance, javaParser.getSourceSet(ctx));
parseResources(getTestResources(getModel(maven).getRequested(), projectDirectory, ctx, parserInputProvider), projectDirectory, sourceFiles, projectProvenance, testSourceSet);
}
return sourceFiles;

View File

@@ -24,15 +24,21 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.io.IOUtils;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.openrewrite.Tree;
import org.openrewrite.Parser.Input;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.java.tree.JavaType;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.utils.DocumentContentProvider;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
@@ -65,6 +71,8 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis
private final Cache<URI, Set<URI>> projectToDocs;
private final Cache<URI, JavaParser> javaParsers;
private final Cache<URI, List<JavaType.FullyQualified>> sourceSetClasspath;
public RewriteCompilationUnitCache(JavaProjectFinder projectFinder, SimpleLanguageServer server, ProjectObserver projectObserver) {
// this.projectFinder = projectFinder;
this.projectObserver = projectObserver;
@@ -100,7 +108,17 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis
.build();
this.projectToDocs = CacheBuilder.newBuilder().build();
this.javaParsers = CacheBuilder.newBuilder().build();
this.javaParsers = CacheBuilder.newBuilder()
.removalListener(new RemovalListener<URI, JavaParser>() {
@Override
public void onRemoval(RemovalNotification<URI, JavaParser> notification) {
sourceSetClasspath.invalidate(notification.getKey());
}
})
.build();
this.sourceSetClasspath = CacheBuilder.newBuilder().build();
this.documentService = server == null ? null : server.getTextDocumentService();
@@ -222,14 +240,13 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis
}
private CompilationUnit doParse(IJavaProject project, URI uri) throws Exception {
boolean newParser = javaParsers.getIfPresent(project) == null;
JavaParser javaParser = null;;
boolean newParser = javaParsers.getIfPresent(project.getLocationUri()) == null;
JavaParser javaParser = null;
try {
logger.debug("Parsing CU {}", uri);
javaParser = loadJavaParser(project);
Path sourcePath = Paths.get(uri);
javaParser.setSourceSet(ORAstUtils.getSourceSetName(project, sourcePath));
Input input = new Input(sourcePath, () -> {
try {
@@ -241,6 +258,10 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis
List<CompilationUnit> cus = ORAstUtils.parseInputs(javaParser, List.of(input), null);
CompilationUnit cu = cus.get(0);
// Manually add source set
JavaSourceSet sourceSet = createSourceSet(project, ORAstUtils.getSourceSetName(project, sourcePath));
cu = cu.withMarkers(cu.getMarkers().computeByType(sourceSet, (original, updated) -> updated));
if (cu != null) {
projectToDocs.get(project.getLocationUri(), () -> new HashSet<>()).add(uri);
return cu;
@@ -259,6 +280,20 @@ public class RewriteCompilationUnitCache implements DocumentContentProvider, Dis
}
}
private JavaSourceSet createSourceSet(IJavaProject project, String name) {
List<FullyQualified> fqNames;
try {
fqNames = sourceSetClasspath.get(project.getLocationUri(), () -> {
List<Path> classpath = IClasspathUtil.getAllBinaryRoots(project.getClasspath()).stream().map(f -> f.toPath()).collect(Collectors.toList());
return JavaSourceSet.build("", classpath, null, false).getClasspath();
});
} catch (ExecutionException e) {
logger.error("", e);
fqNames = Collections.emptyList();
}
return new JavaSourceSet(Tree.randomId(), name, fqNames);
}
/**
* Does not need to be via callback - kept the same in order to keep the same API to replace JDT with Rewrite in distant future
*/

View File

@@ -28,7 +28,9 @@ import org.openrewrite.ExecutionContext;
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.Parser;
import org.openrewrite.Tree;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.marker.JavaSourceSet;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.J.CompilationUnit;
import org.openrewrite.marker.Marker;
@@ -157,11 +159,16 @@ public class RewriteReconciler implements JavaReconciler {
}
}
JavaParser javaParser = ORAstUtils.createJavaParser(project);
javaParser.setSourceSet(MavenProjectParser.MAIN);
allProblems.putAll(doReconcile(project, mainSources, javaParser, incrementProgress));
javaParser.setSourceSet(MavenProjectParser.TEST);
allProblems.putAll(doReconcile(project, testSources, javaParser, incrementProgress));
List<Path> classpath = IClasspathUtil.getAllBinaryRoots(project.getClasspath()).stream().map(f -> f.toPath()).collect(Collectors.toList());
JavaParser javaParser = ORAstUtils.createJavaParser(() -> JavaParser.fromJavaVersion().classpath(classpath));
// Pass in source sets created from classpath. (Perhaps it is a good idea to have separate classpath and parsers for test and main, TBD)
// Perhaps it is even better to create empty classpath java source sets as reconcile step seem to only need name of the java source set
// Usually java source set classpath is required to figure out how to organize imports for sources
JavaSourceSet mainJavaSourceSet = JavaSourceSet.build(MavenProjectParser.MAIN, classpath, null, false);
JavaSourceSet testJavaSourceSet = new JavaSourceSet(Tree.randomId(), MavenProjectParser.TEST, mainJavaSourceSet.getClasspath());
allProblems.putAll(doReconcile(project, mainSources, javaParser, mainJavaSourceSet, incrementProgress));
allProblems.putAll(doReconcile(project, testSources, javaParser, testJavaSourceSet, incrementProgress));
long end = System.currentTimeMillis();
log.info("reconciling project (OpenRewrite): " + project.getElementName() + " - " + docs.size() + " done in " + (end - start) + "ms");
@@ -242,7 +249,7 @@ public class RewriteReconciler implements JavaReconciler {
private static final int BATCH = 50;
// Parse in batches and share the parser
private Map<IDocument, Collection<ReconcileProblem>> doReconcile(IJavaProject project, List<TextDocument> docs, JavaParser javaParser, Runnable incrementProgress) {
private Map<IDocument, Collection<ReconcileProblem>> doReconcile(IJavaProject project, List<TextDocument> docs, JavaParser javaParser, JavaSourceSet javaSourceSet, Runnable incrementProgress) {
Map<IDocument, Collection<ReconcileProblem>> allProblems = new HashMap<>();
if (javaParser != null && config.isRewriteReconcileEnabled()) {
try {
@@ -259,6 +266,8 @@ public class RewriteReconciler implements JavaReconciler {
return new ByteArrayInputStream(d.get().getBytes());
})).collect(Collectors.toList()), source -> incrementProgress.run());
cus = ListUtils.map(cus, cu -> cu.withMarkers(cu.getMarkers().computeByType(javaSourceSet, (original, updated) -> updated)));
/*
* If exception occurs during parsing inputs the list of inputs would become shorter than the list of corresponding documents
*/