first cut for two-pass symbol indexing to avoid method body parsing for everything

This commit is contained in:
Martin Lippert
2019-03-25 22:24:16 +01:00
parent 3f70e16f37
commit 6397d8171c
11 changed files with 321 additions and 201 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc.
* Copyright (c) 2017, 2019 Pivotal, 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
@@ -27,10 +27,12 @@ import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
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.utils.ASTUtils;
import org.springframework.ide.vscode.boot.java.utils.CachedSymbol;
import org.springframework.ide.vscode.boot.java.utils.FunctionUtils;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
@@ -46,37 +48,37 @@ import reactor.util.function.Tuples;
* @author Martin Lippert
* @author Kris De Volder
*/
public class BeansSymbolProvider implements SymbolProvider {
public class BeansSymbolProvider extends AbstractSymbolProvider {
private static final String[] NAME_ATTRIBUTES = {"value", "name"};
@Override
public Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
if (isMethodAbstract(node)) return null;
ImmutableList.Builder<EnhancedSymbolInformation> symbols = ImmutableList.builder();
protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
if (isMethodAbstract(node)) return;
boolean isFunction = isFunctionBean(node);
String beanType = getBeanType(node);
String markerString = getAnnotations(node);
for (Tuple2<String, DocumentRegion> nameAndRegion : getBeanNames(node, doc)) {
try {
symbols.add(new EnhancedSymbolInformation(
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(
new SymbolInformation(
beanLabel(isFunction, nameAndRegion.getT1(), beanType, "@Bean" + markerString),
SymbolKind.Interface,
new Location(doc.getUri(), doc.toRange(nameAndRegion.getT2()))),
null
));
);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
} catch (BadLocationException e) {
Log.log(e);
}
}
return symbols.build();
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
// this checks function beans that are defined as implementations of Function interfaces
Tuple3<String, String, DocumentRegion> functionBean = FunctionUtils.getFunctionBean(typeDeclaration, doc);
if (functionBean != null) {
@@ -85,12 +87,13 @@ public class BeansSymbolProvider implements SymbolProvider {
beanLabel(true, functionBean.getT1(), functionBean.getT2(), null),
SymbolKind.Interface,
new Location(doc.getUri(), doc.toRange(functionBean.getT3())));
return ImmutableList.of(new EnhancedSymbolInformation(symbol, null));
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), new EnhancedSymbolInformation(symbol, null)));
} catch (BadLocationException e) {
Log.log(e);
}
}
return ImmutableList.of();
}
protected Collection<Tuple2<String, DocumentRegion>> getBeanNames(Annotation node, TextDocument doc) {
@@ -213,9 +216,4 @@ public class BeansSymbolProvider implements SymbolProvider {
return false;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc.
* Copyright (c) 2017, 2019 Pivotal, 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
@@ -16,36 +16,33 @@ import java.util.stream.Collectors;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
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.utils.CachedSymbol;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
/**
* @author Martin Lippert
* @author Kris De Volder
*/
public class ComponentSymbolProvider implements SymbolProvider {
public class ComponentSymbolProvider extends AbstractSymbolProvider {
@Override
public Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
try {
return ImmutableList.of(
createSymbol(node, annotationType, metaAnnotations, doc)
);
EnhancedSymbolInformation enhancedSymbol = createSymbol(node, annotationType, metaAnnotations, doc);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
}
catch (Exception e) {
Log.log(e);
}
return ImmutableList.of();
}
protected EnhancedSymbolInformation createSymbol(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) throws BadLocationException {
@@ -110,14 +107,4 @@ public class ComponentSymbolProvider implements SymbolProvider {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -10,11 +10,7 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.data;
import java.util.Collection;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
@@ -22,27 +18,27 @@ import org.eclipse.lsp4j.SymbolKind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.java.beans.BeanUtils;
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
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.utils.ASTUtils;
import org.springframework.ide.vscode.boot.java.utils.CachedSymbol;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
import reactor.util.function.Tuple4;
import reactor.util.function.Tuples;
/**
* @author Martin Lippert
*/
public class DataRepositorySymbolProvider implements SymbolProvider {
public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
private static final Logger log = LoggerFactory.getLogger(DataRepositorySymbolProvider.class);
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
// this checks spring data repository beans that are defined as extensions of the repository interface
Tuple4<String, String, String, DocumentRegion> repositoryBean = getRepositoryBean(typeDeclaration, doc);
if (repositoryBean != null) {
@@ -51,12 +47,12 @@ public class DataRepositorySymbolProvider implements SymbolProvider {
beanLabel(true, repositoryBean.getT1(), repositoryBean.getT2(), repositoryBean.getT3()),
SymbolKind.Interface,
new Location(doc.getUri(), doc.toRange(repositoryBean.getT4())));
return ImmutableList.of(new EnhancedSymbolInformation(symbol, null));
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
} catch (BadLocationException e) {
log.error("error creating data repository symbol for a specific range", e);
}
}
return ImmutableList.of();
}
protected String beanLabel(boolean isFunctionBean, String beanName, String beanType, String markerString) {
@@ -135,13 +131,4 @@ public class DataRepositorySymbolProvider implements SymbolProvider {
return BeanUtils.getBeanNameFromType(beanName);
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2019 Pivotal, 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.util.Collection;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava.SCAN_PASS;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
/**
* @author Martin Lippert
*/
public class AbstractSymbolProvider implements SymbolProvider {
@Override
public void addSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
if (SCAN_PASS.ONE.equals(context.getPass())) {
addSymbolsPass1(node, typeBinding, metaAnnotations, context, doc);
}
else if (SCAN_PASS.TWO.equals(context.getPass())) {
addSymbolsPass2(node, typeBinding, metaAnnotations, context, doc);
}
}
@Override
public void addSymbols(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
if (SCAN_PASS.ONE.equals(context.getPass())) {
addSymbolsPass1(typeDeclaration, context, doc);
}
else if (SCAN_PASS.TWO.equals(context.getPass())) {
addSymbolsPass2(typeDeclaration, context, doc);
}
}
@Override
public void addSymbols(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
if (SCAN_PASS.ONE.equals(context.getPass())) {
addSymbolsPass1(methodDeclaration, context, doc);
}
else if (SCAN_PASS.TWO.equals(context.getPass())) {
addSymbolsPass2(methodDeclaration, context, doc);
}
}
//
// implementations can decide whether to implement just pass1 or if they need 2 phases, they would have to implement both methods (pass1 + pass2)
//
protected void addSymbolsPass1(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
}
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
}
protected void addSymbolsPass1(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
}
protected void addSymbolsPass2(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
}
protected void addSymbolsPass2(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
}
protected void addSymbolsPass2(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc.
* Copyright (c) 2017, 2019 Pivotal, 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
@@ -16,6 +16,7 @@ import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
@@ -24,8 +25,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public interface SymbolProvider {
Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, TextDocument doc);
Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc);
Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc);
void addSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc);
void addSymbols(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc);
void addSymbols(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc);
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc.
* Copyright (c) 2017, 2019 Pivotal, 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
@@ -29,18 +29,22 @@ import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
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.utils.ASTUtils;
import org.springframework.ide.vscode.boot.java.utils.CachedSymbol;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
* @author Martin Lippert
*/
public class RequestMappingSymbolProvider implements SymbolProvider {
public class RequestMappingSymbolProvider extends AbstractSymbolProvider {
@Override
public Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
if (node.getParent() instanceof MethodDeclaration) {
try {
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));
@@ -50,7 +54,8 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
String[] contentTypes = getContentTypes(node);
String[] acceptTypes = getAcceptTypes(node);
return (parentPath == null ? Stream.of("") : Arrays.stream(parentPath)).filter(Objects::nonNull)
Stream<String> stream = parentPath == null ? Stream.of("") : Arrays.stream(parentPath);
stream.filter(Objects::nonNull)
.flatMap(parent -> (path == null ? Stream.<String>empty() : Arrays.stream(path))
.filter(Objects::nonNull).map(p -> {
String separator = !parent.endsWith("/") && !p.startsWith("/") ? "/" : "";
@@ -61,12 +66,11 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
return resultPath.startsWith("/") ? resultPath : "/" + resultPath;
}))
.map(p -> RouteUtils.createRouteSymbol(location, p, methods, contentTypes, acceptTypes, null))
.collect(Collectors.toList());
.forEach((enhancedSymbol) -> context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)));
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
private String[] getMethod(Annotation node) {
@@ -173,7 +177,7 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
}
return null;
}
private String[] getAcceptTypes(Annotation node) {
if (node.isNormalAnnotation()) {
NormalAnnotation normNode = (NormalAnnotation) node;
@@ -212,14 +216,4 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
return new String[0];
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* Copyright (c) 2018, 2019 Pivotal, 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
@@ -17,7 +17,6 @@ import java.util.function.Function;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ExpressionMethodReference;
import org.eclipse.jdt.core.dom.IMethodBinding;
@@ -31,66 +30,58 @@ import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.Range;
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
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.utils.CachedSymbol;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava.SCAN_PASS;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
* @author Martin Lippert
*/
public class WebfluxRouterSymbolProvider implements SymbolProvider {
public class WebfluxRouterSymbolProvider extends AbstractSymbolProvider {
@Override
public Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding,
Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
public void addSymbols(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
Type returnType = methodDeclaration.getReturnType2();
if (returnType != null) {
ITypeBinding resolvedBinding = returnType.resolveBinding();
if (resolvedBinding != null) {
if (WebfluxUtils.ROUTER_FUNCTION_TYPE.equals(resolvedBinding.getBinaryName())) {
return getSymbolsForRouterFunction(methodDeclaration, doc);
Block methodBody = methodDeclaration.getBody();
if (methodBody != null && methodBody.statements() != null && methodBody.statements().size() > 0) {
addSymbolsForRouterFunction(methodBody, context, doc);
}
else if (SCAN_PASS.ONE.equals(context.getPass())) {
context.getNextPassFiles().add(context.getFile());
}
}
}
}
return null;
}
private Collection<EnhancedSymbolInformation> getSymbolsForRouterFunction(MethodDeclaration methodDeclaration,
TextDocument doc) {
List<EnhancedSymbolInformation> result = new ArrayList<>();
Block body = methodDeclaration.getBody();
body.accept(new ASTVisitor() {
private void addSymbolsForRouterFunction(Block methodBody, SpringIndexerJavaContext context, TextDocument doc) {
methodBody.accept(new ASTVisitor() {
@Override
public boolean visit(MethodInvocation node) {
IMethodBinding methodBinding = node.resolveMethodBinding();
if (methodBinding != null && WebfluxUtils.isRouteMethodInvocation(methodBinding)) {
extractMappingSymbol(node, doc, result);
extractMappingSymbol(node, doc, context);
}
return super.visit(node);
}
});
return result;
}
protected void extractMappingSymbol(MethodInvocation node, TextDocument doc, List<EnhancedSymbolInformation> result) {
protected void extractMappingSymbol(MethodInvocation node, TextDocument doc, SpringIndexerJavaContext context) {
WebfluxRouteElement[] pathElements = extractPath(node, doc);
WebfluxRouteElement[] httpMethods = extractMethods(node, doc);
WebfluxRouteElement[] contentTypes = extractContentTypes(node, doc);
@@ -113,8 +104,10 @@ public class WebfluxRouterSymbolProvider implements SymbolProvider {
WebfluxHandlerInformation handler = extractHandlerInformation(node, path, httpMethods, contentTypes, acceptTypes);
WebfluxElementsInformation elements = extractElementsInformation(pathElements, httpMethods, contentTypes, acceptTypes);
result.add(RouteUtils.createRouteSymbol(location, path, getElementStrings(httpMethods),
getElementStrings(contentTypes), getElementStrings(acceptTypes), new SymbolAddOnInformation[] {handler, elements}));
EnhancedSymbolInformation enhancedSymbol = RouteUtils.createRouteSymbol(location, path, getElementStrings(httpMethods),
getElementStrings(contentTypes), getElementStrings(acceptTypes), new SymbolAddOnInformation[] {handler, elements});
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
} catch (BadLocationException e) {
e.printStackTrace();

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* Copyright (c) 2018, 2019 Pivotal, 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
@@ -18,36 +18,29 @@ import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.collect.ImmutableList;
/**
* @author Martin Lippert
*/
public class RestrictedDefaultSymbolProvider implements SymbolProvider {
public class RestrictedDefaultSymbolProvider extends AbstractSymbolProvider {
@Override
public Collection<EnhancedSymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding,
Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
protected void addSymbolsPass1(Annotation node, ITypeBinding typeBinding,
Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
// provide default symbol only in case this annotation is not combined with @Bean annotation
if (isCombinedWithAnnotation(node, Annotations.BEAN)) {
return null;
}
else {
ImmutableList.Builder<EnhancedSymbolInformation> symbols = ImmutableList.builder();
if (!isCombinedWithAnnotation(node, Annotations.BEAN)) {
try {
symbols.add(new EnhancedSymbolInformation(DefaultSymbolProvider.provideDefaultSymbol(node, doc), null));
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(DefaultSymbolProvider.provideDefaultSymbol(node, doc), null);
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
} catch (Exception e) {
Log.log(e);
}
return symbols.build();
}
}
@@ -74,14 +67,4 @@ public class RestrictedDefaultSymbolProvider implements SymbolProvider {
return false;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
return null;
}
@Override
public Collection<EnhancedSymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -54,6 +54,10 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public class SpringIndexerJava implements SpringIndexer {
public static enum SCAN_PASS {
ONE, TWO
}
private static final Logger log = LoggerFactory.getLogger(SpringIndexerJava.class);
private final SymbolHandler symbolHandler;
@@ -108,7 +112,7 @@ public class SpringIndexerJava implements SpringIndexer {
}
private void scanFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
ASTParser parser = createParser(project);
ASTParser parser = createParser(project, false);
String unitName = docURI.substring(docURI.lastIndexOf("/"));
parser.setUnitName(unitName);
@@ -118,12 +122,15 @@ public class SpringIndexerJava implements SpringIndexer {
if (cu != null) {
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
AtomicReference<TextDocument> docRef = new AtomicReference<>();
scanAST(project, cu, docURI, lastModified, docRef, content, generatedSymbols);
String file = new File(new URI(docURI)).getAbsolutePath();
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, file,
lastModified, docRef, content, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>());
scanAST(context);
SymbolCacheKey cacheKey = getCacheKey(project);
String file = new File(new URI(docURI)).getAbsolutePath();
this.cache.update(cacheKey, file, lastModified, generatedSymbols);
for (CachedSymbol symbol : generatedSymbols) {
@@ -139,21 +146,11 @@ public class SpringIndexerJava implements SpringIndexer {
if (symbols == null) {
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
ASTParser parser = createParser(project);
String[] pass2Files = scanFiles(project, javaFiles, generatedSymbols, SCAN_PASS.ONE);
if (pass2Files.length > 0) {
scanFiles(project, pass2Files, generatedSymbols, SCAN_PASS.TWO);
}
FileASTRequestor requestor = new FileASTRequestor() {
@Override
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
File file = new File(sourceFilePath);
String docURI = UriUtil.toUri(file).toString();
long lastModified = file.lastModified();
AtomicReference<TextDocument> docRef = new AtomicReference<>();
scanAST(project, cu, docURI, lastModified, docRef, null, generatedSymbols);
}
};
parser.createASTs(javaFiles, null, new String[0], requestor, null);
this.cache.store(cacheKey, javaFiles, generatedSymbols);
symbols = (CachedSymbol[]) generatedSymbols.toArray(new CachedSymbol[generatedSymbols.size()]);
@@ -170,16 +167,42 @@ public class SpringIndexerJava implements SpringIndexer {
}
}
private void scanAST(final IJavaProject project, final CompilationUnit cu, final String docURI, long lastModified, AtomicReference<TextDocument> docRef, final String content, List<CachedSymbol> generatedSymbols) {
cu.accept(new ASTVisitor() {
private String[] scanFiles(IJavaProject project, String[] javaFiles, List<CachedSymbol> generatedSymbols, SCAN_PASS pass)
throws Exception {
ASTParser parser = createParser(project, SCAN_PASS.ONE.equals(pass));
List<String> nextPassFiles = new ArrayList<>();
FileASTRequestor requestor = new FileASTRequestor() {
@Override
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
File file = new File(sourceFilePath);
String docURI = UriUtil.toUri(file).toString();
long lastModified = file.lastModified();
AtomicReference<TextDocument> docRef = new AtomicReference<>();
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath,
lastModified, docRef, null, generatedSymbols, pass, nextPassFiles);
scanAST(context);
}
};
parser.createASTs(javaFiles, null, new String[0], requestor, null);
return (String[]) nextPassFiles.toArray(new String[nextPassFiles.size()]);
}
private void scanAST(final SpringIndexerJavaContext context) {
context.getCu().accept(new ASTVisitor() {
@Override
public boolean visit(TypeDeclaration node) {
try {
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
extractSymbolInformation(node, context);
}
catch (Exception e) {
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
}
return super.visit(node);
}
@@ -187,10 +210,10 @@ public class SpringIndexerJava implements SpringIndexer {
@Override
public boolean visit(MethodDeclaration node) {
try {
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
extractSymbolInformation(node, context);
}
catch (Exception e) {
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
}
return super.visit(node);
}
@@ -198,10 +221,10 @@ public class SpringIndexerJava implements SpringIndexer {
@Override
public boolean visit(SingleMemberAnnotation node) {
try {
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
extractSymbolInformation(node, context);
}
catch (Exception e) {
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
}
return super.visit(node);
@@ -210,10 +233,10 @@ public class SpringIndexerJava implements SpringIndexer {
@Override
public boolean visit(NormalAnnotation node) {
try {
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
extractSymbolInformation(node, context);
}
catch (Exception e) {
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
}
return super.visit(node);
@@ -222,10 +245,10 @@ public class SpringIndexerJava implements SpringIndexer {
@Override
public boolean visit(MarkerAnnotation node) {
try {
extractSymbolInformation(project, node, docURI, docRef, content, lastModified, generatedSymbols);
extractSymbolInformation(node, context);
}
catch (Exception e) {
log.error("error extracting symbol information in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
}
return super.visit(node);
@@ -233,84 +256,66 @@ public class SpringIndexerJava implements SpringIndexer {
});
}
private void extractSymbolInformation(IJavaProject project, TypeDeclaration typeDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content,
long lastModified, List<CachedSymbol> generatedSymbols) throws Exception {
private void extractSymbolInformation(TypeDeclaration typeDeclaration, final SpringIndexerJavaContext context) throws Exception {
Collection<SymbolProvider> providers = symbolProviders.getAll();
if (!providers.isEmpty()) {
TextDocument doc = DocumentUtils.getTempTextDocument(docURI, docRef, content);
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
for (SymbolProvider provider : providers) {
Collection<EnhancedSymbolInformation> sbls = provider.getSymbols(typeDeclaration, doc);
if (sbls != null) {
sbls.forEach(enhancedSymbol -> {
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
});
}
provider.addSymbols(typeDeclaration, context, doc);
}
}
}
private void extractSymbolInformation(IJavaProject project, MethodDeclaration methodDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content,
long lastModified, List<CachedSymbol> generatedSymbols) throws Exception {
private void extractSymbolInformation(MethodDeclaration methodDeclaration, final SpringIndexerJavaContext context) throws Exception {
Collection<SymbolProvider> providers = symbolProviders.getAll();
if (!providers.isEmpty()) {
TextDocument doc = DocumentUtils.getTempTextDocument(docURI, docRef, content);
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
for (SymbolProvider provider : providers) {
Collection<EnhancedSymbolInformation> sbls = provider.getSymbols(methodDeclaration, doc);
if (sbls != null) {
sbls.forEach(enhancedSymbol -> {
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
});
}
provider.addSymbols(methodDeclaration, context, doc);
}
}
}
private void extractSymbolInformation(IJavaProject project, Annotation node, String docURI, AtomicReference<TextDocument> docRef, String content,
long lastModified, List<CachedSymbol> generatedSymbols) throws Exception {
private void extractSymbolInformation(Annotation node, final SpringIndexerJavaContext context) throws Exception {
ITypeBinding typeBinding = node.resolveTypeBinding();
if (typeBinding != null) {
Collection<SymbolProvider> providers = symbolProviders.get(typeBinding);
Collection<ITypeBinding> metaAnnotations = AnnotationHierarchies.getMetaAnnotations(typeBinding, symbolProviders::containsKey);
if (!providers.isEmpty()) {
TextDocument doc = DocumentUtils.getTempTextDocument(docURI, docRef, content);
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
for (SymbolProvider provider : providers) {
Collection<EnhancedSymbolInformation> sbls = provider.getSymbols(node, typeBinding, metaAnnotations, doc);
if (sbls != null) {
sbls.forEach(enhancedSymbol -> {
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
});
}
provider.addSymbols(node, typeBinding, metaAnnotations, context, doc);
}
} else {
SymbolInformation symbol = provideDefaultSymbol(project, node, docURI, docRef, content);
SymbolInformation symbol = provideDefaultSymbol(node, context);
if (symbol != null) {
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null);
generatedSymbols.add(new CachedSymbol(docURI, lastModified, enhancedSymbol));
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
}
}
}
}
private SymbolInformation provideDefaultSymbol(IJavaProject project, Annotation node, String docURI, AtomicReference<TextDocument> docRef, String content) {
private SymbolInformation provideDefaultSymbol(Annotation node, final SpringIndexerJavaContext context) {
try {
ITypeBinding type = node.resolveTypeBinding();
if (type != null) {
String qualifiedName = type.getQualifiedName();
if (qualifiedName != null && qualifiedName.startsWith("org.springframework")) {
TextDocument doc = DocumentUtils.getTempTextDocument(docURI, docRef, content);
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
return DefaultSymbolProvider.provideDefaultSymbol(node, doc);
}
}
}
catch (Exception e) {
log.error("error creating default symbol in project '" + project.getElementName() + "' - for docURI '" + docURI + "' - on node: " + node.toString(), e);
log.error("error creating default symbol in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
}
return null;
}
private ASTParser createParser(IJavaProject project) throws Exception {
private ASTParser createParser(IJavaProject project, boolean ignoreMethodBodies) throws Exception {
String[] classpathEntries = getClasspathEntries(project);
ASTParser parser = ASTParser.newParser(AST.JLS11);
@@ -321,8 +326,6 @@ public class SpringIndexerJava implements SpringIndexer {
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
boolean ignoreMethodBodies = "true".equals(System.getProperty("boot.ls.symbols.ignoreMethodBodies", "false"));
parser.setIgnoreMethodBodies(ignoreMethodBodies);
String[] sourceEntries = new String[] {};

View File

@@ -0,0 +1,93 @@
/*******************************************************************************
* Copyright (c) 2017, 2019 Pivotal, 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:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.utils;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jdt.core.dom.CompilationUnit;
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.util.text.TextDocument;
/**
* @author Martin Lippert
*/
public class SpringIndexerJavaContext {
private final IJavaProject project;
private final CompilationUnit cu;
private final String docURI;
private final String file;
private final long lastModified;
private final AtomicReference<TextDocument> docRef;
private final String content;
private final List<CachedSymbol> generatedSymbols;
private final SCAN_PASS pass;
private final List<String> nextPassFiles;
public SpringIndexerJavaContext(IJavaProject project, CompilationUnit cu, String docURI, String file, long lastModified,
AtomicReference<TextDocument> docRef, String content, List<CachedSymbol> generatedSymbols, SCAN_PASS pass,
List<String> nextPassFiles) {
super();
this.project = project;
this.cu = cu;
this.docURI = docURI;
this.file = file;
this.lastModified = lastModified;
this.docRef = docRef;
this.content = content;
this.generatedSymbols = generatedSymbols;
this.pass = pass;
this.nextPassFiles = nextPassFiles;
}
public IJavaProject getProject() {
return project;
}
public CompilationUnit getCu() {
return cu;
}
public String getDocURI() {
return docURI;
}
public String getFile() {
return file;
}
public long getLastModified() {
return lastModified;
}
public AtomicReference<TextDocument> getDocRef() {
return docRef;
}
public String getContent() {
return content;
}
public List<CachedSymbol> getGeneratedSymbols() {
return generatedSymbols;
}
public SCAN_PASS getPass() {
return pass;
}
public List<String> getNextPassFiles() {
return nextPassFiles;
}
}

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2018 Pivotal, Inc.
* Copyright (c) 2018, 2019 Pivotal, 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