PT #153100339 Don't cache CU unless there is a project for it
This commit is contained in:
@@ -15,7 +15,6 @@ import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
@@ -31,7 +30,6 @@ 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.SimpleTextDocumentService;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -87,18 +85,32 @@ public final class CompilationUnitCache {
|
||||
*/
|
||||
public <T> T withCompilationUnit(TextDocument document, Function<CompilationUnit, T> requestor) {
|
||||
URI uri = URI.create(document.getUri());
|
||||
readLock.lock();
|
||||
try {
|
||||
CompilationUnit cu = uriToCu.get(uri, () -> parse(document));
|
||||
if (cu!=null) {
|
||||
synchronized (cu.getAST()) {
|
||||
return requestor.apply(cu);
|
||||
IJavaProject project = projectFinder.find(document.getId()).orElse(null);
|
||||
if (project != null) {
|
||||
readLock.lock();
|
||||
try {
|
||||
CompilationUnit cu = uriToCu.get(uri, () -> {
|
||||
CompilationUnit cUnit = parse(document, project);
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(URI.create(document.getUri()));
|
||||
return cUnit;
|
||||
});
|
||||
if (cu!=null) {
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(URI.create(document.getUri()));
|
||||
synchronized (cu.getAST()) {
|
||||
return requestor.apply(cu);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
return requestor.apply(parse(document, null));
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
return requestor.apply(null);
|
||||
}
|
||||
@@ -137,16 +149,6 @@ public final class CompilationUnitCache {
|
||||
return cu;
|
||||
}
|
||||
|
||||
private CompilationUnit parse(TextDocument document)
|
||||
throws Exception, BadLocationException {
|
||||
IJavaProject project = projectFinder.find(document.getId()).orElse(null);
|
||||
CompilationUnit cu = parse(document, project);
|
||||
if (project != null) {
|
||||
projectToDocs.get(project, () -> new HashSet<>()).add(URI.create(document.getUri()));
|
||||
}
|
||||
return cu;
|
||||
}
|
||||
|
||||
private static String[] getClasspathEntries(TextDocument document, IJavaProject project) throws Exception {
|
||||
if (project == null) {
|
||||
return new String[0];
|
||||
|
||||
@@ -23,11 +23,12 @@ import java.nio.file.Paths;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||
import org.springframework.ide.vscode.commons.java.DelegatingCachedClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IClasspath;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
import org.springframework.ide.vscode.commons.util.text.LanguageId;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
|
||||
@@ -39,7 +40,7 @@ import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
*/
|
||||
public class CompilationUnitCacheTest {
|
||||
|
||||
private LanguageServerHarness<BootJavaLanguageServer> harness;
|
||||
private BootLanguageServerHarness harness;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
@@ -48,6 +49,14 @@ public class CompilationUnitCacheTest {
|
||||
|
||||
@Test
|
||||
public void cu_cached() throws Exception {
|
||||
harness = BootLanguageServerHarness.builder()
|
||||
.mockDefaults().build();
|
||||
harness.useProject(new IJavaProject() {
|
||||
@Override
|
||||
public IClasspath getClasspath() {
|
||||
return new DelegatingCachedClasspath<>(() -> null, null);
|
||||
}
|
||||
});
|
||||
harness.intialize(null);
|
||||
|
||||
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
|
||||
@@ -62,12 +71,36 @@ public class CompilationUnitCacheTest {
|
||||
assertTrue(cu == cuAnother);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cu_not_cached_without_project() throws Exception {
|
||||
harness.intialize(null);
|
||||
|
||||
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
|
||||
"\n" +
|
||||
"public class SomeClass {\n" +
|
||||
"\n" +
|
||||
"}\n");
|
||||
CompilationUnit cu = getCompilationUnit(doc);
|
||||
assertNotNull(cu);
|
||||
|
||||
CompilationUnit cuAnother = getCompilationUnit(doc);
|
||||
assertFalse(cu == cuAnother);
|
||||
}
|
||||
|
||||
private CompilationUnit getCompilationUnit(TextDocument doc) {
|
||||
return harness.getServer().getCompilationUnitCache().withCompilationUnit(doc, cu -> cu);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cu_cache_invalidated_by_doc_change() throws Exception {
|
||||
harness = BootLanguageServerHarness.builder()
|
||||
.mockDefaults().build();
|
||||
harness.useProject(new IJavaProject() {
|
||||
@Override
|
||||
public IClasspath getClasspath() {
|
||||
return new DelegatingCachedClasspath<>(() -> null, null);
|
||||
}
|
||||
});
|
||||
harness.intialize(null);
|
||||
|
||||
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
|
||||
@@ -91,6 +124,14 @@ public class CompilationUnitCacheTest {
|
||||
|
||||
@Test
|
||||
public void cu_cache_invalidated_by_doc_close() throws Exception {
|
||||
harness = BootLanguageServerHarness.builder()
|
||||
.mockDefaults().build();
|
||||
harness.useProject(new IJavaProject() {
|
||||
@Override
|
||||
public IClasspath getClasspath() {
|
||||
return new DelegatingCachedClasspath<>(() -> null, null);
|
||||
}
|
||||
});
|
||||
harness.intialize(null);
|
||||
|
||||
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
|
||||
|
||||
@@ -334,14 +334,19 @@ public class PropertiesCompletionProposalsCalculator {
|
||||
DocumentEdits docEdits;
|
||||
try {
|
||||
docEdits = LazyProposalApplier.from(() -> {
|
||||
Type type = TypeParser.parse(match.data.getType());
|
||||
DocumentEdits edits = new DocumentEdits(doc);
|
||||
edits.delete(offset-prefix.length(), offset);
|
||||
edits.insert(offset, match.data.getId() + propertyCompletionPostfix(typeUtil, type));
|
||||
return edits;
|
||||
try {
|
||||
Type type = TypeParser.parse(match.data.getType());
|
||||
DocumentEdits edits = new DocumentEdits(doc);
|
||||
edits.delete(offset-prefix.length(), offset);
|
||||
edits.insert(offset, match.data.getId() + propertyCompletionPostfix(typeUtil, type));
|
||||
return edits;
|
||||
} catch (Throwable t) {
|
||||
Log.log(t);
|
||||
return new DocumentEdits(doc);
|
||||
}
|
||||
});
|
||||
proposals.add(completionFactory.property(doc, docEdits, match, typeUtil));
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,7 @@ public class GradleProjectCache extends AbstractFileToProjectCache<GradleJavaPro
|
||||
GradleJavaProject gradleJavaProject = new GradleJavaProject(gradle, gradleFile,
|
||||
projectCacheFolder == null ? null : gradleFile.toPath().resolve(projectCacheFolder)
|
||||
);
|
||||
boolean cached = gradleJavaProject.getClasspath().isCached();
|
||||
performUpdate(gradleJavaProject, cached && asyncUpdate, cached);
|
||||
performUpdate(gradleJavaProject, asyncUpdate, asyncUpdate);
|
||||
return gradleJavaProject;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,8 @@ import reactor.util.function.Tuple2;
|
||||
public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspath {
|
||||
|
||||
public static final String CLASSPATH_DATA_CACHE_FILE = "classpath-data.json";
|
||||
private static final ClasspathData EMPTY_CLASSPATH_DATA = new ClasspathData(null, Collections.emptySet(),
|
||||
Collections.emptySet(), null);
|
||||
|
||||
private static final String OUTPUT_FOLDER_PROPERTY = "outputFolder";
|
||||
private static final String CLASSPATH_RESOURCES_PROPERTY = "classpathResources";
|
||||
@@ -238,15 +240,20 @@ public class DelegatingCachedClasspath<T extends IClasspath> implements IClasspa
|
||||
|
||||
@Override
|
||||
public Flux<IType> allSubtypesOf(IType type) {
|
||||
return cachedDelegate.get().allSubtypesOf(type);
|
||||
T t = cachedDelegate.get();
|
||||
return t == null ? Flux.empty() : t.allSubtypesOf(type);
|
||||
}
|
||||
|
||||
protected ClasspathData createClasspathData() throws Exception {
|
||||
T newDelegate = delegateCreator.call();
|
||||
cachedDelegate.set(newDelegate);
|
||||
LinkedHashSet<Path> classpathEntries = new LinkedHashSet<>(newDelegate.getClasspathEntries());
|
||||
return new ClasspathData(newDelegate.getName(), classpathEntries,
|
||||
new LinkedHashSet<>(newDelegate.getClasspathResources()), newDelegate.getOutputFolder());
|
||||
if (newDelegate == null) {
|
||||
return EMPTY_CLASSPATH_DATA;
|
||||
} else {
|
||||
LinkedHashSet<Path> classpathEntries = new LinkedHashSet<>(newDelegate.getClasspathEntries());
|
||||
return new ClasspathData(newDelegate.getName(), classpathEntries,
|
||||
new LinkedHashSet<>(newDelegate.getClasspathResources()), newDelegate.getOutputFolder());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,8 +50,7 @@ public class MavenProjectCache extends AbstractFileToProjectCache<MavenJavaProje
|
||||
MavenJavaProject mavenJavaProject = new MavenJavaProject(maven, pomFile,
|
||||
projectCacheFolder == null ? null : pomFile.getParentFile().toPath().resolve(projectCacheFolder)
|
||||
);
|
||||
boolean cached = mavenJavaProject.getClasspath().isCached();
|
||||
performUpdate(mavenJavaProject, cached && asyncUpdate, cached);
|
||||
performUpdate(mavenJavaProject, asyncUpdate, asyncUpdate);
|
||||
return mavenJavaProject;
|
||||
}
|
||||
|
||||
|
||||
@@ -176,13 +176,7 @@ public class MavenProjectCacheTest {
|
||||
|
||||
MavenProjectCache cache = new MavenProjectCache(server, MavenCore.getDefault(), true, cacheFolder);
|
||||
MavenJavaProject project = cache.project(pomFile);
|
||||
assertEquals(48, project.getClasspath().getClasspathEntries().size());
|
||||
|
||||
progressDone.set(false);
|
||||
|
||||
writeContent(pomFile,
|
||||
new String(Files.readAllBytes(testProjectPath.resolve("pom.newxml")), Charset.defaultCharset()));
|
||||
fileObserver.notifyFileChanged(pomFile.toURI().toString());
|
||||
assertTrue(project.getClasspath().getClasspathEntries().isEmpty());
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
while (!progressDone.get()) {
|
||||
@@ -195,7 +189,7 @@ public class MavenProjectCacheTest {
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
|
||||
assertTrue(classpathCacheFile.exists());
|
||||
assertEquals(49, project.getClasspath().getClasspathEntries().size());
|
||||
assertEquals(48, project.getClasspath().getClasspathEntries().size());
|
||||
|
||||
progressDone.set(false);
|
||||
|
||||
@@ -204,18 +198,7 @@ public class MavenProjectCacheTest {
|
||||
|
||||
// Check loaded from cache file
|
||||
project = cache.project(pomFile);
|
||||
assertEquals(49, project.getClasspath().getClasspathEntries().size());
|
||||
|
||||
// check async project update (no changes no project changed event)
|
||||
CompletableFuture.runAsync(() -> {
|
||||
while (!progressDone.get()) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
assertEquals(48, project.getClasspath().getClasspathEntries().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -243,8 +226,19 @@ public class MavenProjectCacheTest {
|
||||
|
||||
MavenProjectCache cache = new MavenProjectCache(server, MavenCore.getDefault(), true, cacheFolder);
|
||||
MavenJavaProject project = cache.project(pomFile);
|
||||
assertEquals(48, project.getClasspath().getClasspathEntries().size());
|
||||
|
||||
assertTrue(project.getClasspath().getClasspathEntries().isEmpty());
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
while (!progressDone.get()) {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
progressDone.set(false);
|
||||
|
||||
verify(diagnosticService, never()).diagnosticEvent(any(ShowMessageException.class));
|
||||
|
||||
progressDone.set(false);
|
||||
|
||||
Reference in New Issue
Block a user