PT #153100339 Don't cache CU unless there is a project for it

This commit is contained in:
BoykoAlex
2017-11-22 14:20:31 -05:00
parent 8c956bf962
commit a50c09097a
7 changed files with 108 additions and 61 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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