diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java index 9a78e82f2..51f03a005 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java @@ -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; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java index d55a05f1f..71f2135c9 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServerComponents.java @@ -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; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java index 420343506..08956a01c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java @@ -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. *

* 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 getDirectSuperAnnotations(ITypeBinding typeBinding) { - synchronized(lock) { - try { - IAnnotationBinding[] annotations = typeBinding.getAnnotations(); - if (annotations != null && annotations.length != 0) { - ImmutableList.Builder superAnnotations = ImmutableList.builder(); - for (IAnnotationBinding ab : annotations) { - ITypeBinding sa = ab.getAnnotationType(); - if (sa != null) { - if (!ignoreAnnotation(sa.getQualifiedName())) { - superAnnotations.add(sa); - } - } + public static Collection getDirectSuperAnnotations(FullyQualified type) { + try { + List annotations = type.getAnnotations(); + if (annotations != null && !annotations.isEmpty()) { + ImmutableList.Builder 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 getTransitiveSuperAnnotations(ITypeBinding typeBinding) { - synchronized(lock) { - Set seen = new HashSet<>(); - findTransitiveSupers(typeBinding, seen).collect(Collectors.toList()); - return seen; - } + public static Set getTransitiveSuperAnnotations(FullyQualified type) { + Set seen = new HashSet<>(); + findTransitiveSupers(type, seen).collect(Collectors.toList()); + return seen; } - public static Stream findTransitiveSupers(ITypeBinding typeBinding, Set 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 findTransitiveSupers(FullyQualified type, Set 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 getMetaAnnotations(ITypeBinding actualAnnotation, Predicate isKeyAnnotationName) { - synchronized(lock) { - Stream 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 getMetaAnnotations(FullyQualified actualAnnotation, + Predicate isKeyAnnotationName) { + Stream 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 isKeyAnnotationName) { + private static boolean isMetaAnnotation(FullyQualified candidate, Predicate isKeyAnnotationName) { return findTransitiveSupers(candidate, new HashSet<>()) - .anyMatch(sa -> isKeyAnnotationName.test(sa.getQualifiedName())); + .anyMatch(sa -> isKeyAnnotationName.test(sa.getFullyQualifiedName())); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchyAwareLookup.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchyAwareLookup.java index e8516bc83..45fd105b0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchyAwareLookup.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchyAwareLookup.java @@ -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 { * 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 get(ITypeBinding annotationType) { + public Collection get(FullyQualified annotationType) { ImmutableList.Builder found = ImmutableList.builder(); findElements(annotationType, new LinkedHashSet<>(), found::add); return found.build(); @@ -98,8 +98,8 @@ public class AnnotationHierarchyAwareLookup { return found.build(); } - private void findElements(ITypeBinding typeBinding, HashSet seen, Consumer requestor) { - String qname = typeBinding.getQualifiedName(); + private void findElements(FullyQualified type, HashSet seen, Consumer requestor) { + String qname = type.getFullyQualifiedName(); if (seen.add(qname)) { Binding binding = bindings.get(qname); @@ -110,8 +110,8 @@ public class AnnotationHierarchyAwareLookup { } if (!isOverriding) { - Collection directSuperAnnotations = AnnotationHierarchies.getDirectSuperAnnotations(typeBinding); - for (ITypeBinding superAnnotation : directSuperAnnotations) { + Collection directSuperAnnotations = AnnotationHierarchies.getDirectSuperAnnotations(type); + for (FullyQualified superAnnotation : directSuperAnnotations) { findElements(superAnnotation, seen, requestor); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java index 1db0eaecf..6ed82a53d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/autowired/AutowiredHoverProvider.java @@ -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 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 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 getRelevantAutowiredBeans(IJavaProject project, ASTNode declarationNode, SpringProcessLiveData liveData, LiveBean definedBean) { + public static List getRelevantAutowiredBeans(IJavaProject project, J declarationNode, SpringProcessLiveData liveData, LiveBean definedBean) { List relevantBeans = LiveHoverUtils.findRelevantBeans(liveData, definedBean); return getRelevantAutowiredBeans(project, declarationNode, liveData, relevantBeans); } - public static List getRelevantAutowiredBeans(IJavaProject project, ASTNode declarationNode, SpringProcessLiveData liveData, List relevantBeans) { + public static List getRelevantAutowiredBeans(IJavaProject project, J declarationNode, SpringProcessLiveData liveData, List relevantBeans) { if (!relevantBeans.isEmpty()) { List allDependencyBeans = LiveHoverUtils.findAllDependencyBeans(liveData, relevantBeans); @@ -184,32 +188,26 @@ public class AutowiredHoverProvider implements HoverProvider { } @SuppressWarnings("unchecked") - public static List findAutowiredBeans(IJavaProject project, ASTNode declarationNode, Collection beans) { + public static List findAutowiredBeans(IJavaProject project, J declarationNode, Collection beans) { if (declarationNode instanceof MethodDeclaration) { MethodDeclaration methodDeclaration = (MethodDeclaration)declarationNode; - return ((List)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 matchBeans(IJavaProject project, Collection beans, ITypeBinding typeBinding, List modifiers) { - Optional beanId = ASTUtils.beanId(modifiers); + private static List matchBeans(IJavaProject project, Collection beans, JavaType type, List annotations) { + Optional beanId = ORAstUtils.beanId(annotations); Collection searchScope = beanId.isPresent() ? beans.stream() .filter(b -> beanId.get().equals(b.getId())) @@ -217,34 +215,33 @@ public class AutowiredHoverProvider implements HoverProvider { .map(bean -> (Collection) 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 matchBeansByTypeOrCollection(IJavaProject project, Collection beans, ITypeBinding type) { + private static List matchBeansByTypeOrCollection(IJavaProject project, Collection 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 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; } } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java index d2c868628..0c8d385d4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java @@ -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> 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; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositoryCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositoryCompletionProcessor.java index c77fbbe41..60bcb21be 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositoryCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositoryCompletionProcessor.java @@ -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 diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java index 0e75cccf7..4a0176c53 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/AnnotationParamReconciler.java @@ -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 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 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 allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding); + Set 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); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java index dc5a9c001..7fd46d3b3 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaHoverProvider.java @@ -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 result = new LinkedHashSet<>(); try { if (cu != null) { - cu.accept(new ASTVisitor() { - - @Override - public boolean visit(TypeDeclaration node) { + new JavaIsoVisitor>() { + + public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, Collection 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 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 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 result) { Collection 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 result) { - ITypeBinding type = annotation.resolveTypeBinding(); + FullyQualified type = TypeUtils.asFullyQualified(annotation.getType()); if (type != null) { for (HoverProvider provider : this.hoverProviders.get(type)) { Collection 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; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java index efaa08d0c..41a749e10 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/BootJavaReconcileEngine.java @@ -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() { + 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); - } - } - } - + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java index 2af069787..87530988e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/handlers/HoverProvider.java @@ -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 getLiveHintCodeLenses(IJavaProject project,TypeDeclaration typeDeclaration, TextDocument doc, SpringProcessLiveData[] processLiveData) { + default Collection getLiveHintCodeLenses(IJavaProject project, ClassDeclaration typeDeclaration, TextDocument doc, SpringProcessLiveData[] processLiveData) { return null; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java index d8f70a8e3..a454d4020 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/AbstractInjectedIntoHoverProvider.java @@ -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 nameRange = ASTUtils.nameRange(doc, annotation); + Optional nameRange = ORAstUtils.nameRange(doc, annotation); if (nameRange.isPresent()) { List 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 nameRange = ASTUtils.nameRange(doc, annotation); + Optional nameRange = ORAstUtils.nameRange(doc, annotation); if (nameRange.isPresent()) { hover.setRange(nameRange.get()); } @@ -104,7 +103,7 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider } protected List assembleCodeLenses(IJavaProject project, SpringProcessLiveData[] processLiveData, DefinedBeanProvider definedBeanProvider, - TextDocument doc, Range range, ASTNode node) { + TextDocument doc, Range range, J node) { List codeLenses = null; boolean beanFound = false; for (SpringProcessLiveData liveData : processLiveData) { @@ -156,17 +155,17 @@ public abstract class AbstractInjectedIntoHoverProvider implements HoverProvider return null; } - protected List assembleCodeLenseForAutowired(List wiredBeans, IJavaProject project, SpringProcessLiveData processLiveData, TextDocument doc, Range nameRange, ASTNode astNode) { + protected List assembleCodeLenseForAutowired(List 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 findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List relevantBeans, ASTNode astNode) { + protected List findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List 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) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java index 1726242eb..93c984265 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ActiveProfilesProvider.java @@ -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 optional = nameRange(doc, annotation); + Optional optional = ORAstUtils.nameRange(doc, annotation); if (optional.isPresent()) { hover.setRange(optional.get()); } @@ -93,19 +90,19 @@ public class ActiveProfilesProvider implements HoverProvider { Set 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>() { + public Literal visitLiteral(Literal literal, Builder 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 rangeOf(TextDocument doc, StringLiteral node) { + private static Optional 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++; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java index c531304b2..3a2a69520 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/BeanInjectedIntoHoverProvider.java @@ -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 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 findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List relevantBeans, ASTNode astNode) { + protected List findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List 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 assembleCodeLenseForAutowired(List wiredBeans, IJavaProject project, - SpringProcessLiveData liveData, TextDocument doc, Range nameRange, ASTNode astNode) { + SpringProcessLiveData liveData, TextDocument doc, Range nameRange, J astNode) { ImmutableList.Builder 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) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java index e179d7961..47881fd62 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java @@ -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 getLiveHintCodeLenses(IJavaProject project, TypeDeclaration typeDeclaration, + public Collection 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 nameRange = Optional.of(ASTUtils.nodeRegion(doc, typeDeclaration.getName()).asRange()); + String id = getBeanId(null, beanType, Modifier.hasModifier(typeDeclaration.getModifiers(), Modifier.Type.Static)); + Optional nameRange = Optional.of(ORAstUtils.nodeRegion(doc, typeDeclaration.getName()).asRange()); if (nameRange.isPresent()) { List 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 findWiredBeans(IJavaProject project, SpringProcessLiveData liveData, List 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 transitiveSuperAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(type); for (String annotationType : transitiveSuperAnnotations) { if (Annotations.COMPONENT.equals(annotationType)) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java index 10a3a36e3..a507195fc 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/LiveHoverUtils.java @@ -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 createCodeLensForMethodParameters(SpringProcessLiveData liveData, IJavaProject project, MethodDeclaration method, TextDocument doc, List wiredBeans) { ImmutableList.Builder builder = ImmutableList.builder(); - method.parameters().forEach(p -> { - if (p instanceof SingleVariableDeclaration) { - SingleVariableDeclaration parameter = (SingleVariableDeclaration) p; - List 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 params = method.getParameters(); + if (params != null) { + for (Statement p : params) { + if (p instanceof VariableDeclarations) { + VariableDeclarations parameter = (VariableDeclarations) p; + List 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(); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/snippets/JavaSnippetManager.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/snippets/JavaSnippetManager.java index 57e744cdf..c2b432226 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/snippets/JavaSnippetManager.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/snippets/JavaSnippetManager.java @@ -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 diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java index 2e792c8a7..8f07f0c88 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java @@ -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 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 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 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 dependencies) { if (exp instanceof StringLiteral) { return getLiteralValue((StringLiteral) exp); @@ -244,20 +114,6 @@ public class ASTUtils { } - public static Collection getAnnotations(TypeDeclaration declaringType) { - Object modifiersObj = declaringType.getStructuralProperty(TypeDeclaration.MODIFIERS2_PROPERTY); - if (modifiersObj instanceof List) { - ImmutableList.Builder 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 beanId(List 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; - } - + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ORAstUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ORAstUtils.java index c5b777978..2da9509e1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ORAstUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ORAstUtils.java @@ -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 getFields(ClassDeclaration classDecl) { + return classDecl.getBody().getStatements().stream() + .filter(J.VariableDeclarations.class::isInstance) + .map(J.VariableDeclarations.class::cast) + .collect(Collectors.toList()); + } + + public static List 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 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 getAttribute(Annotation annotation, String name) { + if (annotation != null) { + try { + List 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 getFirstString(Expression exp) { + if (exp instanceof Literal) { + return Optional.ofNullable(getLiteralValue((Literal) exp)); + } else if (exp instanceof NewArray) { + NewArray array = (NewArray) exp; + List entries = array.getInitializer(); + if (entries != null) { + for (Expression e : entries) { + Optional 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 beanId(List 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 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; + } + }