- Out of block modification strategy for Kotlin block expression

- Separate project analysis for IDEA needs: headers + bodies
This commit is contained in:
Nikolay Krasko
2012-05-27 17:39:56 +04:00
parent e38aac1dce
commit e946a0f908
23 changed files with 516 additions and 227 deletions
@@ -33,6 +33,8 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticUtils;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.BodiesResolveContext;
import org.jetbrains.jet.lang.resolve.DelegatingBindingTrace;
import java.util.Collection;
import java.util.Collections;
@@ -44,7 +46,9 @@ public final class AnalyzerFacadeWithCache {
private static final Logger LOG = Logger.getInstance("org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache");
private final static Key<CachedValue<AnalyzeExhaust>> ANALYZE_EXHAUST = Key.create("ANALYZE_EXHAUST");
private final static Key<CachedValue<AnalyzeExhaust>> ANALYZE_EXHAUST_HEADERS = Key.create("ANALYZE_EXHAUST_HEADERS");
private final static Key<CachedValue<AnalyzeExhaust>> ANALYZE_EXHAUST_FULL = Key.create("ANALYZE_EXHAUST_FULL");
private static final Object lock = new Object();
public static final Function<JetFile, Collection<JetFile>> SINGLE_DECLARATION_PROVIDER = new Function<JetFile, Collection<JetFile>>() {
@Override
@@ -64,48 +68,87 @@ public final class AnalyzerFacadeWithCache {
* @param declarationProvider
* @return
*/
// TODO: Also need to pass several files when user have multi-file environment
@NotNull
public static AnalyzeExhaust analyzeFileWithCache(@NotNull final JetFile file,
@NotNull final Function<JetFile, Collection<JetFile>> declarationProvider) {
// Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously
synchronized (lock) {
CachedValue<AnalyzeExhaust> bindingContextCachedValue = file.getUserData(ANALYZE_EXHAUST);
CachedValue<AnalyzeExhaust> bindingContextCachedValue = file.getUserData(ANALYZE_EXHAUST_FULL);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
try {
AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(file)
.analyzeFiles(file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<AnalyzeExhaust>(exhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
handleError(e);
return emptyExhaustWithDiagnosticOnFile(e);
}
}
CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
try {
// System.out.println("===============ReCache - In-Block==============");
@NotNull
private Result<AnalyzeExhaust> emptyExhaustWithDiagnosticOnFile(Throwable e) {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
AnalyzeExhaust analyzeExhaust = AnalyzeExhaust.error(bindingTraceContext.getBindingContext(), e);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
file.putUserData(ANALYZE_EXHAUST, bindingContextCachedValue);
// Collect context for headers first
Collection<JetFile> allFilesToAnalyze = declarationProvider.fun(file);
AnalyzeExhaust analyzeExhaustHeaders = analyzeHeadersWithCacheOnFile(file, allFilesToAnalyze);
BodiesResolveContext context = analyzeExhaustHeaders.getBodiesResolveContext();
assert context != null : "Headers resolver should prepare and stored information for bodies resolve";
// Need to resolve bodies in given file
AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(file).analyzeBodiesInFiles(
file.getProject(),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY,
new DelegatingBindingTrace(analyzeExhaustHeaders.getBindingContext()),
context);
return new Result<AnalyzeExhaust>(exhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
handleError(e);
return emptyExhaustWithDiagnosticOnFile(e);
}
}
@NotNull
private Result<AnalyzeExhaust> emptyExhaustWithDiagnosticOnFile(Throwable e) {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
bindingTraceContext.report(Errors.EXCEPTION_WHILE_ANALYZING.on(file, e));
AnalyzeExhaust analyzeExhaust = AnalyzeExhaust.error(bindingTraceContext.getBindingContext(), e);
return new Result<AnalyzeExhaust>(analyzeExhaust, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
file.putUserData(ANALYZE_EXHAUST_FULL, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
}
private static AnalyzeExhaust analyzeHeadersWithCacheOnFile(@NotNull final JetFile fileToCache,
@NotNull final Collection<JetFile> headerFiles) {
CachedValue<AnalyzeExhaust> bindingContextCachedValue = fileToCache.getUserData(ANALYZE_EXHAUST_HEADERS);
if (bindingContextCachedValue == null) {
bindingContextCachedValue =
CachedValuesManager.getManager(fileToCache.getProject()).createCachedValue(new CachedValueProvider<AnalyzeExhaust>() {
@Override
public Result<AnalyzeExhaust> compute() {
// System.out.println("===============ReCache - OUT-OF-BLOCK==============");
AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(fileToCache)
.analyzeFiles(fileToCache.getProject(),
headerFiles,
Predicates.<PsiFile>alwaysFalse(),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<AnalyzeExhaust>(exhaust, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
}
}, false);
fileToCache.putUserData(ANALYZE_EXHAUST_HEADERS, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
private static void handleError(@NotNull Throwable e) {
DiagnosticUtils.throwIfRunningOnServer(e);
LOG.error(e);
@@ -24,8 +24,8 @@ import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.analyzer.AnalyzerFacade;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.BodiesResolveContext;
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
import java.util.Collection;
@@ -46,7 +46,16 @@ public enum JSAnalyzerFacadeForIDEA implements AnalyzerFacade {
@NotNull Collection<JetFile> files,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
BindingContext context = AnalyzerFacadeForJS.analyzeFiles(files, filesToAnalyzeCompletely, new IDEAConfig(project));
return AnalyzeExhaust.success(context, JetStandardLibrary.getInstance());
return AnalyzerFacadeForJS.analyzeFiles(files, filesToAnalyzeCompletely, new IDEAConfig(project), true);
}
@NotNull
@Override
public AnalyzeExhaust analyzeBodiesInFiles(@NotNull Project project,
@NotNull Predicate<PsiFile> filesForBodiesResolve,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
@NotNull BindingTrace traceContext,
@NotNull BodiesResolveContext bodiesResolveContext) {
return AnalyzerFacadeForJS.analyzeBodiesInFiles(filesForBodiesResolve, new IDEAConfig(project), traceContext, bodiesResolveContext);
}
}
@@ -1,7 +1,7 @@
//package a {
val afoo = abar()
val afoo = <error descr="[TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM] Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly">abar()</error>
fun abar() = <error descr="[TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM] Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly">afoo</error>
fun abar() = afoo
//}
//package b {