GH-1068: initial version of running a single validation as part of the indexing machinery

This commit is contained in:
Martin Lippert
2023-07-20 20:57:00 +02:00
parent 72f0da117a
commit b55f9000e2
10 changed files with 243 additions and 46 deletions

View File

@@ -30,6 +30,8 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -137,7 +139,8 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
private static final int FORCED_EXIT_DELAY_IN_SECONDS = 3;
public final String EXTENSION_ID;
private final String CODE_ACTION_COMMAND_ID;
public final String CODE_ACTION_COMMAND_ID;
public final LazyCompletionResolver completionResolver = createCompletionResolver();
private SimpleTextDocumentService tds;
@@ -706,7 +709,7 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
testListener.reconcileStarted(docId.getUri(), doc.getVersion());
}
IProblemCollector problems = createProblemCollector(doc);
IProblemCollector problems = createProblemCollector(new AtomicReference<TextDocument>(doc), null);
engine.reconcile(doc, problems);
})
@@ -749,9 +752,10 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
}
}
public IProblemCollector createProblemCollector(TextDocument doc) {
SimpleTextDocumentService documents = getTextDocumentService();
TextDocumentIdentifier docId = doc.getId();
public IProblemCollector createProblemCollector(AtomicReference<TextDocument> docRef, BiConsumer<String, Diagnostic> diagnosticsCollector) {
SimpleTextDocumentService documentsService = getTextDocumentService();
return new IProblemCollector() {
private LinkedHashSet<Diagnostic> diagnostics = new LinkedHashSet<>();
@@ -759,8 +763,8 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
@Override
public void endCollecting() {
documents.setQuickfixes(docId, quickfixes);
documents.publishDiagnostics(docId, diagnostics);
documentsService.setQuickfixes(docRef.get().getId(), quickfixes);
documentsService.publishDiagnostics(docRef.get().getId(), diagnostics);
log.debug("Reconcile done sent {} diagnostics", diagnostics.size());
}
@@ -772,8 +776,8 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
@Override
public void checkPointCollecting() {
// publish what has been collected so far
documents.setQuickfixes(docId, quickfixes);
documents.publishDiagnostics(docId, diagnostics);
documentsService.setQuickfixes(docRef.get().getId(), quickfixes);
documentsService.publishDiagnostics(docRef.get().getId(), diagnostics);
log.debug("Reconcile checkpoint sent {} diagnostics", diagnostics.size());
}
@@ -787,7 +791,7 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
Diagnostic d = new Diagnostic();
d.setCode(problem.getCode());
d.setMessage(problem.getMessage());
Range rng = doc.toRange(problem.getOffset(), problem.getLength());
Range rng = docRef.get().toRange(problem.getOffset(), problem.getLength());
d.setRange(rng);
d.setSeverity(severity);
d.setSource(getServer().EXTENSION_ID);
@@ -810,9 +814,14 @@ public final class SimpleLanguageServer implements Sts4LanguageServer, SpringInd
}).collect(Collectors.toList()));
}
diagnostics.add(d);
if (diagnosticsCollector != null) {
diagnosticsCollector.accept(docRef.get().getId().getUri(), d);
}
}
} catch (BadLocationException e) {
log.warn("Invalid reconcile problem ignored: " + doc.getUri() + " - problem position: " + problem.getOffset() + "/" + problem.getLength(), e);
log.warn("Invalid reconcile problem ignored: " + docRef.get().getId().getUri() + " - problem position: " + problem.getOffset() + "/" + problem.getLength(), e);
}
}
};

View File

@@ -29,11 +29,15 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.WorkspaceSymbol;
@@ -50,6 +54,8 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyA
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.reconcilers.AnnotationReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.BeanMethodNotPublicReconciler;
import org.springframework.ide.vscode.boot.java.utils.DocumentDescriptor;
import org.springframework.ide.vscode.boot.java.utils.SpringFactoriesIndexer;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
@@ -65,6 +71,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.FutureProjectF
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver.Listener;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.util.ListenerList;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
@@ -156,7 +163,9 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
SymbolHandler handler = new SymbolHandler() {
@Override
public void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions) {
public void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions,
List<Diagnostic> diagnostics) {
if (enhancedSymbols != null) {
SpringSymbolIndex.this.addSymbolsByDoc(project, docURI, enhancedSymbols);
}
@@ -164,11 +173,16 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
if (beanDefinitions != null) {
springIndex.updateBeans(project.getElementName(), docURI, beanDefinitions);
}
if (diagnostics != null) {
server.getTextDocumentService().publishDiagnostics(new TextDocumentIdentifier(docURI), diagnostics);
// TODO: need to use real TextDocumentIdentifier because of the document version
}
}
@Override
public void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols,
Bean[] beanDefinitions) {
Bean[] beanDefinitions, Map<String, List<Diagnostic>> diagnosticsPerDoc) {
if (enhancedSymbols != null) {
@@ -208,12 +222,21 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
}
if (diagnosticsPerDoc != null) {
for (String docURI : diagnosticsPerDoc.keySet()) {
server.getTextDocumentService().publishDiagnostics(new TextDocumentIdentifier(docURI), diagnosticsPerDoc.get(docURI));
// TODO: need to use real TextDocumentIdentifier because of the document version
}
}
}
@Override
public void removeSymbols(IJavaProject project, String docURI) {
SpringSymbolIndex.this.removeSymbolsByDoc(project, docURI);
springIndex.removeBeans(project.getElementName(), docURI);
// TODO remove diagnostics ?!? maybe, maybe not
}
};
@@ -221,7 +244,13 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler = new HashMap<>();
namespaceHandler.put("http://www.springframework.org/schema/beans", new SpringIndexerXMLNamespaceHandlerBeans());
springIndexerXML = new SpringIndexerXML(handler, namespaceHandler, this.cache, projectFinder());
springIndexerJava = new SpringIndexerJava(handler, specificProviders, this.cache, projectFinder(), server.getProgressService());
List<AnnotationReconciler> reconcilers = new ArrayList<>();
reconcilers.add(new BeanMethodNotPublicReconciler());
BiFunction<AtomicReference<TextDocument>, BiConsumer<String, Diagnostic>, IProblemCollector> problemCollectorFactory = (docRef, aggregator) -> server.createProblemCollector(docRef, aggregator);
springIndexerJava = new SpringIndexerJava(handler, specificProviders, this.cache, projectFinder(), server.getProgressService(), reconcilers, problemCollectorFactory);
factoriesIndexer = new SpringFactoriesIndexer(handler, cache);
this.indexers = new SpringIndexer[] {springIndexerJava, factoriesIndexer};

View File

@@ -18,6 +18,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -133,7 +134,7 @@ public class BootJavaReconcileEngine implements IReconcileEngine, IJavaProjectRe
.map(docId -> new LazyTextDocument(docId.getUri(), LanguageId.JAVA)).collect(Collectors.toList());
Map<IDocument, IProblemCollector> problemCollectors = docs.stream()
.collect(Collectors.toMap(d -> d, d -> server.createProblemCollector(d)));
.collect(Collectors.toMap(doc -> doc, doc -> server.createProblemCollector(new AtomicReference<>(doc), null)));
problemCollectors.values().forEach(c -> c.beginCollecting());

View File

@@ -0,0 +1,82 @@
/*******************************************************************************
* Copyright (c) 2022, 2023 VMware, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.reconcilers;
import java.lang.reflect.Field;
import java.util.List;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Modifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
import org.springframework.ide.vscode.commons.java.Version;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
import org.springframework.ide.vscode.commons.util.text.IDocument;
public class BeanMethodNotPublicReconciler implements AnnotationReconciler {
private static final Logger log = LoggerFactory.getLogger(BeanMethodNotPublicReconciler.class);
@Override
public void visit(IJavaProject project, IDocument doc, Annotation node, ITypeBinding typeBinding,
IProblemCollector problemCollector) {
if (Annotations.BEAN.equals(typeBinding.getQualifiedName()) && node.getParent() instanceof MethodDeclaration) {
MethodDeclaration m = (MethodDeclaration) node.getParent();
Version version = SpringProjectUtil.getDependencyVersion(project, SpringProjectUtil.SPRING_BOOT);
if (version.getMajor() >= 2) {
IMethodBinding methodBinding = m.resolveBinding();
if (isNotOverridingPublicMethod(methodBinding)) {
ReconcileProblemImpl problem = ((List<?>)m.modifiers()).stream()
.filter(Modifier.class::isInstance)
.map(Modifier.class::cast)
.filter(modifier -> modifier.isPublic())
.findFirst()
.map(modifier -> new ReconcileProblemImpl(
Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD, "super special DIAGNOSTICS with public @Bean method",
modifier.getStartPosition(), modifier.getLength()))
.orElse(new ReconcileProblemImpl(
Boot2JavaProblemType.JAVA_PUBLIC_BEAN_METHOD, "super special DIAGNOSTICS with public @Bean method",
m.getName().getStartPosition(), m.getName().getLength()));
problemCollector.accept(problem);
}
}
}
}
private static final boolean isOverriding(IMethodBinding binding) {
try {
Field f = binding.getClass().getDeclaredField("binding");
f.setAccessible(true);
org.eclipse.jdt.internal.compiler.lookup.MethodBinding value = (org.eclipse.jdt.internal.compiler.lookup.MethodBinding) f.get(binding);
return value.isOverriding();
} catch (Exception e) {
log.error("", e);
}
return false;
}
public static final boolean isNotOverridingPublicMethod(IMethodBinding methodBinding) {
return !isOverriding(methodBinding) && (methodBinding.getModifiers() & Modifier.PUBLIC) != 0;
}
}

View File

@@ -10,12 +10,20 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.reconcilers;
import org.eclipse.lsp4j.Diagnostic;
import org.springframework.ide.vscode.boot.index.cache.AbstractIndexCacheable;
public class CachedDiagnostics extends AbstractIndexCacheable {
public CachedDiagnostics(String docURI) {
private final Diagnostic diagnostic;
public CachedDiagnostics(String docURI, Diagnostic diagnostic) {
super(docURI);
this.diagnostic= diagnostic;
}
public Diagnostic getDiagnostic() {
return this.diagnostic;
}
}

View File

@@ -187,7 +187,7 @@ public class SpringFactoriesIndexer implements SpringIndexer {
if (symbols != null) {
EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
symbolHandler.addSymbols(project, enhancedSymbols, null);
symbolHandler.addSymbols(project, enhancedSymbols, null, null);
}
long endTime = System.currentTimeMillis();
@@ -257,7 +257,7 @@ public class SpringFactoriesIndexer implements SpringIndexer {
this.cache.update(cacheKey, file, updatedDoc.getLastModified(), generatedSymbols, null, CachedSymbol.class);
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
symbolHandler.addSymbols(project, docURI, symbols, null);
symbolHandler.addSymbols(project, docURI, symbols, null, null);
}
}

View File

@@ -26,6 +26,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -45,6 +47,7 @@ import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.WorkspaceSymbol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,6 +58,7 @@ import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyA
import org.springframework.ide.vscode.boot.java.beans.CachedBean;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.reconcilers.AnnotationReconciler;
import org.springframework.ide.vscode.boot.java.reconcilers.CachedDiagnostics;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
@@ -62,6 +66,8 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.PercentageProgressTask;
import org.springframework.ide.vscode.commons.languageserver.ProgressService;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.util.UriUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -89,9 +95,9 @@ public class SpringIndexerJava implements SpringIndexer {
private static final String BEANS_KEY = "beans";
private static final String DIAGNOSTICS_KEY = "diagnostics";
private final SymbolHandler symbolHandler;
private final AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders;
private final List<AnnotationReconciler> reconcilers;
private final IndexCache cache;
private final JavaProjectFinder projectFinder;
private final ProgressService progressService;
@@ -100,14 +106,19 @@ public class SpringIndexerJava implements SpringIndexer {
private FileScanListener fileScanListener = null; //used by test code only
private final SpringIndexerJavaDependencyTracker dependencyTracker = new SpringIndexerJavaDependencyTracker();
private final BiFunction<AtomicReference<TextDocument>, BiConsumer<String, Diagnostic>, IProblemCollector> problemCollectorCreator;
public SpringIndexerJava(SymbolHandler symbolHandler, AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders, IndexCache cache,
JavaProjectFinder projectFimder, ProgressService progressService) {
JavaProjectFinder projectFimder, ProgressService progressService, List<AnnotationReconciler> reconcilers,
BiFunction<AtomicReference<TextDocument>, BiConsumer<String, Diagnostic>, IProblemCollector> problemCollectorCreator) {
this.symbolHandler = symbolHandler;
this.symbolProviders = symbolProviders;
this.reconcilers = reconcilers;
this.cache = cache;
this.projectFinder = projectFimder;
this.progressService = progressService;
this.problemCollectorCreator = problemCollectorCreator;
}
public SpringIndexerJavaDependencyTracker getDependencyTracker() {
@@ -259,8 +270,18 @@ public class SpringIndexerJava implements SpringIndexer {
AtomicReference<TextDocument> docRef = new AtomicReference<>();
String file = UriUtil.toFileString(docURI);
BiConsumer<String, Diagnostic> diagnosticsAggregator = new BiConsumer<>() {
@Override
public void accept(String docURI, Diagnostic diagnostic) {
generatedDiagnostics.add(new CachedDiagnostics(docURI, diagnostic));
}
};
IProblemCollector problemCollector = problemCollectorCreator.apply(docRef, diagnosticsAggregator);
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file,
lastModified, docRef, content, generatedSymbols, generatedBeans, generatedDiagnostics, SCAN_PASS.ONE, new ArrayList<>());
lastModified, docRef, content, generatedSymbols, generatedBeans, problemCollector, SCAN_PASS.ONE, new ArrayList<>());
scanAST(context);
@@ -275,8 +296,9 @@ public class SpringIndexerJava implements SpringIndexer {
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
List<Diagnostic> diagnostics = generatedDiagnostics.stream().filter(cachedDiagnostics -> cachedDiagnostics.getDiagnostic() != null).map(cachedDiagnostic -> cachedDiagnostic.getDiagnostic()).collect(Collectors.toList());
symbolHandler.addSymbols(project, docURI, symbols, beans);
symbolHandler.addSymbols(project, docURI, symbols, beans, diagnostics);
Set<String> scannedFiles = new HashSet<>();
scannedFiles.add(file);
@@ -299,22 +321,33 @@ public class SpringIndexerJava implements SpringIndexer {
if (cu != null) {
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
List<CachedBean> generatedBeans = new ArrayList<CachedBean>();
List<CachedDiagnostics> generatedDiagnostics = new ArrayList<CachedDiagnostics>();
IProblemCollector voidProblemCollector = new IProblemCollector() {
@Override
public void endCollecting() {
}
@Override
public void beginCollecting() {
}
@Override
public void accept(ReconcileProblem problem) {
}
};
AtomicReference<TextDocument> docRef = new AtomicReference<>();
String file = UriUtil.toFileString(docURI);
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file,
0, docRef, content, generatedSymbols, generatedBeans, generatedDiagnostics, SCAN_PASS.ONE, new ArrayList<>());
0, docRef, content, generatedSymbols, generatedBeans, voidProblemCollector, SCAN_PASS.ONE, new ArrayList<>());
scanAST(context);
return generatedSymbols.stream().map(s -> s.getEnhancedSymbol()).collect(Collectors.toList());
}
}
return Collections.emptyList();
}
private Set<String> scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
@@ -341,6 +374,13 @@ public class SpringIndexerJava implements SpringIndexer {
List<CachedDiagnostics> generatedDiagnostics = new ArrayList<CachedDiagnostics>();
Multimap<String, String> dependencies = MultimapBuilder.hashKeys().hashSetValues().build();
BiConsumer<String, Diagnostic> diagnosticsAggregator = new BiConsumer<>() {
@Override
public void accept(String docURI, Diagnostic diagnostic) {
generatedDiagnostics.add(new CachedDiagnostics(docURI, diagnostic));
}
};
FileASTRequestor requestor = new FileASTRequestor() {
@Override
@@ -353,8 +393,10 @@ public class SpringIndexerJava implements SpringIndexer {
AtomicReference<TextDocument> docRef = new AtomicReference<>();
IProblemCollector problemCollector = problemCollectorCreator.apply(docRef, diagnosticsAggregator);
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath,
lastModified, docRef, null, generatedSymbols, generatedBeans, generatedDiagnostics, SCAN_PASS.ONE, new ArrayList<>());
lastModified, docRef, null, generatedSymbols, generatedBeans, problemCollector, SCAN_PASS.ONE, new ArrayList<>());
scanAST(context);
@@ -369,7 +411,8 @@ public class SpringIndexerJava implements SpringIndexer {
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
symbolHandler.addSymbols(project, symbols, beans);
Map<String, List<Diagnostic>> diagnosticsByDoc = generatedDiagnostics.stream().filter(cachedDiagnostic -> cachedDiagnostic.getDiagnostic() != null).collect(Collectors.groupingBy(CachedDiagnostics::getDocURI, Collectors.mapping(CachedDiagnostics::getDiagnostic, Collectors.toList())));
symbolHandler.addSymbols(project, symbols, beans, diagnosticsByDoc);
IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY);
IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY);
@@ -433,12 +476,19 @@ public class SpringIndexerJava implements SpringIndexer {
log.info("scan java files, AST parse, pass 1 for files: {}", javaFiles.length);
String[] pass2Files = scanFiles(project, javaFiles, generatedSymbols, generatedBeans, generatedDiagnostics, SCAN_PASS.ONE);
BiConsumer<String, Diagnostic> diagnosticsAggregator = new BiConsumer<>() {
@Override
public void accept(String docURI, Diagnostic diagnostic) {
generatedDiagnostics.add(new CachedDiagnostics(docURI, diagnostic));
}
};
String[] pass2Files = scanFiles(project, javaFiles, generatedSymbols, generatedBeans, diagnosticsAggregator, SCAN_PASS.ONE);
if (pass2Files.length > 0) {
log.info("scan java files, AST parse, pass 2 for files: {}", javaFiles.length);
scanFiles(project, pass2Files, generatedSymbols, generatedBeans, generatedDiagnostics, SCAN_PASS.TWO);
scanFiles(project, pass2Files, generatedSymbols, generatedBeans, diagnosticsAggregator, SCAN_PASS.TWO);
}
log.info("scan java files done, number of symbols created: " + generatedSymbols.size());
@@ -465,12 +515,13 @@ public class SpringIndexerJava implements SpringIndexer {
if (symbols != null && beans != null) {
EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
symbolHandler.addSymbols(project, enhancedSymbols, allBeans);
Map<String, List<Diagnostic>> diagnosticsByDoc = Arrays.stream(diagnostics).filter(cachedDiagnostic -> cachedDiagnostic.getDiagnostic() != null).collect(Collectors.groupingBy(CachedDiagnostics::getDocURI, Collectors.mapping(CachedDiagnostics::getDiagnostic, Collectors.toList())));
symbolHandler.addSymbols(project, enhancedSymbols, allBeans, diagnosticsByDoc);
}
}
private String[] scanFiles(IJavaProject project, String[] javaFiles, List<CachedSymbol> generatedSymbols, List<CachedBean> generatedBeans,
List<CachedDiagnostics> generatedDiagnostics, SCAN_PASS pass) throws Exception {
BiConsumer<String, Diagnostic> diagnosticsAggregator, SCAN_PASS pass) throws Exception {
PercentageProgressTask progressTask = this.progressService.createPercentageProgressTask(INDEX_FILES_TASK_ID + project.getElementName(),
javaFiles.length, "Spring Tools: Indexing Java Sources for '" + project.getElementName() + "'");
@@ -480,6 +531,7 @@ public class SpringIndexerJava implements SpringIndexer {
List<String> nextPassFiles = new ArrayList<>();
FileASTRequestor requestor = new FileASTRequestor() {
@Override
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
File file = new File(sourceFilePath);
@@ -487,8 +539,10 @@ public class SpringIndexerJava implements SpringIndexer {
long lastModified = file.lastModified();
AtomicReference<TextDocument> docRef = new AtomicReference<>();
IProblemCollector problemCollector = problemCollectorCreator.apply(docRef, diagnosticsAggregator);
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath,
lastModified, docRef, null, generatedSymbols, generatedBeans, generatedDiagnostics, pass, nextPassFiles);
lastModified, docRef, null, generatedSymbols, generatedBeans, problemCollector, pass, nextPassFiles);
scanAST(context);
progressTask.increment();
@@ -594,6 +648,8 @@ public class SpringIndexerJava implements SpringIndexer {
ITypeBinding typeBinding = node.resolveTypeBinding();
if (typeBinding != null) {
// symbol and index scanning
Collection<SymbolProvider> providers = symbolProviders.get(typeBinding);
Collection<ITypeBinding> metaAnnotations = AnnotationHierarchies.getMetaAnnotations(typeBinding, symbolProviders::containsKey);
@@ -609,6 +665,12 @@ public class SpringIndexerJava implements SpringIndexer {
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
}
}
// reconciling
for (AnnotationReconciler reconciler : this.reconcilers) {
reconciler.visit(context.getProject(), context.getDocRef().get(), node, typeBinding, context.getProblemCollector());
}
}
else {
log.debug("type binding not around: " + context.getDocURI() + " - " + node.toString());

View File

@@ -18,9 +18,9 @@ import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.springframework.ide.vscode.boot.java.beans.CachedBean;
import org.springframework.ide.vscode.boot.java.reconcilers.CachedDiagnostics;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava.SCAN_PASS;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
@@ -37,13 +37,14 @@ public class SpringIndexerJavaContext {
private final String content;
private final List<CachedSymbol> generatedSymbols;
private final List<CachedBean> beans;
private final List<CachedDiagnostics> diagnostics;
private final IProblemCollector getProblemCollector;
private final SCAN_PASS pass;
private final List<String> nextPassFiles;
private final Set<String> dependencies = new HashSet<>();
private final Set<String> scannedTypes = new HashSet<>();
public SpringIndexerJavaContext(
IJavaProject project,
CompilationUnit cu,
@@ -54,7 +55,7 @@ public class SpringIndexerJavaContext {
String content,
List<CachedSymbol> generatedSymbols,
List<CachedBean> beans,
List<CachedDiagnostics> diagnostics,
IProblemCollector problemCollector,
SCAN_PASS pass,
List<String> nextPassFiles
) {
@@ -67,8 +68,8 @@ public class SpringIndexerJavaContext {
this.docRef = docRef;
this.content = content;
this.generatedSymbols = generatedSymbols;
this.getProblemCollector = problemCollector;
this.beans = beans;
this.diagnostics = diagnostics;
this.pass = pass;
this.nextPassFiles = nextPassFiles;
}
@@ -109,10 +110,6 @@ public class SpringIndexerJavaContext {
return beans;
}
public List<CachedDiagnostics> getDiagnostics() {
return diagnostics;
}
public SCAN_PASS getPass() {
return pass;
}
@@ -146,4 +143,9 @@ public class SpringIndexerJavaContext {
dependencies.remove(type);
}
}
public IProblemCollector getProblemCollector() {
return this.getProblemCollector;
}
}

View File

@@ -137,7 +137,7 @@ public class SpringIndexerXML implements SpringIndexer {
if (symbols != null && beans != null) {
EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
symbolHandler.addSymbols(project, enhancedSymbols, allBeans);
symbolHandler.addSymbols(project, enhancedSymbols, allBeans, null);
}
long endTime = System.currentTimeMillis();
@@ -175,7 +175,7 @@ public class SpringIndexerXML implements SpringIndexer {
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
symbolHandler.addSymbols(project, docURI, symbols, beans);
symbolHandler.addSymbols(project, docURI, symbols, beans, null);
}
@Override
@@ -202,7 +202,7 @@ public class SpringIndexerXML implements SpringIndexer {
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
symbolHandler.addSymbols(project, docURI, symbols, beans);
symbolHandler.addSymbols(project, docURI, symbols, beans, null);
}
}

View File

@@ -10,6 +10,10 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.utils;
import java.util.List;
import java.util.Map;
import org.eclipse.lsp4j.Diagnostic;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
@@ -19,8 +23,8 @@ import org.springframework.ide.vscode.commons.protocol.spring.Bean;
*/
public interface SymbolHandler {
void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions);
void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions);
void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions, List<Diagnostic> diagnostics);
void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions, Map<String, List<Diagnostic>> diagnosticsByDoc);
void removeSymbols(IJavaProject project, String docURI);