initial enhancements to support method body analysis for webflux symbol support, not yet finished
This commit is contained in:
@@ -40,6 +40,7 @@ import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHov
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.LiveAppURLSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.WebfluxRouterSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.scope.ScopeCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippet;
|
||||
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetContext;
|
||||
@@ -281,6 +282,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
providers.put(Annotations.COMPONENT, new ComponentSymbolProvider());
|
||||
|
||||
providers.put(Annotations.REPOSITORY, new DataRepositorySymbolProvider());
|
||||
providers.put("", new WebfluxRouterSymbolProvider());
|
||||
|
||||
return new SpringIndexer(server, params, providers);
|
||||
}
|
||||
|
||||
@@ -165,5 +165,9 @@ public class BeansSymbolProvider implements SymbolProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ 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;
|
||||
@@ -116,4 +117,9 @@ public class ComponentSymbolProvider implements SymbolProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ 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;
|
||||
@@ -139,4 +140,9 @@ public class DataRepositorySymbolProvider implements SymbolProvider {
|
||||
}
|
||||
return beanName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ 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.SymbolInformation;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -26,5 +27,6 @@ public interface SymbolProvider {
|
||||
|
||||
Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, TextDocument doc);
|
||||
Collection<SymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc);
|
||||
Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc);
|
||||
|
||||
}
|
||||
|
||||
@@ -181,4 +181,9 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.requestmapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
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.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.MethodInvocation;
|
||||
import org.eclipse.jdt.core.dom.Type;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class WebfluxRouterSymbolProvider implements SymbolProvider {
|
||||
|
||||
private static final String ROUTER_FUNCTION_TYPE = "org.springframework.web.reactive.function.server.RouterFunction";
|
||||
private static final String ROUTER_FUNCTIONS_TYPE = "org.springframework.web.reactive.function.server.RouterFunctions";
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding,
|
||||
Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(TypeDeclaration typeDeclaration, TextDocument doc) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
|
||||
Type returnType = methodDeclaration.getReturnType2();
|
||||
if (returnType != null) {
|
||||
ITypeBinding resolvedBinding = returnType.resolveBinding();
|
||||
if (resolvedBinding != null) {
|
||||
if (ROUTER_FUNCTION_TYPE.equals(resolvedBinding.getBinaryName())) {
|
||||
return getSymbolsForRouterFunction(methodDeclaration, doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Collection<SymbolInformation> getSymbolsForRouterFunction(MethodDeclaration methodDeclaration,
|
||||
TextDocument doc) {
|
||||
List<SymbolInformation> result = new ArrayList<>();
|
||||
|
||||
Block body = methodDeclaration.getBody();
|
||||
body.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodInvocation node) {
|
||||
IMethodBinding methodBinding = node.resolveMethodBinding();
|
||||
|
||||
if (ROUTER_FUNCTIONS_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())
|
||||
&& "route".equals(node.getName().toString())) {
|
||||
extractMappingSymbol(node, doc, result);
|
||||
}
|
||||
else if (ROUTER_FUNCTION_TYPE.equals(methodBinding.getDeclaringClass().getBinaryName())
|
||||
&& "andRoute".equals(node.getName().toString())) {
|
||||
extractMappingSymbol(node, doc, result);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void extractMappingSymbol(MethodInvocation node, TextDocument doc, List<SymbolInformation> result) {
|
||||
List<?> arguments = node.arguments();
|
||||
if (arguments != null) {
|
||||
for (Object argument : arguments) {
|
||||
System.out.println(argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.FileASTRequestor;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MarkerAnnotation;
|
||||
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;
|
||||
@@ -346,7 +347,7 @@ public class SpringIndexer {
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setResolveBindings(false);
|
||||
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
|
||||
@@ -377,7 +378,7 @@ public class SpringIndexer {
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setIgnoreMethodBodies(true);
|
||||
parser.setIgnoreMethodBodies(false);
|
||||
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
|
||||
@@ -408,6 +409,17 @@ public class SpringIndexer {
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
try {
|
||||
extractSymbolInformation(node, docURI, docRef, content);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
try {
|
||||
@@ -462,6 +474,22 @@ public class SpringIndexer {
|
||||
}
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(MethodDeclaration methodDeclaration, String docURI, AtomicReference<TextDocument> docRef, String content) throws Exception {
|
||||
Collection<SymbolProvider> providers = symbolProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
TextDocument doc = getTempTextDocument(docURI, docRef, content);
|
||||
for (SymbolProvider provider : providers) {
|
||||
Collection<SymbolInformation> sbls = provider.getSymbols(methodDeclaration, doc);
|
||||
if (sbls != null) {
|
||||
sbls.forEach(symbol -> {
|
||||
symbols.add(symbol);
|
||||
symbolsByDoc.computeIfAbsent(docURI, s -> new ArrayList<SymbolInformation>()).add(symbol);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(Annotation node, String docURI, AtomicReference<TextDocument> docRef, String content) throws Exception {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
|
||||
|
||||
@@ -47,6 +47,18 @@ public class WebFluxMappingSymbolProviderTest {
|
||||
assertTrue(containsSymbol(symbols, "@/users/{username}", docUri, 24, 1, 24, 85));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoutesMappingSymbols() throws Exception {
|
||||
harness.intialize(new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI()));
|
||||
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-webflux-project/").toURI());
|
||||
|
||||
String docUri = directory.toPath().resolve("src/main/java/org/test/QuoteRouter.java").toUri().toString();
|
||||
List<? extends SymbolInformation> symbols = getSymbols(docUri);
|
||||
assertEquals(6, symbols.size());
|
||||
assertTrue(containsSymbol(symbols, "@/hello", docUri, 22, 23, 22, 81));
|
||||
assertTrue(containsSymbol(symbols, "@/echo", docUri, 23, 1, 23, 85));
|
||||
}
|
||||
|
||||
private boolean containsSymbol(List<? extends SymbolInformation> symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) {
|
||||
for (Iterator<? extends SymbolInformation> iterator = symbols.iterator(); iterator.hasNext();) {
|
||||
SymbolInformation symbol = iterator.next();
|
||||
|
||||
Reference in New Issue
Block a user