From e946a0f908776f6e7512798f4c62b4ead251ab19 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Sun, 27 May 2012 17:39:56 +0400 Subject: [PATCH] - Out of block modification strategy for Kotlin block expression - Separate project analysis for IDEA needs: headers + bodies --- .../jetbrains/jet/cli/js/K2JSCompiler.java | 6 +- .../di/InjectorForTopDownAnalyzerForJvm.java | 47 ++------ .../resolve/java/AnalyzerFacadeForJVM.java | 64 ++++++++-- .../jet/analyzer/AnalyzeExhaust.java | 21 +++- .../jet/analyzer/AnalyzerFacade.java | 9 ++ .../di/InjectorForTopDownAnalyzerBasic.java | 41 ++----- .../jet/lang/psi/JetBlockExpression.java | 9 +- .../jet/lang/psi/JetDeclaration.java | 2 + .../jetbrains/jet/lang/psi/JetElement.java | 2 +- .../lang/psi/JetModifiableBlockHelper.java | 54 +++++++++ .../lang/resolve/BodiesResolveContext.java | 44 +++++++ .../jet/lang/resolve/BodyResolver.java | 14 +-- .../resolve/CachedBodiesResolveContext.java | 111 ++++++++++++++++++ .../jet/lang/resolve/ControlFlowAnalyzer.java | 34 ++---- .../jet/lang/resolve/DeclarationsChecker.java | 28 ++--- .../lang/resolve/DelegatingBindingTrace.java | 10 +- .../lang/resolve/TopDownAnalysisContext.java | 19 ++- .../jet/lang/resolve/TopDownAnalyzer.java | 10 +- .../project/AnalyzerFacadeWithCache.java | 103 +++++++++++----- .../project/JSAnalyzerFacadeForIDEA.java | 17 ++- .../checker/RecursiveTypeInference.jet | 4 +- .../di/InjectorForTopDownAnalyzerForJs.java | 41 ++----- .../k2js/analyze/AnalyzerFacadeForJS.java | 53 ++++++++- 23 files changed, 516 insertions(+), 227 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifiableBlockHelper.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodiesResolveContext.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/CachedBodiesResolveContext.java diff --git a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java index c6a4107acc0..a8e35b5981e 100644 --- a/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java +++ b/compiler/cli/src/org/jetbrains/jet/cli/js/K2JSCompiler.java @@ -31,8 +31,6 @@ import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; import org.jetbrains.jet.cli.common.messages.PrintingMessageCollector; import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment; 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.k2js.analyze.AnalyzerFacadeForJS; import org.jetbrains.k2js.config.Config; import org.jetbrains.k2js.config.EcmaVersion; @@ -110,9 +108,7 @@ public class K2JSCompiler extends CLICompiler() { @Override public AnalyzeExhaust invoke() { - BindingContext context = AnalyzerFacadeForJS - .analyzeFiles(sources, Predicates.alwaysTrue(), config); - return AnalyzeExhaust.success(context, JetStandardLibrary.getInstance()); + return AnalyzerFacadeForJS.analyzeFiles(sources, Predicates.alwaysTrue(), config); } }, sources); return analyzerWithCompilerReport.hasErrors(); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index 69366baf299..5f98e0cdbbe 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -17,44 +17,16 @@ package org.jetbrains.jet.di; -import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisContext; -import org.jetbrains.jet.lang.resolve.BodyResolver; -import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; -import org.jetbrains.jet.lang.resolve.DeclarationsChecker; -import org.jetbrains.jet.lang.resolve.DescriptorResolver; import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; -import org.jetbrains.jet.lang.resolve.java.CompilerSpecialMode; -import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration; -import org.jetbrains.jet.lang.resolve.java.PsiClassFinderForJvm; -import org.jetbrains.jet.lang.resolve.DeclarationResolver; -import org.jetbrains.jet.lang.resolve.AnnotationResolver; -import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; -import org.jetbrains.jet.lang.resolve.TypeResolver; -import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; -import org.jetbrains.jet.lang.resolve.ImportsResolver; -import org.jetbrains.jet.lang.resolve.DelegationResolver; -import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; -import org.jetbrains.jet.lang.resolve.OverloadResolver; -import org.jetbrains.jet.lang.resolve.OverrideResolver; -import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver; -import org.jetbrains.jet.lang.resolve.java.JavaSemanticServices; -import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; -import org.jetbrains.jet.lang.resolve.java.JavaTypeTransformer; -import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.resolve.java.CompilerDependencies; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; +import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; +import org.jetbrains.jet.lang.resolve.java.*; +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; + import javax.annotation.PreDestroy; /* This file is generated by org.jetbrains.jet.di.AllInjectorsGenerator. DO NOT EDIT! */ @@ -149,18 +121,15 @@ public class InjectorForTopDownAnalyzerForJvm { this.topDownAnalysisContext.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setCallResolver(callResolver); - this.bodyResolver.setContext(topDownAnalysisContext); this.bodyResolver.setDescriptorResolver(descriptorResolver); this.bodyResolver.setExpressionTypingServices(expressionTypingServices); this.bodyResolver.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setTrace(observableBindingTrace); - this.controlFlowAnalyzer.setContext(topDownAnalysisContext); this.controlFlowAnalyzer.setFlowDataTraceFactory(jetControlFlowDataTraceFactory); this.controlFlowAnalyzer.setTopDownAnalysisParameters(topDownAnalysisParameters); this.controlFlowAnalyzer.setTrace(observableBindingTrace); - this.declarationsChecker.setContext(topDownAnalysisContext); this.declarationsChecker.setTrace(observableBindingTrace); this.descriptorResolver.setAnnotationResolver(annotationResolver); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java index 8f745b4d233..75e2cf1db01 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AnalyzerFacadeForJVM.java @@ -27,10 +27,7 @@ import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJvm; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.AnalyzingUtils; -import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; +import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; @@ -56,7 +53,21 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { @NotNull Predicate filesToAnalyzeCompletely, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) { return analyzeFilesWithJavaIntegration(project, files, filesToAnalyzeCompletely, flowDataTraceFactory, - compilerDependenciesForProduction(CompilerSpecialMode.REGULAR)); + compilerDependenciesForProduction(CompilerSpecialMode.REGULAR), true); + } + + @NotNull + @Override + public AnalyzeExhaust analyzeBodiesInFiles(@NotNull Project project, + @NotNull Predicate filesForBodiesResolve, + @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, + @NotNull BindingTrace headersTraceContext, + @NotNull BodiesResolveContext bodiesResolveContext + ) { + return analyzeBodiesInFilesWithJavaIntegration( + project, filesForBodiesResolve, flowDataTraceFactory, + compilerDependenciesForProduction(CompilerSpecialMode.REGULAR), + headersTraceContext, bodiesResolveContext); } public static AnalyzeExhaust analyzeOneFileWithJavaIntegrationAndCheckForErrors( @@ -82,6 +93,16 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { Project project, Collection files, Predicate filesToAnalyzeCompletely, JetControlFlowDataTraceFactory flowDataTraceFactory, @NotNull CompilerDependencies compilerDependencies) { + return analyzeFilesWithJavaIntegration( + project, files, filesToAnalyzeCompletely, + flowDataTraceFactory, compilerDependencies, false); + } + + public static AnalyzeExhaust analyzeFilesWithJavaIntegration( + Project project, Collection files, Predicate filesToAnalyzeCompletely, + JetControlFlowDataTraceFactory flowDataTraceFactory, + @NotNull CompilerDependencies compilerDependencies, + boolean storeContextForBodiesResolve) { BindingTraceContext bindingTraceContext = new BindingTraceContext(); final ModuleDescriptor owner = new ModuleDescriptor(Name.special("")); @@ -89,17 +110,42 @@ public enum AnalyzerFacadeForJVM implements AnalyzerFacade { TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters( filesToAnalyzeCompletely, false, false); - InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm( project, topDownAnalysisParameters, new ObservableBindingTrace(bindingTraceContext), owner, flowDataTraceFactory, compilerDependencies); - - try { injector.getTopDownAnalyzer().analyzeFiles(files); + BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ? + new CachedBodiesResolveContext(injector.getTopDownAnalysisContext()) : + null; + return AnalyzeExhaust.success(bindingTraceContext.getBindingContext(), JetStandardLibrary.getInstance(), bodiesResolveContext); + } finally { + injector.destroy(); + } + } - return AnalyzeExhaust.success(bindingTraceContext.getBindingContext(), JetStandardLibrary.getInstance()); + public static AnalyzeExhaust analyzeBodiesInFilesWithJavaIntegration( + Project project, Predicate filesToAnalyzeCompletely, + JetControlFlowDataTraceFactory flowDataTraceFactory, + @NotNull CompilerDependencies compilerDependencies, + @NotNull BindingTrace traceContext, + @NotNull BodiesResolveContext bodiesResolveContext) { + final ModuleDescriptor owner = new ModuleDescriptor(Name.special("")); + + TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters( + filesToAnalyzeCompletely, false, false); + + bodiesResolveContext.setTopDownAnalysisParameters(topDownAnalysisParameters); + + InjectorForTopDownAnalyzerForJvm injector = new InjectorForTopDownAnalyzerForJvm( + project, topDownAnalysisParameters, + new ObservableBindingTrace(traceContext), owner, flowDataTraceFactory, + compilerDependencies); + + try { + injector.getTopDownAnalyzer().doProcessForBodies(bodiesResolveContext); + return AnalyzeExhaust.success(traceContext.getBindingContext(), JetStandardLibrary.getInstance()); } finally { injector.destroy(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzeExhaust.java b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzeExhaust.java index 4c2950bfb42..bf2e2fcf379 100644 --- a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzeExhaust.java +++ b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzeExhaust.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.analyzer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BodiesResolveContext; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; /** @@ -30,19 +31,33 @@ public class AnalyzeExhaust { private final JetStandardLibrary standardLibrary; private final Throwable error; + @Nullable + private final BodiesResolveContext bodiesResolveContext; + private AnalyzeExhaust(@NotNull BindingContext bindingContext, - @Nullable JetStandardLibrary standardLibrary, @Nullable Throwable error) { + @Nullable JetStandardLibrary standardLibrary, @Nullable BodiesResolveContext bodiesResolveContext, @Nullable Throwable error) { this.bindingContext = bindingContext; this.standardLibrary = standardLibrary; this.error = error; + this.bodiesResolveContext = bodiesResolveContext; } public static AnalyzeExhaust success(@NotNull BindingContext bindingContext, @NotNull JetStandardLibrary standardLibrary) { - return new AnalyzeExhaust(bindingContext, standardLibrary, null); + return new AnalyzeExhaust(bindingContext, standardLibrary, null, null); + } + + public static AnalyzeExhaust success(@NotNull BindingContext bindingContext, @NotNull JetStandardLibrary standardLibrary, + BodiesResolveContext bodiesResolveContext) { + return new AnalyzeExhaust(bindingContext, standardLibrary, bodiesResolveContext, null); } public static AnalyzeExhaust error(@NotNull BindingContext bindingContext, @NotNull Throwable error) { - return new AnalyzeExhaust(bindingContext, null, error); + return new AnalyzeExhaust(bindingContext, null, null, error); + } + + @Nullable + public BodiesResolveContext getBodiesResolveContext() { + return bodiesResolveContext; } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java index 7e31fee0773..a80a65f787f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java +++ b/compiler/frontend/src/org/jetbrains/jet/analyzer/AnalyzerFacade.java @@ -22,6 +22,8 @@ import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.BodiesResolveContext; import java.util.Collection; @@ -35,4 +37,11 @@ public interface AnalyzerFacade { @NotNull Collection files, @NotNull Predicate filesToAnalyzeCompletely, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory); + + @NotNull + AnalyzeExhaust analyzeBodiesInFiles(@NotNull Project project, + @NotNull Predicate filesForBodiesResolve, + @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, + @NotNull BindingTrace traceContext, + @NotNull BodiesResolveContext bodiesResolveContext); } diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java index 569ef4f592c..843ec10293a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java @@ -17,38 +17,16 @@ package org.jetbrains.jet.di; -import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisContext; -import org.jetbrains.jet.lang.resolve.BodyResolver; -import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; -import org.jetbrains.jet.lang.resolve.DeclarationsChecker; -import org.jetbrains.jet.lang.resolve.DescriptorResolver; import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.ModuleConfiguration; -import org.jetbrains.jet.lang.resolve.DeclarationResolver; -import org.jetbrains.jet.lang.resolve.AnnotationResolver; -import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; -import org.jetbrains.jet.lang.resolve.TypeResolver; -import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; -import org.jetbrains.jet.lang.resolve.ImportsResolver; -import org.jetbrains.jet.lang.resolve.DelegationResolver; -import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; -import org.jetbrains.jet.lang.resolve.OverloadResolver; -import org.jetbrains.jet.lang.resolve.OverrideResolver; -import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver; -import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.ModuleConfiguration; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.ModuleConfiguration; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; +import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; + import javax.annotation.PreDestroy; /* This file is generated by org.jetbrains.jet.di.AllInjectorsGenerator. DO NOT EDIT! */ @@ -131,18 +109,15 @@ public class InjectorForTopDownAnalyzerBasic { this.topDownAnalysisContext.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setCallResolver(callResolver); - this.bodyResolver.setContext(topDownAnalysisContext); this.bodyResolver.setDescriptorResolver(descriptorResolver); this.bodyResolver.setExpressionTypingServices(expressionTypingServices); this.bodyResolver.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setTrace(observableBindingTrace); - this.controlFlowAnalyzer.setContext(topDownAnalysisContext); this.controlFlowAnalyzer.setFlowDataTraceFactory(jetControlFlowDataTraceFactory); this.controlFlowAnalyzer.setTopDownAnalysisParameters(topDownAnalysisParameters); this.controlFlowAnalyzer.setTrace(observableBindingTrace); - this.declarationsChecker.setContext(topDownAnalysisContext); this.declarationsChecker.setTrace(observableBindingTrace); this.descriptorResolver.setAnnotationResolver(annotationResolver); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java index 2fc18d0b772..7311f52302e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetBlockExpression.java @@ -16,10 +16,10 @@ package org.jetbrains.jet.lang.psi; -import com.google.common.collect.Lists; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiModifiableCodeBlock; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lexer.JetTokens; @@ -30,11 +30,16 @@ import java.util.List; /** * @author max */ -public class JetBlockExpression extends JetExpression implements JetStatementExpression { +public class JetBlockExpression extends JetExpression implements JetStatementExpression, PsiModifiableCodeBlock { public JetBlockExpression(@NotNull ASTNode node) { super(node); } + @Override + public boolean shouldChangeModificationCount(PsiElement place) { + return JetModifiableBlockHelper.shouldChangeModificationCount(place); + } + @Override public void accept(@NotNull JetVisitorVoid visitor) { visitor.visitBlockExpression(this); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetDeclaration.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetDeclaration.java index 392cbfd6e21..def08d80eba 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetDeclaration.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetDeclaration.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.lexer.JetToken; @@ -30,6 +31,7 @@ public abstract class JetDeclaration extends JetExpression implements JetModifie } @Override + @Nullable public JetModifierList getModifierList() { return (JetModifierList) findChildByType(JetNodeTypes.MODIFIER_LIST); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetElement.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetElement.java index 86af9a1012f..ec0d500a60a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetElement.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetElement.java @@ -42,7 +42,7 @@ public class JetElement extends ASTWrapperPsiElement { */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) - public static @interface IfNotParsed {} + public @interface IfNotParsed {} @NotNull @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifiableBlockHelper.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifiableBlockHelper.java new file mode 100644 index 00000000000..9fccc4574c5 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifiableBlockHelper.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2012 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.lang.psi; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; + +/** + * @author Nikolay Krasko + */ +public final class JetModifiableBlockHelper { + private JetModifiableBlockHelper() { + } + + // TODO: Need tests for this method + // TODO: Consider for FUNCTION_LITERALS + public static boolean shouldChangeModificationCount(PsiElement place) { + JetDeclaration declaration = PsiTreeUtil.getParentOfType(place, JetDeclaration.class, true); + if (declaration != null) { + if (declaration instanceof JetNamedFunction) { + JetNamedFunction function = (JetNamedFunction) declaration; + if (function.hasDeclaredReturnType() || function.hasBlockBody()) { + return false; + } + + return shouldChangeModificationCount(function); + } + else if (declaration instanceof JetProperty) { + JetProperty property = (JetProperty) declaration; + if (property.getPropertyTypeRef() != null) { + return false; + } + + return shouldChangeModificationCount(property); + } + } + + return true; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodiesResolveContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodiesResolveContext.java new file mode 100644 index 00000000000..54cd398cef4 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodiesResolveContext.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2012 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.lang.resolve; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; + +import java.util.Map; + +/** +* @author Nikolay Krasko +*/ +public interface BodiesResolveContext { + Map getClasses(); + Map getObjects(); + Map getConstructors(); + Map getProperties(); + Map getFunctions(); + Map getDeclaringScopes(); + Map getScripts(); + Map getScriptScopes(); + + void setTopDownAnalysisParameters(TopDownAnalysisParameters parameters); + + boolean completeAnalysisNeeded(@NotNull PsiElement element); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index 9474a665c33..329530bb637 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -55,7 +55,7 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; */ public class BodyResolver { @NotNull - private TopDownAnalysisContext context; + private BodiesResolveContext context; @NotNull private TopDownAnalysisParameters topDownAnalysisParameters; @NotNull @@ -67,12 +67,6 @@ public class BodyResolver { @NotNull private ObservableBindingTrace trace; - - @Inject - public void setContext(@NotNull TopDownAnalysisContext context) { - this.context = context; - } - @Inject public void setTopDownAnalysisParameters(@NotNull TopDownAnalysisParameters topDownAnalysisParameters) { this.topDownAnalysisParameters = topDownAnalysisParameters; @@ -98,9 +92,9 @@ public class BodyResolver { this.trace = trace; } - - - public void resolveBehaviorDeclarationBodies() { + public void resolveBehaviorDeclarationBodies(@NotNull BodiesResolveContext bodiesResolveContext) { + // Initialize context + context = bodiesResolveContext; resolveDelegationSpecifierLists(); resolveClassAnnotations(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/CachedBodiesResolveContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/CachedBodiesResolveContext.java new file mode 100644 index 00000000000..863ef6323ed --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/CachedBodiesResolveContext.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010-2012 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.lang.resolve; + +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.resolve.scopes.WritableScope; + +import java.util.Collections; +import java.util.Map; + +/** + * A storage for the part of {@see TopDownAnalysisContext} collected during headers analysis that will be used during resolution of + * bodies + * +* @author Nikolay Krasko +*/ +public class CachedBodiesResolveContext implements BodiesResolveContext { + private final Map classes; + private final Map objects; + private final Map constructors; + private final Map properties; + private final Map functions; + private final Map declaringScopes; + private final Map scripts; + private final Map scriptScopes; + + private @NotNull TopDownAnalysisParameters topDownAnalysisParameters; + + public CachedBodiesResolveContext(TopDownAnalysisContext context) { + classes = Collections.unmodifiableMap(context.getClasses()); + objects = Collections.unmodifiableMap(context.getObjects()); + constructors = Collections.unmodifiableMap(context.getConstructors()); + properties = Collections.unmodifiableMap(context.getProperties()); + functions = Collections.unmodifiableMap(context.getFunctions()); + declaringScopes = Collections.unmodifiableMap(context.getDeclaringScopes()); + scripts = Collections.unmodifiableMap(context.getScripts()); + scriptScopes = Collections.unmodifiableMap(context.getScriptScopes()); + + topDownAnalysisParameters = context.getTopDownAnalysisParameters(); + } + + @Override + public Map getClasses() { + return classes; + } + + @Override + public Map getObjects() { + return objects; + } + + @Override + public Map getConstructors() { + return constructors; + } + + @Override + public Map getProperties() { + return properties; + } + + @Override + public Map getFunctions() { + return functions; + } + + @Override + public Map getDeclaringScopes() { + return declaringScopes; + } + + @Override + public Map getScripts() { + return scripts; + } + + @Override + public Map getScriptScopes() { + return scriptScopes; + } + + @Override + public void setTopDownAnalysisParameters(@NotNull TopDownAnalysisParameters parameters) { + topDownAnalysisParameters = parameters; + } + + @Override + public boolean completeAnalysisNeeded(@NotNull PsiElement element) { + PsiFile containingFile = element.getContainingFile(); + return containingFile != null && topDownAnalysisParameters.getAnalyzeCompletely().apply(containingFile); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java index 9805e04b7ca..67efa73f586 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ControlFlowAnalyzer.java @@ -36,21 +36,14 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; */ public class ControlFlowAnalyzer { private TopDownAnalysisParameters topDownAnalysisParameters; - private TopDownAnalysisContext context; private BindingTrace trace; private JetControlFlowDataTraceFactory flowDataTraceFactory; - @Inject public void setTopDownAnalysisParameters(TopDownAnalysisParameters topDownAnalysisParameters) { this.topDownAnalysisParameters = topDownAnalysisParameters; } - @Inject - public void setContext(TopDownAnalysisContext context) { - this.context = context; - } - @Inject public void setTrace(BindingTrace trace) { this.trace = trace; @@ -61,43 +54,42 @@ public class ControlFlowAnalyzer { this.flowDataTraceFactory = flowDataTraceFactory; } - - public void process() { - for (JetClass aClass : context.getClasses().keySet()) { - if (!context.completeAnalysisNeeded(aClass)) continue; + public void process(@NotNull BodiesResolveContext bodiesResolveContext) { + for (JetClass aClass : bodiesResolveContext.getClasses().keySet()) { + if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue; checkClassOrObject(aClass); } - for (JetObjectDeclaration objectDeclaration : context.getObjects().keySet()) { - if (!context.completeAnalysisNeeded(objectDeclaration)) continue; + for (JetObjectDeclaration objectDeclaration : bodiesResolveContext.getObjects().keySet()) { + if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue; checkClassOrObject(objectDeclaration); } - for (Map.Entry entry : context.getFunctions().entrySet()) { + for (Map.Entry entry : bodiesResolveContext.getFunctions().entrySet()) { JetNamedFunction function = entry.getKey(); SimpleFunctionDescriptor functionDescriptor = entry.getValue(); - if (!context.completeAnalysisNeeded(function)) continue; + if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue; final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType() ? NO_EXPECTED_TYPE : functionDescriptor.getReturnType(); checkFunction(function, expectedReturnType); } - for (JetSecondaryConstructor constructor : this.context.getConstructors().keySet()) { - if (!context.completeAnalysisNeeded(constructor)) continue; + for (JetSecondaryConstructor constructor : bodiesResolveContext.getConstructors().keySet()) { + if (!bodiesResolveContext.completeAnalysisNeeded(constructor)) continue; checkFunction(constructor, JetStandardClasses.getUnitType()); } - for (Map.Entry entry : context.getProperties().entrySet()) { + for (Map.Entry entry : bodiesResolveContext.getProperties().entrySet()) { JetProperty property = entry.getKey(); - if (!context.completeAnalysisNeeded(property)) continue; + if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue; PropertyDescriptor propertyDescriptor = entry.getValue(); checkProperty(property, propertyDescriptor); } } - + private void checkClassOrObject(JetClassOrObject klass) { // A pseudocode of class initialization corresponds to a class JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, trace); flowInformationProvider.markUninitializedVariables((JetElement) klass, topDownAnalysisParameters.isDeclaredLocally()); } - + private void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor) { for (JetPropertyAccessor accessor : property.getAccessors()) { PropertyAccessorDescriptor accessorDescriptor = accessor.isGetter() diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java index aba3fac6caf..445ce552334 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DeclarationsChecker.java @@ -44,60 +44,50 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE; * @author svtk */ public class DeclarationsChecker { - @NotNull - private TopDownAnalysisContext context; @NotNull private BindingTrace trace; - - @Inject - public void setContext(@NotNull TopDownAnalysisContext context) { - this.context = context; - } - @Inject public void setTrace(@NotNull BindingTrace trace) { this.trace = trace; } - - - public void process() { - Map classes = context.getClasses(); + public void process(@NotNull BodiesResolveContext bodiesResolveContext) { + Map classes = bodiesResolveContext.getClasses(); for (Map.Entry entry : classes.entrySet()) { JetClass aClass = entry.getKey(); MutableClassDescriptor classDescriptor = entry.getValue(); - if (!context.completeAnalysisNeeded(aClass)) continue; + if (!bodiesResolveContext.completeAnalysisNeeded(aClass)) continue; checkClass(aClass, classDescriptor); checkModifiers(aClass.getModifierList(), classDescriptor); } - Map objects = context.getObjects(); + Map objects = bodiesResolveContext.getObjects(); for (Map.Entry entry : objects.entrySet()) { JetObjectDeclaration objectDeclaration = entry.getKey(); MutableClassDescriptor objectDescriptor = entry.getValue(); - if (!context.completeAnalysisNeeded(objectDeclaration)) continue; + if (!bodiesResolveContext.completeAnalysisNeeded(objectDeclaration)) continue; checkObject(objectDeclaration, objectDescriptor); } - Map functions = context.getFunctions(); + Map functions = bodiesResolveContext.getFunctions(); for (Map.Entry entry : functions.entrySet()) { JetNamedFunction function = entry.getKey(); SimpleFunctionDescriptor functionDescriptor = entry.getValue(); - if (!context.completeAnalysisNeeded(function)) continue; + if (!bodiesResolveContext.completeAnalysisNeeded(function)) continue; checkFunction(function, functionDescriptor); checkModifiers(function.getModifierList(), functionDescriptor); } - Map properties = context.getProperties(); + Map properties = bodiesResolveContext.getProperties(); for (Map.Entry entry : properties.entrySet()) { JetProperty property = entry.getKey(); PropertyDescriptor propertyDescriptor = entry.getValue(); - if (!context.completeAnalysisNeeded(property)) continue; + if (!bodiesResolveContext.completeAnalysisNeeded(property)) continue; checkProperty(property, propertyDescriptor); checkModifiers(property.getModifierList(), propertyDescriptor); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java index f7159a905cc..8eb22fa32f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DelegatingBindingTrace.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.util.slicedmap.*; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -36,7 +37,9 @@ public class DelegatingBindingTrace implements BindingTrace { private final BindingContext bindingContext = new BindingContext() { @Override public Collection getDiagnostics() { - return diagnostics; + ArrayList mergedDiagnostics = new ArrayList(diagnostics); + mergedDiagnostics.addAll(parentContext.getDiagnostics()); + return mergedDiagnostics; } @Override @@ -79,9 +82,10 @@ public class DelegatingBindingTrace implements BindingTrace { assert value != null; if (value.equals(true)) return value; } - else { - if (value != null) return value; + else if (value != null) { + return value; } + return parentContext.get(slice, key); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java index b982e93ab54..6901d2434b9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalysisContext.java @@ -17,7 +17,6 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; @@ -33,7 +32,7 @@ import java.util.Map; /** * @author abreslav */ -public class TopDownAnalysisContext { +public class TopDownAnalysisContext implements BodiesResolveContext { private final Map classes = Maps.newLinkedHashMap(); private final Map objects = Maps.newLinkedHashMap(); @@ -62,13 +61,15 @@ public class TopDownAnalysisContext { private TopDownAnalysisParameters topDownAnalysisParameters; + @Override @Inject public void setTopDownAnalysisParameters(TopDownAnalysisParameters topDownAnalysisParameters) { this.topDownAnalysisParameters = topDownAnalysisParameters; } - - + public TopDownAnalysisParameters getTopDownAnalysisParameters() { + return topDownAnalysisParameters; + } public void debug(Object message) { if (debugOutput != null) { @@ -76,6 +77,7 @@ public class TopDownAnalysisContext { } } + @SuppressWarnings("UnusedDeclaration") /*package*/ void enableDebugOutput() { if (debugOutput == null) { debugOutput = new StringBuilder(); @@ -88,6 +90,7 @@ public class TopDownAnalysisContext { } } + @Override public boolean completeAnalysisNeeded(@NotNull PsiElement element) { PsiFile containingFile = element.getContainingFile(); boolean result = containingFile != null && topDownAnalysisParameters.getAnalyzeCompletely().apply(containingFile); @@ -97,10 +100,12 @@ public class TopDownAnalysisContext { return result; } + @Override public Map getClasses() { return classes; } + @Override public Map getObjects() { return objects; } @@ -123,11 +128,13 @@ public class TopDownAnalysisContext { return namespaceDescriptors; } + @Override @NotNull public Map getScripts() { return scripts; } + @Override @NotNull public Map getScriptScopes() { return scriptScopes; @@ -137,18 +144,22 @@ public class TopDownAnalysisContext { return primaryConstructorParameterProperties; } + @Override public Map getConstructors() { return constructors; } + @Override public Map getProperties() { return properties; } + @Override public Map getDeclaringScopes() { return declaringScopes; } + @Override public Map getFunctions() { return functions; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 8a9599c9f9e..4fbb5f140ac 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -136,7 +136,6 @@ public class TopDownAnalyzer { this.declarationsChecker = declarationsChecker; } - public void doProcess( JetScope outerScope, NamespaceLikeBuilder owner, @@ -154,15 +153,18 @@ public class TopDownAnalyzer { overloadResolver.process(); if (!topDownAnalysisParameters.isAnalyzingBootstrapLibrary()) { - bodyResolver.resolveBehaviorDeclarationBodies(); - controlFlowAnalyzer.process(); - declarationsChecker.process(); + doProcessForBodies(context); } context.debug("Exit"); context.printDebugOutput(System.out); } + public void doProcessForBodies(BodiesResolveContext bodiesResolveContext) { + bodyResolver.resolveBehaviorDeclarationBodies(bodiesResolveContext); + controlFlowAnalyzer.process(bodiesResolveContext); + declarationsChecker.process(bodiesResolveContext); + } private void lockScopes() { for (MutableClassDescriptor mutableClassDescriptor : context.getClasses().values()) { diff --git a/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java b/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java index fac916c618c..dcd3b4bf4d1 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java +++ b/idea/src/org/jetbrains/jet/plugin/project/AnalyzerFacadeWithCache.java @@ -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> ANALYZE_EXHAUST = Key.create("ANALYZE_EXHAUST"); + private final static Key> ANALYZE_EXHAUST_HEADERS = Key.create("ANALYZE_EXHAUST_HEADERS"); + private final static Key> ANALYZE_EXHAUST_FULL = Key.create("ANALYZE_EXHAUST_FULL"); + private static final Object lock = new Object(); public static final Function> SINGLE_DECLARATION_PROVIDER = new Function>() { @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> declarationProvider) { // Need lock for getValue(), because parallel threads can start evaluation of compute() simultaneously synchronized (lock) { - CachedValue bindingContextCachedValue = file.getUserData(ANALYZE_EXHAUST); + CachedValue bindingContextCachedValue = file.getUserData(ANALYZE_EXHAUST_FULL); if (bindingContextCachedValue == null) { bindingContextCachedValue = - CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { - @Override - public Result compute() { - try { - AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(file) - .analyzeFiles(file.getProject(), - declarationProvider.fun(file), - Predicates.equalTo(file), - JetControlFlowDataTraceFactory.EMPTY); - return new Result(exhaust, PsiModificationTracker.MODIFICATION_COUNT); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Throwable e) { - handleError(e); - return emptyExhaustWithDiagnosticOnFile(e); - } - } + CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + try { + // System.out.println("===============ReCache - In-Block=============="); - @NotNull - private Result 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, PsiModificationTracker.MODIFICATION_COUNT); - } - }, false); - file.putUserData(ANALYZE_EXHAUST, bindingContextCachedValue); + // Collect context for headers first + Collection 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.equalTo(file), + JetControlFlowDataTraceFactory.EMPTY, + new DelegatingBindingTrace(analyzeExhaustHeaders.getBindingContext()), + context); + + return new Result(exhaust, PsiModificationTracker.MODIFICATION_COUNT); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (Throwable e) { + handleError(e); + return emptyExhaustWithDiagnosticOnFile(e); + } + } + + @NotNull + private Result 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, PsiModificationTracker.MODIFICATION_COUNT); + } + }, false); + + file.putUserData(ANALYZE_EXHAUST_FULL, bindingContextCachedValue); } + return bindingContextCachedValue.getValue(); } } + private static AnalyzeExhaust analyzeHeadersWithCacheOnFile(@NotNull final JetFile fileToCache, + @NotNull final Collection headerFiles) { + CachedValue bindingContextCachedValue = fileToCache.getUserData(ANALYZE_EXHAUST_HEADERS); + if (bindingContextCachedValue == null) { + bindingContextCachedValue = + CachedValuesManager.getManager(fileToCache.getProject()).createCachedValue(new CachedValueProvider() { + @Override + public Result compute() { + // System.out.println("===============ReCache - OUT-OF-BLOCK=============="); + AnalyzeExhaust exhaust = AnalyzerFacadeProvider.getAnalyzerFacadeForFile(fileToCache) + .analyzeFiles(fileToCache.getProject(), + headerFiles, + Predicates.alwaysFalse(), + JetControlFlowDataTraceFactory.EMPTY); + + return new Result(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); diff --git a/idea/src/org/jetbrains/jet/plugin/project/JSAnalyzerFacadeForIDEA.java b/idea/src/org/jetbrains/jet/plugin/project/JSAnalyzerFacadeForIDEA.java index 53a9bf59d2d..78f8a8495df 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/JSAnalyzerFacadeForIDEA.java +++ b/idea/src/org/jetbrains/jet/plugin/project/JSAnalyzerFacadeForIDEA.java @@ -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 files, @NotNull Predicate 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 filesForBodiesResolve, + @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory, + @NotNull BindingTrace traceContext, + @NotNull BodiesResolveContext bodiesResolveContext) { + return AnalyzerFacadeForJS.analyzeBodiesInFiles(filesForBodiesResolve, new IDEAConfig(project), traceContext, bodiesResolveContext); } } diff --git a/idea/testData/checker/RecursiveTypeInference.jet b/idea/testData/checker/RecursiveTypeInference.jet index fff8972fd72..f3763ce3f94 100644 --- a/idea/testData/checker/RecursiveTypeInference.jet +++ b/idea/testData/checker/RecursiveTypeInference.jet @@ -1,7 +1,7 @@ //package a { - val afoo = abar() + val afoo = abar() - fun abar() = afoo + fun abar() = afoo //} //package b { diff --git a/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java b/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java index 2eae6436681..61bd7e28bc6 100644 --- a/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java +++ b/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java @@ -17,38 +17,16 @@ package org.jetbrains.jet.di; -import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisContext; -import org.jetbrains.jet.lang.resolve.BodyResolver; -import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; -import org.jetbrains.jet.lang.resolve.DeclarationsChecker; -import org.jetbrains.jet.lang.resolve.DescriptorResolver; import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.ModuleConfiguration; -import org.jetbrains.jet.lang.resolve.DeclarationResolver; -import org.jetbrains.jet.lang.resolve.AnnotationResolver; -import org.jetbrains.jet.lang.resolve.calls.CallResolver; -import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; -import org.jetbrains.jet.lang.resolve.TypeResolver; -import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; -import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; -import org.jetbrains.jet.lang.resolve.ImportsResolver; -import org.jetbrains.jet.lang.resolve.DelegationResolver; -import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl; -import org.jetbrains.jet.lang.resolve.OverloadResolver; -import org.jetbrains.jet.lang.resolve.OverrideResolver; -import org.jetbrains.jet.lang.resolve.TypeHierarchyResolver; -import com.intellij.openapi.project.Project; -import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; -import org.jetbrains.jet.lang.resolve.ObservableBindingTrace; -import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; -import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.ModuleConfiguration; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.ModuleConfiguration; +import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; +import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; +import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.calls.CallResolver; +import org.jetbrains.jet.lang.resolve.calls.OverloadingConflictResolver; +import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; + import javax.annotation.PreDestroy; /* This file is generated by org.jetbrains.jet.di.AllInjectorsGenerator. DO NOT EDIT! */ @@ -131,18 +109,15 @@ public class InjectorForTopDownAnalyzerForJs { this.topDownAnalysisContext.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setCallResolver(callResolver); - this.bodyResolver.setContext(topDownAnalysisContext); this.bodyResolver.setDescriptorResolver(descriptorResolver); this.bodyResolver.setExpressionTypingServices(expressionTypingServices); this.bodyResolver.setTopDownAnalysisParameters(topDownAnalysisParameters); this.bodyResolver.setTrace(observableBindingTrace); - this.controlFlowAnalyzer.setContext(topDownAnalysisContext); this.controlFlowAnalyzer.setFlowDataTraceFactory(jetControlFlowDataTraceFactory); this.controlFlowAnalyzer.setTopDownAnalysisParameters(topDownAnalysisParameters); this.controlFlowAnalyzer.setTrace(observableBindingTrace); - this.declarationsChecker.setContext(topDownAnalysisContext); this.declarationsChecker.setTrace(observableBindingTrace); this.descriptorResolver.setAnnotationResolver(annotationResolver); diff --git a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java index 7e8f5b569d2..1c644c96496 100644 --- a/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java +++ b/js/js.translator/src/org/jetbrains/k2js/analyze/AnalyzerFacadeForJS.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.analyzer.AnalyzeExhaust; import org.jetbrains.jet.di.InjectorForTopDownAnalyzerForJs; import org.jetbrains.jet.lang.DefaultModuleConfiguration; import org.jetbrains.jet.lang.ModuleConfiguration; @@ -37,6 +38,7 @@ import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; +import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.k2js.config.Config; import java.util.Collection; @@ -54,7 +56,7 @@ public final class AnalyzerFacadeForJS { @NotNull public static BindingContext analyzeFilesAndCheckErrors(@NotNull List files, @NotNull Config config) { - BindingContext bindingContext = analyzeFiles(files, Predicates.alwaysTrue(), config); + BindingContext bindingContext = analyzeFiles(files, Predicates.alwaysTrue(), config).getBindingContext(); checkForErrors(withJsLibAdded(files, config), bindingContext); return bindingContext; } @@ -64,12 +66,21 @@ public final class AnalyzerFacadeForJS { @SuppressWarnings("UnusedDeclaration") @NotNull public static BindingContext analyzeFiles(@NotNull Collection files, @NotNull Config config) { - return analyzeFiles(files, Predicates.alwaysTrue(), config); + return analyzeFiles(files, Predicates.alwaysTrue(), config).getBindingContext(); } @NotNull - public static BindingContext analyzeFiles(@NotNull Collection files, + public static AnalyzeExhaust analyzeFiles( + @NotNull Collection files, @NotNull Predicate filesToAnalyzeCompletely, @NotNull Config config) { + return analyzeFiles(files, filesToAnalyzeCompletely, config, false); + } + + @NotNull + public static AnalyzeExhaust analyzeFiles( + @NotNull Collection files, + @NotNull Predicate filesToAnalyzeCompletely, @NotNull Config config, + boolean storeContextForBodiesResolve) { Project project = config.getProject(); BindingTraceContext bindingTraceContext = new BindingTraceContext(); @@ -82,9 +93,41 @@ public final class AnalyzerFacadeForJS { InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs( project, topDownAnalysisParameters, new ObservableBindingTrace(bindingTraceContext), owner, JetControlFlowDataTraceFactory.EMPTY, JsConfiguration.jsLibConfiguration(project)); + try { + injector.getTopDownAnalyzer().analyzeFiles(withJsLibAdded(files, config)); + BodiesResolveContext bodiesResolveContext = storeContextForBodiesResolve ? + new CachedBodiesResolveContext(injector.getTopDownAnalysisContext()) : + null; + return AnalyzeExhaust.success(bindingTraceContext.getBindingContext(), JetStandardLibrary.getInstance(), bodiesResolveContext); + } finally { + injector.destroy(); + } + } + + public static AnalyzeExhaust analyzeBodiesInFiles( + @NotNull Predicate filesToAnalyzeCompletely, + @NotNull Config config, + @NotNull BindingTrace traceContext, + @NotNull BodiesResolveContext bodiesResolveContext + ) { + Project project = config.getProject(); + final ModuleDescriptor owner = new ModuleDescriptor(Name.special("")); + Predicate completely = Predicates.and(notLibFiles(config.getLibFiles()), filesToAnalyzeCompletely); + + TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters(completely, false, false); + + InjectorForTopDownAnalyzerForJs injector = new InjectorForTopDownAnalyzerForJs( + project, topDownAnalysisParameters, new ObservableBindingTrace(traceContext), owner, + JetControlFlowDataTraceFactory.EMPTY, JsConfiguration.jsLibConfiguration(project)); + + try { + bodiesResolveContext.setTopDownAnalysisParameters(topDownAnalysisParameters); + injector.getTopDownAnalyzer().doProcessForBodies(bodiesResolveContext); + return AnalyzeExhaust.success(traceContext.getBindingContext(), JetStandardLibrary.getInstance()); + } finally { + injector.destroy(); + } - injector.getTopDownAnalyzer().analyzeFiles(withJsLibAdded(files, config)); - return bindingTraceContext.getBindingContext(); } private static void checkForErrors(@NotNull Collection allFiles, @NotNull BindingContext bindingContext) {