reuse compilation unit cache when searching for references instead of on-demand parsing

This commit is contained in:
Martin Lippert
2024-06-20 12:56:15 +02:00
parent db83524515
commit 142321fc90
5 changed files with 44 additions and 71 deletions

View File

@@ -121,25 +121,26 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
projectFinder = serverParams.projectFinder;
projectObserver = serverParams.projectObserver;
this.cuCache = appContext.getBean(CompilationUnitCache.class);
propertyIndexProvider = serverParams.indexProvider;
SimpleWorkspaceService workspaceService = server.getWorkspaceService();
SimpleTextDocumentService documents = server.getTextDocumentService();
this.cuCache = appContext.getBean(CompilationUnitCache.class);
SpringSymbolIndex springSymbolIndex = appContext.getBean(SpringSymbolIndex.class);
SpringMetamodelIndex springIndex = appContext.getBean(SpringMetamodelIndex.class);
BootJavaConfig config = appContext.getBean(BootJavaConfig.class);
SourceLinks sourceLinks = appContext.getBean(SourceLinks.class);
liveDataService = appContext.getBean(SpringProcessConnectorService.class);
this.liveDataService = appContext.getBean(SpringProcessConnectorService.class);
SpringProcessLiveDataProvider liveDataProvider = appContext.getBean(SpringProcessLiveDataProvider.class);
reconcileEngine = appContext.getBean(BootJavaReconcileEngine.class);
codeActionProvider = appContext.getBean(BootJavaCodeActionProvider.class);
this.reconcileEngine = appContext.getBean(BootJavaReconcileEngine.class);
this.codeActionProvider = appContext.getBean(BootJavaCodeActionProvider.class);
ReferencesHandler referencesHandler = createReferenceHandler(server, projectFinder, springIndex, springSymbolIndex);
ReferencesHandler referencesHandler = createReferenceHandler(server, projectFinder, springIndex, springSymbolIndex, cuCache);
documents.onReferences(referencesHandler);
//
@@ -291,12 +292,12 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
}
protected ReferencesHandler createReferenceHandler(SimpleLanguageServer server, JavaProjectFinder projectFinder,
SpringMetamodelIndex index, SpringSymbolIndex symbolIndex) {
SpringMetamodelIndex index, SpringSymbolIndex symbolIndex, CompilationUnitCache cuCache) {
Map<String, ReferenceProvider> providers = new HashMap<>();
providers.put(Annotations.VALUE, new ValuePropertyReferencesProvider(server));
providers.put(Annotations.QUALIFIER, new QualifierReferencesProvider(index, symbolIndex));
return new BootJavaReferencesHandler(this, projectFinder, providers);
return new BootJavaReferencesHandler(this, cuCache, projectFinder, providers);
}
protected BootJavaCodeLensEngine createCodeLensEngine(SpringSymbolIndex index) {

View File

@@ -27,7 +27,6 @@ import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
* @author Martin Lippert
@@ -43,7 +42,7 @@ public class QualifierReferencesProvider implements ReferenceProvider {
}
@Override
public List<? extends Location> provideReferences(CancelChecker cancelToken, IJavaProject project, ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc) {
public List<? extends Location> provideReferences(CancelChecker cancelToken, IJavaProject project, ASTNode node, Annotation annotation, ITypeBinding type, int offset) {
cancelToken.checkCanceled();

View File

@@ -10,19 +10,14 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.io.File;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.stream.Stream;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.NodeFinder;
import org.eclipse.lsp4j.Location;
@@ -30,13 +25,11 @@ import org.eclipse.lsp4j.ReferenceParams;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
@@ -44,12 +37,14 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public class BootJavaReferencesHandler implements ReferencesHandler {
private JavaProjectFinder projectFinder;
private BootJavaLanguageServerComponents server;
private Map<String, ReferenceProvider> referenceProviders;
private final JavaProjectFinder projectFinder;
private final BootJavaLanguageServerComponents server;
private final Map<String, ReferenceProvider> referenceProviders;
private final CompilationUnitCache cuCache;
public BootJavaReferencesHandler(BootJavaLanguageServerComponents server, JavaProjectFinder projectFinder, Map<String, ReferenceProvider> specificProviders) {
public BootJavaReferencesHandler(BootJavaLanguageServerComponents server, CompilationUnitCache cuCache, JavaProjectFinder projectFinder, Map<String, ReferenceProvider> specificProviders) {
this.server = server;
this.cuCache = cuCache;
this.projectFinder = projectFinder;
this.referenceProviders = specificProviders;
}
@@ -67,7 +62,7 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
cancelToken.checkCanceled();
List<? extends Location> referencesResult = provideReferences(cancelToken, doc, offset);
List<? extends Location> referencesResult = provideReferences(cancelToken, doc.getId(), offset);
if (referencesResult != null) {
return referencesResult;
}
@@ -83,39 +78,31 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
return SimpleTextDocumentService.NO_REFERENCES;
}
private List<? extends Location> provideReferences(CancelChecker cancelToken, TextDocument document, int offset) throws Exception {
ASTParser parser = ASTParser.newParser(AST.JLS21);
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_21, options);
parser.setCompilerOptions(options);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
private List<? extends Location> provideReferences(CancelChecker cancelToken, TextDocumentIdentifier docID, int offset) throws Exception {
Optional<IJavaProject> projectOptional = projectFinder.find(docID);
String[] classpathEntries = getClasspathEntries(document);
String[] sourceEntries = new String[] {};
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
if (projectOptional.isPresent()) {
IJavaProject project = projectOptional.get();
String docURI = document.getUri();
String unitName = docURI.substring(docURI.lastIndexOf("/"));
parser.setUnitName(unitName);
parser.setSource(document.get(0, document.getLength()).toCharArray());
cancelToken.checkCanceled();
URI docUri = URI.create(docID.getUri());
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
ASTNode node = NodeFinder.perform(cu, offset, 0);
if (node != null) {
cancelToken.checkCanceled();
return provideReferencesForAnnotation(cancelToken, node, offset, document);
return cuCache.withCompilationUnit(project, docUri, cu -> {
cancelToken.checkCanceled();
ASTNode node = NodeFinder.perform(cu, offset, 0);
if (node != null) {
return provideReferencesForAnnotation(cancelToken, project, node, offset);
}
else {
return null;
}
});
}
return null;
}
private List<? extends Location> provideReferencesForAnnotation(CancelChecker cancelToken, ASTNode node, int offset, TextDocument doc) {
private List<? extends Location> provideReferencesForAnnotation(CancelChecker cancelToken, IJavaProject project, ASTNode node, int offset) {
Annotation annotation = null;
ASTNode annotationNode = node;
@@ -135,10 +122,7 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
ReferenceProvider provider = this.referenceProviders.get(qualifiedName);
if (provider != null) {
Optional<IJavaProject> projectOptional = projectFinder.find(doc.getId());
if (projectOptional.isPresent()) {
return provider.provideReferences(cancelToken, projectOptional.get(), node, annotation, type, offset, doc);
}
return provider.provideReferences(cancelToken, project, node, annotation, type, offset);
}
}
}
@@ -147,14 +131,4 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
return null;
}
private String[] getClasspathEntries(IDocument doc) throws Exception {
IJavaProject project = this.projectFinder.find(new TextDocumentIdentifier(doc.getUri())).get();
IClasspath classpath = project.getClasspath();
Stream<File> classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream();
return classpathEntries
.filter(file -> file.exists())
.map(file -> file.getAbsolutePath())
.toArray(String[]::new);
}
}

View File

@@ -18,7 +18,6 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
* @author Martin Lippert
@@ -26,6 +25,6 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
public interface ReferenceProvider {
List<? extends Location> provideReferences(CancelChecker cancelToken, IJavaProject project, ASTNode node, Annotation annotation,
ITypeBinding type, int offset, TextDocument doc);
ITypeBinding type, int offset);
}

View File

@@ -15,6 +15,7 @@ import static org.springframework.ide.vscode.commons.yaml.ast.NodeUtil.asScalar;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -71,8 +72,7 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
}
@Override
public List<? extends Location> provideReferences(CancelChecker cancelToken, IJavaProject project, ASTNode node, Annotation annotation,
ITypeBinding type, int offset, TextDocument doc) {
public List<? extends Location> provideReferences(CancelChecker cancelToken, IJavaProject project, ASTNode node, Annotation annotation, ITypeBinding type, int offset) {
cancelToken.checkCanceled();
@@ -80,14 +80,14 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
// case: @Value("prefix<*>")
if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
return provideReferences(node.toString(), offset - node.getStartPosition(), node.getStartPosition(), doc);
return provideReferences(node.toString(), offset - node.getStartPosition(), node.getStartPosition());
}
}
// case: @Value(value="prefix<*>")
else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
return provideReferences(node.toString(), offset - node.getStartPosition(), node.getStartPosition(), doc);
return provideReferences(node.toString(), offset - node.getStartPosition(), node.getStartPosition());
}
}
}
@@ -98,7 +98,7 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
return null;
}
private List<? extends Location> provideReferences(String value, int offset, int nodeStartOffset, TextDocument doc) {
private List<? extends Location> provideReferences(String value, int offset, int nodeStartOffset) {
try {
LocalRange range = getPropertyRange(value, offset);
@@ -194,7 +194,7 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
List<Location> foundLocations = new ArrayList<>();
try {
String fileContent = FileUtils.readFileToString(file);
String fileContent = FileUtils.readFileToString(file, Charset.defaultCharset());
YamlASTProvider parser = new YamlParser();
@@ -279,7 +279,7 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
static List<Location> findReferencesInPropertiesFile(File file, String propertyKey, BiFunction<KeyValuePair, TextDocument, Optional<Location>> processor) {
List<Location> foundLocations = new ArrayList<>();
try {
String fileContent = FileUtils.readFileToString(file);
String fileContent = FileUtils.readFileToString(file, Charset.defaultCharset());
Parser parser = new AntlrParser();
ParseResults parseResults = parser.parse(fileContent);