Use lazy analysis for highlighting and other purposes
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.plugin.caches.resolve
|
||||
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.jet.lang.psi.JetElement
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.analyzer.AnalyzeExhaust
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils
|
||||
import com.intellij.util.containers.SLRUCache
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.openapi.project.DumbService
|
||||
import org.jetbrains.jet.plugin.util.ApplicationUtils
|
||||
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm
|
||||
import org.jetbrains.jet.context.SimpleGlobalContext
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.MemberFilter
|
||||
import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass<KotlinResolveCache>())
|
||||
|
||||
class KotlinResolveCache(
|
||||
val project: Project,
|
||||
val resolveSession: ResolveSession
|
||||
) {
|
||||
private val analysisResults = CachedValuesManager.getManager(project).createCachedValue ({
|
||||
val results = object : SLRUCache<JetElement, AnalyzeExhaust>(2, 3) {
|
||||
override fun createValue(element: JetElement?): AnalyzeExhaust {
|
||||
element!!
|
||||
|
||||
if (DumbService.isDumb(project)) {
|
||||
return AnalyzeExhaust.EMPTY
|
||||
}
|
||||
|
||||
ApplicationUtils.warnTimeConsuming(LOG)
|
||||
|
||||
try {
|
||||
if (element !is JetFile) {
|
||||
error("Only files are supported")
|
||||
}
|
||||
|
||||
// todo: look for pre-existing results for this element or its parents
|
||||
val trace = DelegatingBindingTrace(resolveSession.getBindingContext(), "Trace for resolution of " + element)
|
||||
val injector = InjectorForTopDownAnalyzerForJvm(
|
||||
project,
|
||||
SimpleGlobalContext(resolveSession.getStorageManager(), resolveSession.getExceptionTracker()),
|
||||
trace,
|
||||
resolveSession.getModuleDescriptor(),
|
||||
MemberFilter.ALWAYS_TRUE
|
||||
)
|
||||
val resultingContext = injector.getLazyTopDownAnalyzer()!!.analyzeDeclarations(
|
||||
resolveSession,
|
||||
TopDownAnalysisParameters.createForLazy(
|
||||
resolveSession.getStorageManager(),
|
||||
resolveSession.getExceptionTracker(),
|
||||
analyzeCompletely = { true },
|
||||
analyzingBootstrapLibrary = false,
|
||||
declaredLocally = false
|
||||
),
|
||||
listOf(getContainingNonlocalDeclaration(element))
|
||||
)
|
||||
return AnalyzeExhaust.success(
|
||||
trace.getBindingContext(),
|
||||
resultingContext,
|
||||
resolveSession.getModuleDescriptor()
|
||||
)
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
throw e
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
handleError(e)
|
||||
|
||||
// Exception during body resolve analyze can harm internal caches in declarations cache
|
||||
KotlinCacheManager.getInstance(project).invalidateCache()
|
||||
|
||||
val bindingTraceContext = BindingTraceContext()
|
||||
return AnalyzeExhaust.error(bindingTraceContext.getBindingContext(), e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CachedValueProvider.Result(results, PsiModificationTracker.MODIFICATION_COUNT, resolveSession.getExceptionTracker())
|
||||
}, false)
|
||||
|
||||
fun getAnalysisResultsForElement(element: JetElement): AnalyzeExhaust {
|
||||
return synchronized(analysisResults) {
|
||||
analysisResults.getValue()!![element]
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContainingNonlocalDeclaration(element: JetElement): JetElement? {
|
||||
return PsiTreeUtil.getParentOfType(element, javaClass<JetFile>(), false);
|
||||
}
|
||||
|
||||
private fun handleError(e: Throwable) {
|
||||
DiagnosticUtils.throwIfRunningOnServer(e)
|
||||
LOG.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.project;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.libraries.LibraryUtil;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
@@ -34,33 +26,19 @@ import com.intellij.util.containers.SLRUCache;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
|
||||
import org.jetbrains.jet.asJava.LightClassUtil;
|
||||
import org.jetbrains.jet.context.ContextPackage;
|
||||
import org.jetbrains.jet.context.GlobalContext;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.MemberFilter;
|
||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.*;
|
||||
import org.jetbrains.jet.plugin.util.ApplicationUtils;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.DeclarationsCacheProvider;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.KotlinCacheManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
public final class AnalyzerFacadeWithCache {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache");
|
||||
|
||||
private final static Key<CachedValue<SLRUCache<JetFile, AnalyzeExhaust>>> ANALYZE_EXHAUST_FULL = Key.create("ANALYZE_EXHAUST_FULL");
|
||||
|
||||
private static final Object lock = new Object();
|
||||
|
||||
private AnalyzerFacadeWithCache() {
|
||||
}
|
||||
|
||||
@@ -70,16 +48,7 @@ public final class AnalyzerFacadeWithCache {
|
||||
// TODO: Also need to pass several files when user have multi-file environment
|
||||
@NotNull
|
||||
public static AnalyzeExhaust analyzeFileWithCache(@NotNull JetFile file) {
|
||||
// Need lock, because parallel threads can start evaluation of compute() simultaneously
|
||||
synchronized (lock) {
|
||||
Project project = file.getProject();
|
||||
return CachedValuesManager.getManager(project).getCachedValue(
|
||||
project,
|
||||
ANALYZE_EXHAUST_FULL,
|
||||
new SLRUCachedAnalyzeExhaustProvider(),
|
||||
false
|
||||
).get(file);
|
||||
}
|
||||
return getLazyResolveSessionForFile(file).getResolveCache().getAnalysisResultsForElement(file);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -107,13 +76,6 @@ public final class AnalyzerFacadeWithCache {
|
||||
return provider.getLazyResolveSession();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static AnalyzeExhaust emptyExhaustWithDiagnosticOnFile(JetFile file, Throwable e) {
|
||||
BindingTraceContext bindingTraceContext = new BindingTraceContext();
|
||||
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
|
||||
return AnalyzeExhaust.error(bindingTraceContext.getBindingContext(), e);
|
||||
}
|
||||
|
||||
private static final SLRUCache<JetFile, CachedValue<ResolveSessionForBodies>> PER_FILE_SESSION_CACHE = new SLRUCache<JetFile, CachedValue<ResolveSessionForBodies>>(2, 3) {
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -147,86 +109,4 @@ public final class AnalyzerFacadeWithCache {
|
||||
true);
|
||||
}
|
||||
};
|
||||
|
||||
private static class SLRUCachedAnalyzeExhaustProvider implements CachedValueProvider<SLRUCache<JetFile, AnalyzeExhaust>> {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<SLRUCache<JetFile, AnalyzeExhaust>> compute() {
|
||||
final GlobalContext globalContext = ContextPackage.GlobalContext();
|
||||
SLRUCache<JetFile, AnalyzeExhaust> cache = new SLRUCache<JetFile, AnalyzeExhaust>(3, 8) {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AnalyzeExhaust createValue(JetFile file) {
|
||||
try {
|
||||
if (DumbService.isDumb(file.getProject())) {
|
||||
return AnalyzeExhaust.EMPTY;
|
||||
}
|
||||
|
||||
ApplicationUtils.warnTimeConsuming(LOG);
|
||||
|
||||
AnalyzeExhaust analyzeExhaustHeaders = analyzeHeadersWithCacheOnFile(file, globalContext);
|
||||
return analyzeBodies(analyzeExhaustHeaders, file);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e) {
|
||||
handleError(e);
|
||||
|
||||
// Exception during body resolve analyze can harm internal caches in declarations cache
|
||||
KotlinCacheManager.getInstance(file.getProject()).invalidateCache();
|
||||
|
||||
return emptyExhaustWithDiagnosticOnFile(file, e);
|
||||
}
|
||||
}
|
||||
};
|
||||
return Result.create(cache, PsiModificationTracker.MODIFICATION_COUNT, globalContext.getExceptionTracker());
|
||||
}
|
||||
|
||||
private static AnalyzeExhaust analyzeHeadersWithCacheOnFile(@NotNull JetFile fileToCache, @NotNull GlobalContext globalContext) {
|
||||
VirtualFile virtualFile = fileToCache.getVirtualFile();
|
||||
if (LightClassUtil.belongsToKotlinBuiltIns(fileToCache) ||
|
||||
virtualFile != null && LibraryUtil.findLibraryEntry(virtualFile, fileToCache.getProject()) != null) {
|
||||
// Library sources:
|
||||
// Mark file to skip
|
||||
fileToCache.putUserData(LibrarySourceHacks.SKIP_TOP_LEVEL_MEMBERS, true);
|
||||
// Resolve this file, not only project files (as KotlinCacheManager do)
|
||||
|
||||
return AnalyzerFacadeForJVM
|
||||
.analyzeFilesWithJavaIntegrationInGlobalContext(
|
||||
fileToCache.getProject(),
|
||||
Collections.singleton(fileToCache),
|
||||
new BindingTraceContext(),
|
||||
Predicates.<PsiFile>alwaysFalse(),
|
||||
true,
|
||||
AnalyzerFacadeForJVM.createJavaModule("<module>"),
|
||||
globalContext,
|
||||
MemberFilter.ALWAYS_TRUE
|
||||
);
|
||||
}
|
||||
|
||||
KotlinDeclarationsCache cache = KotlinCacheManagerUtil.getDeclarationsFromProject(fileToCache);
|
||||
return ((KotlinDeclarationsCacheImpl) cache).getAnalyzeExhaust();
|
||||
}
|
||||
|
||||
private static AnalyzeExhaust analyzeBodies(AnalyzeExhaust analyzeExhaustHeaders, JetFile file) {
|
||||
BodiesResolveContext context = analyzeExhaustHeaders.getBodiesResolveContext();
|
||||
assert context != null : "Headers resolver should prepare and stored information for bodies resolve";
|
||||
|
||||
// Need to resolve bodies in given file and all in the same package
|
||||
return AnalyzerFacadeProvider.getAnalyzerFacadeForFile(file).analyzeBodiesInFiles(
|
||||
file.getProject(),
|
||||
new JetFilesProvider.SameJetFilePredicate(file),
|
||||
new DelegatingBindingTrace(analyzeExhaustHeaders.getBindingContext(),
|
||||
"trace to resolve bodies in file", file.getName()),
|
||||
context,
|
||||
analyzeExhaustHeaders.getModuleDescriptor());
|
||||
}
|
||||
|
||||
private static void handleError(@NotNull Throwable e) {
|
||||
DiagnosticUtils.throwIfRunningOnServer(e);
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,13 @@ import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
|
||||
import org.jetbrains.jet.plugin.caches.resolve.KotlinResolveCache;
|
||||
|
||||
public class ResolveSessionForBodies implements KotlinCodeAnalyzer, ModificationTracker {
|
||||
private final Object createdForObject;
|
||||
private final ResolveSession resolveSession;
|
||||
private final ResolveElementCache resolveElementCache;
|
||||
private final KotlinResolveCache resolveCache;
|
||||
|
||||
public ResolveSessionForBodies(@NotNull JetFile file, @NotNull ResolveSession resolveSession) {
|
||||
this(file, file.getProject(), resolveSession);
|
||||
@@ -47,6 +49,7 @@ public class ResolveSessionForBodies implements KotlinCodeAnalyzer, Modification
|
||||
this.createdForObject = createdForObject;
|
||||
this.resolveSession = resolveSession;
|
||||
this.resolveElementCache = new ResolveElementCache(resolveSession, project);
|
||||
this.resolveCache = new KotlinResolveCache(project, resolveSession);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -92,4 +95,9 @@ public class ResolveSessionForBodies implements KotlinCodeAnalyzer, Modification
|
||||
public String toString() {
|
||||
return "ResolveSessionForBodies: " + getModificationCount() + " " + createdForObject + " " + createdForObject.hashCode();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public KotlinResolveCache getResolveCache() {
|
||||
return resolveCache;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user