When a file is changed in the IDE, we do not recheck function bodies and other executable code in other files: only declarations to povide resolution context for the changed file

This commit is contained in:
Andrey Breslav
2011-11-01 16:04:55 +03:00
parent 43faa77478
commit 3588779f19
10 changed files with 117 additions and 45 deletions
@@ -1,5 +1,6 @@
package org.jetbrains.jet.cli;
import com.google.common.base.Predicates;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
@@ -82,7 +83,7 @@ public class CompileSession {
final AnalyzingUtils instance = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS);
List<JetNamespace> allNamespaces = new ArrayList<JetNamespace>(mySourceFileNamespaces);
allNamespaces.addAll(myLibrarySourceFileNamespaces);
myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, JetControlFlowDataTraceFactory.EMPTY);
myBindingContext = instance.analyzeNamespaces(myEnvironment.getProject(), allNamespaces, Predicates.<PsiFile>alwaysTrue(), JetControlFlowDataTraceFactory.EMPTY);
ErrorCollector errorCollector = new ErrorCollector(myBindingContext);
errorCollector.report();
return !errorCollector.hasErrors;
@@ -1,7 +1,9 @@
package org.jetbrains.jet.lang.resolve.java;
import com.google.common.base.Predicates;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
@@ -58,6 +60,7 @@ public class AnalyzerFacade {
BindingContext bindingContext = analyzingUtils.analyzeNamespaces(
file.getProject(),
declarationProvider.fun(file),
Predicates.<PsiFile>equalTo(file),
JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
@@ -1,9 +1,12 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
@@ -59,19 +62,24 @@ public class AnalyzingUtils {
Project project = namespace.getProject();
List<JetDeclaration> declarations = Collections.<JetDeclaration>singletonList(namespace);
return analyzeNamespaces(project, declarations, flowDataTraceFactory);
return analyzeNamespaces(project, declarations, Predicates.equalTo(namespace.getContainingFile()), flowDataTraceFactory);
}
public BindingContext analyzeNamespaces(@NotNull Project project, @NotNull Collection<? extends JetDeclaration> declarations, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
public BindingContext analyzeNamespaces(
@NotNull Project project,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> filesToAnalyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
BindingTraceContext bindingTraceContext = new BindingTraceContext();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project);
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
ModuleDescriptor owner = new ModuleDescriptor("<module>");
// final WritableScope scope = new WritableScopeImpl(libraryScope, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace");
final WritableScope scope = new WritableScopeImpl(JetScope.EMPTY, owner, new TraceBasedRedeclarationHandler(bindingTraceContext)).setDebugName("Root scope in analyzeNamespace");
importingStrategy.addImports(project, semanticServices, bindingTraceContext, scope);
scope.importScope(libraryScope);
TopDownAnalyzer.process(semanticServices, bindingTraceContext, scope, new NamespaceLike.Adapter(owner) {
@Override
@@ -103,7 +111,7 @@ public class AnalyzingUtils {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
throw new IllegalStateException("Must be guaranteed not to happen by the parser");
}
}, declarations, flowDataTraceFactory);
}, declarations, filesToAnalyzeCompletely, flowDataTraceFactory);
return bindingTraceContext.getBindingContext();
}
@@ -71,7 +71,6 @@ public class BodyResolver {
}
public void resolveBehaviorDeclarationBodies() {
resolveDelegationSpecifierLists();
@@ -86,34 +85,6 @@ public class BodyResolver {
computeDeferredTypes();
}
private void computeDeferredTypes() {
Collection<DeferredType> deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY);
if (deferredTypes != null) {
final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size());
context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<BindingContext.DeferredTypeKey, DeferredType>() {
@Override
public void handleRecord(WritableSlice<BindingContext.DeferredTypeKey, DeferredType> deferredTypeKeyDeferredTypeWritableSlice, BindingContext.DeferredTypeKey key, DeferredType value) {
queue.addLast(value);
}
});
for (DeferredType deferredType : deferredTypes) {
queue.addLast(deferredType);
}
while (!queue.isEmpty()) {
DeferredType deferredType = queue.pullFirst();
if (!deferredType.isComputed()) {
try {
deferredType.getActualType(); // to compute
}
catch (ReenteringLazyValueComputationException e) {
// A problem should be reported while computing the type
}
}
}
}
}
private void resolveDelegationSpecifierLists() {
// TODO : Make sure the same thing is not initialized twice
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
@@ -125,6 +96,7 @@ public class BodyResolver {
}
private void resolveDelegationSpecifierList(final JetClassOrObject jetClass, final MutableClassDescriptor descriptor) {
if (!context.completeAnalysisNeeded(jetClass)) return;
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
final JetScope scopeForConstructor = primaryConstructor == null
? null
@@ -278,7 +250,6 @@ public class BodyResolver {
}
private void resolveClassAnnotations() {
}
private void resolveAnonymousInitializers() {
@@ -291,6 +262,7 @@ public class BodyResolver {
}
private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) {
if (!context.completeAnalysisNeeded(jetClassOrObject)) return;
List<JetClassInitializer> anonymousInitializers = jetClassOrObject.getAnonymousInitializers();
if (jetClassOrObject.hasPrimaryConstructor()) {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
@@ -320,6 +292,7 @@ public class BodyResolver {
}
private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) {
if (!context.completeAnalysisNeeded(declaration)) return;
final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false);
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo
@@ -419,6 +392,7 @@ public class BodyResolver {
Set<JetProperty> processed = Sets.newHashSet();
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
JetClass jetClass = entry.getKey();
if (!context.completeAnalysisNeeded(jetClass)) continue;
MutableClassDescriptor classDescriptor = entry.getValue();
for (JetProperty property : jetClass.getProperties()) {
@@ -444,6 +418,7 @@ public class BodyResolver {
// Top-level properties & properties of objects
for (Map.Entry<JetProperty, PropertyDescriptor> entry : this.context.getProperties().entrySet()) {
JetProperty property = entry.getKey();
if (!context.completeAnalysisNeeded(property)) return;
if (processed.contains(property)) continue;
final PropertyDescriptor propertyDescriptor = entry.getValue();
@@ -556,6 +531,7 @@ public class BodyResolver {
@NotNull JetDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull JetScope declaringScope) {
if (!context.completeAnalysisNeeded(function)) return;
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
@@ -580,4 +556,31 @@ public class BodyResolver {
assert functionDescriptor.getReturnType() != null;
}
private void computeDeferredTypes() {
Collection<DeferredType> deferredTypes = context.getTrace().get(DEFERRED_TYPES, DEFERRED_TYPE_KEY);
if (deferredTypes != null) {
final Queue<DeferredType> queue = new Queue<DeferredType>(deferredTypes.size());
context.getTrace().addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler<BindingContext.DeferredTypeKey, DeferredType>() {
@Override
public void handleRecord(WritableSlice<BindingContext.DeferredTypeKey, DeferredType> deferredTypeKeyDeferredTypeWritableSlice, BindingContext.DeferredTypeKey key, DeferredType value) {
queue.addLast(value);
}
});
for (DeferredType deferredType : deferredTypes) {
queue.addLast(deferredType);
}
while (!queue.isEmpty()) {
DeferredType deferredType = queue.pullFirst();
if (!deferredType.isComputed()) {
try {
deferredType.getActualType(); // to compute
}
catch (ReenteringLazyValueComputationException e) {
// A problem should be reported while computing the type
}
}
}
}
}
}
@@ -42,6 +42,8 @@ public class ControlFlowAnalyzer {
JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(function)) continue;
final JetType expectedReturnType = !function.hasBlockBody() && !function.hasDeclaredReturnType()
? NO_EXPECTED_TYPE
: functionDescriptor.getReturnType();
@@ -40,7 +40,8 @@ public class DeclarationsChecker {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
JetClass aClass = entry.getKey();
MutableClassDescriptor classDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(aClass)) continue;
checkClass(aClass, classDescriptor);
checkModifiers(aClass.getModifierList());
}
@@ -50,6 +51,7 @@ public class DeclarationsChecker {
JetObjectDeclaration objectDeclaration = entry.getKey();
MutableClassDescriptor objectDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(objectDeclaration)) continue;
checkObject(objectDeclaration, objectDescriptor);
}
@@ -58,6 +60,7 @@ public class DeclarationsChecker {
JetNamedFunction function = entry.getKey();
FunctionDescriptorImpl functionDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(function)) continue;
checkFunction(function, functionDescriptor);
checkModifiers(function.getModifierList());
}
@@ -67,6 +70,7 @@ public class DeclarationsChecker {
JetProperty property = entry.getKey();
PropertyDescriptor propertyDescriptor = entry.getValue();
if (!context.completeAnalysisNeeded(property)) continue;
checkProperty(property, propertyDescriptor);
checkModifiers(property.getModifierList());
}
@@ -77,6 +81,7 @@ public class DeclarationsChecker {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey();
if (!context.completeAnalysisNeeded(jetClass)) return;
if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null && !(classDescriptor.getKind() == ClassKind.TRAIT)) {
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
if (context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
@@ -1,13 +1,18 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
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;
import org.jetbrains.jet.lang.JetSemanticServices;
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.io.PrintStream;
import java.util.Map;
import java.util.Set;
@@ -32,10 +37,42 @@ import java.util.Set;
private final Map<JetProperty, PropertyDescriptor> properties = Maps.newLinkedHashMap();
private final Set<PropertyDescriptor> primaryConstructorParameterProperties = Sets.newHashSet();
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace) {
private final Predicate<PsiFile> analyzeCompletely;
private StringBuilder debugOutput;
public TopDownAnalysisContext(JetSemanticServices semanticServices, BindingTrace trace, Predicate<PsiFile> analyzeCompletely) {
this.trace = new ObservableBindingTrace(trace);
this.semanticServices = semanticServices;
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
this.analyzeCompletely = analyzeCompletely;
}
public void debug(Object message) {
if (debugOutput != null) {
debugOutput.append(message).append("\n");
}
}
/*package*/ void enableDebugOutput() {
if (debugOutput == null) {
debugOutput = new StringBuilder();
}
}
/*package*/ void printDebugOutput(PrintStream out) {
if (debugOutput != null) {
out.print(debugOutput);
}
}
public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
PsiFile containingFile = element.getContainingFile();
boolean result = containingFile != null && analyzeCompletely.apply(containingFile);
if (!result) {
debug(containingFile);
}
return result;
}
public ObservableBindingTrace getTrace() {
@@ -1,5 +1,8 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
@@ -25,21 +28,25 @@ public class TopDownAnalyzer {
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull JetScope outerScope,
NamespaceLike owner,
@NotNull NamespaceLike owner,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> analyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
process(semanticServices, trace, outerScope, owner, declarations, flowDataTraceFactory, false);
process(semanticServices, trace, outerScope, owner, declarations, analyzeCompletely, flowDataTraceFactory, false);
}
private static void process(
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull JetScope outerScope,
NamespaceLike owner,
@NotNull NamespaceLike owner,
@NotNull Collection<? extends JetDeclaration> declarations,
@NotNull Predicate<PsiFile> analyzeCompletely,
@NotNull JetControlFlowDataTraceFactory flowDataTraceFactory,
boolean declaredLocally) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, analyzeCompletely);
// context.enableDebugOutput();
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
new DeclarationResolver(context).process();
new DelegationResolver(context).process();
@@ -47,13 +54,15 @@ public class TopDownAnalyzer {
new BodyResolver(context).resolveBehaviorDeclarationBodies();
new DeclarationsChecker(context).process();
new ControlFlowAnalyzer(context, flowDataTraceFactory, declaredLocally).process();
context.printDebugOutput(System.out);
}
public static void processStandardLibraryNamespace(
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull WritableScope outerScope, @NotNull NamespaceDescriptorImpl standardLibraryNamespace, @NotNull JetNamespace namespace) {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace, Predicates.<PsiFile>alwaysTrue());
context.getNamespaceScopes().put(namespace, standardLibraryNamespace.getMemberScope());
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
context.getDeclaringScopes().put(namespace, outerScope);
@@ -107,7 +116,7 @@ public class TopDownAnalyzer {
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
return ClassObjectStatus.NOT_ALLOWED;
}
}, Collections.<JetDeclaration>singletonList(object), JetControlFlowDataTraceFactory.EMPTY, true);
}, Collections.<JetDeclaration>singletonList(object), Predicates.equalTo(object.getContainingFile()), JetControlFlowDataTraceFactory.EMPTY, true);
}
}
@@ -36,7 +36,7 @@ public class TypeHierarchyResolver {
this.context = context;
}
public void process(@NotNull JetScope outerScope, NamespaceLike owner, @NotNull Collection<? extends JetDeclaration> declarations) {
public void process(@NotNull JetScope outerScope, @NotNull NamespaceLike owner, @NotNull Collection<? extends JetDeclaration> declarations) {
collectNamespacesAndClassifiers(outerScope, owner, declarations); // namespaceScopes, classes
processTypeImports();
@@ -1,5 +1,6 @@
package org.jetbrains.jet.plugin.compiler;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
@@ -77,7 +78,10 @@ public class JetCompiler implements TranslatingCompiler {
}
}
BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(compileContext.getProject(), namespaces, JetControlFlowDataTraceFactory.EMPTY);
BindingContext bindingContext = AnalyzingUtils.getInstance(JavaDefaultImports.JAVA_DEFAULT_IMPORTS).analyzeNamespaces(
compileContext.getProject(), namespaces,
Predicates.<PsiFile>alwaysTrue(),
JetControlFlowDataTraceFactory.EMPTY);
boolean errors = false;
for (Diagnostic diagnostic : bindingContext.getDiagnostics()) {