Remove JDT
This commit is contained in:
@@ -99,12 +99,12 @@
|
||||
<artifactId>commons-language-server</artifactId>
|
||||
<version>${dependencies.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>org.eclipse.jdt</groupId>
|
||||
<artifactId>org.eclipse.jdt.core</artifactId>
|
||||
<version>${jdt.core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
--> <dependency>
|
||||
<groupId>org.openrewrite</groupId>
|
||||
<artifactId>rewrite-java</artifactId>
|
||||
<version>${rewrite-version}</version>
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.springframework.ide.vscode.boot.java.links.JdtJavaDocumentUriProvider
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
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.java.utils.SymbolCacheOnDisc;
|
||||
@@ -159,8 +158,8 @@ public class BootLanguageServerBootApp {
|
||||
return new ORCompilationUnitCache(params.projectFinder, server, params.projectObserver);
|
||||
}
|
||||
|
||||
@Bean CompilationUnitCache cuCache(SimpleLanguageServer server, BootLanguageServerParams params) {
|
||||
return new CompilationUnitCache(params.projectFinder, server, params.projectObserver);
|
||||
@Bean ORCompilationUnitCache cuCache(SimpleLanguageServer server, BootLanguageServerParams params) {
|
||||
return new ORCompilationUnitCache(params.projectFinder, server, params.projectObserver);
|
||||
}
|
||||
|
||||
@Bean SpringXMLCompletionEngine xmlCompletionEngine(SimpleLanguageServer server, JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex, BootJavaConfig config) {
|
||||
|
||||
@@ -302,7 +302,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE,
|
||||
new ValuePropertyReferencesProvider(server));
|
||||
|
||||
return new BootJavaReferencesHandler(this, projectFinder, providers);
|
||||
return new BootJavaReferencesHandler(this, projectFinder, providers, cuCache);
|
||||
}
|
||||
|
||||
protected BootJavaCodeLensEngine createCodeLensEngine(SpringSymbolIndex index) {
|
||||
|
||||
@@ -18,7 +18,6 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
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;
|
||||
@@ -48,21 +47,15 @@ public abstract class AnnotationHierarchies {
|
||||
};
|
||||
|
||||
public static Collection<FullyQualified> getDirectSuperAnnotations(FullyQualified type) {
|
||||
try {
|
||||
List<FullyQualified> annotations = type.getAnnotations();
|
||||
if (annotations != null && !annotations.isEmpty()) {
|
||||
ImmutableList.Builder<FullyQualified> superAnnotations = ImmutableList.builder();
|
||||
for (FullyQualified ab : annotations) {
|
||||
if (!ignoreAnnotation(ab.getFullyQualifiedName())) {
|
||||
superAnnotations.add(ab);
|
||||
}
|
||||
List<FullyQualified> annotations = type.getAnnotations();
|
||||
if (annotations != null && !annotations.isEmpty()) {
|
||||
ImmutableList.Builder<FullyQualified> superAnnotations = ImmutableList.builder();
|
||||
for (FullyQualified ab : annotations) {
|
||||
if (!ignoreAnnotation(ab.getFullyQualifiedName())) {
|
||||
superAnnotations.add(ab);
|
||||
}
|
||||
return superAnnotations.build();
|
||||
}
|
||||
} 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 superAnnotations.build();
|
||||
}
|
||||
|
||||
return ImmutableList.of();
|
||||
|
||||
@@ -11,12 +11,10 @@
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.openrewrite.internal.lang.Nullable;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
@@ -25,13 +23,11 @@ import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.J.Modifier;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.JavaType.Method;
|
||||
import org.openrewrite.java.tree.JavaType.Parameterized;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CachedSymbol;
|
||||
import org.springframework.ide.vscode.boot.java.utils.FunctionUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
@@ -42,7 +38,6 @@ import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.reflect.Parameter;
|
||||
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuple3;
|
||||
|
||||
@@ -11,24 +11,24 @@
|
||||
package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.NodeFinder;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.ReferenceParams;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
@@ -46,11 +46,14 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
|
||||
private JavaProjectFinder projectFinder;
|
||||
private BootJavaLanguageServerComponents server;
|
||||
private Map<String, ReferenceProvider> referenceProviders;
|
||||
private ORCompilationUnitCache cuCache;
|
||||
|
||||
public BootJavaReferencesHandler(BootJavaLanguageServerComponents server, JavaProjectFinder projectFinder, Map<String, ReferenceProvider> specificProviders) {
|
||||
public BootJavaReferencesHandler(BootJavaLanguageServerComponents server, JavaProjectFinder projectFinder, Map<String, ReferenceProvider> specificProviders, ORCompilationUnitCache cuCache) {
|
||||
this.server = server;
|
||||
this.projectFinder = projectFinder;
|
||||
this.referenceProviders = specificProviders;
|
||||
this.cuCache = cuCache;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,59 +86,38 @@ public class BootJavaReferencesHandler implements ReferencesHandler {
|
||||
}
|
||||
|
||||
private List<? extends Location> provideReferences(CancelChecker cancelToken, TextDocument document, int offset) throws Exception {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS16);
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_16, options);
|
||||
parser.setCompilerOptions(options);
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
parser.setStatementsRecovery(true);
|
||||
parser.setBindingsRecovery(true);
|
||||
parser.setResolveBindings(true);
|
||||
Optional<IJavaProject> project = projectFinder.find(document.getId());
|
||||
if (project.isPresent()) {
|
||||
return cuCache.withCompilationUnit(project.get(), URI.create(document.getUri()), cu -> {
|
||||
J node = ORAstUtils.findAstNodeAt(cu, offset);
|
||||
|
||||
if (node != null) {
|
||||
cancelToken.checkCanceled();
|
||||
return provideReferencesForAnnotation(cancelToken, node, offset, document);
|
||||
}
|
||||
|
||||
String[] classpathEntries = getClasspathEntries(document);
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
|
||||
|
||||
String docURI = document.getUri();
|
||||
String unitName = docURI.substring(docURI.lastIndexOf("/"));
|
||||
parser.setUnitName(unitName);
|
||||
parser.setSource(document.get(0, document.getLength()).toCharArray());
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
ASTNode node = NodeFinder.perform(cu, offset, 0);
|
||||
|
||||
if (node != null) {
|
||||
cancelToken.checkCanceled();
|
||||
return provideReferencesForAnnotation(cancelToken, node, offset, document);
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<? extends Location> provideReferencesForAnnotation(CancelChecker cancelToken, ASTNode node, int offset, TextDocument doc) {
|
||||
Annotation annotation = null;
|
||||
|
||||
while (node != null && !(node instanceof Annotation)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
private List<? extends Location> provideReferencesForAnnotation(CancelChecker cancelToken, J node, int offset, TextDocument doc) {
|
||||
if (node != null) {
|
||||
annotation = (Annotation) node;
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
Annotation annotation = ORAstUtils.findNode(node, Annotation.class);
|
||||
|
||||
String qualifiedName = type.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
ReferenceProvider provider = this.referenceProviders.get(qualifiedName);
|
||||
if (provider != null) {
|
||||
return provider.provideReferences(cancelToken, node, annotation, type, offset, doc);
|
||||
}
|
||||
if (annotation != null) {
|
||||
FullyQualified type = TypeUtils.asFullyQualified(annotation.getType());
|
||||
if (type != null) {
|
||||
ReferenceProvider provider = this.referenceProviders.get(type.getFullyQualifiedName());
|
||||
if (provider != null) {
|
||||
return provider.provideReferences(cancelToken, node, annotation, type, offset, doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,11 +12,11 @@ package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.Location;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
*/
|
||||
public interface ReferenceProvider {
|
||||
|
||||
List<? extends Location> provideReferences(CancelChecker cancelToken, ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc);
|
||||
List<? extends Location> provideReferences(CancelChecker cancelToken, J node, Annotation annotation,
|
||||
FullyQualified type, int offset, TextDocument doc);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,558 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Derived from:
|
||||
* org.eclipse.jdt.core.dom.rewrite.ImportRewrite
|
||||
*
|
||||
* for use in STS4, where IProject and ICompilationUnit are not available when parsing a Java source.
|
||||
*
|
||||
* Original license:
|
||||
*
|
||||
* Copyright (c) 2000, 2016 IBM Corporation and others.
|
||||
* 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM Corporation - initial API and implementation
|
||||
* John Glassmyer <jogl@google.com> - import group sorting is broken - https://bugs.eclipse.org/430303
|
||||
* Lars Vogel <Lars.Vogel@vogella.com> - Contributions for
|
||||
* Bug 473178
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.jdt.imports;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.jdt.core.ICompilationUnit;
|
||||
import org.eclipse.jdt.core.compiler.CharOperation;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.Comment;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ImportDeclaration;
|
||||
import org.eclipse.jdt.core.dom.PackageDeclaration;
|
||||
import org.eclipse.jdt.core.dom.PrimitiveType;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
|
||||
/**
|
||||
* The {@link ImportRewrite} helps updating imports following a import order and on-demand imports threshold as configured by a project.
|
||||
* <p>
|
||||
* The import rewrite is created on a compilation unit and collects references to types that are added or removed. When adding imports, e.g. using
|
||||
* {@link #addImport(String)}, the import rewrite evaluates if the type can be imported and returns the a reference to the type that can be used in code.
|
||||
* This reference is either unqualified if the import could be added, or fully qualified if the import failed due to a conflict with another element of the same name.
|
||||
* </p>
|
||||
* <p>
|
||||
* On {@link #rewriteImports(IProgressMonitor)} the rewrite translates these descriptions into
|
||||
* text edits that can then be applied to the original source. The rewrite infrastructure tries to generate minimal text changes and only
|
||||
* works on the import statements. It is possible to combine the result of an import rewrite with the result of a {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite}
|
||||
* as long as no import statements are modified by the AST rewrite.
|
||||
* </p>
|
||||
* <p>The options controlling the import order and on-demand thresholds are:
|
||||
* <ul><li>{@link #setImportOrder(String[])} specifies the import groups and their preferred order</li>
|
||||
* <li>{@link #setOnDemandImportThreshold(int)} specifies the number of imports in a group needed for a on-demand import statement (star import)</li>
|
||||
* <li>{@link #setStaticOnDemandImportThreshold(int)} specifies the number of static imports in a group needed for a on-demand import statement (star import)</li>
|
||||
*</ul>
|
||||
* This class is not intended to be subclassed.
|
||||
* </p>
|
||||
* @since 3.2
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public final class ImportRewrite {
|
||||
|
||||
/**
|
||||
* A {@link ImportRewrite.ImportRewriteContext} can optionally be used in e.g. {@link ImportRewrite#addImport(String, ImportRewrite.ImportRewriteContext)} to
|
||||
* give more information about the types visible in the scope. These types can be for example inherited inner types where it is
|
||||
* unnecessary to add import statements for.
|
||||
*
|
||||
* </p>
|
||||
* <p>
|
||||
* This class can be implemented by clients.
|
||||
* </p>
|
||||
*/
|
||||
public static abstract class ImportRewriteContext {
|
||||
|
||||
/**
|
||||
* Result constant signaling that the given element is know in the context.
|
||||
*/
|
||||
public final static int RES_NAME_FOUND= 1;
|
||||
|
||||
/**
|
||||
* Result constant signaling that the given element is not know in the context.
|
||||
*/
|
||||
public final static int RES_NAME_UNKNOWN= 2;
|
||||
|
||||
/**
|
||||
* Result constant signaling that the given element is conflicting with an other element in the context.
|
||||
*/
|
||||
public final static int RES_NAME_CONFLICT= 3;
|
||||
|
||||
/**
|
||||
* Result constant signaling that the given element must be imported explicitly (and must not be folded into
|
||||
* an on-demand import or filtered as an implicit import).
|
||||
*
|
||||
* @since 3.11
|
||||
*/
|
||||
public final static int RES_NAME_UNKNOWN_NEEDS_EXPLICIT_IMPORT= 4;
|
||||
|
||||
/**
|
||||
* Kind constant specifying that the element is a type import.
|
||||
*/
|
||||
public final static int KIND_TYPE= 1;
|
||||
|
||||
/**
|
||||
* Kind constant specifying that the element is a static field import.
|
||||
*/
|
||||
public final static int KIND_STATIC_FIELD= 2;
|
||||
|
||||
/**
|
||||
* Kind constant specifying that the element is a static method import.
|
||||
*/
|
||||
public final static int KIND_STATIC_METHOD= 3;
|
||||
|
||||
/**
|
||||
* Searches for the given element in the context and reports if the element is known ({@link #RES_NAME_FOUND}),
|
||||
* unknown ({@link #RES_NAME_UNKNOWN}), unknown in the context but known to require an explicit import
|
||||
* ({@link #RES_NAME_UNKNOWN_NEEDS_EXPLICIT_IMPORT}), or if its name conflicts ({@link #RES_NAME_CONFLICT})
|
||||
* with an other element.
|
||||
*
|
||||
* @param qualifier The qualifier of the element, can be package or the qualified name of a type
|
||||
* @param name The simple name of the element; either a type, method or field name or * for on-demand imports.
|
||||
* @param kind The kind of the element. Can be either {@link #KIND_TYPE}, {@link #KIND_STATIC_FIELD} or
|
||||
* {@link #KIND_STATIC_METHOD}. Implementors should be prepared for new, currently unspecified kinds and return
|
||||
* {@link #RES_NAME_UNKNOWN} by default.
|
||||
* @return Returns the result of the lookup. Can be either {@link #RES_NAME_FOUND}, {@link #RES_NAME_UNKNOWN},
|
||||
* {@link #RES_NAME_CONFLICT}, or {@link #RES_NAME_UNKNOWN_NEEDS_EXPLICIT_IMPORT}.
|
||||
*/
|
||||
public abstract int findInContext(String qualifier, String name, int kind);
|
||||
}
|
||||
|
||||
private static final char STATIC_PREFIX= 's';
|
||||
private static final char NORMAL_PREFIX= 'n';
|
||||
|
||||
private final ImportRewriteContext defaultContext;
|
||||
|
||||
private final CompilationUnit astRoot;
|
||||
|
||||
private final boolean restoreExistingImports;
|
||||
private final List existingImports;
|
||||
|
||||
|
||||
private List<String> addedImports;
|
||||
|
||||
/**
|
||||
* Simple names of non-static imports which must not be reduced into on-demand imports
|
||||
* or filtered out as implicit.
|
||||
*/
|
||||
private Set<String> typeExplicitSimpleNames;
|
||||
|
||||
|
||||
private boolean filterImplicitImports;
|
||||
private boolean useContextToFilterImplicitImports;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an {@link ImportRewrite} from an AST ({@link CompilationUnit}). The AST has to be created from an
|
||||
* {@link ICompilationUnit}, that means {@link ASTParser#setSource(ICompilationUnit)} has been used when creating the
|
||||
* AST. If <code>restoreExistingImports</code> is <code>true</code>, all existing imports are kept, and new imports
|
||||
* will be inserted at best matching locations. If <code>restoreExistingImports</code> is <code>false</code>, the
|
||||
* existing imports will be removed and only the newly added imports will be created.
|
||||
* <p>
|
||||
* Note that this method is more efficient than using {@link #create(ICompilationUnit, boolean)} if an AST is already available.
|
||||
* </p>
|
||||
* @param astRoot the AST root node to create the imports for
|
||||
* @param restoreExistingImports specifies if the existing imports should be kept or removed.
|
||||
* @return the created import rewriter.
|
||||
* @throws IllegalArgumentException thrown when the passed AST is null or was not created from a compilation unit.
|
||||
*/
|
||||
public static ImportRewrite create(CompilationUnit astRoot, boolean restoreExistingImports) {
|
||||
if (astRoot == null) {
|
||||
throw new IllegalArgumentException("AST must not be null"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
List existingImport= null;
|
||||
if (restoreExistingImports) {
|
||||
existingImport= new ArrayList();
|
||||
List imports= astRoot.imports();
|
||||
for (int i= 0; i < imports.size(); i++) {
|
||||
ImportDeclaration curr= (ImportDeclaration) imports.get(i);
|
||||
StringBuffer buf= new StringBuffer();
|
||||
buf.append(curr.isStatic() ? STATIC_PREFIX : NORMAL_PREFIX).append(curr.getName().getFullyQualifiedName());
|
||||
if (curr.isOnDemand()) {
|
||||
if (buf.length() > 1)
|
||||
buf.append('.');
|
||||
buf.append('*');
|
||||
}
|
||||
existingImport.add(buf.toString());
|
||||
}
|
||||
}
|
||||
return new ImportRewrite(astRoot, existingImport);
|
||||
}
|
||||
|
||||
private ImportRewrite(CompilationUnit astRoot, List existingImports) {
|
||||
this.astRoot= astRoot; // might be null
|
||||
if (existingImports != null) {
|
||||
this.existingImports= existingImports;
|
||||
this.restoreExistingImports= !existingImports.isEmpty();
|
||||
} else {
|
||||
this.existingImports= new ArrayList();
|
||||
this.restoreExistingImports= false;
|
||||
}
|
||||
this.filterImplicitImports= true;
|
||||
// consider that no contexts are used
|
||||
this.useContextToFilterImplicitImports = false;
|
||||
|
||||
this.defaultContext= new ImportRewriteContext() {
|
||||
@Override
|
||||
public int findInContext(String qualifier, String name, int kind) {
|
||||
return findInImports(qualifier, name, kind);
|
||||
}
|
||||
};
|
||||
this.addedImports= new ArrayList<>();
|
||||
this.typeExplicitSimpleNames = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default rewrite context that only knows about the imported types. Clients
|
||||
* can write their own context and use the default context for the default behavior.
|
||||
* @return the default import rewrite context.
|
||||
*/
|
||||
public ImportRewriteContext getDefaultImportRewriteContext() {
|
||||
return this.defaultContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that implicit imports (for types in <code>java.lang</code>, types in the same package as the rewrite
|
||||
* compilation unit, and types in the compilation unit's main type) should not be created, except if necessary to
|
||||
* resolve an on-demand import conflict.
|
||||
* <p>
|
||||
* The filter is enabled by default.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: {@link #setUseContextToFilterImplicitImports(boolean)} can be used to filter implicit imports
|
||||
* when a context is used.
|
||||
* </p>
|
||||
*
|
||||
* @param filterImplicitImports
|
||||
* if <code>true</code>, implicit imports will be filtered
|
||||
*
|
||||
* @see #setUseContextToFilterImplicitImports(boolean)
|
||||
*/
|
||||
public void setFilterImplicitImports(boolean filterImplicitImports) {
|
||||
this.filterImplicitImports= filterImplicitImports;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a context should be used to properly filter implicit imports.
|
||||
* <p>
|
||||
* By default, the option is disabled to preserve pre-3.6 behavior.
|
||||
* </p>
|
||||
* <p>
|
||||
* When this option is set, the context passed to the <code>addImport*(...)</code> methods is used to determine
|
||||
* whether an import can be filtered because the type is implicitly visible. Note that too many imports
|
||||
* may be kept if this option is set and <code>addImport*(...)</code> methods are called without a context.
|
||||
* </p>
|
||||
*
|
||||
* @param useContextToFilterImplicitImports the given setting
|
||||
*
|
||||
* @see #setFilterImplicitImports(boolean)
|
||||
* @since 3.6
|
||||
*/
|
||||
public void setUseContextToFilterImplicitImports(boolean useContextToFilterImplicitImports) {
|
||||
this.useContextToFilterImplicitImports = useContextToFilterImplicitImports;
|
||||
}
|
||||
|
||||
private static int compareImport(char prefix, String qualifier, String name, String curr) {
|
||||
if (curr.charAt(0) != prefix || !curr.endsWith(name)) {
|
||||
return ImportRewriteContext.RES_NAME_UNKNOWN;
|
||||
}
|
||||
|
||||
curr= curr.substring(1); // remove the prefix
|
||||
|
||||
if (curr.length() == name.length()) {
|
||||
if (qualifier.length() == 0) {
|
||||
return ImportRewriteContext.RES_NAME_FOUND;
|
||||
}
|
||||
return ImportRewriteContext.RES_NAME_CONFLICT;
|
||||
}
|
||||
// at this place: curr.length > name.length
|
||||
|
||||
int dotPos= curr.length() - name.length() - 1;
|
||||
if (curr.charAt(dotPos) != '.') {
|
||||
return ImportRewriteContext.RES_NAME_UNKNOWN;
|
||||
}
|
||||
if (qualifier.length() != dotPos || !curr.startsWith(qualifier)) {
|
||||
return ImportRewriteContext.RES_NAME_CONFLICT;
|
||||
}
|
||||
return ImportRewriteContext.RES_NAME_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not API, package visibility as accessed from an anonymous type
|
||||
*/
|
||||
/* package */ final int findInImports(String qualifier, String name, int kind) {
|
||||
boolean allowAmbiguity= (kind == ImportRewriteContext.KIND_STATIC_METHOD) || (name.length() == 1 && name.charAt(0) == '*');
|
||||
List imports= this.existingImports;
|
||||
char prefix= (kind == ImportRewriteContext.KIND_TYPE) ? NORMAL_PREFIX : STATIC_PREFIX;
|
||||
|
||||
for (int i= imports.size() - 1; i >= 0 ; i--) {
|
||||
String curr= (String) imports.get(i);
|
||||
int res= compareImport(prefix, qualifier, name, curr);
|
||||
if (res != ImportRewriteContext.RES_NAME_UNKNOWN) {
|
||||
if (!allowAmbiguity || res == ImportRewriteContext.RES_NAME_FOUND) {
|
||||
if (prefix != STATIC_PREFIX) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String packageName = getPackageName();
|
||||
if (kind == ImportRewriteContext.KIND_TYPE) {
|
||||
if (this.filterImplicitImports && this.useContextToFilterImplicitImports) {
|
||||
|
||||
// [STS4] No ICompilationUnit available as there is no class file or associated IJavaElement available for the source
|
||||
|
||||
// String mainTypeSimpleName= JavaCore.removeJavaLikeExtension(this.compilationUnit.getElementName());
|
||||
// String mainTypeName= Util.concatenateName(packageName, mainTypeSimpleName, '.');
|
||||
// if (qualifier.equals(packageName)
|
||||
// || mainTypeName.equals(Util.concatenateName(qualifier, name, '.'))) {
|
||||
// return ImportRewriteContext.RES_NAME_FOUND;
|
||||
// }
|
||||
|
||||
if (this.astRoot != null) {
|
||||
List<AbstractTypeDeclaration> types = this.astRoot.types();
|
||||
int nTypes = types.size();
|
||||
for (int i = 0; i < nTypes; i++) {
|
||||
AbstractTypeDeclaration type = types.get(i);
|
||||
SimpleName simpleName = type.getName();
|
||||
if (simpleName.getIdentifier().equals(name)) {
|
||||
return qualifier.equals(packageName)
|
||||
? ImportRewriteContext.RES_NAME_FOUND
|
||||
: ImportRewriteContext.RES_NAME_CONFLICT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// [STS4] No ICompilationUnit available as there is no class file or associated IJavaElement available for the source
|
||||
// try {
|
||||
// IType[] types = this.compilationUnit.getTypes();
|
||||
// int nTypes = types.length;
|
||||
// for (int i = 0; i < nTypes; i++) {
|
||||
// IType type = types[i];
|
||||
// String typeName = type.getElementName();
|
||||
// if (typeName.equals(name)) {
|
||||
// return qualifier.equals(packageName)
|
||||
// ? ImportRewriteContext.RES_NAME_FOUND
|
||||
// : ImportRewriteContext.RES_NAME_CONFLICT;
|
||||
// }
|
||||
// }
|
||||
// } catch (JavaModelException e) {
|
||||
// // don't want to throw an exception here
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ImportRewriteContext.RES_NAME_UNKNOWN;
|
||||
}
|
||||
|
||||
private String getPackageName() {
|
||||
// [STS4] No ICompilationUnit available as there is no class file or associated IJavaElement available for the source
|
||||
// this.compilationUnit.getParent().getElementName();
|
||||
return this.astRoot.getPackage().getName().getFullyQualifiedName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new import to the rewriter's record and returns a type reference that can be used
|
||||
* in the code. The type binding can only be an array or non-generic type.
|
||||
* <p>
|
||||
* No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead.
|
||||
* </p>
|
||||
* <p>
|
||||
* The content of the compilation unit itself is actually not modified
|
||||
* in any way by this method; rather, the rewriter just records that a new import has been added.
|
||||
* </p>
|
||||
* @param qualifiedTypeName the qualified type name of the type to be added
|
||||
* @param context an optional context that knows about types visible in the current scope or <code>null</code>
|
||||
* to use the default context only using the available imports.
|
||||
* @return a type reference for the given qualified type name. The type name is a simple name if an import could be used,
|
||||
* or else a qualified name if an import conflict prevented an import.
|
||||
*/
|
||||
public String addImport(String qualifiedTypeName, ImportRewriteContext context) {
|
||||
int angleBracketOffset= qualifiedTypeName.indexOf('<');
|
||||
if (angleBracketOffset != -1) {
|
||||
return internalAddImport(qualifiedTypeName.substring(0, angleBracketOffset), context) + qualifiedTypeName.substring(angleBracketOffset);
|
||||
}
|
||||
int bracketOffset= qualifiedTypeName.indexOf('[');
|
||||
if (bracketOffset != -1) {
|
||||
return internalAddImport(qualifiedTypeName.substring(0, bracketOffset), context) + qualifiedTypeName.substring(bracketOffset);
|
||||
}
|
||||
return internalAddImport(qualifiedTypeName, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new import to the rewriter's record and returns a type reference that can be used
|
||||
* in the code. The type binding can only be an array or non-generic type.
|
||||
* <p>
|
||||
* No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead.
|
||||
* </p>
|
||||
* <p>
|
||||
* The content of the compilation unit itself is actually not modified
|
||||
* in any way by this method; rather, the rewriter just records that a new import has been added.
|
||||
* </p>
|
||||
* @param qualifiedTypeName the qualified type name of the type to be added
|
||||
* @return a type reference for the given qualified type name. The type name is a simple name if an import could be used,
|
||||
* or else a qualified name if an import conflict prevented an import.
|
||||
*/
|
||||
public String addImport(String qualifiedTypeName) {
|
||||
return addImport(qualifiedTypeName, this.defaultContext);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String internalAddImport(String fullTypeName, ImportRewriteContext context) {
|
||||
int idx= fullTypeName.lastIndexOf('.');
|
||||
String typeContainerName, typeName;
|
||||
if (idx != -1) {
|
||||
typeContainerName= fullTypeName.substring(0, idx);
|
||||
typeName= fullTypeName.substring(idx + 1);
|
||||
} else {
|
||||
typeContainerName= ""; //$NON-NLS-1$
|
||||
typeName= fullTypeName;
|
||||
}
|
||||
|
||||
if (typeContainerName.length() == 0 && PrimitiveType.toCode(typeName) != null) {
|
||||
return fullTypeName;
|
||||
}
|
||||
|
||||
if (context == null)
|
||||
context= this.defaultContext;
|
||||
|
||||
int res= context.findInContext(typeContainerName, typeName, ImportRewriteContext.KIND_TYPE);
|
||||
if (res == ImportRewriteContext.RES_NAME_CONFLICT) {
|
||||
return fullTypeName;
|
||||
}
|
||||
if (res == ImportRewriteContext.RES_NAME_UNKNOWN) {
|
||||
addEntry(NORMAL_PREFIX + fullTypeName);
|
||||
}
|
||||
if (res == ImportRewriteContext.RES_NAME_UNKNOWN_NEEDS_EXPLICIT_IMPORT) {
|
||||
addEntry(NORMAL_PREFIX + fullTypeName);
|
||||
this.typeExplicitSimpleNames.add(typeName);
|
||||
}
|
||||
return typeName;
|
||||
}
|
||||
|
||||
private void addEntry(String entry) {
|
||||
this.existingImports.add(entry);
|
||||
|
||||
this.addedImports.add(entry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all non-static imports that are recorded to be added.
|
||||
*
|
||||
* @return the imports recorded to be added.
|
||||
*/
|
||||
public String[] getAddedImports() {
|
||||
return filterFromList(this.addedImports, NORMAL_PREFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if imports have been recorded to be added or removed.
|
||||
* @return boolean returns if any changes to imports have been recorded.
|
||||
*/
|
||||
public boolean hasRecordedChanges() {
|
||||
return !this.restoreExistingImports
|
||||
|| !this.addedImports.isEmpty();
|
||||
}
|
||||
|
||||
private static String[] filterFromList(List<String> imports, char prefix) {
|
||||
if (imports == null) {
|
||||
return CharOperation.NO_STRINGS;
|
||||
}
|
||||
List<String> res= new ArrayList<>();
|
||||
for (String curr : imports) {
|
||||
if (prefix == curr.charAt(0)) {
|
||||
res.add(curr.substring(1));
|
||||
}
|
||||
}
|
||||
return res.toArray(new String[res.size()]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the positions of each existing import declaration along with any associated comments,
|
||||
* and returns these in a list whose iteration order reflects the existing order of the imports
|
||||
* in the compilation unit.
|
||||
*/
|
||||
private int getAddedImportsInsertLocation() {
|
||||
List<ImportDeclaration> importDeclarations = astRoot.imports();
|
||||
|
||||
if (importDeclarations == null) {
|
||||
importDeclarations = Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Comment> comments = astRoot.getCommentList();
|
||||
|
||||
int currentCommentIndex = 0;
|
||||
|
||||
// Skip over package and file header comments (see https://bugs.eclipse.org/121428).
|
||||
ImportDeclaration firstImport = importDeclarations.get(0);
|
||||
PackageDeclaration packageDeclaration = astRoot.getPackage();
|
||||
int firstImportStartPosition = packageDeclaration == null
|
||||
? firstImport.getStartPosition()
|
||||
: astRoot.getExtendedStartPosition(packageDeclaration)
|
||||
+ astRoot.getExtendedLength(packageDeclaration);
|
||||
while (currentCommentIndex < comments.size()
|
||||
&& comments.get(currentCommentIndex).getStartPosition() < firstImportStartPosition) {
|
||||
currentCommentIndex++;
|
||||
}
|
||||
|
||||
int previousExtendedEndPosition = -1;
|
||||
for (ImportDeclaration currentImport : importDeclarations) {
|
||||
int extendedEndPosition = astRoot.getExtendedStartPosition(currentImport)
|
||||
+ astRoot.getExtendedLength(currentImport);
|
||||
|
||||
int commentAfterImportIndex = currentCommentIndex;
|
||||
while (commentAfterImportIndex < comments.size()
|
||||
&& comments.get(commentAfterImportIndex).getStartPosition() < extendedEndPosition) {
|
||||
commentAfterImportIndex++;
|
||||
}
|
||||
|
||||
|
||||
currentCommentIndex = commentAfterImportIndex;
|
||||
previousExtendedEndPosition = extendedEndPosition;
|
||||
}
|
||||
|
||||
return previousExtendedEndPosition;
|
||||
}
|
||||
|
||||
public DocumentEdits createEdit(IDocument doc) {
|
||||
DocumentEdits edits = null;
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
String[] createdImprts = getAddedImports();
|
||||
if (createdImprts != null && createdImprts.length >0) {
|
||||
edits =new DocumentEdits(doc, false);
|
||||
buffer.append('\n');
|
||||
for (String imp : createdImprts) {
|
||||
buffer.append("import ");
|
||||
buffer.append(imp);
|
||||
buffer.append(';');
|
||||
buffer.append('\n');
|
||||
}
|
||||
edits.insert(getAddedImportsInsertLocation(), buffer.toString());
|
||||
|
||||
}
|
||||
return edits;
|
||||
}
|
||||
}
|
||||
@@ -15,24 +15,14 @@ import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
|
||||
import org.eclipse.jdt.core.dom.EnumDeclaration;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IField;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.IMember;
|
||||
import org.springframework.ide.vscode.commons.java.IMethod;
|
||||
import org.springframework.ide.vscode.commons.java.IType;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
public class DefaultJavaElementLocationProvider implements JavaElementLocationProvider {
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
@@ -28,7 +27,6 @@ import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider
|
||||
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;
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.lsp4j.CodeLens;
|
||||
import org.eclipse.lsp4j.Command;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
@@ -33,7 +32,6 @@ 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.boot.java.utils.SpringResource;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2019 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
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.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;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public class ASTUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ASTUtils.class);
|
||||
|
||||
public static DocumentRegion nameRegion(TextDocument doc, Annotation annotation) {
|
||||
int start = annotation.getTypeName().getStartPosition();
|
||||
int end = start + annotation.getTypeName().getLength();
|
||||
if (doc.getSafeChar(start - 1) == '@') {
|
||||
start--;
|
||||
}
|
||||
return new DocumentRegion(doc, start, end);
|
||||
}
|
||||
|
||||
public static Optional<Range> nameRange(TextDocument doc, Annotation annotation) {
|
||||
try {
|
||||
return Optional.of(nameRegion(doc, annotation).asRange());
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentRegion stringRegion(TextDocument doc, StringLiteral node) {
|
||||
DocumentRegion nodeRegion = nodeRegion(doc, node);
|
||||
if (nodeRegion.startsWith("\"")) {
|
||||
nodeRegion = nodeRegion.subSequence(1);
|
||||
}
|
||||
if (nodeRegion.endsWith("\"")) {
|
||||
nodeRegion = nodeRegion.subSequence(0, nodeRegion.getLength()-1);
|
||||
}
|
||||
return nodeRegion;
|
||||
}
|
||||
|
||||
|
||||
public static DocumentRegion nodeRegion(TextDocument doc, ASTNode node) {
|
||||
int start = node.getStartPosition();
|
||||
int end = start + node.getLength();
|
||||
return new DocumentRegion(doc, start, end);
|
||||
}
|
||||
|
||||
public static Optional<Expression> getAttribute(Annotation annotation, String name) {
|
||||
if (annotation != null) {
|
||||
try {
|
||||
if (annotation.isSingleMemberAnnotation() && name.equals("value")) {
|
||||
SingleMemberAnnotation sma = (SingleMemberAnnotation) annotation;
|
||||
return Optional.ofNullable(sma.getValue());
|
||||
} else if (annotation.isNormalAnnotation()) {
|
||||
NormalAnnotation na = (NormalAnnotation) annotation;
|
||||
Object attributeObjs = na.getStructuralProperty(NormalAnnotation.VALUES_PROPERTY);
|
||||
if (attributeObjs instanceof List) {
|
||||
for (Object atrObj : (List<?>)attributeObjs) {
|
||||
if (atrObj instanceof MemberValuePair) {
|
||||
MemberValuePair mvPair = (MemberValuePair) atrObj;
|
||||
if (name.equals(mvPair.getName().getIdentifier())) {
|
||||
return Optional.ofNullable(mvPair.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* For case where a expression can be either a String or a array of Strings and
|
||||
* we are interested in the first element of the array. (I.e. typical case
|
||||
* when annotation attribute is of type String[] (because Java allows using a single
|
||||
* value as a convenient syntax for writing an array of length 1 in that case.
|
||||
*/
|
||||
public static Optional<String> getFirstString(Expression exp) {
|
||||
if (exp instanceof StringLiteral) {
|
||||
return Optional.ofNullable(getLiteralValue((StringLiteral) exp));
|
||||
} else if (exp instanceof ArrayInitializer) {
|
||||
ArrayInitializer array = (ArrayInitializer) exp;
|
||||
Object objs = array.getStructuralProperty(ArrayInitializer.EXPRESSIONS_PROPERTY);
|
||||
if (objs instanceof List) {
|
||||
List<?> list = (List<?>) objs;
|
||||
if (!list.isEmpty()) {
|
||||
Object firstObj = list.get(0);
|
||||
if (firstObj instanceof Expression) {
|
||||
return getFirstString((Expression) firstObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static TypeDeclaration findDeclaringType(ASTNode node) {
|
||||
while (node != null && !(node instanceof TypeDeclaration)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
return node != null ? (TypeDeclaration) node : null;
|
||||
}
|
||||
|
||||
public static boolean hasExactlyOneConstructor(TypeDeclaration typeDecl) {
|
||||
boolean oneFound = false;
|
||||
MethodDeclaration[] methods = typeDecl.getMethods();
|
||||
for (MethodDeclaration methodDeclaration : methods) {
|
||||
if (methodDeclaration.isConstructor()) {
|
||||
if (oneFound) {
|
||||
return false;
|
||||
} else {
|
||||
oneFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return oneFound;
|
||||
}
|
||||
|
||||
public static MethodDeclaration getAnnotatedMethod(Annotation annotation) {
|
||||
ASTNode parent = annotation.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
return (MethodDeclaration)parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TypeDeclaration getAnnotatedType(Annotation annotation) {
|
||||
ASTNode parent = annotation.getParent();
|
||||
if (parent instanceof TypeDeclaration) {
|
||||
return (TypeDeclaration)parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getLiteralValue(StringLiteral node) {
|
||||
synchronized (node.getAST()) {
|
||||
return node.getLiteralValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getExpressionValueAsString(Expression exp, Consumer<ITypeBinding> dependencies) {
|
||||
if (exp instanceof StringLiteral) {
|
||||
return getLiteralValue((StringLiteral) exp);
|
||||
} else if (exp instanceof Name) {
|
||||
IBinding binding = ((Name) exp).resolveBinding();
|
||||
if (binding != null && binding.getKind() == IBinding.VARIABLE) {
|
||||
IVariableBinding varBinding = (IVariableBinding) binding;
|
||||
ITypeBinding klass = varBinding.getDeclaringClass();
|
||||
if (klass!=null) {
|
||||
dependencies.accept(klass);
|
||||
|
||||
|
||||
}
|
||||
Object constValue = varBinding.getConstantValue();
|
||||
if (constValue != null) {
|
||||
return constValue.toString();
|
||||
}
|
||||
}
|
||||
if (exp instanceof QualifiedName) {
|
||||
return getExpressionValueAsString(((QualifiedName) exp).getName(), dependencies);
|
||||
}
|
||||
else if (exp instanceof SimpleName) {
|
||||
return ((SimpleName) exp).getIdentifier();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static String[] getExpressionValueAsArray(Expression exp, Consumer<ITypeBinding> dependencies) {
|
||||
if (exp instanceof ArrayInitializer) {
|
||||
ArrayInitializer array = (ArrayInitializer) exp;
|
||||
return ((List<Expression>) array.expressions()).stream().map(e -> getExpressionValueAsString(e, dependencies))
|
||||
.filter(Objects::nonNull).toArray(String[]::new);
|
||||
} else {
|
||||
String rm = getExpressionValueAsString(exp, dependencies);
|
||||
if (rm != null) {
|
||||
return new String[] { rm };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<StringLiteral> getExpressionValueAsListOfLiterals(Expression exp) {
|
||||
if (exp instanceof ArrayInitializer) {
|
||||
ArrayInitializer array = (ArrayInitializer) exp;
|
||||
return ((List<Expression>) array.expressions()).stream()
|
||||
.flatMap(e -> e instanceof StringLiteral
|
||||
? Stream.of((StringLiteral)e)
|
||||
: Stream.empty()
|
||||
)
|
||||
.collect(CollectorUtil.toImmutableList());
|
||||
} else if (exp instanceof StringLiteral){
|
||||
return ImmutableList.of((StringLiteral)exp);
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
public static Collection<Annotation> getAnnotations(TypeDeclaration declaringType) {
|
||||
Object modifiersObj = declaringType.getStructuralProperty(TypeDeclaration.MODIFIERS2_PROPERTY);
|
||||
if (modifiersObj instanceof List) {
|
||||
ImmutableList.Builder<Annotation> annotations = ImmutableList.builder();
|
||||
for (Object node : (List<?>)modifiersObj) {
|
||||
if (node instanceof Annotation) {
|
||||
annotations.add((Annotation) node);
|
||||
}
|
||||
}
|
||||
return annotations.build();
|
||||
}
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
|
||||
public static String getAnnotationType(Annotation annotation) {
|
||||
ITypeBinding binding = annotation.resolveTypeBinding();
|
||||
if (binding!=null) {
|
||||
return binding.getQualifiedName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Optional<String> beanId(List<Object> modifiers) {
|
||||
return modifiers.stream()
|
||||
.filter(m -> m instanceof SingleMemberAnnotation)
|
||||
.map(m -> (SingleMemberAnnotation) m)
|
||||
.filter(m -> {
|
||||
ITypeBinding typeBinding = m.resolveTypeBinding();
|
||||
if (typeBinding != null) {
|
||||
return Annotations.QUALIFIER.equals(typeBinding.getQualifiedName());
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.findFirst()
|
||||
.map(a -> a.getValue())
|
||||
.filter(e -> e != null)
|
||||
.map(e -> e.resolveConstantExpressionValue())
|
||||
.filter(o -> o instanceof String)
|
||||
.map(o -> (String) o);
|
||||
}
|
||||
|
||||
public static Annotation getBeanAnnotation(MethodDeclaration method) {
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
ITypeBinding typeBinding = annotation.resolveTypeBinding();
|
||||
if (typeBinding != null) {
|
||||
String fqName = typeBinding.getQualifiedName();
|
||||
if (Annotations.BEAN.equals(fqName)) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,361 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.jdt.core.ICompilationUnit;
|
||||
import org.eclipse.jdt.core.JavaModelException;
|
||||
import org.eclipse.jdt.core.WorkingCopyOwner;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
|
||||
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
|
||||
import org.eclipse.jdt.internal.compiler.IProblemFactory;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
|
||||
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
|
||||
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
|
||||
import org.eclipse.jdt.internal.core.CancelableProblemFactory;
|
||||
import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* Reflection based implementation of JDT package public CompilationUnitResolver.
|
||||
* It is used to resolve the {@link CompilationUnitDeclaration}
|
||||
*
|
||||
* @author Alex Boyko
|
||||
*
|
||||
*/
|
||||
class CUResolver {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CUResolver.class);
|
||||
|
||||
private static final Supplier<Class<?>> BINDING_TABLES_CLASS = () -> {
|
||||
try {
|
||||
return Class.forName("org.eclipse.jdt.core.dom.DefaultBindingResolver$BindingTables");
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("{}", e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Supplier<Constructor<?>> BINDING_TABLES_CONSTRUCTOR = () -> {
|
||||
try {
|
||||
Class<?> clazz = BINDING_TABLES_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Constructor<?> ctor = clazz.getDeclaredConstructor();
|
||||
ctor.setAccessible(true);
|
||||
return ctor;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Method> GET_CLASSPATH_METHOD = () -> {
|
||||
try {
|
||||
Method getClasspathMethod = ASTParser.class.getDeclaredMethod("getClasspath");
|
||||
getClasspathMethod.setAccessible(true);
|
||||
return getClasspathMethod;
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Supplier<Class<?>> COMPILATION_UNIT_RESOLVER_CLASS = () -> {
|
||||
try {
|
||||
return Class.forName("org.eclipse.jdt.core.dom.CompilationUnitResolver");
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("{}", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private static final Supplier<Constructor<?>> COMPILATION_UNIT_RESOLVER_CONSTRUCTOR = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Constructor<?> ctor = clazz.getDeclaredConstructor(INameEnvironment.class, IErrorHandlingPolicy.class,
|
||||
CompilerOptions.class, ICompilerRequestor.class, IProblemFactory.class, IProgressMonitor.class,
|
||||
boolean.class);
|
||||
ctor.setAccessible(true);
|
||||
return ctor;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Constructor<?>> LOOKUP_ENVIRONMENT_CONSTRUCTOR = () -> {
|
||||
Class<?> nameEnvironmentWithProgressClass;
|
||||
try {
|
||||
nameEnvironmentWithProgressClass = Class.forName("org.eclipse.jdt.core.dom.NameEnvironmentWithProgress");
|
||||
Constructor<?> lookupCtor = nameEnvironmentWithProgressClass.getDeclaredConstructor(
|
||||
Classpath[].class,
|
||||
String[].class,
|
||||
IProgressMonitor.class
|
||||
);
|
||||
lookupCtor.setAccessible(true);
|
||||
return lookupCtor;
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Supplier<Method> GET_HANDLER_POLICY_METHOD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Method handlerPolicyMethod = clazz.getDeclaredMethod("getHandlingPolicy");
|
||||
handlerPolicyMethod.setAccessible(true);
|
||||
return handlerPolicyMethod;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Method> GET_REQUESTOR_METHOD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Method getRequestorMethod = clazz.getDeclaredMethod("getRequestor");
|
||||
getRequestorMethod.setAccessible(true);
|
||||
return getRequestorMethod;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Method> GET_COMPILER_OPTIONS_METHOD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Method compilerOptionsMethod = clazz.getDeclaredMethod("getCompilerOptions", Map.class, boolean.class);
|
||||
compilerOptionsMethod.setAccessible(true);
|
||||
return compilerOptionsMethod;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Class<?>> NODE_SEARCHER_CLASS = () -> {
|
||||
try {
|
||||
return Class.forName("org.eclipse.jdt.core.dom.NodeSearcher");
|
||||
} catch (ClassNotFoundException e) {
|
||||
log.error("{}", e);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Supplier<Method> PARSE_METHOD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
Class<?> nodeSearcherClass = NODE_SEARCHER_CLASS.get();
|
||||
if (clazz != null && nodeSearcherClass != null) {
|
||||
Method parseMethod = clazz.getDeclaredMethod("parse",
|
||||
org.eclipse.jdt.internal.compiler.env.ICompilationUnit.class,
|
||||
nodeSearcherClass,
|
||||
Map.class,
|
||||
int.class);
|
||||
parseMethod.setAccessible(true);
|
||||
return parseMethod;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Method> RESOLVE_METHOD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
Class<?> nodeSearcherClass = NODE_SEARCHER_CLASS.get();
|
||||
if (clazz != null && nodeSearcherClass != null) {
|
||||
Method resolveMethod = clazz.getDeclaredMethod("resolve",
|
||||
CompilationUnitDeclaration.class,
|
||||
org.eclipse.jdt.internal.compiler.env.ICompilationUnit.class,
|
||||
nodeSearcherClass,
|
||||
boolean.class,
|
||||
boolean.class,
|
||||
boolean.class);
|
||||
resolveMethod.setAccessible(true);
|
||||
return resolveMethod;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Method> CONVERT_METHOD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Method convertMethod = clazz.getDeclaredMethod("convert",
|
||||
CompilationUnitDeclaration.class,
|
||||
char[].class,
|
||||
int.class,
|
||||
Map.class,
|
||||
boolean.class,
|
||||
WorkingCopyOwner.class,
|
||||
BINDING_TABLES_CLASS.get(),
|
||||
int.class,
|
||||
IProgressMonitor.class,
|
||||
boolean.class);
|
||||
convertMethod.setAccessible(true);
|
||||
return convertMethod;
|
||||
}
|
||||
} catch (NoSuchMethodException | SecurityException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
private static final Supplier<Field> HAS_COMPILATION_ABORTED_FIELD = () -> {
|
||||
try {
|
||||
Class<?> clazz = COMPILATION_UNIT_RESOLVER_CLASS.get();
|
||||
if (clazz != null) {
|
||||
Field field = clazz.getDeclaredField("hasCompilationAborted");
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
static CompilationUnitDeclaration resolve(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit,
|
||||
List<Classpath> classpaths, Map<String, String> options, int flags, INameEnvironmentWithProgress environment)
|
||||
throws JavaModelException {
|
||||
try {
|
||||
|
||||
CompilerOptions compilerOptions = (CompilerOptions) GET_COMPILER_OPTIONS_METHOD.get().invoke(null, options,
|
||||
(flags & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0);
|
||||
CancelableProblemFactory problemFactory = new CancelableProblemFactory(new NullProgressMonitor());
|
||||
boolean ignoreMethodBodies = (flags & ICompilationUnit.IGNORE_METHOD_BODIES) != 0;
|
||||
compilerOptions.ignoreMethodBodies = ignoreMethodBodies;
|
||||
Object resolver = COMPILATION_UNIT_RESOLVER_CONSTRUCTOR.get().newInstance(environment,
|
||||
GET_HANDLER_POLICY_METHOD.get().invoke(null), compilerOptions,
|
||||
GET_REQUESTOR_METHOD.get().invoke(null), problemFactory, new NullProgressMonitor(), false);
|
||||
boolean analyzeAndGenerateCode = !ignoreMethodBodies;
|
||||
// no existing compilation unit declaration
|
||||
CompilationUnitDeclaration unit = (CompilationUnitDeclaration) RESOLVE_METHOD.get().invoke(resolver, null,
|
||||
sourceUnit, null, true, // method verification
|
||||
analyzeAndGenerateCode, // analyze code
|
||||
analyzeAndGenerateCode); // generate code
|
||||
boolean hasCompilationAborted = HAS_COMPILATION_ABORTED_FIELD.get().getBoolean(resolver);
|
||||
if (hasCompilationAborted) {
|
||||
// the bindings could not be resolved due to missing types in name environment
|
||||
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=86541
|
||||
CompilationUnitDeclaration unitDeclaration = parse(sourceUnit, options, flags);
|
||||
// if (unit != null) {
|
||||
// final int problemCount = unit.compilationResult.problemCount;
|
||||
// if (problemCount != 0) {
|
||||
// unitDeclaration.compilationResult.problems = new CategorizedProblem[problemCount];
|
||||
// System.arraycopy(unit.compilationResult.problems, 0, unitDeclaration.compilationResult.problems, 0, problemCount);
|
||||
// unitDeclaration.compilationResult.problemCount = problemCount;
|
||||
// }
|
||||
// } else if (resolver.abortProblem != null) {
|
||||
// unitDeclaration.compilationResult.problemCount = 1;
|
||||
// unitDeclaration.compilationResult.problems = new CategorizedProblem[] { resolver.abortProblem };
|
||||
// }
|
||||
return unitDeclaration;
|
||||
}
|
||||
return unit;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static CompilationUnitDeclaration parse(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, Map<String, String> options, int flags) {
|
||||
try {
|
||||
return (CompilationUnitDeclaration) PARSE_METHOD.get()
|
||||
.invoke(null, sourceUnit, null, options, flags);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static CompilationUnit convert(
|
||||
CompilationUnitDeclaration compilationUnitDeclaration,
|
||||
char[] source,
|
||||
int apiLevel,
|
||||
Map<String, String> options,
|
||||
boolean needToResolveBindings,
|
||||
WorkingCopyOwner owner,
|
||||
int flags) {
|
||||
try {
|
||||
return (CompilationUnit) CONVERT_METHOD.get().invoke(null,
|
||||
compilationUnitDeclaration,
|
||||
source,
|
||||
apiLevel,
|
||||
options,
|
||||
needToResolveBindings,
|
||||
owner,
|
||||
needToResolveBindings ? BINDING_TABLES_CONSTRUCTOR.get().newInstance() : null,
|
||||
flags,
|
||||
new NullProgressMonitor(),
|
||||
false);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
|
||||
| InstantiationException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
static INameEnvironmentWithProgress createLookupEnvironment(Classpath[] classpath) {
|
||||
try {
|
||||
return (INameEnvironmentWithProgress) LOOKUP_ENVIRONMENT_CONSTRUCTOR.get().newInstance(classpath, null, new NullProgressMonitor());
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static List<Classpath> getClasspath(ASTParser parser) {
|
||||
try {
|
||||
return (List<Classpath>) GET_CLASSPATH_METHOD.get().invoke(parser);
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,307 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017, 2021 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jdt.core.ICompilationUnit;
|
||||
import org.eclipse.jdt.core.IJavaElement;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath;
|
||||
import org.eclipse.jdt.internal.core.BasicCompilationUnit;
|
||||
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
|
||||
import org.eclipse.jdt.internal.core.INameEnvironmentWithProgress;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuples;
|
||||
|
||||
public final class CompilationUnitCache implements DocumentContentProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompilationUnitCache.class);
|
||||
|
||||
private static final long CU_ACCESS_EXPIRATION = 1;
|
||||
private JavaProjectFinder projectFinder;
|
||||
private ProjectObserver projectObserver;
|
||||
|
||||
private final ProjectObserver.Listener projectListener;
|
||||
private final SimpleTextDocumentService documentService;
|
||||
|
||||
private final Cache<URI, CompilationUnit> uriToCu;
|
||||
private final Cache<IJavaProject, Set<URI>> projectToDocs;
|
||||
private final Cache<IJavaProject, Tuple2<List<Classpath>, INameEnvironmentWithProgress>> lookupEnvCache;
|
||||
|
||||
public CompilationUnitCache(JavaProjectFinder projectFinder, SimpleLanguageServer server, ProjectObserver projectObserver) {
|
||||
this.projectFinder = projectFinder;
|
||||
this.projectObserver = projectObserver;
|
||||
|
||||
// PT 154618835 - Avoid retaining the CU in the cache as it consumes memory if it hasn't been
|
||||
// accessed after some time
|
||||
this.uriToCu = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(CU_ACCESS_EXPIRATION, TimeUnit.MINUTES)
|
||||
.build();
|
||||
this.projectToDocs = CacheBuilder.newBuilder().build();
|
||||
this.lookupEnvCache = CacheBuilder.newBuilder().build();
|
||||
|
||||
this.documentService = server == null ? null : server.getTextDocumentService();
|
||||
|
||||
// IMPORTANT ===> these notifications arrive within the lsp message loop, so reactions to them have to be fast
|
||||
// and not be blocked by waiting for anything
|
||||
if (this.documentService != null) {
|
||||
this.documentService.onDidChangeContent(doc -> invalidateCuForJavaFile(doc.getDocument().getId().getUri()));
|
||||
this.documentService.onDidClose(doc -> invalidateCuForJavaFile(doc.getId().getUri()));
|
||||
}
|
||||
|
||||
if (this.projectFinder != null) {
|
||||
for (IJavaProject project : this.projectFinder.all()) {
|
||||
logger.info("CU Cache: initial lookup env creation for project <{}>", project.getElementName());
|
||||
loadLookupEnvTuple(project);
|
||||
}
|
||||
}
|
||||
|
||||
this.projectListener = new ProjectObserver.Listener() {
|
||||
|
||||
@Override
|
||||
public void deleted(IJavaProject project) {
|
||||
logger.info("CU Cache: deleted project {}", project.getElementName());
|
||||
invalidateProject(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(IJavaProject project) {
|
||||
logger.info("CU Cache: created project {}", project.getElementName());
|
||||
invalidateProject(project);
|
||||
loadLookupEnvTuple(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changed(IJavaProject project) {
|
||||
logger.info("CU Cache: changed project {}", project.getElementName());
|
||||
invalidateProject(project);
|
||||
// Load the new cache the value right away
|
||||
loadLookupEnvTuple(project);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.projectObserver != null) {
|
||||
this.projectObserver.addListener(this.projectListener);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (this.projectObserver != null) {
|
||||
this.projectObserver.removeListener(this.projectListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Never research shows at the AST is thread-safe when used in read-only mode:
|
||||
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=58314
|
||||
*
|
||||
* This means that the previous implemented synchronization around the requestor
|
||||
* working on the AST is not necessary as long as the requestor operates in read-only
|
||||
* mode on the AST nodes.
|
||||
*
|
||||
* Warning: Callers should take care to do all AST processing inside of the requestor callback and
|
||||
* not pass of AST nodes to helper functions that work aynchronously or store AST nodes or ITypeBindings
|
||||
* for later use. The JDT ASTs are not thread safe!
|
||||
*/
|
||||
@Deprecated
|
||||
public <T> T withCompilationUnit(TextDocument document, Function<CompilationUnit, T> requestor) {
|
||||
IJavaProject project = this.projectFinder != null ? projectFinder.find(document.getId()).orElse(null) : null;
|
||||
|
||||
URI uri = URI.create(document.getUri());
|
||||
return withCompilationUnit(project, uri, requestor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Never research shows at the AST is thread-safe when used in read-only mode:
|
||||
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=58314
|
||||
*
|
||||
* This means that the previous implemented synchronization around the requestor
|
||||
* working on the AST is not necessary as long as the requestor operates in read-only
|
||||
* mode on the AST nodes.
|
||||
*
|
||||
* Warning: Callers should take care to do all AST processing inside of the requestor callback and
|
||||
* not pass of AST nodes to helper functions that work aynchronously or store AST nodes or ITypeBindings
|
||||
* for later use. The JDT ASTs are not thread safe!
|
||||
*/
|
||||
public <T> T withCompilationUnit(IJavaProject project, URI uri, Function<CompilationUnit, T> requestor) {
|
||||
logger.info("CU Cache: work item submitted for doc {}", uri.toString());
|
||||
|
||||
if (project != null) {
|
||||
|
||||
CompilationUnit cu = null;
|
||||
|
||||
try {
|
||||
cu = uriToCu.get(uri, () -> {
|
||||
Tuple2<List<Classpath>, INameEnvironmentWithProgress> lookupEnvTuple = loadLookupEnvTuple(project);
|
||||
String utiStr = uri.toString();
|
||||
String unitName = utiStr.substring(utiStr.lastIndexOf("/"));
|
||||
CompilationUnit cUnit = parse2(fetchContent(uri).toCharArray(), utiStr, unitName, lookupEnvTuple.getT1(), lookupEnvTuple.getT2());
|
||||
|
||||
logger.info("CU Cache: created new AST for {}", uri.toString());
|
||||
|
||||
return cUnit;
|
||||
});
|
||||
|
||||
if (cu != null) {
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(uri);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
|
||||
if (cu != null) {
|
||||
try {
|
||||
logger.info("CU Cache: start work on AST for {}", uri.toString());
|
||||
return requestor.apply(cu);
|
||||
}
|
||||
catch (CancellationException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("", e);
|
||||
}
|
||||
finally {
|
||||
logger.info("CU Cache: end work on AST for {}", uri.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return requestor.apply(null);
|
||||
}
|
||||
|
||||
|
||||
public static CompilationUnit parse2(char[] source, String docURI, String unitName, IJavaProject project) throws Exception {
|
||||
List<Classpath> classpaths = createClasspath(getClasspathEntries(project));
|
||||
return parse2(source, docURI, unitName, classpaths, null);
|
||||
}
|
||||
|
||||
private static CompilationUnit parse2(char[] source, String docURI, String unitName, List<Classpath> classpaths, INameEnvironmentWithProgress environment) throws Exception {
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
String apiLevel = JavaCore.VERSION_16;
|
||||
JavaCore.setComplianceOptions(apiLevel, options);
|
||||
if (environment == null) {
|
||||
environment = CUResolver.createLookupEnvironment(classpaths.toArray(new Classpath[classpaths.size()]));
|
||||
}
|
||||
|
||||
BasicCompilationUnit sourceUnit = new BasicCompilationUnit(source, null, unitName, (IJavaElement) null);
|
||||
|
||||
int flags = 0;
|
||||
boolean needToResolveBindings = true;
|
||||
flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
|
||||
flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
|
||||
CompilationUnitDeclaration unit = null;
|
||||
try {
|
||||
unit = CUResolver.resolve(sourceUnit, classpaths, options, flags, environment);
|
||||
} catch (Exception e) {
|
||||
flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
|
||||
unit = CUResolver.parse(sourceUnit, options, flags);
|
||||
needToResolveBindings = false;
|
||||
}
|
||||
|
||||
CompilationUnit cu = CUResolver.convert(unit, source, AST.JLS16, options, needToResolveBindings, DefaultWorkingCopyOwner.PRIMARY, flags);
|
||||
|
||||
return cu;
|
||||
}
|
||||
|
||||
private static List<Classpath> createClasspath(String[] classpathEntries) {
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS16);
|
||||
String[] sourceEntries = new String[] {};
|
||||
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
|
||||
return CUResolver.getClasspath(parser);
|
||||
}
|
||||
|
||||
private Tuple2<List<Classpath>, INameEnvironmentWithProgress> loadLookupEnvTuple(IJavaProject project) {
|
||||
try {
|
||||
return lookupEnvCache.get(project, () -> {
|
||||
List<Classpath> classpaths = createClasspath(getClasspathEntries(project));
|
||||
INameEnvironmentWithProgress environment = CUResolver.createLookupEnvironment(classpaths.toArray(new Classpath[classpaths.size()]));
|
||||
return Tuples.of(classpaths, environment);
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
logger.error("{}", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] getClasspathEntries(IJavaProject project) throws Exception {
|
||||
if (project == null) {
|
||||
return new String[0];
|
||||
} else {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
Stream<File> classpathEntries = IClasspathUtil.getAllBinaryRoots(classpath).stream();
|
||||
return classpathEntries
|
||||
.filter(file -> file.exists())
|
||||
.map(file -> file.getAbsolutePath()).toArray(String[]::new);
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateCuForJavaFile(String uriStr) {
|
||||
logger.info("CU Cache: invalidate AST for {}", uriStr);
|
||||
|
||||
URI uri = URI.create(uriStr);
|
||||
uriToCu.invalidate(uri);
|
||||
}
|
||||
|
||||
private void invalidateProject(IJavaProject project) {
|
||||
logger.info("CU Cache: invalidate project <{}>", project.getElementName());
|
||||
|
||||
Set<URI> docUris = projectToDocs.getIfPresent(project);
|
||||
if (docUris != null) {
|
||||
uriToCu.invalidateAll(docUris);
|
||||
projectToDocs.invalidate(project);
|
||||
}
|
||||
lookupEnvCache.invalidate(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fetchContent(URI uri) throws Exception {
|
||||
if (documentService != null) {
|
||||
TextDocument document = documentService.getLatestSnapshot(uri.toString());
|
||||
if (document != null) {
|
||||
return document.get();
|
||||
}
|
||||
}
|
||||
return IOUtils.toString(uri);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.FileASTRequestor;
|
||||
import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class NameEnvironmentAwareASTRequestor extends FileASTRequestor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NameEnvironmentAwareASTRequestor.class);
|
||||
|
||||
private FileASTRequestor realOne;
|
||||
private INameEnvironment nameEnvironment;
|
||||
|
||||
public NameEnvironmentAwareASTRequestor(FileASTRequestor realOne) {
|
||||
this.realOne = realOne;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
|
||||
if (nameEnvironment == null) {
|
||||
extractNameEnvironment();
|
||||
}
|
||||
|
||||
realOne.acceptAST(sourceFilePath, cu);
|
||||
}
|
||||
|
||||
public INameEnvironment getNameEnvironment() {
|
||||
return nameEnvironment;
|
||||
}
|
||||
|
||||
private void extractNameEnvironment() {
|
||||
try {
|
||||
Field declaredField = FileASTRequestor.class.getDeclaredField("compilationUnitResolver");
|
||||
declaredField.setAccessible(true);
|
||||
|
||||
Object compilationUnitResolver = declaredField.get(this);
|
||||
Object lookupEnvironment = compilationUnitResolver.getClass().getField("lookupEnvironment")
|
||||
.get(compilationUnitResolver);
|
||||
nameEnvironment = (INameEnvironment) lookupEnvironment.getClass()
|
||||
.getField("nameEnvironment").get(lookupEnvironment);
|
||||
} catch (Exception e) {
|
||||
log.error(" could not identify name environment when scanning for symbols in Java code - " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,8 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.openrewrite.InMemoryExecutionContext;
|
||||
import org.openrewrite.Parser.Input;
|
||||
import org.openrewrite.Result;
|
||||
import org.openrewrite.java.JavaParser;
|
||||
import org.openrewrite.java.UpdateSourcePositions;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -41,7 +38,7 @@ import reactor.core.Disposable;
|
||||
|
||||
public class ORCompilationUnitCache implements DocumentContentProvider, Disposable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CompilationUnitCache.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(ORCompilationUnitCache.class);
|
||||
|
||||
private static final long CU_ACCESS_EXPIRATION = 1;
|
||||
private JavaProjectFinder projectFinder;
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.openrewrite.java.tree.J.CompilationUnit;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJava.SCAN_PASS;
|
||||
|
||||
@@ -13,7 +13,7 @@ package org.springframework.ide.vscode.boot.java.utils;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -26,8 +26,8 @@ public class SpringIndexerJavaDependencyTracker {
|
||||
|
||||
private Multimap<String, String> dependencies = MultimapBuilder.hashKeys().hashSetValues().build();
|
||||
|
||||
public void addDependency(String sourceFile, ITypeBinding dependsOn) {
|
||||
dependencies.put(sourceFile, dependsOn.getKey());
|
||||
public void addDependency(String sourceFile, FullyQualified dependsOn) {
|
||||
dependencies.put(sourceFile, dependsOn.getFullyQualifiedName());
|
||||
}
|
||||
|
||||
public void dump() {
|
||||
|
||||
@@ -18,15 +18,12 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.openrewrite.java.tree.J;
|
||||
import org.openrewrite.java.tree.J.Annotation;
|
||||
import org.openrewrite.marker.Range;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider;
|
||||
import org.springframework.ide.vscode.boot.metadata.PropertyInfo;
|
||||
import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider;
|
||||
@@ -109,12 +106,13 @@ public class ValueCompletionProcessor implements CompletionProvider {
|
||||
public void provideCompletions(J node, int offset, IDocument doc, Collection<ICompletionProposal> completions) {
|
||||
}
|
||||
|
||||
private void computeProposalsForSimpleName(ASTNode node, Collection<ICompletionProposal> completions, int offset,
|
||||
private void computeProposalsForSimpleName(J node, Collection<ICompletionProposal> completions, int offset,
|
||||
IDocument doc) {
|
||||
String prefix = identifyPropertyPrefix(node.toString(), offset - node.getStartPosition());
|
||||
Range r = ORAstUtils.getRange(node);
|
||||
int startOffset = r.getStart().getOffset();
|
||||
int endOffset = r.getEnd().getOffset();
|
||||
|
||||
int startOffset = node.getStartPosition();
|
||||
int endOffset = node.getStartPosition() + node.getLength();
|
||||
String prefix = identifyPropertyPrefix(node.toString(), offset - startOffset);
|
||||
|
||||
String proposalPrefix = "\"";
|
||||
String proposalPostfix = "\"";
|
||||
|
||||
@@ -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
|
||||
@@ -24,17 +24,18 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
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.MemberValuePair;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.WorkspaceFolder;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
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.Literal;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
@@ -63,23 +64,27 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Location> provideReferences(CancelChecker cancelToken, ASTNode node, Annotation annotation,
|
||||
ITypeBinding type, int offset, TextDocument doc) {
|
||||
public List<? extends Location> provideReferences(CancelChecker cancelToken, J node, Annotation annotation,
|
||||
FullyQualified type, int offset, TextDocument doc) {
|
||||
|
||||
cancelToken.checkCanceled();
|
||||
|
||||
try {
|
||||
// case: @Value("prefix<*>")
|
||||
if (node instanceof StringLiteral && node.getParent() instanceof Annotation) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
return provideReferences(node.toString(), offset - node.getStartPosition(), node.getStartPosition(), doc);
|
||||
if (node instanceof Literal && ORAstUtils.getParent(node) instanceof Annotation) {
|
||||
String nodeStr = node.printTrimmed();
|
||||
if (nodeStr.startsWith("\"") && nodeStr.endsWith("\"")) {
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(node);
|
||||
return provideReferences(node.toString(), offset - r.getStart().getOffset(), r.getStart().getOffset(), doc);
|
||||
}
|
||||
}
|
||||
// case: @Value(value="prefix<*>")
|
||||
else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair
|
||||
&& "value".equals(((MemberValuePair)node.getParent()).getName().toString())) {
|
||||
if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) {
|
||||
return provideReferences(node.toString(), offset - node.getStartPosition(), node.getStartPosition(), doc);
|
||||
else if (node instanceof Literal && ORAstUtils.getParent(node) instanceof Assignment
|
||||
&& "value".equals(((Assignment)ORAstUtils.getParent(node)).getVariable().printTrimmed())) {
|
||||
String nodeStr = node.printTrimmed();
|
||||
if (nodeStr.startsWith("\"") && nodeStr.endsWith("\"")) {
|
||||
org.openrewrite.marker.Range r = ORAstUtils.getRange(node);
|
||||
return provideReferences(node.toString(), offset - r.getStart().getOffset(), r.getStart().getOffset(), doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
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.java.utils.SymbolCacheVoid;
|
||||
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry;
|
||||
@@ -73,11 +73,11 @@ public class PropertyEditorTestConf {
|
||||
return serverParams.projectFinder;
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(CompilationUnitCache cuCache) {
|
||||
@Bean SourceLinks sourceLinks(ORCompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
@Bean DefinitionLinkAsserts definitionLinkAsserts(JavaDocumentUriProvider javaDocumentUriProvider, CompilationUnitCache cuCache) {
|
||||
@Bean DefinitionLinkAsserts definitionLinkAsserts(JavaDocumentUriProvider javaDocumentUriProvider, ORCompilationUnitCache cuCache) {
|
||||
return new DefinitionLinkAsserts(javaDocumentUriProvider, cuCache);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
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.java.utils.SymbolCacheVoid;
|
||||
import org.springframework.ide.vscode.boot.java.utils.test.MockProjectObserver;
|
||||
@@ -64,7 +64,7 @@ public class XmlBeansTestConf {
|
||||
return (DefaultSpringPropertyIndexProvider) serverParams.indexProvider;
|
||||
}
|
||||
|
||||
@Bean DefinitionLinkAsserts definitionLinkAsserts(JavaDocumentUriProvider javaDocumentUriProvider, CompilationUnitCache cuCache) {
|
||||
@Bean DefinitionLinkAsserts definitionLinkAsserts(JavaDocumentUriProvider javaDocumentUriProvider, ORCompilationUnitCache cuCache) {
|
||||
return new DefinitionLinkAsserts(javaDocumentUriProvider, cuCache);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 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
|
||||
* https://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.utils.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.FieldDeclaration;
|
||||
import org.eclipse.jdt.core.dom.IAnnotationBinding;
|
||||
import org.eclipse.jdt.core.dom.IMethodBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MarkerAnnotation;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.NormalAnnotation;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.maven.java.MavenJavaProject;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
|
||||
public class AstParserTest {
|
||||
|
||||
private ProjectsHarness projects = ProjectsHarness.INSTANCE;
|
||||
|
||||
private MavenJavaProject jp;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
jp = projects.mavenProject("empty-boot-15-web-app");
|
||||
assertTrue(jp.getIndex().findType("org.springframework.boot.SpringApplication").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() throws Exception {
|
||||
URL sourceUrl = SourceLinks.source(jp, "org.springframework.boot.SpringApplication").get();
|
||||
|
||||
URI uri = sourceUrl.toURI();
|
||||
|
||||
String unitName = "SpringApplication";
|
||||
|
||||
char[] content = IOUtils.toString(uri).toCharArray();
|
||||
|
||||
CompilationUnit cu = CompilationUnitCache.parse2(content, uri.toString(), unitName, jp);
|
||||
|
||||
assertNotNull(cu);
|
||||
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
ITypeBinding binding = node.resolveBinding();
|
||||
assertNotNull(binding);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
IAnnotationBinding annotationBinding = node.resolveAnnotationBinding();
|
||||
assertNotNull(annotationBinding);
|
||||
ITypeBinding binding = node.resolveTypeBinding();
|
||||
assertNotNull(binding);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(NormalAnnotation node) {
|
||||
IAnnotationBinding annotationBinding = node.resolveAnnotationBinding();
|
||||
assertNotNull(annotationBinding);
|
||||
ITypeBinding binding = node.resolveTypeBinding();
|
||||
assertNotNull(binding);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MarkerAnnotation node) {
|
||||
IAnnotationBinding annotationBinding = node.resolveAnnotationBinding();
|
||||
assertNotNull(annotationBinding);
|
||||
ITypeBinding binding = node.resolveTypeBinding();
|
||||
assertNotNull(binding);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
IMethodBinding binding = node.resolveBinding();
|
||||
assertNotNull(binding);
|
||||
if (node.getReturnType2() != null) {
|
||||
ITypeBinding returnTypeBinding = node.getReturnType2().resolveBinding();
|
||||
assertNotNull(returnTypeBinding);
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(FieldDeclaration node) {
|
||||
ITypeBinding binding = node.getType().resolveBinding();
|
||||
assertNotNull(binding);
|
||||
return super.visit(node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@ import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
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.java.utils.SymbolCacheVoid;
|
||||
import org.springframework.ide.vscode.boot.metadata.ValueProviderRegistry;
|
||||
@@ -104,7 +104,7 @@ public class CompilationUnitCacheTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, CompilationUnitCache cuCache) {
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, ORCompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.ide.vscode.boot.editor.harness.AdHocPropertyHarness;
|
||||
import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
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.java.utils.SymbolCacheVoid;
|
||||
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
|
||||
@@ -121,7 +121,7 @@ public class ValueCompletionTest {
|
||||
return new SymbolCacheVoid();
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, CompilationUnitCache cuCache) {
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, ORCompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ import org.springframework.ide.vscode.boot.editor.harness.PropertyIndexHarness;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaReconcileEngine;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
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.java.utils.SymbolCacheVoid;
|
||||
@@ -130,7 +129,7 @@ public class ValueSpelExpressionValidationTest {
|
||||
return new SymbolCacheVoid();
|
||||
}
|
||||
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, CompilationUnitCache cuCache) {
|
||||
@Bean SourceLinks sourceLinks(SimpleTextDocumentService documents, ORCompilationUnitCache cuCache) {
|
||||
return SourceLinkFactory.NO_SOURCE_LINKS;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,22 +17,24 @@ import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
|
||||
import org.eclipse.jdt.core.dom.EnumDeclaration;
|
||||
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.Location;
|
||||
import org.eclipse.lsp4j.LocationLink;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.openrewrite.Cursor;
|
||||
import org.openrewrite.java.JavaIsoVisitor;
|
||||
import org.openrewrite.java.tree.J.ClassDeclaration;
|
||||
import org.openrewrite.java.tree.J.EnumValue;
|
||||
import org.openrewrite.java.tree.J.Identifier;
|
||||
import org.openrewrite.java.tree.J.MethodDeclaration;
|
||||
import org.openrewrite.java.tree.JavaType;
|
||||
import org.openrewrite.java.tree.JavaType.FullyQualified;
|
||||
import org.openrewrite.java.tree.JavaType.Method;
|
||||
import org.openrewrite.java.tree.TypeUtils;
|
||||
import org.springframework.ide.vscode.boot.java.links.JavaDocumentUriProvider;
|
||||
import org.springframework.ide.vscode.boot.java.links.SourceLinks;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORAstUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.ORCompilationUnitCache;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
@@ -44,7 +46,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
public class DefinitionLinkAsserts {
|
||||
|
||||
private JavaDocumentUriProvider javaDocumentUriProvider;
|
||||
private CompilationUnitCache cuCache;
|
||||
private ORCompilationUnitCache cuCache;
|
||||
|
||||
public static JavaMethod method(String fqClassName, String methodName, String... params) {
|
||||
return new JavaMethod(fqClassName, methodName, params);
|
||||
@@ -84,7 +86,7 @@ public class DefinitionLinkAsserts {
|
||||
}
|
||||
}
|
||||
|
||||
public DefinitionLinkAsserts(JavaDocumentUriProvider javaDocumentUriProvider, CompilationUnitCache cuCache) {
|
||||
public DefinitionLinkAsserts(JavaDocumentUriProvider javaDocumentUriProvider, ORCompilationUnitCache cuCache) {
|
||||
this.javaDocumentUriProvider = javaDocumentUriProvider;
|
||||
this.cuCache = cuCache;
|
||||
|
||||
@@ -133,33 +135,23 @@ public class DefinitionLinkAsserts {
|
||||
TextDocument doc = new TextDocument(sourceUrl.get().toString(), LanguageId.JAVA);
|
||||
doc.setText(cuCache.fetchContent(sourceUri));
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
private boolean proceessTypeNode(TextDocument doc, String typeName,
|
||||
AtomicReference<Range> range, AbstractTypeDeclaration node) {
|
||||
SimpleName nameNode = node.getName();
|
||||
if (nameNode.getIdentifier().equals(typeName)) {
|
||||
|
||||
new JavaIsoVisitor<AtomicReference<Range>>() {
|
||||
@Override
|
||||
public ClassDeclaration visitClassDeclaration(ClassDeclaration classDecl, AtomicReference<Range> p) {
|
||||
if (typeName.equals(classDecl.getSimpleName())) {
|
||||
try {
|
||||
range.set(doc.toRange(nameNode.getStartPosition(), nameNode.getLength()));
|
||||
return false;
|
||||
org.openrewrite.marker.Range cuRange = ORAstUtils.getRange(classDecl.getName());
|
||||
p.set(doc.toRange(cuRange.getStart().getOffset(), cuRange.length()));
|
||||
return classDecl;
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return super.visitClassDeclaration(classDecl, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(TypeDeclaration node) {
|
||||
return proceessTypeNode(doc, typeName, range, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumDeclaration node) {
|
||||
return proceessTypeNode(doc, typeName, range, node);
|
||||
}
|
||||
|
||||
});
|
||||
}.visitNonNull(cu, range);
|
||||
|
||||
return range.get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
@@ -187,37 +179,38 @@ public class DefinitionLinkAsserts {
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
TextDocument doc = new TextDocument(sourceUrl.get().toString(), LanguageId.JAVA);
|
||||
doc.setText(cuCache.fetchContent(sourceUri));
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
|
||||
new JavaIsoVisitor<AtomicReference<Range>>() {
|
||||
@Override
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
SimpleName nameNode = node.getName();
|
||||
if (nameNode.getIdentifier().equals(method.methodName)) {
|
||||
if (node.parameters().size() != method.params.length) {
|
||||
return false;
|
||||
}
|
||||
int i = 0;
|
||||
for (Object _p : node.parameters()) {
|
||||
if (_p instanceof SingleVariableDeclaration) {
|
||||
SingleVariableDeclaration p = (SingleVariableDeclaration) _p;
|
||||
String fqName = p.getType().resolveBinding().getErasure().getQualifiedName();
|
||||
if (!fqName.equals(method.params[i++])) {
|
||||
return false;
|
||||
public MethodDeclaration visitMethodDeclaration(MethodDeclaration m,
|
||||
AtomicReference<Range> p) {
|
||||
if (m.getSimpleName().equals(method.methodName) && m.getParameters().size() == method.params.length) {
|
||||
Method methodType = m.getMethodType();
|
||||
if (methodType != null) {
|
||||
int i = 0;
|
||||
for (JavaType paramType : methodType.getParameterTypes()) {
|
||||
FullyQualified fqType = TypeUtils.asFullyQualified(paramType);
|
||||
if (fqType == null) {
|
||||
if (!method.params[i++].equals(paramType.toString())) {
|
||||
return m;
|
||||
}
|
||||
} else {
|
||||
if (!fqType.getFullyQualifiedName().equals(method.params[i++])) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
org.openrewrite.marker.Range cuRange = ORAstUtils.getRange(m.getName());
|
||||
p.set(doc.toRange(cuRange.getStart().getOffset(), cuRange.length()));
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
range.set(doc.toRange(nameNode.getStartPosition(), nameNode.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return m;
|
||||
}
|
||||
|
||||
});
|
||||
}.visitNonNull(cu, range);
|
||||
return range.get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
@@ -247,36 +240,31 @@ public class DefinitionLinkAsserts {
|
||||
AtomicReference<Range> range = new AtomicReference<>(null);
|
||||
TextDocument doc = new TextDocument(sourceUrl.get().toString(), LanguageId.JAVA);
|
||||
doc.setText(cuCache.fetchContent(sourceUri));
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
boolean foundType = false;
|
||||
|
||||
|
||||
String enumName = field.fqName.substring(field.fqName.lastIndexOf('.') + 1);
|
||||
new JavaIsoVisitor<AtomicReference<Range>>() {
|
||||
@Override
|
||||
public boolean visit(EnumConstantDeclaration node) {
|
||||
if (foundType) {
|
||||
SimpleName nameNode = node.getName();
|
||||
if (nameNode.getIdentifier().equals(field.fieldName)) {
|
||||
try {
|
||||
range.set(doc.toRange(nameNode.getStartPosition(), nameNode.getLength()));
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
public EnumValue visitEnumValue(EnumValue _enum, AtomicReference<Range> p) {
|
||||
Cursor delcaringTypeCursor = getCursor().dropParentUntil(ClassDeclaration.class::isInstance);
|
||||
if (delcaringTypeCursor != null) {
|
||||
ClassDeclaration declaringType = delcaringTypeCursor.getValue();
|
||||
if (enumName.equals(declaringType.getSimpleName())) {
|
||||
Identifier nameNode = _enum.getName();
|
||||
if (field.fieldName.equals(nameNode.printTrimmed())) {
|
||||
try {
|
||||
org.openrewrite.marker.Range nameNodeRange = ORAstUtils.getRange(nameNode);
|
||||
p.set(doc.toRange(nameNodeRange.getStart().getOffset(), nameNodeRange.length()));
|
||||
} catch (BadLocationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
// TODO Auto-generated method stub
|
||||
return super.visitEnumValue(_enum, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean visit(EnumDeclaration node) {
|
||||
if (node.getName().getIdentifier()
|
||||
.equals(field.fqName.substring(field.fqName.lastIndexOf('.') + 1))) {
|
||||
foundType = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
}.visitNonNull(cu, range);
|
||||
|
||||
return range.get();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
|
||||
Reference in New Issue
Block a user