Hover providers WIP
This commit is contained in:
@@ -22,7 +22,7 @@ import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveDataProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCache;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents;
|
||||
@@ -54,7 +54,7 @@ public class BootLanguageServerInitializer implements InitializingBean {
|
||||
@Autowired SimpleLanguageServer server;
|
||||
@Autowired BootLanguageServerParams params;
|
||||
@Autowired SourceLinks sourceLinks;
|
||||
@Autowired CompilationUnitCache cuCache;
|
||||
@Autowired ORCompilationUnitCache cuCache;
|
||||
@Autowired JavaElementLocationProvider javaElementLocationProvider;
|
||||
@Autowired YamlASTProvider parser;
|
||||
@Autowired YamlStructureProvider yamlStructureProvider;
|
||||
|
||||
@@ -18,7 +18,6 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
|
||||
@@ -27,9 +26,7 @@ import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.conditionals.ConditionalsLiveHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.data.DataRepositoryCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCodeLensEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaCompletionEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaDocumentHighlightEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaDocumentSymbolHandler;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaHoverProvider;
|
||||
@@ -37,7 +34,6 @@ import org.springframework.ide.vscode.boot.java.handlers.BootJavaReconcileEngine
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaReferencesHandler;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaWorkspaceSymbolHandler;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CodeLensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HighlightProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider;
|
||||
@@ -56,19 +52,13 @@ import org.springframework.ide.vscode.boot.java.requestmapping.LiveAppURLSymbolP
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.WebfluxHandlerCodeLensProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.WebfluxRouteHighlightProdivder;
|
||||
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;
|
||||
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringLiveChangeDetectionWatchdog;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCache;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValuePropertyReferencesProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.composable.LanguageServerComponents;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
@@ -76,14 +66,12 @@ import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcil
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.CodeLensHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentHighlightHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.LspClient;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ReferencesHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleWorkspaceService;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
@@ -113,7 +101,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
|
||||
private final SpringLiveChangeDetectionWatchdog liveChangeDetectionWatchdog;
|
||||
private final ProjectObserver projectObserver;
|
||||
private final CompilationUnitCache cuCache;
|
||||
private final ORCompilationUnitCache cuCache;
|
||||
|
||||
private JavaProjectFinder projectFinder;
|
||||
private BootJavaHoverProvider hoverProvider;
|
||||
@@ -127,7 +115,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
SimpleLanguageServer server,
|
||||
BootLanguageServerParams serverParams,
|
||||
SourceLinks sourceLinks,
|
||||
CompilationUnitCache cuCache,
|
||||
ORCompilationUnitCache cuCache,
|
||||
ProjectBasedPropertyIndexProvider adHocIndexProvider,
|
||||
SymbolCache symbolCache,
|
||||
SpringProcessLiveDataProvider liveDataProvider,
|
||||
@@ -343,7 +331,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
return propertyIndexProvider;
|
||||
}
|
||||
|
||||
public CompilationUnitCache getCompilationUnitCache() {
|
||||
public ORCompilationUnitCache getCompilationUnitCache() {
|
||||
return cuCache;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,15 +12,16 @@ package org.springframework.ide.vscode.boot.java.annotations;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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.internal.compiler.problem.AbortCompilation;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
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.commons.util.CollectorUtil;
|
||||
@@ -28,99 +29,82 @@ import org.springframework.ide.vscode.commons.util.CollectorUtil;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Utility class for working with annotation and discovering / understanding their
|
||||
* 'inheritance' structure.
|
||||
* Utility class for working with annotation and discovering / understanding
|
||||
* their 'inheritance' structure.
|
||||
* <p>
|
||||
* Provides methods to ask questions about inheritance between annotations.
|
||||
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public abstract class AnnotationHierarchies {
|
||||
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AnnotationHierarchies.class);
|
||||
|
||||
// this lock is used to protect multi-threaded access to this helper class
|
||||
// due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=571247
|
||||
private static final Object lock = new Object();
|
||||
|
||||
protected static boolean ignoreAnnotation(String fqname) {
|
||||
return fqname.startsWith("java."); //mostly intended to capture java.lang.annotation.* types. But really it should be
|
||||
//safe to ignore any type defined by the JRE since it can't possibly be inheriting from a spring annotation.
|
||||
return fqname.startsWith("java."); // mostly intended to capture java.lang.annotation.* types. But really it
|
||||
// should be
|
||||
// safe to ignore any type defined by the JRE since it can't possibly be
|
||||
// inheriting from a spring annotation.
|
||||
};
|
||||
|
||||
public static Collection<ITypeBinding> getDirectSuperAnnotations(ITypeBinding typeBinding) {
|
||||
synchronized(lock) {
|
||||
try {
|
||||
IAnnotationBinding[] annotations = typeBinding.getAnnotations();
|
||||
if (annotations != null && annotations.length != 0) {
|
||||
ImmutableList.Builder<ITypeBinding> superAnnotations = ImmutableList.builder();
|
||||
for (IAnnotationBinding ab : annotations) {
|
||||
ITypeBinding sa = ab.getAnnotationType();
|
||||
if (sa != null) {
|
||||
if (!ignoreAnnotation(sa.getQualifiedName())) {
|
||||
superAnnotations.add(sa);
|
||||
}
|
||||
}
|
||||
public static Collection<FullyQualified> getDirectSuperAnnotations(FullyQualified type) {
|
||||
try {
|
||||
List<FullyQualified> annotations = type.getAnnotations();
|
||||
if (annotations != null && !annotations.isEmpty()) {
|
||||
ImmutableList.Builder<FullyQualified> superAnnotations = ImmutableList.builder();
|
||||
for (FullyQualified ab : annotations) {
|
||||
if (!ignoreAnnotation(ab.getFullyQualifiedName())) {
|
||||
superAnnotations.add(ab);
|
||||
}
|
||||
return superAnnotations.build();
|
||||
}
|
||||
return superAnnotations.build();
|
||||
}
|
||||
catch (AbortCompilation e) {
|
||||
log.debug("compilation aborted ", e);
|
||||
// ignore this, it is most likely caused by broken source code, a broken classpath, or some optional dependencies not being on the classpath
|
||||
}
|
||||
|
||||
return ImmutableList.of();
|
||||
} catch (AbortCompilation e) {
|
||||
log.debug("compilation aborted ", e);
|
||||
// ignore this, it is most likely caused by broken source code, a broken
|
||||
// classpath, or some optional dependencies not being on the classpath
|
||||
}
|
||||
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
public static Set<String> getTransitiveSuperAnnotations(ITypeBinding typeBinding) {
|
||||
synchronized(lock) {
|
||||
Set<String> seen = new HashSet<>();
|
||||
findTransitiveSupers(typeBinding, seen).collect(Collectors.toList());
|
||||
return seen;
|
||||
}
|
||||
public static Set<String> getTransitiveSuperAnnotations(FullyQualified type) {
|
||||
Set<String> seen = new HashSet<>();
|
||||
findTransitiveSupers(type, seen).collect(Collectors.toList());
|
||||
return seen;
|
||||
}
|
||||
|
||||
public static Stream<ITypeBinding> findTransitiveSupers(ITypeBinding typeBinding, Set<String> seen) {
|
||||
synchronized(lock) {
|
||||
String qname = typeBinding.getQualifiedName();
|
||||
if (seen.add(qname)) {
|
||||
return Stream.concat(
|
||||
Stream.of(typeBinding),
|
||||
getDirectSuperAnnotations(typeBinding).stream().flatMap(superBinding ->
|
||||
findTransitiveSupers(superBinding, seen)
|
||||
)
|
||||
);
|
||||
}
|
||||
return Stream.empty();
|
||||
public static Stream<FullyQualified> findTransitiveSupers(FullyQualified type, Set<String> seen) {
|
||||
String qname = type.getFullyQualifiedName();
|
||||
if (seen.add(qname)) {
|
||||
return Stream.concat(Stream.of(type), getDirectSuperAnnotations(type).stream()
|
||||
.flatMap(superAnnotation -> findTransitiveSupers(superAnnotation, seen)));
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
public static boolean isSubtypeOf(Annotation annotation, String fqAnnotationTypeName) {
|
||||
synchronized(lock) {
|
||||
ITypeBinding annotationType = annotation.resolveTypeBinding();
|
||||
if (annotationType!=null) {
|
||||
return findTransitiveSupers(annotationType, new HashSet<>())
|
||||
.anyMatch(superType -> superType.getQualifiedName().equals(fqAnnotationTypeName));
|
||||
}
|
||||
return false;
|
||||
FullyQualified annotationType = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (annotationType != null) {
|
||||
return findTransitiveSupers(annotationType, new HashSet<>())
|
||||
.anyMatch(superType -> fqAnnotationTypeName.equals(superType.getFullyQualifiedName()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Collection<ITypeBinding> getMetaAnnotations(ITypeBinding actualAnnotation, Predicate<String> isKeyAnnotationName) {
|
||||
synchronized(lock) {
|
||||
Stream<ITypeBinding> allSupers = findTransitiveSupers(actualAnnotation, new HashSet<>())
|
||||
.skip(1); //Don't include 'actualAnnotation' itself.
|
||||
return allSupers
|
||||
.filter(candidate -> isMetaAnnotation(candidate, isKeyAnnotationName))
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
}
|
||||
public static Collection<FullyQualified> getMetaAnnotations(FullyQualified actualAnnotation,
|
||||
Predicate<String> isKeyAnnotationName) {
|
||||
Stream<FullyQualified> allSupers = findTransitiveSupers(actualAnnotation, new HashSet<>()).skip(1); // Don't
|
||||
// include
|
||||
// 'actualAnnotation'
|
||||
// itself.
|
||||
return allSupers.filter(candidate -> isMetaAnnotation(candidate, isKeyAnnotationName))
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
}
|
||||
|
||||
private static boolean isMetaAnnotation(ITypeBinding candidate, Predicate<String> isKeyAnnotationName) {
|
||||
private static boolean isMetaAnnotation(FullyQualified candidate, Predicate<String> isKeyAnnotationName) {
|
||||
return findTransitiveSupers(candidate, new HashSet<>())
|
||||
.anyMatch(sa -> isKeyAnnotationName.test(sa.getQualifiedName()));
|
||||
.anyMatch(sa -> isKeyAnnotationName.test(sa.getFullyQualifiedName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -85,7 +85,7 @@ public class AnnotationHierarchyAwareLookup<T> {
|
||||
* a symbol provider for Components should be asked to produce symbols for Component, Controller and RestController,
|
||||
* so should result in 3 separate calls to the symbols provider.
|
||||
*/
|
||||
public Collection<T> get(ITypeBinding annotationType) {
|
||||
public Collection<T> get(FullyQualified annotationType) {
|
||||
ImmutableList.Builder<T> found = ImmutableList.builder();
|
||||
findElements(annotationType, new LinkedHashSet<>(), found::add);
|
||||
return found.build();
|
||||
@@ -98,8 +98,8 @@ public class AnnotationHierarchyAwareLookup<T> {
|
||||
return found.build();
|
||||
}
|
||||
|
||||
private void findElements(ITypeBinding typeBinding, HashSet<String> seen, Consumer<T> requestor) {
|
||||
String qname = typeBinding.getQualifiedName();
|
||||
private void findElements(FullyQualified type, HashSet<String> seen, Consumer<T> requestor) {
|
||||
String qname = type.getFullyQualifiedName();
|
||||
if (seen.add(qname)) {
|
||||
Binding<T> binding = bindings.get(qname);
|
||||
|
||||
@@ -110,8 +110,8 @@ public class AnnotationHierarchyAwareLookup<T> {
|
||||
}
|
||||
|
||||
if (!isOverriding) {
|
||||
Collection<ITypeBinding> directSuperAnnotations = AnnotationHierarchies.getDirectSuperAnnotations(typeBinding);
|
||||
for (ITypeBinding superAnnotation : directSuperAnnotations) {
|
||||
Collection<FullyQualified> directSuperAnnotations = AnnotationHierarchies.getDirectSuperAnnotations(type);
|
||||
for (FullyQualified superAnnotation : directSuperAnnotations) {
|
||||
findElements(superAnnotation, seen, requestor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,21 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
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.FieldDeclaration;
|
||||
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.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
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.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.Identifier;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
import org.openrewrite.java.tree.JavaType;
|
||||
import org.openrewrite.java.tree.JavaType.Array;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.JavaType.Parameterized;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
@@ -40,7 +42,7 @@ import org.springframework.ide.vscode.boot.java.livehover.ComponentInjectionsHov
|
||||
import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
@@ -76,12 +78,13 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
SpringProcessLiveData[] processLiveData) {
|
||||
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
|
||||
if (processLiveData.length > 0) {
|
||||
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ASTUtils.findDeclaringType(annotation));
|
||||
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ORAstUtils.findDeclaringType(annotation));
|
||||
// Annotation is MarkerNode, parent is some field, method, variable declaration
|
||||
// node.
|
||||
ASTNode declarationNode = annotation.getParent();
|
||||
J declarationNode = ORAstUtils.getParent(annotation);
|
||||
try {
|
||||
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());
|
||||
for (SpringProcessLiveData liveData : processLiveData) {
|
||||
List<LiveBean> relevantBeans = getRelevantAutowiredBeans(project, declarationNode, liveData,
|
||||
definedBean);
|
||||
@@ -99,16 +102,17 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset,
|
||||
public Hover provideHover(J node, Annotation annotation, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
if (processLiveData.length > 0) {
|
||||
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ASTUtils.findDeclaringType(annotation));
|
||||
LiveBean definedBean = getDefinedBeanForTypeDeclaration(ORAstUtils.findDeclaringType(annotation));
|
||||
// Annotation is MarkerNode, parent is some field, method, variable declaration node.
|
||||
ASTNode declarationNode = annotation.getParent();
|
||||
J declarationNode = ORAstUtils.getParent(annotation);
|
||||
Hover hover = provideHover(definedBean, declarationNode, offset, doc, project, processLiveData);
|
||||
if (hover != null) {
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(annotation);
|
||||
try {
|
||||
hover.setRange(doc.toRange(annotation.getStartPosition(), annotation.getLength()));
|
||||
hover.setRange(doc.toRange(r.getStart().getOffset(), r.length()));
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
@@ -118,7 +122,7 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHover(LiveBean definedBean, ASTNode declarationNode, int offset, TextDocument doc,
|
||||
private Hover provideHover(LiveBean definedBean, J declarationNode, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
if (definedBean != null) {
|
||||
|
||||
@@ -158,12 +162,12 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
hover.append("\n \n");
|
||||
}
|
||||
|
||||
public static List<LiveBean> getRelevantAutowiredBeans(IJavaProject project, ASTNode declarationNode, SpringProcessLiveData liveData, LiveBean definedBean) {
|
||||
public static List<LiveBean> getRelevantAutowiredBeans(IJavaProject project, J declarationNode, SpringProcessLiveData liveData, LiveBean definedBean) {
|
||||
List<LiveBean> relevantBeans = LiveHoverUtils.findRelevantBeans(liveData, definedBean);
|
||||
return getRelevantAutowiredBeans(project, declarationNode, liveData, relevantBeans);
|
||||
}
|
||||
|
||||
public static List<LiveBean> getRelevantAutowiredBeans(IJavaProject project, ASTNode declarationNode, SpringProcessLiveData liveData, List<LiveBean> relevantBeans) {
|
||||
public static List<LiveBean> getRelevantAutowiredBeans(IJavaProject project, J declarationNode, SpringProcessLiveData liveData, List<LiveBean> relevantBeans) {
|
||||
if (!relevantBeans.isEmpty()) {
|
||||
List<LiveBean> allDependencyBeans = LiveHoverUtils.findAllDependencyBeans(liveData, relevantBeans);
|
||||
|
||||
@@ -184,32 +188,26 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<LiveBean> findAutowiredBeans(IJavaProject project, ASTNode declarationNode, Collection<LiveBean> beans) {
|
||||
public static List<LiveBean> findAutowiredBeans(IJavaProject project, J declarationNode, Collection<LiveBean> beans) {
|
||||
if (declarationNode instanceof MethodDeclaration) {
|
||||
MethodDeclaration methodDeclaration = (MethodDeclaration)declarationNode;
|
||||
return ((List<Object>)methodDeclaration.parameters()).stream()
|
||||
.filter(p -> p instanceof SingleVariableDeclaration)
|
||||
.map(p -> (SingleVariableDeclaration)p)
|
||||
.flatMap(singleVariableDeclaration -> findAutowiredBeans(project, singleVariableDeclaration, beans).stream())
|
||||
.collect(Collectors.toList());
|
||||
} else if (declarationNode instanceof FieldDeclaration) {
|
||||
FieldDeclaration fieldDeclaration = (FieldDeclaration)declarationNode;
|
||||
ITypeBinding fieldType = fieldDeclaration.getType().resolveBinding();
|
||||
if (fieldType != null) {
|
||||
return matchBeans(project, beans, fieldType, fieldDeclaration.modifiers());
|
||||
}
|
||||
} else if (declarationNode instanceof SingleVariableDeclaration) {
|
||||
SingleVariableDeclaration singleVariableDeclaration = (SingleVariableDeclaration)declarationNode;
|
||||
ITypeBinding varType = singleVariableDeclaration.getType().resolveBinding();
|
||||
return methodDeclaration.getParameters().stream()
|
||||
.filter(VariableDeclarations.class::isInstance)
|
||||
.map(VariableDeclarations.class::cast)
|
||||
.flatMap(v -> findAutowiredBeans(project, v, beans).stream())
|
||||
.collect(Collectors.toList());
|
||||
} else if (declarationNode instanceof VariableDeclarations) {
|
||||
VariableDeclarations varDeclaration = (VariableDeclarations) declarationNode;
|
||||
JavaType varType = varDeclaration.getType();
|
||||
if (varType != null) {
|
||||
return matchBeans(project, beans, varType, singleVariableDeclaration.modifiers());
|
||||
return matchBeans(project, beans, varType, varDeclaration.getLeadingAnnotations());
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<LiveBean> matchBeans(IJavaProject project, Collection<LiveBean> beans, ITypeBinding typeBinding, List<Object> modifiers) {
|
||||
Optional<String> beanId = ASTUtils.beanId(modifiers);
|
||||
private static List<LiveBean> matchBeans(IJavaProject project, Collection<LiveBean> beans, JavaType type, List<Annotation> annotations) {
|
||||
Optional<String> beanId = ORAstUtils.beanId(annotations);
|
||||
Collection<LiveBean> searchScope = beanId.isPresent() ?
|
||||
beans.stream()
|
||||
.filter(b -> beanId.get().equals(b.getId()))
|
||||
@@ -217,34 +215,33 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
.map(bean -> (Collection<LiveBean>) ImmutableList.of(bean))
|
||||
.orElse(ImmutableList.of())
|
||||
: beans;
|
||||
return matchBeansByTypeOrCollection(project, searchScope, typeBinding);
|
||||
return matchBeansByTypeOrCollection(project, searchScope, type);
|
||||
}
|
||||
|
||||
private static boolean isInstanceOfCollection(ITypeBinding typeBinding) {
|
||||
if (typeBinding == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (JAVA_COLLECTION.equals(typeBinding.getTypeDeclaration().getQualifiedName())) {
|
||||
return true;
|
||||
} else {
|
||||
for (ITypeBinding superInterface : typeBinding.getInterfaces()) {
|
||||
if (isInstanceOfCollection(superInterface)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return isInstanceOfCollection(typeBinding.getSuperclass());
|
||||
}
|
||||
}
|
||||
private static boolean isInstanceOfCollection(JavaType type) {
|
||||
return type == null ? false : TypeUtils.isAssignableTo(JAVA_COLLECTION, type);
|
||||
}
|
||||
|
||||
private static List<LiveBean> matchBeansByTypeOrCollection(IJavaProject project, Collection<LiveBean> beans, ITypeBinding type) {
|
||||
private static List<LiveBean> matchBeansByTypeOrCollection(IJavaProject project, Collection<LiveBean> beans, JavaType type) {
|
||||
if (isInstanceOfCollection(type)) {
|
||||
// Raw collections shouldn't match any beans
|
||||
return type.getTypeArguments().length == 1 ? matchBeansByType(project, beans, type.getTypeArguments()[0].getQualifiedName(), false) : ImmutableList.of();
|
||||
} else if (type.isArray() && type.getDimensions() == 1) {
|
||||
return matchBeansByType(project, beans, type.getElementType().getErasure().getBinaryName(), false);
|
||||
if (type instanceof Parameterized) {
|
||||
Parameterized parameterized = (Parameterized) type;
|
||||
if (parameterized.getTypeParameters().size() == 1) {
|
||||
FullyQualified parameterType = TypeUtils.asFullyQualified(parameterized.getTypeParameters().get(0));
|
||||
if (parameterType != null) {
|
||||
return matchBeansByType(project, beans, parameterType.getFullyQualifiedName(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ImmutableList.of();
|
||||
} else if (type instanceof Array && ((Array) type).getManagedReference() == 1) {
|
||||
Array array = (Array) type;
|
||||
FullyQualified arrayType = TypeUtils.asFullyQualified(array.getElemType());
|
||||
return matchBeansByType(project, beans, arrayType == null ? null : arrayType.getFullyQualifiedName(), false);
|
||||
} else {
|
||||
return matchBeansByType(project, beans, type.getErasure().getBinaryName(), true);
|
||||
FullyQualified fq = TypeUtils.asFullyQualified(type);
|
||||
return matchBeansByType(project, beans, fq == null ? null : fq.getFullyQualifiedName(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,9 +278,9 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
private LiveBean getDefinedBeanForTypeDeclaration(TypeDeclaration declaringType) {
|
||||
private LiveBean getDefinedBeanForTypeDeclaration(ClassDeclaration declaringType) {
|
||||
if (declaringType != null) {
|
||||
for (Annotation annotation : ASTUtils.getAnnotations(declaringType)) {
|
||||
for (Annotation annotation : ORAstUtils.getAnnotations(declaringType)) {
|
||||
if (AnnotationHierarchies.isSubtypeOf(annotation, Annotations.COMPONENT)) {
|
||||
return ComponentInjectionsHoverProvider.getDefinedBeanForComponent(annotation);
|
||||
}
|
||||
@@ -292,9 +289,9 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
// cases, but is probably
|
||||
// missing logics for special cases where annotation attributes on the declaring
|
||||
// type matter.
|
||||
ITypeBinding beanType = declaringType.resolveBinding();
|
||||
FullyQualified beanType = declaringType.getType();
|
||||
if (beanType != null) {
|
||||
String beanTypeName = beanType.getName();
|
||||
String beanTypeName = beanType.getClassName();
|
||||
if (StringUtil.hasText(beanTypeName)) {
|
||||
return LiveBean.builder()
|
||||
.id(getId(beanTypeName))
|
||||
@@ -314,9 +311,10 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(methodDeclaration);
|
||||
Hover hover = provideHover(definedBean, methodDeclaration, offset, doc, project, processLiveData);
|
||||
if (hover != null) {
|
||||
SimpleName name = methodDeclaration.getName();
|
||||
Identifier name = methodDeclaration.getName();
|
||||
try {
|
||||
hover.setRange(doc.toRange(name.getStartPosition(), name.getLength()));
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(name);
|
||||
hover.setRange(doc.toRange(r.getStart().getOffset(), r.length()));
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
@@ -325,15 +323,16 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideMethodParameterHover(SingleVariableDeclaration parameter, int offset, TextDocument doc,
|
||||
public Hover provideMethodParameterHover(VariableDeclarations parameter, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
MethodDeclaration method = (MethodDeclaration) parameter.getParent();
|
||||
MethodDeclaration method = (MethodDeclaration) ORAstUtils.getParent(parameter);
|
||||
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(method);
|
||||
Hover hover = provideHover(definedBean, parameter, offset, doc, project, processLiveData);
|
||||
if (hover != null) {
|
||||
SimpleName name = parameter.getName();
|
||||
Identifier name = parameter.getVariables().get(0).getName();
|
||||
try {
|
||||
hover.setRange(doc.toRange(name.getStartPosition(), name.getLength()));
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(name);
|
||||
hover.setRange(doc.toRange(r.getStart().getOffset(), r.length()));
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
@@ -348,8 +347,8 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
LiveBean definedBean = getDefinedBeanForImplicitAutowiredConstructor(methodDeclaration);
|
||||
if (definedBean != null) {
|
||||
try {
|
||||
Range hoverRange = doc.toRange(methodDeclaration.getName().getStartPosition(),
|
||||
methodDeclaration.getName().getLength());
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(methodDeclaration.getName());
|
||||
Range hoverRange = doc.toRange(r.getStart().getOffset(), r.length());
|
||||
|
||||
for (SpringProcessLiveData liveData : processLiveData) {
|
||||
List<LiveBean> relevantBeans = getRelevantAutowiredBeans(project, methodDeclaration, liveData,
|
||||
@@ -376,9 +375,9 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
private LiveBean getDefinedBeanForImplicitAutowiredConstructor(MethodDeclaration methodDeclaration) {
|
||||
if (methodDeclaration.isConstructor() && !methodDeclaration.parameters().isEmpty()) {
|
||||
TypeDeclaration typeDeclaration = ASTUtils.findDeclaringType(methodDeclaration);
|
||||
if (typeDeclaration != null && ASTUtils.hasExactlyOneConstructor(typeDeclaration) && !hasAutowiredAnnotation(methodDeclaration)) {
|
||||
if (methodDeclaration.isConstructor() && !methodDeclaration.getParameters().isEmpty()) {
|
||||
ClassDeclaration typeDeclaration = ORAstUtils.findDeclaringType(methodDeclaration);
|
||||
if (typeDeclaration != null && ORAstUtils.hasExactlyOneConstructor(typeDeclaration) && !hasAutowiredAnnotation(methodDeclaration)) {
|
||||
return getDefinedBeanForTypeDeclaration(typeDeclaration);
|
||||
}
|
||||
}
|
||||
@@ -386,13 +385,12 @@ public class AutowiredHoverProvider implements HoverProvider {
|
||||
}
|
||||
|
||||
private boolean hasAutowiredAnnotation(MethodDeclaration constructor) {
|
||||
List<?> modifiers = constructor.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof MarkerAnnotation) {
|
||||
ITypeBinding typeBinding = ((MarkerAnnotation) modifier).resolveTypeBinding();
|
||||
if (typeBinding != null) {
|
||||
String fqName = typeBinding.getQualifiedName();
|
||||
return Annotations.AUTOWIRED.equals(fqName) || Annotations.INJECT.equals(fqName);
|
||||
for (Annotation a : constructor.getLeadingAnnotations()) {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(a.getType());
|
||||
if (type != null) {
|
||||
String fqName = type.getFullyQualifiedName();
|
||||
if (Annotations.AUTOWIRED.equals(fqName) || Annotations.INJECT.equals(fqName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,23 +16,24 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
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.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
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.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveConditional;
|
||||
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.text.TextDocument;
|
||||
|
||||
@@ -48,7 +49,7 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(ConditionalsLiveHoverProvider.class);
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset,
|
||||
public Hover provideHover(J node, Annotation annotation, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
return provideHover(annotation, doc, processLiveData);
|
||||
}
|
||||
@@ -58,7 +59,8 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
try {
|
||||
Optional<List<LiveConditional>> val = getMatchedLiveConditionals(annotation, processLiveData);
|
||||
if (val.isPresent()) {
|
||||
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 ImmutableList.of(new CodeLens(hoverRange));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -101,7 +103,8 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
addHoverContent(val.get(), hoverContent);
|
||||
}
|
||||
|
||||
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 hover = new Hover();
|
||||
|
||||
hover.setContents(hoverContent);
|
||||
@@ -134,24 +137,31 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
protected boolean matchesAnnotation(Annotation annotation, LiveConditional liveConditional) {
|
||||
|
||||
// First check that the annotation matches the live conditional annotation
|
||||
String annotationName = annotation.resolveTypeBinding().getName();
|
||||
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String annotationName = type.getClassName();
|
||||
if (!liveConditional.getMessage().contains(annotationName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that Java type in annotation in editor matches Java information in the live Conditional
|
||||
ASTNode parent = annotation.getParent();
|
||||
J parent = ORAstUtils.getParent(annotation);
|
||||
String typeInfo = liveConditional.getTypeInfo();
|
||||
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration methodDec = (MethodDeclaration) parent;
|
||||
IMethodBinding binding = methodDec.resolveBinding();
|
||||
String annotationDeclaringClassName = binding.getDeclaringClass().getName();
|
||||
String annotationMethodName = binding.getName();
|
||||
return typeInfo.contains(annotationDeclaringClassName) && typeInfo.contains(annotationMethodName);
|
||||
} else if (parent instanceof TypeDeclaration) {
|
||||
TypeDeclaration typeDec = (TypeDeclaration) parent;
|
||||
String annotationDeclaringClassName = typeDec.resolveBinding().getName();
|
||||
ClassDeclaration declaringType = ORAstUtils.findNode(methodDec, ClassDeclaration.class);
|
||||
if (declaringType == null) {
|
||||
return false;
|
||||
}
|
||||
String annotationMethodName = methodDec.getSimpleName();
|
||||
return typeInfo.contains(declaringType.getType().getClassName()) && typeInfo.contains(annotationMethodName);
|
||||
} else if (parent instanceof ClassDeclaration) {
|
||||
ClassDeclaration typeDec = (ClassDeclaration) parent;
|
||||
String annotationDeclaringClassName = typeDec.getType().getClassName();
|
||||
return typeInfo.contains(annotationDeclaringClassName);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -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,15 +10,14 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
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.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.openrewrite.java.tree.Expression;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.Assignment;
|
||||
import org.openrewrite.java.tree.J.Literal;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
|
||||
@@ -42,56 +41,58 @@ public class AnnotationParamReconciler {
|
||||
this.reconciler = reconciler;
|
||||
}
|
||||
|
||||
public void visit(SingleMemberAnnotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) {
|
||||
if (this.paramName != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding);
|
||||
if (!allAnnotations.contains(this.annotationType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Expression valueExp = node.getValue();
|
||||
|
||||
if (valueExp instanceof StringLiteral) {
|
||||
reconcileStringLiteral((StringLiteral) valueExp, problemCollector);
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(NormalAnnotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) {
|
||||
// public void visit(SingleMemberAnnotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) {
|
||||
// if (this.paramName != null) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Set<String> allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding);
|
||||
// if (!allAnnotations.contains(this.annotationType)) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Expression valueExp = node.getValue();
|
||||
//
|
||||
// if (valueExp instanceof StringLiteral) {
|
||||
// reconcileStringLiteral((StringLiteral) valueExp, problemCollector);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
public void visit(Annotation annotation, IProblemCollector problemCollector) {
|
||||
if (paramName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding);
|
||||
Set<String> allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(TypeUtils.asFullyQualified(annotation.getType()));
|
||||
if (!allAnnotations.contains(this.annotationType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<?> values = node.values();
|
||||
|
||||
for (Object value : values) {
|
||||
if (value instanceof MemberValuePair) {
|
||||
MemberValuePair pair = (MemberValuePair) value;
|
||||
String name = pair.getName().getFullyQualifiedName();
|
||||
for (Expression value : annotation.getArguments()) {
|
||||
if (value instanceof Literal) {
|
||||
reconcileStringLiteral((Literal) value, problemCollector);
|
||||
}
|
||||
else if (value instanceof Assignment) {
|
||||
Assignment assignment = (Assignment) value;
|
||||
String name = assignment.getVariable().printTrimmed();
|
||||
if (name != null && name.equals(paramName)) {
|
||||
Expression expression = pair.getValue();
|
||||
if (expression instanceof StringLiteral) {
|
||||
reconcileStringLiteral((StringLiteral) expression, problemCollector);
|
||||
Expression expression = assignment.getAssignment();
|
||||
if (expression instanceof Literal) {
|
||||
reconcileStringLiteral((Literal) expression, problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reconcileStringLiteral(StringLiteral valueExp, IProblemCollector problemCollector) {
|
||||
String value = valueExp.getLiteralValue();
|
||||
private void reconcileStringLiteral(Literal valueExp, IProblemCollector problemCollector) {
|
||||
String value = valueExp.printTrimmed();
|
||||
|
||||
if (value != null && value.startsWith(paramValuePrefix) && value.endsWith(paramValuePostfix)) {
|
||||
String valueToReconcile = value.substring(paramValuePrefix.length(), value.length() - paramValuePostfix.length());
|
||||
|
||||
reconciler.reconcile(valueToReconcile, valueExp.getStartPosition() + paramValuePrefix.length() + 1, problemCollector);
|
||||
Range r = valueExp.getMarkers().findFirst(Range.class).orElseThrow();
|
||||
reconciler.reconcile(valueToReconcile, r.getStart().getOffset() + paramValuePrefix.length() + 1, problemCollector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,36 +10,33 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.beans.Statement;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Optional;
|
||||
|
||||
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.MarkerAnnotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.HoverParams;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
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.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
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.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveDataProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
@@ -104,65 +101,37 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
Collection<CodeLens> result = new LinkedHashSet<>();
|
||||
try {
|
||||
if (cu != null) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
new JavaIsoVisitor<Collection<CodeLens>>() {
|
||||
|
||||
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, Collection<CodeLens> p) {
|
||||
try {
|
||||
extractLiveHintsForType(node, document, project, processLiveData, result);
|
||||
extractLiveHintsForType(classDecl, document, project, processLiveData, result);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + node.toString(), e);
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + classDecl.printTrimmed(), e);
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
return super.visitClassDeclaration(classDecl, p);
|
||||
};
|
||||
|
||||
public Annotation visitAnnotation(Annotation annotation, Collection<CodeLens> p) {
|
||||
try {
|
||||
extractLiveHintsForAnnotation(node, document, project, processLiveData, result);
|
||||
extractLiveHintsForAnnotation(annotation, document, project, processLiveData, result);
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + node.toString(), e);
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + annotation.printTrimmed(), e);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
return super.visitAnnotation(annotation, p);
|
||||
};
|
||||
|
||||
public MethodDeclaration visitMethodDeclaration(MethodDeclaration method, Collection<CodeLens> p) {
|
||||
try {
|
||||
extractLiveHintsForAnnotation(node, document, project, processLiveData, result);
|
||||
extractLiveHintsForMethod(method, document, project, processLiveData, result);
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + node.toString(), e);
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + method.printTrimmed(), e);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MarkerAnnotation node) {
|
||||
try {
|
||||
extractLiveHintsForAnnotation(node, document, project, processLiveData, result);
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + node.toString(), e);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
try {
|
||||
extractLiveHintsForMethod(node, document, project, processLiveData, result);
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri() + "' - on node: " + node.toString(), e);
|
||||
}
|
||||
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
return super.visitMethodDeclaration(method, p);
|
||||
};
|
||||
|
||||
}.visitNonNull(cu, result);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("error extracting live hint information for docURI '" + document.getUri(), e);
|
||||
@@ -182,7 +151,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractLiveHintsForType(TypeDeclaration typeDeclaration, TextDocument doc, IJavaProject project,
|
||||
protected void extractLiveHintsForType(ClassDeclaration typeDeclaration, TextDocument doc, IJavaProject project,
|
||||
SpringProcessLiveData[] processLiveData, Collection<CodeLens> result) {
|
||||
Collection<HoverProvider> providers = this.hoverProviders.getAll();
|
||||
for (HoverProvider provider : providers) {
|
||||
@@ -195,7 +164,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
|
||||
protected void extractLiveHintsForAnnotation(Annotation annotation, TextDocument doc, IJavaProject project,
|
||||
SpringProcessLiveData[] processLiveData, Collection<CodeLens> result) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (type != null) {
|
||||
for (HoverProvider provider : this.hoverProviders.get(type)) {
|
||||
Collection<CodeLens> hints = provider.getLiveHintCodeLenses(project, annotation, doc, processLiveData);
|
||||
@@ -217,7 +186,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0);
|
||||
J node = ORAstUtils.findAstNodeAt(cu, offset);
|
||||
if (node != null) {
|
||||
return provideHover(cancelToken, node, offset, document, project, processLiveData);
|
||||
}
|
||||
@@ -227,32 +196,29 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHover(CancelChecker cancelToken, ASTNode node, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
private Hover provideHover(CancelChecker cancelToken, J node, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
|
||||
// look for spring annotations first
|
||||
ASTNode annotationNode = node;
|
||||
while (annotationNode != null && !(annotationNode instanceof Annotation)) {
|
||||
annotationNode = annotationNode.getParent();
|
||||
}
|
||||
Annotation annotationNode = ORAstUtils.findNode(node, Annotation.class);
|
||||
if (annotationNode != null) {
|
||||
return provideHoverForAnnotation(cancelToken, node, (Annotation) annotationNode, offset, doc, project, processLiveData);
|
||||
return provideHoverForAnnotation(cancelToken, node, annotationNode, offset, doc, project, processLiveData);
|
||||
}
|
||||
|
||||
// then do additional AST node coverage
|
||||
if (node instanceof SimpleName) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof TypeDeclaration) {
|
||||
return provideHoverForTypeDeclaration(cancelToken, node, (TypeDeclaration) parent, offset, doc, project, processLiveData);
|
||||
if (node instanceof Statement) {
|
||||
J parent = ORAstUtils.getParent(node);
|
||||
if (parent instanceof ClassDeclaration) {
|
||||
return provideHoverForTypeDeclaration(cancelToken, node, (ClassDeclaration) parent, offset, doc, project, processLiveData);
|
||||
} else if (parent instanceof MethodDeclaration) {
|
||||
return provideHoverForMethodDeclaration(cancelToken, (MethodDeclaration) parent, offset, doc, project, processLiveData);
|
||||
} else if (parent instanceof SingleVariableDeclaration && parent.getParent() instanceof MethodDeclaration) {
|
||||
return provideHoverForMethodParameter(cancelToken, (SingleVariableDeclaration) parent, offset, doc, project, processLiveData);
|
||||
} else if (parent instanceof VariableDeclarations && ORAstUtils.getParent(parent) instanceof MethodDeclaration) {
|
||||
return provideHoverForMethodParameter(cancelToken, (VariableDeclarations) parent, offset, doc, project, processLiveData);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHoverForMethodParameter(CancelChecker cancelToken, SingleVariableDeclaration parameter, int offset, TextDocument doc,
|
||||
private Hover provideHoverForMethodParameter(CancelChecker cancelToken, VariableDeclarations parameter, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
if (processLiveData.length > 0) {
|
||||
for (HoverProvider provider : this.hoverProviders.getAll()) {
|
||||
@@ -285,11 +251,11 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHoverForAnnotation(CancelChecker cancelToken, ASTNode exactNode, Annotation annotation, int offset, TextDocument doc, IJavaProject project,
|
||||
private Hover provideHoverForAnnotation(CancelChecker cancelToken, J exactNode, Annotation annotation, int offset, TextDocument doc, IJavaProject project,
|
||||
SpringProcessLiveData[] processLiveData) {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (type != null) {
|
||||
logger.debug("Hover requested for "+type.getName());
|
||||
logger.debug("Hover requested for "+type.getClassName());
|
||||
|
||||
if (processLiveData.length > 0) {
|
||||
|
||||
@@ -297,7 +263,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
Hover hover = provider.provideHover(exactNode, annotation, type, offset, doc, project, processLiveData);
|
||||
Hover hover = provider.provideHover(exactNode, annotation, offset, doc, project, processLiveData);
|
||||
if (hover != null) {
|
||||
logger.debug("Hover found: "+hover);
|
||||
//TODO: compose multiple hovers somehow instead of just returning the first one?
|
||||
@@ -308,7 +274,7 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
|
||||
//Only reaching here if we didn't get a hover.
|
||||
if (!SpringProjectUtil.hasBootActuators(project)) {
|
||||
DocumentRegion region = ASTUtils.nameRegion(doc, annotation);
|
||||
DocumentRegion region = ORAstUtils.nameRegion(doc, annotation);
|
||||
if (region.containsOffset(offset)) {
|
||||
return liveHoverWarning(project);
|
||||
}
|
||||
@@ -318,16 +284,15 @@ public class BootJavaHoverProvider implements HoverHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Hover provideHoverForTypeDeclaration(CancelChecker cancelToken, ASTNode exactNode, TypeDeclaration typeDeclaration, int offset, TextDocument doc,
|
||||
private Hover provideHoverForTypeDeclaration(CancelChecker cancelToken, J exactNode, ClassDeclaration typeDeclaration, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
if (processLiveData.length > 0) {
|
||||
ITypeBinding type = typeDeclaration.resolveBinding();
|
||||
|
||||
for (HoverProvider provider : this.hoverProviders.getAll()) {
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
Hover hover = provider.provideHover(exactNode, typeDeclaration, type, offset, doc, project, processLiveData);
|
||||
Hover hover = provider.provideHover(exactNode, typeDeclaration, offset, doc, project, processLiveData);
|
||||
if (hover!=null) {
|
||||
//TODO: compose multiple hovers somehow instead of just returning the first one?
|
||||
return hover;
|
||||
|
||||
@@ -12,15 +12,14 @@ package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.java.tree.JavaType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.value.Constants;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
@@ -49,11 +48,11 @@ public class BootJavaReconcileEngine implements IReconcileEngine {
|
||||
private static final Logger log = LoggerFactory.getLogger(BootJavaReconcileEngine.class);
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final CompilationUnitCache compilationUnitCache;
|
||||
private final ORCompilationUnitCache compilationUnitCache;
|
||||
private final AnnotationParamReconciler[] reconcilers;
|
||||
private final SpelExpressionReconciler spelExpressionReconciler;
|
||||
|
||||
public BootJavaReconcileEngine(CompilationUnitCache compilationUnitCache, JavaProjectFinder projectFinder) {
|
||||
public BootJavaReconcileEngine(ORCompilationUnitCache compilationUnitCache, JavaProjectFinder projectFinder) {
|
||||
this.compilationUnitCache = compilationUnitCache;
|
||||
this.projectFinder = projectFinder;
|
||||
|
||||
@@ -116,49 +115,21 @@ public class BootJavaReconcileEngine implements IReconcileEngine {
|
||||
}
|
||||
|
||||
private void reconcileAST(CompilationUnit cu, IProblemCollector problemCollector) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
try {
|
||||
visitAnnotationWithDefaultParam(node, problemCollector);
|
||||
|
||||
new JavaIsoVisitor<IProblemCollector>() {
|
||||
public Annotation visitAnnotation(Annotation annotation, IProblemCollector p) {
|
||||
if (!annotation.getArguments().isEmpty()) {
|
||||
JavaType type = annotation.getType();
|
||||
|
||||
if (type != null) {
|
||||
for (int i = 0; i < reconcilers.length; i++) {
|
||||
reconcilers[i].visit(annotation, problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
try {
|
||||
visitAnnotationWithParams(node, problemCollector);
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
});
|
||||
return super.visitAnnotation(annotation, p);
|
||||
};
|
||||
}.visitNonNull(cu, problemCollector);
|
||||
}
|
||||
|
||||
protected void visitAnnotationWithDefaultParam(SingleMemberAnnotation node, IProblemCollector problemCollector) {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
|
||||
if (typeBinding != null) {
|
||||
for (int i = 0; i < reconcilers.length; i++) {
|
||||
reconcilers[i].visit(node, typeBinding, problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void visitAnnotationWithParams(NormalAnnotation node, IProblemCollector problemCollector) {
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
|
||||
if (typeBinding != null) {
|
||||
for (int i = 0; i < reconcilers.length; i++) {
|
||||
reconcilers[i].visit(node, typeBinding, problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -12,14 +12,13 @@ package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
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.SingleVariableDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
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.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -29,11 +28,11 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
*/
|
||||
public interface HoverProvider {
|
||||
|
||||
default Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
default Hover provideHover(J node, Annotation annotation, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Hover provideHover(ASTNode node, TypeDeclaration typeDeclaration, ITypeBinding type, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
default Hover provideHover(J node, ClassDeclaration typeDeclaration, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -41,7 +40,7 @@ public interface HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Hover provideMethodParameterHover(SingleVariableDeclaration parameter, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
default Hover provideMethodParameterHover(VariableDeclarations parameter, int offset, TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -49,7 +48,7 @@ public interface HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project,TypeDeclaration typeDeclaration, TextDocument doc, SpringProcessLiveData[] processLiveData) {
|
||||
default Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, ClassDeclaration typeDeclaration, TextDocument doc, SpringProcessLiveData[] processLiveData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,12 @@ import java.util.Optional;
|
||||
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.ITypeBinding;
|
||||
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.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
@@ -33,7 +32,7 @@ import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -69,7 +68,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
LiveBean definedBean = getDefinedBean(annotation);
|
||||
if (definedBean != null) {
|
||||
if (Stream.of(processLiveData).anyMatch(app -> LiveHoverUtils.hasRelevantBeans(app, definedBean))) {
|
||||
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
|
||||
Optional<Range> nameRange = ORAstUtils.nameRange(doc, annotation);
|
||||
if (nameRange.isPresent()) {
|
||||
List<CodeLens> codeLenses = assembleCodeLenses(project, processLiveData, app -> definedBean, doc, nameRange.get(), annotation);
|
||||
return codeLenses;
|
||||
@@ -84,7 +83,7 @@ public abstract class AbstractInjectedIntoHoverProvider 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) {
|
||||
if (processLiveData.length > 0) {
|
||||
|
||||
@@ -92,7 +91,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
if (definedBean != null) {
|
||||
Hover hover = assembleHover(project, processLiveData, app -> definedBean, annotation, true, true);
|
||||
if (hover != null) {
|
||||
Optional<Range> nameRange = ASTUtils.nameRange(doc, annotation);
|
||||
Optional<Range> nameRange = ORAstUtils.nameRange(doc, annotation);
|
||||
if (nameRange.isPresent()) {
|
||||
hover.setRange(nameRange.get());
|
||||
}
|
||||
@@ -104,7 +103,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
}
|
||||
|
||||
protected List<CodeLens> assembleCodeLenses(IJavaProject project, SpringProcessLiveData[] processLiveData, DefinedBeanProvider definedBeanProvider,
|
||||
TextDocument doc, Range range, ASTNode node) {
|
||||
TextDocument doc, Range range, J node) {
|
||||
List<CodeLens> codeLenses = null;
|
||||
boolean beanFound = false;
|
||||
for (SpringProcessLiveData liveData : processLiveData) {
|
||||
@@ -156,17 +155,17 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<CodeLens> assembleCodeLenseForAutowired(List<LiveBean> wiredBeans, IJavaProject project, SpringProcessLiveData processLiveData, TextDocument doc, Range nameRange, ASTNode astNode) {
|
||||
protected List<CodeLens> assembleCodeLenseForAutowired(List<LiveBean> wiredBeans, IJavaProject project, SpringProcessLiveData processLiveData, TextDocument doc, Range nameRange, J astNode) {
|
||||
return LiveHoverUtils.createCodeLensesForBeans(nameRange, wiredBeans,
|
||||
AutowiredHoverProvider.BEANS_PREFIX_PLAIN_TEXT, MAX_INLINE_BEANS_STRING_LENGTH,
|
||||
INLINE_BEANS_STRING_SEPARATOR);
|
||||
}
|
||||
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List<LiveBean> relevantBeans, ASTNode astNode) {
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List<LiveBean> relevantBeans, J astNode) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected Hover assembleHover(IJavaProject project, SpringProcessLiveData[] processLiveData, DefinedBeanProvider definedBeanProvider, ASTNode astNode, boolean injected, boolean wired) {
|
||||
protected Hover assembleHover(IJavaProject project, SpringProcessLiveData[] processLiveData, DefinedBeanProvider definedBeanProvider, J astNode, boolean injected, boolean wired) {
|
||||
StringBuilder hover = new StringBuilder();
|
||||
|
||||
for (SpringProcessLiveData liveData : processLiveData) {
|
||||
|
||||
@@ -10,27 +10,24 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.livehover;
|
||||
|
||||
import static org.springframework.ide.vscode.boot.java.utils.ASTUtils.nameRange;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
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.StringLiteral;
|
||||
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.Literal;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -46,7 +43,7 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
private static final Logger log = LoggerFactory.getLogger(ActiveProfilesProvider.class);
|
||||
|
||||
@Override
|
||||
public Hover provideHover(ASTNode node, Annotation annotation, ITypeBinding type, int offset,
|
||||
public Hover provideHover(J node, Annotation annotation, int offset,
|
||||
TextDocument doc, IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
|
||||
if (processLiveData.length > 0) {
|
||||
@@ -75,7 +72,7 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
ImmutableList.of(Either.forLeft(markdown.toString()))
|
||||
);
|
||||
if (hover != null) {
|
||||
Optional<Range> optional = nameRange(doc, annotation);
|
||||
Optional<Range> optional = ORAstUtils.nameRange(doc, annotation);
|
||||
if (optional.isPresent()) {
|
||||
hover.setRange(optional.get());
|
||||
}
|
||||
@@ -93,19 +90,19 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
|
||||
Set<String> allActiveProfiles = getAllActiveProfiles(processLiveData);
|
||||
if (allActiveProfiles != null && allActiveProfiles.size() > 0) {
|
||||
nameRange(doc, annotation).map(CodeLens::new).ifPresent(codeLenses::add);
|
||||
ORAstUtils.nameRange(doc, annotation).map(CodeLens::new).ifPresent(codeLenses::add);
|
||||
}
|
||||
|
||||
annotation.accept(new ASTVisitor() {
|
||||
@Override
|
||||
public boolean visit(StringLiteral node) {
|
||||
String value = ASTUtils.getLiteralValue(node);
|
||||
if (value!=null && allActiveProfiles.contains(value)) {
|
||||
rangeOf(doc, node).map(CodeLens::new).ifPresent(codeLenses::add);
|
||||
|
||||
new JavaIsoVisitor<Builder<CodeLens>>() {
|
||||
public Literal visitLiteral(Literal literal, Builder<CodeLens> cl) {
|
||||
String value = ORAstUtils.getLiteralValue(literal);
|
||||
if (value != null && allActiveProfiles.contains(value)) {
|
||||
rangeOf(doc, literal).map(CodeLens::new).ifPresent(cl::add);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return super.visitLiteral(literal, cl);
|
||||
};
|
||||
}.visitNonNull(annotation, codeLenses);
|
||||
|
||||
return codeLenses.build();
|
||||
}
|
||||
return ImmutableList.of();
|
||||
@@ -122,10 +119,11 @@ public class ActiveProfilesProvider implements HoverProvider {
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Optional<Range> rangeOf(TextDocument doc, StringLiteral node) {
|
||||
private static Optional<Range> rangeOf(TextDocument doc, Literal node) {
|
||||
try {
|
||||
int start = node.getStartPosition();
|
||||
int end = start + node.getLength();
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(node);
|
||||
int start = r.getStart().getOffset();
|
||||
int end = r.getEnd().getOffset();
|
||||
if (doc.getSafeChar(start)=='"') {
|
||||
start++;
|
||||
}
|
||||
|
||||
@@ -14,13 +14,14 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
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.J.VariableDeclarations;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.Optionals;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
@@ -44,7 +46,7 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
|
||||
@Override
|
||||
protected LiveBean getDefinedBean(Annotation annotation) {
|
||||
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod(annotation);
|
||||
MethodDeclaration beanMethod = ORAstUtils.getAnnotatedMethod(annotation);
|
||||
if (beanMethod!=null) {
|
||||
Optional<String> beanId = getBeanId(annotation, beanMethod);
|
||||
if (beanId.isPresent()) {
|
||||
@@ -77,21 +79,21 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
// @Bean(name="beanId", ...)
|
||||
// @Bean(name={"beanId", "alias1"}, ...)
|
||||
return Optionals.tryInOrder(
|
||||
() -> ASTUtils.getAttribute(annotation, "value").flatMap(ASTUtils::getFirstString),
|
||||
() -> ASTUtils.getAttribute(annotation, "name").flatMap(ASTUtils::getFirstString),
|
||||
() -> Optional.ofNullable(beanMethod.getName().getIdentifier())
|
||||
() -> ORAstUtils.getAttribute(annotation, "value").flatMap(ORAstUtils::getFirstString),
|
||||
() -> ORAstUtils.getAttribute(annotation, "name").flatMap(ORAstUtils::getFirstString),
|
||||
() -> Optional.ofNullable(beanMethod.getName().getSimpleName())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List<LiveBean> relevantBeans, ASTNode astNode) {
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List<LiveBean> relevantBeans, J astNode) {
|
||||
if (astNode instanceof Annotation) {
|
||||
// @Bean annotation case
|
||||
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod((Annotation) astNode);
|
||||
MethodDeclaration beanMethod = ORAstUtils.getAnnotatedMethod((Annotation) astNode);
|
||||
if (beanMethod != null) {
|
||||
return AutowiredHoverProvider.getRelevantAutowiredBeans(project, beanMethod, liveData, relevantBeans);
|
||||
}
|
||||
} else if (astNode instanceof SingleVariableDeclaration) {
|
||||
} else if (astNode instanceof VariableDeclarations) {
|
||||
// Bean method parameter case
|
||||
return AutowiredHoverProvider.getRelevantAutowiredBeans(project, astNode, liveData, relevantBeans);
|
||||
}
|
||||
@@ -100,7 +102,7 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
|
||||
@Override
|
||||
protected List<CodeLens> assembleCodeLenseForAutowired(List<LiveBean> wiredBeans, IJavaProject project,
|
||||
SpringProcessLiveData liveData, TextDocument doc, Range nameRange, ASTNode astNode) {
|
||||
SpringProcessLiveData liveData, TextDocument doc, Range nameRange, J astNode) {
|
||||
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
|
||||
|
||||
// Code lens for the @Bean annotation
|
||||
@@ -108,7 +110,7 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
|
||||
if (astNode instanceof Annotation) {
|
||||
// Add code lenses for method parameters
|
||||
MethodDeclaration beanMethod = ASTUtils.getAnnotatedMethod((Annotation) astNode);
|
||||
MethodDeclaration beanMethod = ORAstUtils.getAnnotatedMethod((Annotation) astNode);
|
||||
if (beanMethod != null) {
|
||||
builder.addAll(LiveHoverUtils.createCodeLensForMethodParameters(liveData, project, beanMethod, doc, wiredBeans));
|
||||
}
|
||||
@@ -118,13 +120,13 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hover provideMethodParameterHover(SingleVariableDeclaration parameter, int offset, TextDocument doc,
|
||||
public Hover provideMethodParameterHover(VariableDeclarations parameter, int offset, TextDocument doc,
|
||||
IJavaProject project, SpringProcessLiveData[] processLiveData) {
|
||||
try {
|
||||
if (processLiveData.length > 0) {
|
||||
Range range = ASTUtils.nodeRegion(doc, parameter.getName()).asRange();
|
||||
MethodDeclaration method = (MethodDeclaration) parameter.getParent();
|
||||
Annotation beanAnnotation = ASTUtils.getBeanAnnotation(method);
|
||||
Range range = ORAstUtils.nodeRegion(doc, parameter.getVariables().get(0)).asRange();
|
||||
MethodDeclaration method = (MethodDeclaration) ORAstUtils.getParent(parameter);
|
||||
Annotation beanAnnotation = ORAstUtils.getBeanAnnotation(method);
|
||||
if (beanAnnotation != null) {
|
||||
LiveBean definedBean = getDefinedBean(beanAnnotation);
|
||||
if (definedBean != null) {
|
||||
@@ -134,7 +136,6 @@ public class BeanInjectedIntoHoverProvider extends AbstractInjectedIntoHoverProv
|
||||
}
|
||||
return hover;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -16,15 +16,15 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.core.Flags;
|
||||
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.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
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.Modifier;
|
||||
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;
|
||||
@@ -34,7 +34,7 @@ import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
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.StringUtil;
|
||||
@@ -57,15 +57,15 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
|
||||
public static LiveBean getDefinedBeanForComponent(Annotation annotation) {
|
||||
//Move to ASTUtils?
|
||||
TypeDeclaration declaringType = ASTUtils.getAnnotatedType(annotation);
|
||||
ClassDeclaration declaringType = ORAstUtils.getAnnotatedType(annotation);
|
||||
return getDefinedBeanForType(declaringType, annotation);
|
||||
}
|
||||
|
||||
private static LiveBean getDefinedBeanForType(TypeDeclaration declaringType, Annotation annotation) {
|
||||
private static LiveBean getDefinedBeanForType(ClassDeclaration declaringType, Annotation annotation) {
|
||||
if (declaringType != null) {
|
||||
ITypeBinding beanType = declaringType.resolveBinding();
|
||||
FullyQualified beanType = declaringType.getType();
|
||||
if (beanType != null) {
|
||||
String id = getBeanId(annotation, beanType, Flags.isStatic(declaringType.getModifiers()));
|
||||
String id = getBeanId(annotation, beanType, Modifier.hasModifier(declaringType.getModifiers(), Modifier.Type.Static));
|
||||
if (StringUtil.hasText(id)) {
|
||||
return LiveBean.builder().id(id).type(getBeanType(beanType).toString()).build();
|
||||
}
|
||||
@@ -74,20 +74,22 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getBeanId(Annotation annotation, ITypeBinding beanType, boolean isStatic) {
|
||||
return ASTUtils.getAttribute(annotation, "value").flatMap(ASTUtils::getFirstString).orElseGet(() -> {
|
||||
ITypeBinding declaringClass = beanType.getDeclaringClass();
|
||||
private static String getBeanId(Annotation annotation, FullyQualified beanType, boolean isStatic) {
|
||||
return ORAstUtils.getAttribute(annotation, "value").flatMap(ORAstUtils::getFirstString).orElseGet(() -> {
|
||||
FullyQualified declaringClass = beanType.getOwningClass();
|
||||
if (declaringClass == null) {
|
||||
return BeanUtils.getBeanNameFromType(beanType.getName());
|
||||
return BeanUtils.getBeanNameFromType(beanType.getClassName());
|
||||
} else {
|
||||
if (isStatic) {
|
||||
// Static inner class case id `outerClass.InnerClass`
|
||||
String typeName = beanType.getBinaryName();
|
||||
// Trim package prefix and replace $ with . inner class separator
|
||||
int idx = typeName.lastIndexOf('.');
|
||||
if (idx >= 0) {
|
||||
typeName = typeName.substring(idx + 1).replace('$', '.');
|
||||
}
|
||||
// OR class name for inner class is outer/inner classes separated by dots
|
||||
String typeName = beanType.getClassName();
|
||||
|
||||
// // Trim package prefix and replace $ with . inner class separator
|
||||
// int idx = typeName.lastIndexOf('.');
|
||||
// if (idx >= 0) {
|
||||
// typeName = typeName.substring(idx + 1).replace('$', '.');
|
||||
// }
|
||||
return BeanUtils.getBeanNameFromType(typeName);
|
||||
} else {
|
||||
// Non-static inner class id case is binary type name
|
||||
@@ -97,19 +99,19 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
});
|
||||
}
|
||||
|
||||
private static String getBeanType(ITypeBinding beanType) {
|
||||
return beanType.getBinaryName();
|
||||
private static String getBeanType(FullyQualified beanType) {
|
||||
return beanType.getClassName().replace('.', '$');
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, TypeDeclaration typeDeclaration,
|
||||
public Collection<CodeLens> getLiveHintCodeLenses(IJavaProject project, ClassDeclaration typeDeclaration,
|
||||
TextDocument doc, SpringProcessLiveData[] processLiveData) {
|
||||
if (processLiveData.length > 0 && !isComponentAnnotatedType(typeDeclaration)) {
|
||||
try {
|
||||
ITypeBinding beanType = typeDeclaration.resolveBinding();
|
||||
FullyQualified beanType = typeDeclaration.getType();
|
||||
if (beanType != null) {
|
||||
String id = getBeanId(null, beanType, Flags.isStatic(typeDeclaration.getModifiers()));
|
||||
Optional<Range> nameRange = Optional.of(ASTUtils.nodeRegion(doc, typeDeclaration.getName()).asRange());
|
||||
String id = getBeanId(null, beanType, Modifier.hasModifier(typeDeclaration.getModifiers(), Modifier.Type.Static));
|
||||
Optional<Range> nameRange = Optional.of(ORAstUtils.nodeRegion(doc, typeDeclaration.getName()).asRange());
|
||||
if (nameRange.isPresent()) {
|
||||
List<CodeLens> codeLenses = assembleCodeLenses(project, processLiveData, liveData -> definedBean(liveData, getBeanType(beanType), id), doc,
|
||||
nameRange.get(), typeDeclaration);
|
||||
@@ -143,19 +145,19 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
||||
if (processLiveData.length > 0 && !isComponentAnnotatedType(typeDeclaration)) {
|
||||
ITypeBinding beanType = typeDeclaration.resolveBinding();
|
||||
FullyQualified beanType = typeDeclaration.getType();
|
||||
if (beanType != null) {
|
||||
String id = getBeanId(null, beanType, Flags.isStatic(typeDeclaration.getModifiers()));
|
||||
String id = getBeanId(null, beanType, Modifier.hasModifier(typeDeclaration.getModifiers(), Modifier.Type.Static));
|
||||
|
||||
Hover hover = assembleHover(project, processLiveData, app -> definedBean(app, getBeanType(beanType), id), typeDeclaration, true, true);
|
||||
if (hover != null) {
|
||||
SimpleName name = typeDeclaration.getName();
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(typeDeclaration.getName());
|
||||
try {
|
||||
hover.setRange(doc.toRange(name.getStartPosition(), name.getLength()));
|
||||
hover.setRange(doc.toRange(r.getStart().getOffset(), r.length()));
|
||||
} catch (BadLocationException e) {
|
||||
LOG.error("", e);
|
||||
}
|
||||
@@ -168,30 +170,27 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
|
||||
|
||||
@Override
|
||||
protected List<LiveBean> findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List<LiveBean> relevantBeans,
|
||||
ASTNode astNode) {
|
||||
TypeDeclaration typeDeclaration = null;
|
||||
if (astNode instanceof TypeDeclaration) {
|
||||
typeDeclaration = (TypeDeclaration) astNode;
|
||||
J astNode) {
|
||||
ClassDeclaration typeDeclaration = null;
|
||||
if (astNode instanceof ClassDeclaration) {
|
||||
typeDeclaration = (ClassDeclaration) astNode;
|
||||
} else if (astNode instanceof Annotation) {
|
||||
typeDeclaration = ASTUtils.getAnnotatedType((Annotation) astNode);
|
||||
typeDeclaration = ORAstUtils.getAnnotatedType((Annotation) astNode);
|
||||
}
|
||||
return typeDeclaration == null ? Collections.emptyList() : LiveHoverUtils.findAllDependencyBeans(liveData, relevantBeans);
|
||||
}
|
||||
|
||||
private boolean isComponentAnnotatedType(TypeDeclaration typeDeclaration) {
|
||||
List<?> modifiers = typeDeclaration.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
ITypeBinding typeBinding = ((Annotation) modifier).resolveTypeBinding();
|
||||
if (isComponentAnnotation(typeBinding)) {
|
||||
return true;
|
||||
}
|
||||
private boolean isComponentAnnotatedType(ClassDeclaration typeDeclaration) {
|
||||
for (Annotation a : typeDeclaration.getLeadingAnnotations()) {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(a.getType());
|
||||
if (type != null && isComponentAnnotation(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isComponentAnnotation(ITypeBinding type) {
|
||||
private boolean isComponentAnnotation(FullyQualified type) {
|
||||
Set<String> transitiveSuperAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(type);
|
||||
for (String annotationType : transitiveSuperAnnotations) {
|
||||
if (Annotations.COMPONENT.equals(annotationType)) {
|
||||
|
||||
@@ -19,11 +19,13 @@ import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
import org.openrewrite.java.tree.Statement;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
|
||||
@@ -32,6 +34,7 @@ import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBean;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.boot.java.livehover.v2.SpringProcessLiveData;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringResource;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
@@ -230,21 +233,24 @@ public class LiveHoverUtils {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<CodeLens> createCodeLensForMethodParameters(SpringProcessLiveData liveData, IJavaProject project, MethodDeclaration method, TextDocument doc, List<LiveBean> wiredBeans) {
|
||||
ImmutableList.Builder<CodeLens> builder = ImmutableList.builder();
|
||||
method.parameters().forEach(p -> {
|
||||
if (p instanceof SingleVariableDeclaration) {
|
||||
SingleVariableDeclaration parameter = (SingleVariableDeclaration) p;
|
||||
List<LiveBean> parameterMatchingBean = AutowiredHoverProvider.findAutowiredBeans(project, parameter, wiredBeans);
|
||||
if (parameterMatchingBean.size() == 0) {
|
||||
log.warn("No Live Bean matching parameter `" + parameter.getName().getIdentifier() + " for method " + method);
|
||||
} else {
|
||||
try {
|
||||
builder.add(new CodeLens(ASTUtils.nodeRegion(doc, parameter.getName()).asRange()));
|
||||
} catch (BadLocationException e) {
|
||||
// ignore
|
||||
List<Statement> params = method.getParameters();
|
||||
if (params != null) {
|
||||
for (Statement p : params) {
|
||||
if (p instanceof VariableDeclarations) {
|
||||
VariableDeclarations parameter = (VariableDeclarations) p;
|
||||
List<LiveBean> parameterMatchingBean = AutowiredHoverProvider.findAutowiredBeans(project, parameter, wiredBeans);
|
||||
if (parameterMatchingBean.size() == 0) {
|
||||
log.warn("No Live Bean matching parameter `" + parameter.printTrimmed() + " for method " + method);
|
||||
} else {
|
||||
try {
|
||||
builder.add(new CodeLens(ORAstUtils.nodeRegion(doc, parameter.getVariables().get(0)).asRange()));
|
||||
} catch (BadLocationException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2018 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
|
||||
|
||||
@@ -10,33 +10,24 @@
|
||||
*******************************************************************************/
|
||||
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.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.openrewrite.java.tree.J.Modifier;
|
||||
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;
|
||||
@@ -47,24 +38,6 @@ 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("\"")) {
|
||||
@@ -77,109 +50,6 @@ 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);
|
||||
@@ -244,20 +114,6 @@ 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();
|
||||
@@ -266,41 +122,5 @@ 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,21 +1,42 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.openrewrite.Cursor;
|
||||
import org.openrewrite.SourceFile;
|
||||
import org.openrewrite.Tree;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.tree.Expression;
|
||||
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.CompilationUnit;
|
||||
import org.openrewrite.java.tree.J.EnumValueSet;
|
||||
import org.openrewrite.java.tree.J.Literal;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.NewArray;
|
||||
import org.openrewrite.java.tree.J.VariableDeclarations;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.openrewrite.marker.Marker;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class ORAstUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ORAstUtils.class);
|
||||
|
||||
private static class AncestersMarker implements Marker {
|
||||
|
||||
private UUID uuid;
|
||||
@@ -100,5 +121,177 @@ public class ORAstUtils {
|
||||
AncestersMarker ancestry = node.getMarkers().findFirst(AncestersMarker.class).orElseThrow();
|
||||
return ancestry.getParent();
|
||||
}
|
||||
|
||||
public static EnumValueSet getEnumValues(ClassDeclaration classDecl) {
|
||||
return classDecl.getBody().getStatements().stream()
|
||||
.filter(J.EnumValueSet.class::isInstance)
|
||||
.map(J.EnumValueSet.class::cast)
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public static List<VariableDeclarations> getFields(ClassDeclaration classDecl) {
|
||||
return classDecl.getBody().getStatements().stream()
|
||||
.filter(J.VariableDeclarations.class::isInstance)
|
||||
.map(J.VariableDeclarations.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static List<MethodDeclaration> getMethods(ClassDeclaration classDecl) {
|
||||
return classDecl.getBody().getStatements().stream()
|
||||
.filter(J.MethodDeclaration.class::isInstance)
|
||||
.map(J.MethodDeclaration.class::cast)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static DocumentRegion nodeRegion(TextDocument doc, J node) {
|
||||
Range r = node.getMarkers().findFirst(Range.class).orElseThrow();
|
||||
int start = r.getStart().getOffset();
|
||||
int end = r.getEnd().getOffset();
|
||||
return new DocumentRegion(doc, start, end);
|
||||
}
|
||||
|
||||
public static DocumentRegion nameRegion(TextDocument doc, Annotation annotation) {
|
||||
Range r = annotation.getAnnotationType().getMarkers().findFirst(Range.class).orElseThrow();
|
||||
int start = r.getStart().getOffset();
|
||||
int end = r.getEnd().getOffset();
|
||||
// TODO: OR AST what about '@'???
|
||||
if (doc.getSafeChar(start - 1) == '@') {
|
||||
start--;
|
||||
}
|
||||
return new DocumentRegion(doc, start, end);
|
||||
}
|
||||
|
||||
public static Optional<org.eclipse.lsp4j.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 MethodDeclaration getAnnotatedMethod(Annotation annotation) {
|
||||
J parent = getParent(annotation);
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
return (MethodDeclaration)parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Annotation getBeanAnnotation(MethodDeclaration method) {
|
||||
for (Annotation a : method.getLeadingAnnotations()) {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(a.getType());
|
||||
if (type != null) {
|
||||
if (Annotations.BEAN.equals(type.getFullyQualifiedName())) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Optional<Expression> getAttribute(Annotation annotation, String name) {
|
||||
if (annotation != null) {
|
||||
try {
|
||||
List<Expression> args = annotation.getArguments();
|
||||
if (name.equals("value") && args.size() == 1 && !(args.get(0) instanceof Assignment)) {
|
||||
return Optional.ofNullable(args.get(0));
|
||||
} else {
|
||||
for (Expression arg : args) {
|
||||
if (arg instanceof Assignment) {
|
||||
Assignment assignment = (Assignment) arg;
|
||||
if (name.equals(assignment.getVariable().printTrimmed())) {
|
||||
return Optional.ofNullable(assignment.getAssignment());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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 Literal) {
|
||||
return Optional.ofNullable(getLiteralValue((Literal) exp));
|
||||
} else if (exp instanceof NewArray) {
|
||||
NewArray array = (NewArray) exp;
|
||||
List<Expression> entries = array.getInitializer();
|
||||
if (entries != null) {
|
||||
for (Expression e : entries) {
|
||||
Optional<String> s = getFirstString(e);
|
||||
if (s.isPresent()) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static String getLiteralValue(Literal node) {
|
||||
return node.getValueSource();
|
||||
}
|
||||
|
||||
public static ClassDeclaration findDeclaringType(J node) {
|
||||
return node == null ? null : findNode(node, ClassDeclaration.class);
|
||||
}
|
||||
|
||||
public static Range getRange(J node) {
|
||||
return node.getMarkers().findFirst(Range.class).orElseThrow();
|
||||
}
|
||||
|
||||
public static Optional<String> beanId(List<Annotation> annotations) {
|
||||
return annotations.stream()
|
||||
.filter(a -> {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(a.getType());
|
||||
if (type != null) {
|
||||
return Annotations.QUALIFIER.equals(type.getFullyQualifiedName());
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.findFirst()
|
||||
.map(a -> a.getArguments())
|
||||
.filter(args -> args != null && !args.isEmpty())
|
||||
.map(args -> args.get(0))
|
||||
.filter(Literal.class::isInstance)
|
||||
.map(arg -> arg.printTrimmed());
|
||||
}
|
||||
|
||||
public static Collection<Annotation> getAnnotations(ClassDeclaration declaringType) {
|
||||
return declaringType.getLeadingAnnotations();
|
||||
}
|
||||
|
||||
public static boolean hasExactlyOneConstructor(ClassDeclaration typeDecl) {
|
||||
boolean oneFound = false;
|
||||
for (MethodDeclaration methodDeclaration : getMethods(typeDecl)) {
|
||||
if (methodDeclaration.isConstructor()) {
|
||||
if (oneFound) {
|
||||
return false;
|
||||
} else {
|
||||
oneFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oneFound;
|
||||
}
|
||||
|
||||
public static ClassDeclaration getAnnotatedType(Annotation annotation) {
|
||||
J parent = getParent(annotation);
|
||||
if (parent instanceof ClassDeclaration) {
|
||||
return (ClassDeclaration)parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user