initial enhancements to support method body analysis for webflux symbol support, not yet finished

This commit is contained in:
Martin Lippert
2018-02-22 08:27:50 +01:00
parent 315d4286e9
commit f381aa72d5
9 changed files with 167 additions and 2 deletions

View File

@@ -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);
}

View File

@@ -165,5 +165,9 @@ public class BeansSymbolProvider implements SymbolProvider {
return false;
}
@Override
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -181,4 +181,9 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
return null;
}
@Override
public Collection<SymbolInformation> getSymbols(MethodDeclaration methodDeclaration, TextDocument doc) {
return null;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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();

View File

@@ -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();