PT #166190159: AST parser sharing lookup environment uses java reflection

This commit is contained in:
BoykoAlex
2019-06-05 10:36:20 -04:00
parent 602bfd88e5
commit f7eefdbaeb
4 changed files with 649 additions and 42 deletions

View File

@@ -113,7 +113,9 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP
if (nameRange.isPresent()) {
List<CodeLens> codeLenses = assembleCodeLenses(project, runningApps, app -> definedBean(app, getBeanType(beanType), id), doc,
nameRange.get(), typeDeclaration);
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
if (codeLenses != null) {
return codeLenses.isEmpty() ? ImmutableList.of(new CodeLens(nameRange.get())) : codeLenses;
}
}
}
} catch (Exception e) {

View File

@@ -0,0 +1,361 @@
/*******************************************************************************
* 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,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017, 2018 Pivotal, Inc.
* 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
@@ -13,8 +13,11 @@ 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.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
@@ -23,10 +26,17 @@ 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;
@@ -40,6 +50,9 @@ 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);
@@ -49,6 +62,7 @@ public final class CompilationUnitCache implements DocumentContentProvider {
private ProjectObserver projectObserver;
private Cache<URI, CompilationUnit> uriToCu;
private Cache<IJavaProject, Set<URI>> projectToDocs;
private Cache<IJavaProject, Tuple2<List<Classpath>, INameEnvironmentWithProgress>> lookupEnvCache;
private ProjectObserver.Listener projectListener;
private SimpleTextDocumentService documents;
@@ -59,8 +73,8 @@ public final class CompilationUnitCache implements DocumentContentProvider {
this.projectFinder = projectFinder;
this.projectObserver = projectObserver;
this.documents = documents;
projectListener = ProjectObserver.onAny(this::invalidateProject);
this.lookupEnvCache = CacheBuilder.newBuilder().build();
// PT 154618835 - Avoid retaining the CU in the cache as it consumes memory if it hasn't been
// accessed after some time
uriToCu = CacheBuilder.newBuilder()
@@ -77,9 +91,64 @@ public final class CompilationUnitCache implements DocumentContentProvider {
documents.onDidClose(doc -> invalidateCuForJavaFile(doc.getId().getUri()));
}
CompletableFuture.runAsync(() -> {
writeLock.lock();
try {
for (IJavaProject project : projectFinder.all()) {
loadLookupEnvTuple(project);
}
} finally {
writeLock.unlock();
}
});
projectListener = new ProjectObserver.Listener() {
@Override
public void deleted(IJavaProject project) {
CompletableFuture.runAsync(() -> {
writeLock.lock();
try {
invalidateProject(project);
} finally {
writeLock.unlock();
}
});
}
@Override
public void created(IJavaProject project) {
CompletableFuture.runAsync(() -> {
writeLock.lock();
try {
invalidateProject(project);
// Load the new cache the value right away
loadLookupEnvTuple(project);
} finally {
writeLock.unlock();
}
});
}
@Override
public void changed(IJavaProject project) {
CompletableFuture.runAsync(() -> {
writeLock.lock();
try {
invalidateProject(project);
// Load the new cache the value right away
loadLookupEnvTuple(project);
} finally {
writeLock.unlock();
}
});
}
};
if (this.projectObserver != null) {
this.projectObserver.addListener(projectListener);
}
}
public void dispose() {
@@ -111,7 +180,10 @@ public final class CompilationUnitCache implements DocumentContentProvider {
try {
cu = uriToCu.get(uri, () -> {
CompilationUnit cUnit = parse(uri.toString(), fetchContent(uri).toCharArray(), project);
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());
projectToDocs.get(project, () -> new HashSet<>()).add(uri);
return cUnit;
});
@@ -150,41 +222,94 @@ public final class CompilationUnitCache implements DocumentContentProvider {
}
}
public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
String[] classpathEntries = getClasspathEntries(project);
String docURI = document.getUri();
String unitName = docURI.substring(docURI.lastIndexOf("/"));
char[] source = document.get(0, document.getLength()).toCharArray();
return parse(source, docURI, unitName, classpathEntries);
// public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
// String[] classpathEntries = getClasspathEntries(project);
// String docURI = document.getUri();
// String unitName = docURI.substring(docURI.lastIndexOf("/"));
// char[] source = document.get(0, document.getLength()).toCharArray();
// return parse(source, docURI, unitName, classpathEntries);
// }
//
// public CompilationUnit parse(String uri, char[] source, IJavaProject project) throws Exception {
// String[] classpathEntries = getClasspathEntries(project);
// String unitName = uri.substring(uri.lastIndexOf("/"));
// return parse(source, uri, unitName, classpathEntries);
// }
//
// public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception {
// ASTParser parser = ASTParser.newParser(AST.JLS11);
// Map<String, String> options = JavaCore.getOptions();
// JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);
// parser.setCompilerOptions(options);
// parser.setKind(ASTParser.K_COMPILATION_UNIT);
// parser.setStatementsRecovery(true);
// parser.setBindingsRecovery(true);
// parser.setResolveBindings(true);
//
// String[] sourceEntries = new String[] {};
// parser.setEnvironment(classpathEntries, sourceEntries, null, false);
//
// parser.setUnitName(unitName);
// parser.setSource(source);
//
// CompilationUnit cu = (CompilationUnit) parser.createAST(null);
//
// return cu;
// }
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);
}
public static CompilationUnit parse(String uri, char[] source, IJavaProject project) throws Exception {
String[] classpathEntries = getClasspathEntries(project);
String unitName = uri.substring(uri.lastIndexOf("/"));
return parse(source, uri, unitName, classpathEntries);
}
public static CompilationUnit parse(char[] source, String docURI, String unitName, String[] classpathEntries) throws Exception {
ASTParser parser = ASTParser.newParser(AST.JLS11);
private static CompilationUnit parse2(char[] source, String docURI, String unitName, List<Classpath> classpaths, INameEnvironmentWithProgress environment) throws Exception {
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_11, options);
parser.setCompilerOptions(options);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
String[] sourceEntries = new String[] {};
parser.setEnvironment(classpathEntries, sourceEntries, null, false);
parser.setUnitName(unitName);
parser.setSource(source);
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
String apiLevel = JavaCore.VERSION_11;
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.JLS11, options, needToResolveBindings, DefaultWorkingCopyOwner.PRIMARY, flags);
return cu;
}
private static List<Classpath> createClasspath(String[] classpathEntries) {
ASTParser parser = ASTParser.newParser(AST.JLS11);
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];
@@ -200,14 +325,10 @@ public final class CompilationUnitCache implements DocumentContentProvider {
private void invalidateProject(IJavaProject project) {
Set<URI> docUris = projectToDocs.getIfPresent(project);
if (docUris != null) {
writeLock.lock();
try {
uriToCu.invalidateAll(docUris);
projectToDocs.invalidate(project);
} finally {
writeLock.unlock();
}
uriToCu.invalidateAll(docUris);
projectToDocs.invalidate(project);
}
lookupEnvCache.invalidate(project);
}
@Override

View File

@@ -0,0 +1,123 @@
/*******************************************************************************
* 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);
}
});
}
}