Remove JDT

This commit is contained in:
BoykoAlex
2022-02-11 15:40:55 -05:00
parent 3311884577
commit dd1aaad43f
27 changed files with 163 additions and 1940 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2021 Pivotal, Inc.
* Copyright (c) 2017, 2022 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -12,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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 = "\"";

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2021 Pivotal, Inc.
* Copyright (c) 2017, 2022 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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