Stuck at adding dependency to Spring Indexer Context
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2019, 2022 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
|
||||
@@ -12,13 +12,13 @@ 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.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
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;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
@@ -26,7 +26,7 @@ import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
|
||||
public class AbstractSymbolProvider implements SymbolProvider {
|
||||
|
||||
@Override
|
||||
public void addSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
public void addSymbols(Annotation node, FullyQualified typeBinding, Collection<FullyQualified> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
if (SCAN_PASS.ONE.equals(context.getPass())) {
|
||||
addSymbolsPass1(node, typeBinding, metaAnnotations, context, doc);
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class AbstractSymbolProvider implements SymbolProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSymbols(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
public void addSymbols(ClassDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
if (SCAN_PASS.ONE.equals(context.getPass())) {
|
||||
addSymbolsPass1(typeDeclaration, context, doc);
|
||||
}
|
||||
@@ -60,19 +60,19 @@ public class AbstractSymbolProvider implements SymbolProvider {
|
||||
// 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(Annotation node, FullyQualified typeBinding, Collection<FullyQualified> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
}
|
||||
|
||||
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
protected void addSymbolsPass1(ClassDeclaration 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(Annotation node, FullyQualified typeBinding, Collection<FullyQualified> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
}
|
||||
|
||||
protected void addSymbolsPass2(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
protected void addSymbolsPass2(ClassDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
}
|
||||
|
||||
protected void addSymbolsPass2(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2021 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2022 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
|
||||
@@ -12,9 +12,9 @@ package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2022 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
|
||||
@@ -12,10 +12,10 @@ 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.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -25,8 +25,8 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
*/
|
||||
public interface SymbolProvider {
|
||||
|
||||
void addSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc);
|
||||
void addSymbols(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc);
|
||||
void addSymbols(Annotation node, FullyQualified typeBinding, Collection<FullyQualified> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc);
|
||||
void addSymbols(ClassDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc);
|
||||
void addSymbols(MethodDeclaration methodDeclaration, SpringIndexerJavaContext context, TextDocument doc);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2020 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2022 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,16 +18,17 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
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.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
@@ -35,6 +36,7 @@ import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveRequestMapping;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.RequestMappingMetrics;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
import org.springframework.ide.vscode.commons.util.Renderables;
|
||||
@@ -58,8 +60,8 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
private static final int CODE_LENS_LIMIT = 3;
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
public Hover provideHover(J node, Annotation annotation,
|
||||
int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
return provideHover(annotation, doc, processLiveData);
|
||||
}
|
||||
|
||||
@@ -69,7 +71,8 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
if (processLiveData.length > 0) {
|
||||
List<Tuple2<LiveRequestMapping, SpringProcessLiveData>> val = getRequestMappingMethodFromRunningApp(annotation, processLiveData);
|
||||
if (!val.isEmpty()) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(annotation);
|
||||
Range hoverRange = doc.toRange(r.getStart().getOffset(), r.length());
|
||||
return assembleCodeLenses(hoverRange, val);
|
||||
}
|
||||
}
|
||||
@@ -175,7 +178,8 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
|
||||
if (!val.isEmpty()) {
|
||||
Hover hover = createHoverWithContent(val);
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(annotation);
|
||||
Range hoverRange = doc.toRange(r.getStart().getOffset(), r.length());
|
||||
hover.setRange(hoverRange);
|
||||
return hover;
|
||||
} else {
|
||||
@@ -220,21 +224,26 @@ public class RequestMappingHoverProvider implements HoverProvider {
|
||||
|
||||
rqClassName = rqClassName.replace('$', '.');
|
||||
|
||||
ASTNode parent = annotation.getParent();
|
||||
J parent = ORAstUtils.getParent(annotation);
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration methodDec = (MethodDeclaration) parent;
|
||||
IMethodBinding binding = methodDec.resolveBinding();
|
||||
if (binding != null) {
|
||||
return binding.getDeclaringClass().getQualifiedName().equals(rqClassName)
|
||||
&& binding.getName().equals(rm.getMethodName())
|
||||
&& Arrays.equals(Arrays.stream(binding.getParameterTypes())
|
||||
.map(t -> t.getTypeDeclaration().getQualifiedName())
|
||||
.toArray(String[]::new),
|
||||
rm.getMethodParameters());
|
||||
ClassDeclaration declaringClass = ORAstUtils.findNode(methodDec, ClassDeclaration.class);
|
||||
if (declaringClass != null) {
|
||||
FullyQualified type = declaringClass.getType();
|
||||
return type != null && type.getFullyQualifiedName().equals(rqClassName)
|
||||
&& methodDec.getSimpleName().equals(rm.getMethodName())
|
||||
&& Arrays.equals(rm.getMethodParameters(),
|
||||
methodDec.getParameters().stream()
|
||||
.filter(VariableDeclarations.class::isInstance)
|
||||
.map(VariableDeclarations.class::cast)
|
||||
.map(v -> v.getTypeAsFullyQualified()) // what about primitive types, arrays etc???
|
||||
.map(fq -> fq == null ? "" : fq.getFullyQualifiedName())
|
||||
.toArray(String[]::new)
|
||||
);
|
||||
}
|
||||
// } else if (parent instanceof TypeDeclaration) {
|
||||
// TypeDeclaration typeDec = (TypeDeclaration) parent;
|
||||
// return typeDec.resolveBinding().getQualifiedName().equals(rqClassName);
|
||||
} else if (parent instanceof ClassDeclaration) {
|
||||
ClassDeclaration typeDec = (ClassDeclaration) parent;
|
||||
return typeDec.getType() == null ? false : rqClassName.equals(typeDec.getType().getFullyQualifiedName());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -17,20 +17,20 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
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.Location;
|
||||
import org.openrewrite.internal.lang.Nullable;
|
||||
import org.openrewrite.java.tree.Expression;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.Assignment;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
|
||||
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.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -40,11 +40,12 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
public class RequestMappingSymbolProvider extends AbstractSymbolProvider {
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
protected void addSymbolsPass1(Annotation node, FullyQualified annotationType, Collection<FullyQualified> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
|
||||
if (node.getParent() instanceof MethodDeclaration) {
|
||||
if (ORAstUtils.getParent(node) instanceof MethodDeclaration) {
|
||||
try {
|
||||
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));
|
||||
Range r = ORAstUtils.getRange(node);
|
||||
Location location = new Location(doc.getUri(), doc.toRange(r.getStart().getOffset(), r.length()));
|
||||
String[] path = getPath(node, context);
|
||||
String[] parentPath = getParentPath(node, context);
|
||||
String[] methods = getMethod(node, context);
|
||||
@@ -69,9 +70,40 @@ public class RequestMappingSymbolProvider extends AbstractSymbolProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getRequestMethodFromMultiArgs(Annotation annotation, SpringIndexerJavaContext context) {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (type != null && Annotations.SPRING_REQUEST_MAPPING.equals(type.getFullyQualifiedName())) {
|
||||
for (Expression arg : annotation.getArguments()) {
|
||||
if (arg instanceof Assignment) {
|
||||
Assignment assign = (Assignment) arg;
|
||||
if ("method".equals(assign.getVariable().printTrimmed())) {
|
||||
return ORAstUtils.getExpressionValueAsArray(assign.getAssignment(), context::addDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] getMethod(Annotation node, SpringIndexerJavaContext context) {
|
||||
String[] methods = null;
|
||||
|
||||
|
||||
List<Expression> args = node.getArguments();
|
||||
|
||||
// TODO: OR AST Annotation parameter
|
||||
if (args == null || (args.size() == 1
|
||||
&& (!(args.get(0) instanceof Assignment)) || "value".equals(((Assignment)args.get(0)).getVariable().printTrimmed()) )
|
||||
) {
|
||||
methods = getRequestMethod(node);
|
||||
} else if () {
|
||||
for (Expression arg : args) {
|
||||
if (arg instanceof Assignment && "method".equals(((Assignment) arg).getVariable().printTrimmed())) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (node.isNormalAnnotation()) {
|
||||
NormalAnnotation normNode = (NormalAnnotation) node;
|
||||
@@ -156,10 +188,10 @@ public class RequestMappingSymbolProvider extends AbstractSymbolProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] getRequestMethod(SingleMemberAnnotation annotation) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
private String[] getRequestMethod(Annotation annotation) {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (type != null) {
|
||||
switch (type.getQualifiedName()) {
|
||||
switch (type.getFullyQualifiedName()) {
|
||||
case Annotations.SPRING_GET_MAPPING:
|
||||
return new String[] { "GET" };
|
||||
case Annotations.SPRING_POST_MAPPING:
|
||||
@@ -170,6 +202,8 @@ public class RequestMappingSymbolProvider extends AbstractSymbolProvider {
|
||||
return new String[] { "PUT" };
|
||||
case Annotations.SPRING_PATCH_MAPPING:
|
||||
return new String[] { "PATCH" };
|
||||
case Annotations.SPRING_REQUEST_MAPPING:
|
||||
return new String[] { "GET" };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -12,16 +12,18 @@ package org.springframework.ide.vscode.boot.java.requestmapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CodeLensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -38,25 +40,23 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider {
|
||||
|
||||
@Override
|
||||
public void provideCodeLenses(CancelChecker cancelToken, TextDocument document, CompilationUnit cu, List<CodeLens> resultAccumulator) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
provideCodeLens(cancelToken, node, document, resultAccumulator);
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
new JavaIsoVisitor<List<CodeLens>>() {
|
||||
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, List<CodeLens> cl) {
|
||||
provideCodeLens(cancelToken, method, document, cl);
|
||||
return method;
|
||||
};
|
||||
}.visitNonNull(cu, resultAccumulator);
|
||||
}
|
||||
|
||||
protected void provideCodeLens(CancelChecker cancelToken, MethodDeclaration node, TextDocument document, List<CodeLens> resultAccumulator) {
|
||||
protected void provideCodeLens(CancelChecker cancelToken, MethodDeclaration method, TextDocument document, List<CodeLens> resultAccumulator) {
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
IMethodBinding methodBinding = node.resolveBinding();
|
||||
ClassDeclaration declaringType = ORAstUtils.findDeclaringType(method);
|
||||
|
||||
if (method != null && ORAstUtils.findDeclaringType(method) != null) {
|
||||
|
||||
if (methodBinding != null && methodBinding.getDeclaringClass() != null && methodBinding.getMethodDeclaration() != null
|
||||
&& methodBinding.getDeclaringClass().getBinaryName() != null && methodBinding.getMethodDeclaration().toString() != null) {
|
||||
|
||||
final String handlerClass = methodBinding.getDeclaringClass().getBinaryName().trim();
|
||||
final String handlerMethod = methodBinding.getMethodDeclaration().toString().trim();
|
||||
final String handlerClass = declaringType.getType().getFullyQualifiedName();
|
||||
final String handlerMethod = method.getMethodType().toString(); // TODO: OR AST likely a problem
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
@@ -75,7 +75,8 @@ public class WebfluxHandlerCodeLensProvider implements CodeLensProvider {
|
||||
WebfluxHandlerInformation handlerInfo = (WebfluxHandlerInformation) object;
|
||||
|
||||
CodeLens codeLens = new CodeLens();
|
||||
codeLens.setRange(document.toRange(node.getName().getStartPosition(), node.getName().getLength()));
|
||||
Range r = ORAstUtils.getRange(method.getName());
|
||||
codeLens.setRange(document.toRange(r.getStart().getOffset(), r.length()));
|
||||
|
||||
String httpMethod = WebfluxUtils.getStringRep(handlerInfo.getHttpMethods(), string -> string);
|
||||
String codeLensCommand = httpMethod != null ? httpMethod + " " : "";
|
||||
|
||||
@@ -10,24 +10,33 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ArrayInitializer;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.IBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.IVariableBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.Name;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.QualifiedName;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.openrewrite.java.tree.J.Modifier;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -38,6 +47,24 @@ public class ASTUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ASTUtils.class);
|
||||
|
||||
public static DocumentRegion nameRegion(TextDocument doc, Annotation annotation) {
|
||||
int start = annotation.getTypeName().getStartPosition();
|
||||
int end = start + annotation.getTypeName().getLength();
|
||||
if (doc.getSafeChar(start - 1) == '@') {
|
||||
start--;
|
||||
}
|
||||
return new DocumentRegion(doc, start, end);
|
||||
}
|
||||
|
||||
public static Optional<Range> nameRange(TextDocument doc, Annotation annotation) {
|
||||
try {
|
||||
return Optional.of(nameRegion(doc, annotation).asRange());
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentRegion stringRegion(TextDocument doc, StringLiteral node) {
|
||||
DocumentRegion nodeRegion = nodeRegion(doc, node);
|
||||
if (nodeRegion.startsWith("\"")) {
|
||||
@@ -50,6 +77,109 @@ public class ASTUtils {
|
||||
}
|
||||
|
||||
|
||||
public static DocumentRegion nodeRegion(TextDocument doc, ASTNode node) {
|
||||
int start = node.getStartPosition();
|
||||
int end = start + node.getLength();
|
||||
return new DocumentRegion(doc, start, end);
|
||||
}
|
||||
|
||||
public static Optional<Expression> getAttribute(Annotation annotation, String name) {
|
||||
if (annotation != null) {
|
||||
try {
|
||||
if (annotation.isSingleMemberAnnotation() && name.equals("value")) {
|
||||
SingleMemberAnnotation sma = (SingleMemberAnnotation) annotation;
|
||||
return Optional.ofNullable(sma.getValue());
|
||||
} else if (annotation.isNormalAnnotation()) {
|
||||
NormalAnnotation na = (NormalAnnotation) annotation;
|
||||
Object attributeObjs = na.getStructuralProperty(NormalAnnotation.VALUES_PROPERTY);
|
||||
if (attributeObjs instanceof List) {
|
||||
for (Object atrObj : (List<?>)attributeObjs) {
|
||||
if (atrObj instanceof MemberValuePair) {
|
||||
MemberValuePair mvPair = (MemberValuePair) atrObj;
|
||||
if (name.equals(mvPair.getName().getIdentifier())) {
|
||||
return Optional.ofNullable(mvPair.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* For case where a expression can be either a String or a array of Strings and
|
||||
* we are interested in the first element of the array. (I.e. typical case
|
||||
* when annotation attribute is of type String[] (because Java allows using a single
|
||||
* value as a convenient syntax for writing an array of length 1 in that case.
|
||||
*/
|
||||
public static Optional<String> getFirstString(Expression exp) {
|
||||
if (exp instanceof StringLiteral) {
|
||||
return Optional.ofNullable(getLiteralValue((StringLiteral) exp));
|
||||
} else if (exp instanceof ArrayInitializer) {
|
||||
ArrayInitializer array = (ArrayInitializer) exp;
|
||||
Object objs = array.getStructuralProperty(ArrayInitializer.EXPRESSIONS_PROPERTY);
|
||||
if (objs instanceof List) {
|
||||
List<?> list = (List<?>) objs;
|
||||
if (!list.isEmpty()) {
|
||||
Object firstObj = list.get(0);
|
||||
if (firstObj instanceof Expression) {
|
||||
return getFirstString((Expression) firstObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static TypeDeclaration findDeclaringType(ASTNode node) {
|
||||
while (node != null && !(node instanceof TypeDeclaration)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
return node != null ? (TypeDeclaration) node : null;
|
||||
}
|
||||
|
||||
public static boolean hasExactlyOneConstructor(TypeDeclaration typeDecl) {
|
||||
boolean oneFound = false;
|
||||
MethodDeclaration[] methods = typeDecl.getMethods();
|
||||
for (MethodDeclaration methodDeclaration : methods) {
|
||||
if (methodDeclaration.isConstructor()) {
|
||||
if (oneFound) {
|
||||
return false;
|
||||
} else {
|
||||
oneFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oneFound;
|
||||
}
|
||||
|
||||
public static MethodDeclaration getAnnotatedMethod(Annotation annotation) {
|
||||
ASTNode parent = annotation.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
return (MethodDeclaration)parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TypeDeclaration getAnnotatedType(Annotation annotation) {
|
||||
ASTNode parent = annotation.getParent();
|
||||
if (parent instanceof TypeDeclaration) {
|
||||
return (TypeDeclaration)parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getLiteralValue(StringLiteral node) {
|
||||
synchronized (node.getAST()) {
|
||||
return node.getLiteralValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getExpressionValueAsString(Expression exp, Consumer<ITypeBinding> dependencies) {
|
||||
if (exp instanceof StringLiteral) {
|
||||
return getLiteralValue((StringLiteral) exp);
|
||||
@@ -114,6 +244,20 @@ public class ASTUtils {
|
||||
}
|
||||
|
||||
|
||||
public static Collection<Annotation> getAnnotations(TypeDeclaration declaringType) {
|
||||
Object modifiersObj = declaringType.getStructuralProperty(TypeDeclaration.MODIFIERS2_PROPERTY);
|
||||
if (modifiersObj instanceof List) {
|
||||
ImmutableList.Builder<Annotation> annotations = ImmutableList.builder();
|
||||
for (Object node : (List<?>)modifiersObj) {
|
||||
if (node instanceof Annotation) {
|
||||
annotations.add((Annotation) node);
|
||||
}
|
||||
}
|
||||
return annotations.build();
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
public static String getAnnotationType(Annotation annotation) {
|
||||
ITypeBinding binding = annotation.resolveTypeBinding();
|
||||
@@ -122,5 +266,41 @@ public class ASTUtils {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static Optional<String> beanId(List<Object> modifiers) {
|
||||
return modifiers.stream()
|
||||
.filter(m -> m instanceof SingleMemberAnnotation)
|
||||
.map(m -> (SingleMemberAnnotation) m)
|
||||
.filter(m -> {
|
||||
ITypeBinding typeBinding = m.resolveTypeBinding();
|
||||
if (typeBinding != null) {
|
||||
return Annotations.QUALIFIER.equals(typeBinding.getQualifiedName());
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.findFirst()
|
||||
.map(a -> a.getValue())
|
||||
.filter(e -> e != null)
|
||||
.map(e -> e.resolveConstantExpressionValue())
|
||||
.filter(o -> o instanceof String)
|
||||
.map(o -> (String) o);
|
||||
}
|
||||
|
||||
public static Annotation getBeanAnnotation(MethodDeclaration method) {
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
ITypeBinding typeBinding = annotation.resolveTypeBinding();
|
||||
if (typeBinding != null) {
|
||||
String fqName = typeBinding.getQualifiedName();
|
||||
if (Annotations.BEAN.equals(fqName)) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2022 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
|
||||
@@ -10,10 +10,11 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
@@ -22,8 +23,9 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
public class DefaultSymbolProvider {
|
||||
|
||||
public static SymbolInformation provideDefaultSymbol(Annotation node, TextDocument doc) throws Exception {
|
||||
Range r = ORAstUtils.getRange(node);
|
||||
SymbolInformation symbol = new SymbolInformation(node.toString(), SymbolKind.Interface,
|
||||
new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength())));
|
||||
new Location(doc.getUri(), doc.toRange(r.getStart().getOffset(), r.length())));
|
||||
return symbol;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.openrewrite.Cursor;
|
||||
import org.openrewrite.SourceFile;
|
||||
import org.eclipse.jdt.core.dom.ArrayInitializer;
|
||||
import org.eclipse.jdt.core.dom.IBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.IVariableBinding;
|
||||
import org.eclipse.jdt.core.dom.Name;
|
||||
import org.eclipse.jdt.core.dom.QualifiedName;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.openrewrite.ExecutionContext;
|
||||
import org.openrewrite.InMemoryExecutionContext;
|
||||
import org.openrewrite.Parser;
|
||||
import org.openrewrite.Recipe;
|
||||
import org.openrewrite.Result;
|
||||
import org.openrewrite.Tree;
|
||||
import org.openrewrite.TreeVisitor;
|
||||
import org.openrewrite.internal.lang.Nullable;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.UpdateSourcePositions;
|
||||
import org.openrewrite.java.tree.Expression;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
@@ -19,6 +36,8 @@ import org.openrewrite.java.tree.J.Assignment;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.java.tree.J.EnumValueSet;
|
||||
import org.openrewrite.java.tree.J.FieldAccess;
|
||||
import org.openrewrite.java.tree.J.Identifier;
|
||||
import org.openrewrite.java.tree.J.Literal;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.NewArray;
|
||||
@@ -37,41 +56,110 @@ public class ORAstUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ORAstUtils.class);
|
||||
|
||||
private static class AncestersMarker implements Marker {
|
||||
private static class ParentMarker implements Marker {
|
||||
|
||||
private UUID uuid;
|
||||
private List<J> ancesters = List.of();
|
||||
private J parent;
|
||||
|
||||
public AncestersMarker(List<J> ancesters) {
|
||||
public ParentMarker(J parent) {
|
||||
this.uuid = Tree.randomId();
|
||||
this.ancesters = ancesters;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UUID getId() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getFirstAnsector(Class<T> clazz) {
|
||||
if (ancesters != null) {
|
||||
for (J node : ancesters) {
|
||||
if (clazz.isInstance(node)) {
|
||||
return (T) node;
|
||||
}
|
||||
}
|
||||
public J getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public J getGrandParent() {
|
||||
if (parent != null) {
|
||||
return parent.getMarkers().findFirst(ParentMarker.class).map(m -> m.getParent()).orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public J getParent() {
|
||||
if (ancesters != null && !ancesters.isEmpty()) {
|
||||
return ancesters.get(0);
|
||||
public <T> T getFirstAnsector(Class<T> clazz) {
|
||||
if (clazz.isInstance(parent)) {
|
||||
return clazz.cast(parent);
|
||||
} else if (parent != null) {
|
||||
return parent.getMarkers().findFirst(ParentMarker.class).map(m -> m.getFirstAnsector(clazz)).orElse(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// private static class AncestersMarker implements Marker {
|
||||
//
|
||||
// private UUID uuid;
|
||||
// private List<J> ancesters = List.of();
|
||||
//
|
||||
// public AncestersMarker(List<J> ancesters) {
|
||||
// this.uuid = Tree.randomId();
|
||||
// this.ancesters = ancesters;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public UUID getId() {
|
||||
// return uuid;
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public <T> T getFirstAnsector(Class<T> clazz) {
|
||||
// if (ancesters != null) {
|
||||
// for (J node : ancesters) {
|
||||
// if (clazz.isInstance(node)) {
|
||||
// return (T) node;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public J getParent() {
|
||||
// if (ancesters != null && !ancesters.isEmpty()) {
|
||||
// return ancesters.get(0);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public J getGrandParent() {
|
||||
// if (ancesters != null && ancesters.size() > 1) {
|
||||
// return ancesters.get(1);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
private static class MarkParentRecipe extends Recipe {
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Create parent AST node references via markers";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TreeVisitor<?, ExecutionContext> getVisitor() {
|
||||
return new JavaIsoVisitor<>() {
|
||||
@Override
|
||||
public @Nullable J visit(@Nullable Tree tree, ExecutionContext p) {
|
||||
if (tree instanceof J) {
|
||||
J j = (J) tree;
|
||||
J parent = getCursor().getParent() == null ? null : getCursor().getParent().getValue();
|
||||
J newJ = j.withMarkers(j.getMarkers().addIfAbsent(new ParentMarker(parent)));
|
||||
super.visit(newJ, p);
|
||||
return newJ;
|
||||
}
|
||||
return (J) tree;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static J findAstNodeAt(CompilationUnit cu, int offset) {
|
||||
AtomicReference<J> f = new AtomicReference<>();
|
||||
new JavaIsoVisitor<AtomicReference<J>>() {
|
||||
@@ -87,16 +175,18 @@ public class ORAstUtils {
|
||||
&& offset <= range.getEnd().getOffset()) {
|
||||
super.visit(tree, found);
|
||||
if (found.get() == null) {
|
||||
List<J> ancesters = new ArrayList<>();
|
||||
for (Cursor c = getCursor(); c != null && !(c.getValue() instanceof SourceFile); c = c.getParent()) {
|
||||
Object o = c.getValue();
|
||||
if (o instanceof J) {
|
||||
ancesters.add((J) o);
|
||||
}
|
||||
}
|
||||
J n = node.withMarkers(node.getMarkers().addIfAbsent(new AncestersMarker(ancesters)));
|
||||
found.set(n);
|
||||
return n;
|
||||
// List<J> ancesters = new ArrayList<>();
|
||||
// for (Cursor c = getCursor(); c != null && !(c.getValue() instanceof SourceFile); c = c.getParent()) {
|
||||
// Object o = c.getValue();
|
||||
// if (o instanceof J) {
|
||||
// ancesters.add((J) o);
|
||||
// }
|
||||
// }
|
||||
// J n = node.withMarkers(node.getMarkers().addIfAbsent(new AncestersMarker(ancesters)));
|
||||
// found.set(n);
|
||||
// return n;
|
||||
found.set(node);
|
||||
return node;
|
||||
}
|
||||
} else {
|
||||
return (J) tree;
|
||||
@@ -113,13 +203,15 @@ public class ORAstUtils {
|
||||
if (clazz.isInstance(node)) {
|
||||
return (T) node;
|
||||
}
|
||||
AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
|
||||
return ancestry.getFirstAnsector(clazz);
|
||||
// AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
|
||||
// return ancestry.getFirstAnsector(clazz);
|
||||
return node.getMarkers().findFirst(ParentMarker.class).map(m -> m.getFirstAnsector(clazz)).orElse(null);
|
||||
}
|
||||
|
||||
public static J getParent(J node) {
|
||||
AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
|
||||
return ancestry.getParent();
|
||||
// AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
|
||||
// return ancestry.getParent();
|
||||
return node.getMarkers().findFirst(ParentMarker.class).map(m -> m.getParent()).orElse(null);
|
||||
}
|
||||
|
||||
public static EnumValueSet getEnumValues(ClassDeclaration classDecl) {
|
||||
@@ -293,5 +385,48 @@ public class ORAstUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static J getGrandParent(J j) {
|
||||
return j.getMarkers().findFirst(ParentMarker.class).map(m -> m.getGrandParent()).orElse(null);
|
||||
}
|
||||
|
||||
public static String[] getExpressionValueAsArray(Expression exp, Consumer<FullyQualified> dependencies) {
|
||||
if (exp instanceof NewArray) {
|
||||
NewArray array = (NewArray) exp;
|
||||
return array.getInitializer().stream().map(e -> getExpressionValueAsString(e, dependencies))
|
||||
.filter(Objects::nonNull).toArray(String[]::new);
|
||||
} else {
|
||||
String rm = getExpressionValueAsString(exp, dependencies);
|
||||
if (rm != null) {
|
||||
return new String[] { rm };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getExpressionValueAsString(Expression exp, Consumer<FullyQualified> dependencies) {
|
||||
// TODO: OR AST need to check if there is way to extract constant values from variables
|
||||
if (exp instanceof Literal) {
|
||||
return getLiteralValue((Literal) exp);
|
||||
} else if (exp instanceof Identifier) {
|
||||
Identifier id = (Identifier) exp;
|
||||
return id.getSimpleName();
|
||||
} else if (exp instanceof FieldAccess) {
|
||||
FieldAccess fa = (FieldAccess) exp;
|
||||
return getExpressionValueAsString(fa.getName(), dependencies);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<CompilationUnit> parse(JavaParser parser, Iterable<Path> sourceFiles) {
|
||||
List<CompilationUnit> cus = parser.parse(sourceFiles, null, new InMemoryExecutionContext());
|
||||
List<Result> results = new UpdateSourcePositions().doNext(new MarkParentRecipe()).run(cus);
|
||||
return results.stream().map(r -> r.getAfter() == null ? r.getBefore() : r.getAfter()).map(CompilationUnit.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<CompilationUnit> parseInputs(JavaParser parser, Iterable<Parser.Input> inputs) {
|
||||
List<CompilationUnit> cus = parser.parseInputs(inputs, null, new InMemoryExecutionContext());
|
||||
List<Result> results = new UpdateSourcePositions().doNext(new MarkParentRecipe()).run(cus);
|
||||
return results.stream().map(r -> r.getAfter() == null ? r.getBefore() : r.getAfter()).map(CompilationUnit.class::cast).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,12 +208,10 @@ public class ORCompilationUnitCache implements DocumentContentProvider, Disposab
|
||||
}
|
||||
});
|
||||
|
||||
List<CompilationUnit> parseInputs = javaParser.parseInputs(List.of(input), null, new InMemoryExecutionContext());
|
||||
Result result = new UpdateSourcePositions().run(parseInputs).get(0);
|
||||
|
||||
logger.info("CU Cache: created new AST for {}", uri.toString());
|
||||
|
||||
return (CompilationUnit) (result.getAfter() == null ? result.getBefore() : result.getAfter());
|
||||
|
||||
return ORAstUtils.parseInputs(javaParser, List.of(input)).get(0);
|
||||
|
||||
});
|
||||
|
||||
if (cu != null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2018, 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2018, 2022 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
|
||||
@@ -11,13 +11,12 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
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.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
@@ -33,8 +32,8 @@ public class RestrictedDefaultSymbolProvider extends AbstractSymbolProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(RestrictedDefaultSymbolProvider.class);
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(Annotation node, ITypeBinding typeBinding,
|
||||
Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
protected void addSymbolsPass1(Annotation node, FullyQualified typeBinding,
|
||||
Collection<FullyQualified> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
|
||||
// provide default symbol only in case this annotation is not combined with @Bean annotation
|
||||
if (!isCombinedWithAnnotation(node, Annotations.BEAN)) {
|
||||
@@ -48,21 +47,15 @@ public class RestrictedDefaultSymbolProvider extends AbstractSymbolProvider {
|
||||
}
|
||||
|
||||
private boolean isCombinedWithAnnotation(Annotation node, String annotation) {
|
||||
ASTNode parent = node.getParent();
|
||||
J parent = ORAstUtils.getParent(node);
|
||||
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) parent;
|
||||
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation anno = (Annotation) modifier;
|
||||
IAnnotationBinding annotationBinding = anno.resolveAnnotationBinding();
|
||||
String type = annotationBinding.getAnnotationType().getBinaryName();
|
||||
|
||||
if (type != null && type.equals(annotation)) {
|
||||
return true;
|
||||
}
|
||||
for (Annotation a : method.getLeadingAnnotations()) {
|
||||
FullyQualified otherAnnotationType = TypeUtils.asFullyQualified(a.getType());
|
||||
if (otherAnnotationType != null && annotation.equals(otherAnnotationType.getFullyQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@@ -31,20 +32,19 @@ import java.util.stream.Stream;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
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;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.openrewrite.InMemoryExecutionContext;
|
||||
import org.openrewrite.Parser;
|
||||
import org.openrewrite.internal.lang.Nullable;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.JavaParser.Builder;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
@@ -191,22 +191,20 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
}
|
||||
|
||||
private void scanFile(IJavaProject project, DocumentDescriptor updatedDoc, String content) throws Exception {
|
||||
ASTParser parser = createParser(project, false);
|
||||
JavaParser parser = createParser(project, false);
|
||||
|
||||
String docURI = updatedDoc.getDocURI();
|
||||
long lastModified = updatedDoc.getLastModified();
|
||||
Path path = new File(new URI(docURI)).toPath();
|
||||
|
||||
if (content == null) {
|
||||
Path path = new File(new URI(docURI)).toPath();
|
||||
content = new String(Files.readAllBytes(path));
|
||||
}
|
||||
|
||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
parser.setUnitName(unitName);
|
||||
log.debug("Scan file: {}", unitName);
|
||||
parser.setSource(content.toCharArray());
|
||||
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
byte[] contentBytes = content.getBytes();
|
||||
CompilationUnit cu = ORAstUtils.parseInputs(parser, List.of(new Parser.Input(path, () -> new ByteArrayInputStream(contentBytes)))).get(0);
|
||||
|
||||
if (cu != null) {
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
|
||||
@@ -232,7 +230,7 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
}
|
||||
|
||||
private Set<String> scanFilesInternally(IJavaProject project, DocumentDescriptor[] docs) throws Exception {
|
||||
ASTParser parser = createParser(project, false);
|
||||
JavaParser parser = createParser(project, false);
|
||||
|
||||
// this is to keep track of already scanned files to avoid endless loops due to circular dependencies
|
||||
Set<String> scannedTypes = new HashSet<>();
|
||||
@@ -253,31 +251,30 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
|
||||
Multimap<String, String> dependencies = MultimapBuilder.hashKeys().hashSetValues().build();
|
||||
|
||||
FileASTRequestor requestor = new FileASTRequestor() {
|
||||
@Override
|
||||
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
|
||||
File file = new File(sourceFilePath);
|
||||
String docURI = UriUtil.toUri(file).toString();
|
||||
|
||||
DocumentDescriptor updatedDoc = updatedDocs.get(docURI);
|
||||
long lastModified = updatedDoc.getLastModified();
|
||||
|
||||
AtomicReference<TextDocument> docRef = new AtomicReference<>();
|
||||
|
||||
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath,
|
||||
lastModified, docRef, null, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>());
|
||||
|
||||
scanAST(context);
|
||||
|
||||
dependencies.putAll(sourceFilePath, context.getDependencies());
|
||||
scannedTypes.addAll(context.getScannedTypes());
|
||||
|
||||
fileScannedEvent(sourceFilePath);
|
||||
}
|
||||
};
|
||||
|
||||
parser.createASTs(javaFiles, null, new String[0], requestor, null);
|
||||
Collection<Path> javaPaths = Arrays.stream(javaFiles).map(p -> Path.of(p)).collect(Collectors.toList());
|
||||
List<CompilationUnit> cus = ORAstUtils.parse(parser, javaPaths);
|
||||
|
||||
for (CompilationUnit cu : cus) {
|
||||
File file = cu.getSourcePath().toFile();
|
||||
String sourceFilePath = file.getPath();
|
||||
String docURI = UriUtil.toUri(file).toString();
|
||||
|
||||
DocumentDescriptor updatedDoc = updatedDocs.get(docURI);
|
||||
long lastModifiedStamp = updatedDoc.getLastModified();
|
||||
|
||||
AtomicReference<TextDocument> docRef = new AtomicReference<>();
|
||||
|
||||
SpringIndexerJavaContext context = new SpringIndexerJavaContext(project, cu, docURI, sourceFilePath,
|
||||
lastModifiedStamp, docRef, null, generatedSymbols, SCAN_PASS.ONE, new ArrayList<>());
|
||||
|
||||
scanAST(context);
|
||||
|
||||
dependencies.putAll(sourceFilePath, context.getDependencies());
|
||||
scannedTypes.addAll(context.getScannedTypes());
|
||||
|
||||
fileScannedEvent(sourceFilePath);
|
||||
}
|
||||
|
||||
for (CachedSymbol symbol : generatedSymbols) {
|
||||
symbolHandler.addSymbol(project, symbol.getDocURI(), symbol.getEnhancedSymbol());
|
||||
}
|
||||
@@ -361,96 +358,69 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
|
||||
private String[] scanFiles(IJavaProject project, String[] javaFiles, List<CachedSymbol> generatedSymbols, SCAN_PASS pass)
|
||||
throws Exception {
|
||||
ASTParser parser = createParser(project, SCAN_PASS.ONE.equals(pass));
|
||||
JavaParser parser = createParser(project, SCAN_PASS.ONE.equals(pass));
|
||||
List<String> nextPassFiles = new ArrayList<>();
|
||||
|
||||
Collection<Path> javaPaths = Arrays.stream(javaFiles).map(p -> Path.of(p)).collect(Collectors.toList());
|
||||
List<CompilationUnit> cus = ORAstUtils.parse(parser, javaPaths);
|
||||
|
||||
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<>();
|
||||
for (CompilationUnit cu : cus) {
|
||||
File file = cu.getSourcePath().toFile();
|
||||
String sourceFilePath = file.getPath();
|
||||
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);
|
||||
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);
|
||||
scanAST(context);
|
||||
}
|
||||
|
||||
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) {
|
||||
new JavaIsoVisitor<SpringIndexerJavaContext>() {
|
||||
|
||||
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, SpringIndexerJavaContext indexer) {
|
||||
try {
|
||||
context.addScannedType(node.resolveBinding());
|
||||
extractSymbolInformation(node, context);
|
||||
context.addScannedType(classDecl.getType());
|
||||
extractSymbolInformation(classDecl, indexer);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
|
||||
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + classDecl.getSimpleName(), e);
|
||||
}
|
||||
return super.visit(node);
|
||||
return super.visitClassDeclaration(classDecl, indexer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
|
||||
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, SpringIndexerJavaContext indexer) {
|
||||
try {
|
||||
extractSymbolInformation(node, context);
|
||||
extractSymbolInformation(method, indexer);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
|
||||
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + method.getSimpleName(), e);
|
||||
}
|
||||
return super.visit(node);
|
||||
return super.visitMethodDeclaration(method, indexer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
|
||||
public Annotation visitAnnotation(Annotation annotation, SpringIndexerJavaContext indexer) {
|
||||
try {
|
||||
extractSymbolInformation(node, context);
|
||||
extractSymbolInformation(annotation, context);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + node.toString(), e);
|
||||
log.error("error extracting symbol information in project '" + context.getProject().getElementName() + "' - for docURI '" + context.getDocURI() + "' - on node: " + annotation.printTrimmed(), e);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
return super.visitAnnotation(annotation, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
try {
|
||||
extractSymbolInformation(node, context);
|
||||
}
|
||||
catch (Exception 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MarkerAnnotation node) {
|
||||
try {
|
||||
extractSymbolInformation(node, context);
|
||||
}
|
||||
catch (Exception 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);
|
||||
}
|
||||
});
|
||||
|
||||
}.visitNonNull(context.getCu(), context);
|
||||
|
||||
|
||||
dependencyTracker.update(context.getFile(), context.getDependencies());;
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(TypeDeclaration typeDeclaration, final SpringIndexerJavaContext context) throws Exception {
|
||||
private void extractSymbolInformation(ClassDeclaration typeDeclaration, final SpringIndexerJavaContext context) throws Exception {
|
||||
Collection<SymbolProvider> providers = symbolProviders.getAll();
|
||||
if (!providers.isEmpty()) {
|
||||
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
|
||||
@@ -471,16 +441,16 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
}
|
||||
|
||||
private void extractSymbolInformation(Annotation node, final SpringIndexerJavaContext context) throws Exception {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
FullyQualified type = TypeUtils.asFullyQualified(node.getType());
|
||||
|
||||
if (typeBinding != null) {
|
||||
Collection<SymbolProvider> providers = symbolProviders.get(typeBinding);
|
||||
Collection<ITypeBinding> metaAnnotations = AnnotationHierarchies.getMetaAnnotations(typeBinding, symbolProviders::containsKey);
|
||||
if (type != null) {
|
||||
Collection<SymbolProvider> providers = symbolProviders.get(type);
|
||||
Collection<FullyQualified> metaAnnotations = AnnotationHierarchies.getMetaAnnotations(type, symbolProviders::containsKey);
|
||||
|
||||
if (!providers.isEmpty()) {
|
||||
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
|
||||
for (SymbolProvider provider : providers) {
|
||||
provider.addSymbols(node, typeBinding, metaAnnotations, context, doc);
|
||||
provider.addSymbols(node, type, metaAnnotations, context, doc);
|
||||
}
|
||||
} else {
|
||||
SymbolInformation symbol = provideDefaultSymbol(node, context);
|
||||
@@ -497,9 +467,9 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
|
||||
private SymbolInformation provideDefaultSymbol(Annotation node, final SpringIndexerJavaContext context) {
|
||||
try {
|
||||
ITypeBinding type = node.resolveTypeBinding();
|
||||
FullyQualified type = TypeUtils.asFullyQualified(node.getType());
|
||||
if (type != null) {
|
||||
String qualifiedName = type.getQualifiedName();
|
||||
String qualifiedName = type.getFullyQualifiedName();
|
||||
if (qualifiedName != null && qualifiedName.startsWith("org.springframework")) {
|
||||
TextDocument doc = DocumentUtils.getTempTextDocument(context.getDocURI(), context.getDocRef(), context.getContent());
|
||||
return DefaultSymbolProvider.provideDefaultSymbol(node, doc);
|
||||
@@ -513,31 +483,20 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ASTParser createParser(IJavaProject project, boolean ignoreMethodBodies) throws Exception {
|
||||
String[] classpathEntries = getClasspathEntries(project);
|
||||
String[] sourceEntries = getSourceEntries(project);
|
||||
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS16);
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_16, options);
|
||||
parser.setCompilerOptions(options);
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
parser.setIgnoreMethodBodies(ignoreMethodBodies);
|
||||
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
|
||||
return parser;
|
||||
private JavaParser createParser(IJavaProject project, boolean ignoreMethodBodies) throws Exception {
|
||||
JavaParser jp = JavaParser.fromJavaVersion().build();
|
||||
jp.setClasspath(getClasspathEntries(project));
|
||||
return jp;
|
||||
}
|
||||
|
||||
private String[] getClasspathEntries(IJavaProject project) throws Exception {
|
||||
private Collection<Path> getClasspathEntries(IJavaProject project) throws Exception {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
Stream<File> classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream();
|
||||
return classpathEntries
|
||||
.filter(file -> file.exists())
|
||||
.map(file -> file.getAbsolutePath())
|
||||
.toArray(String[]::new);
|
||||
.map(file -> file.getAbsoluteFile())
|
||||
.map(file -> file.toPath())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private String[] getSourceEntries(IJavaProject project) throws Exception {
|
||||
|
||||
@@ -15,8 +15,9 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
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;
|
||||
@@ -123,9 +124,9 @@ public class SpringIndexerJavaContext {
|
||||
return scannedTypes;
|
||||
}
|
||||
|
||||
public void addScannedType(ITypeBinding scannedType) {
|
||||
public void addScannedType(FullyQualified scannedType) {
|
||||
if (scannedType != null) {
|
||||
String type = scannedType.getKey();
|
||||
String type = scannedType.getFullyQualifiedName();
|
||||
scannedTypes.add(type);
|
||||
dependencies.remove(type);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2019 Pivotal, Inc.
|
||||
* Copyright (c) 2017, 2022 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,18 +18,16 @@ import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
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.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.Assignment;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.Literal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
@@ -37,6 +35,7 @@ import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveProperties;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveProperty;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Renderable;
|
||||
@@ -59,16 +58,18 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc,
|
||||
public Hover provideHover(J node, Annotation annotation, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
|
||||
try {
|
||||
ASTNode foundNode = NodeFinder.perform(node, offset, 0);
|
||||
ASTNode exactNode = getExactNode(foundNode);
|
||||
if (node instanceof Literal) {
|
||||
Literal literal = (Literal) node;
|
||||
|
||||
if (exactNode != null) {
|
||||
return provideHover(exactNode.toString(), offset - exactNode.getStartPosition(),
|
||||
exactNode.getStartPosition(), doc, processLiveData);
|
||||
if (isProperLiteral(literal, annotation)) {
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(literal);
|
||||
return provideHover(literal.printTrimmed(), offset - r.getStart().getOffset(),
|
||||
r.getStart().getOffset(), doc, processLiveData);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error while generating live hovers for @Value", e);
|
||||
@@ -77,23 +78,26 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ASTNode getExactNode(ASTNode exactNode) {
|
||||
if (exactNode != null) {
|
||||
// case: @Value("prefix<*>")
|
||||
if (exactNode instanceof StringLiteral && exactNode.getParent() instanceof Annotation) {
|
||||
if (exactNode.toString().startsWith("\"") && exactNode.toString().endsWith("\"")) {
|
||||
return exactNode;
|
||||
}
|
||||
private boolean isProperLiteral(Literal l, Annotation a) {
|
||||
// case: @Value("prefix<*>")
|
||||
if (ORAstUtils.getParent(l) == a) {
|
||||
String str = ORAstUtils.getLiteralValue(l);
|
||||
if (str.startsWith("\"") && str.endsWith("\"")) {
|
||||
return true;
|
||||
}
|
||||
// case: @Value(value="prefix<*>")
|
||||
else if (exactNode instanceof StringLiteral && exactNode.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair) exactNode.getParent()).getName().toString())) {
|
||||
if (exactNode.toString().startsWith("\"") && exactNode.toString().endsWith("\"")) {
|
||||
return exactNode;
|
||||
}
|
||||
// case: @Value(value="prefix<*>")
|
||||
else if (ORAstUtils.getParent(l) instanceof Assignment && ORAstUtils.getGrandParent(l) == a) {
|
||||
Assignment assign = (Assignment) ORAstUtils.getParent(l);
|
||||
if ("value".equals(assign.getVariable().printTrimmed())) {
|
||||
String str = ORAstUtils.getLiteralValue(l);
|
||||
if (str.startsWith("\"") && str.endsWith("\"")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Hover provideHover(String value, int offset, int nodeStartOffset, TextDocument doc, SpringProcessLiveData[] processLiveData) {
|
||||
@@ -153,10 +157,7 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
* @param processLiveData
|
||||
* @return
|
||||
*/
|
||||
private List<CodeLens> provideHighlightHints(TextDocument doc, StringLiteral node, SpringProcessLiveData[] processLiveData) {
|
||||
ASTNode exactNode = getExactNode(node);
|
||||
|
||||
if (exactNode != null) {
|
||||
private List<CodeLens> provideHighlightHints(TextDocument doc, Literal l, SpringProcessLiveData[] processLiveData) {
|
||||
Map<String, List<LocalRange>> propertiesWithRanges = new HashMap<>();
|
||||
|
||||
// Get the escaped value that INCLUDES the quotes as we want to compute
|
||||
@@ -166,7 +167,7 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
// to highlight a.prop we need to take into account the starting '"' after the
|
||||
// '='
|
||||
// to get the correct range of a.prop
|
||||
String nodeValue = node.getEscapedValue();
|
||||
String nodeValue = ORAstUtils.getLiteralValue(l);
|
||||
if (nodeValue != null) {
|
||||
// Get property names with ranges highlight
|
||||
propertiesWithRanges = parseProperties(nodeValue);
|
||||
@@ -188,7 +189,8 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
|
||||
propRanges.stream().forEach(propRange -> {
|
||||
try {
|
||||
Range hoverRange = doc.toRange(exactNode.getStartPosition() + propRange.getStart(),
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(l);
|
||||
Range hoverRange = doc.toRange(r.getStart().getOffset() + propRange.getStart(),
|
||||
propRange.getEnd() - propRange.getStart());
|
||||
lenses.add(new CodeLens(hoverRange));
|
||||
} catch (BadLocationException e) {
|
||||
@@ -202,7 +204,6 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
}
|
||||
return lenses;
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@@ -360,7 +361,7 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset,
|
||||
public Hover provideHover(J node, ClassDeclaration typeDeclaration, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
return null;
|
||||
}
|
||||
@@ -370,15 +371,18 @@ public class ValueHoverProvider implements HoverProvider {
|
||||
// Show highlight hints for properties in @Value that have live information
|
||||
|
||||
List<CodeLens> lenses = new ArrayList<>();
|
||||
annotation.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(StringLiteral node) {
|
||||
List<CodeLens> provideHighlightHints = provideHighlightHints(doc, node, processLiveData);
|
||||
lenses.addAll(provideHighlightHints);
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
new JavaIsoVisitor<List<CodeLens>>() {
|
||||
|
||||
public Literal visitLiteral(Literal literal, List<CodeLens> cl) {
|
||||
if (isProperLiteral(literal, annotation)) {
|
||||
cl.addAll(provideHighlightHints(doc, literal, processLiveData));
|
||||
}
|
||||
return super.visitLiteral(literal, cl);
|
||||
};
|
||||
|
||||
}.visitNonNull(annotation, lenses);
|
||||
|
||||
return lenses;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user