Hover providers WIP

This commit is contained in:
BoykoAlex
2022-02-09 12:53:44 -05:00
parent aed3398ecb
commit 14571e0c09
19 changed files with 604 additions and 672 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) {

View File

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

View File

@@ -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) {

View File

@@ -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)) {

View File

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

View File

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

View File

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

View File

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