diff --git a/.idea/artifacts/IdeLazyResolver.xml b/.idea/artifacts/IdeLazyResolver.xml new file mode 100644 index 00000000000..3bda3717522 --- /dev/null +++ b/.idea/artifacts/IdeLazyResolver.xml @@ -0,0 +1,9 @@ + + + $PROJECT_DIR$/out/artifacts/IdeLazyResolver + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index f5b93a84a7c..24bf69c4799 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -23,6 +23,7 @@ + diff --git a/build.xml b/build.xml index b56b1f02ba6..94d1e2774dc 100644 --- a/build.xml +++ b/build.xml @@ -665,6 +665,9 @@ source="${java.target}" target="${java.target}"> + + + @@ -674,16 +677,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/idea/ide-lazy-resolve/ide-lazy-resolve.iml b/idea/ide-lazy-resolve/ide-lazy-resolve.iml new file mode 100644 index 00000000000..93933256e46 --- /dev/null +++ b/idea/ide-lazy-resolve/ide-lazy-resolve.iml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/idea/ide-lazy-resolve/src/org/jetbrains/jet/lang/resolve/lazy/ElementResolver.java b/idea/ide-lazy-resolve/src/org/jetbrains/jet/lang/resolve/lazy/ElementResolver.java new file mode 100644 index 00000000000..5057b65ecc0 --- /dev/null +++ b/idea/ide-lazy-resolve/src/org/jetbrains/jet/lang/resolve/lazy/ElementResolver.java @@ -0,0 +1,528 @@ +/* + * 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.lang.resolve.lazy; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Predicates; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.analyzer.AnalyzerPackage; +import org.jetbrains.jet.di.InjectorForBodyResolve; +import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.descriptors.annotations.Annotated; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.*; +import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; +import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor; +import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor; +import org.jetbrains.jet.lang.resolve.name.FqName; +import org.jetbrains.jet.lang.resolve.name.Name; +import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; +import org.jetbrains.jet.lang.types.TypeConstructor; +import org.jetbrains.jet.lang.types.TypeUtils; +import org.jetbrains.jet.storage.ExceptionTracker; +import org.jetbrains.jet.storage.StorageManager; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public class ElementResolver { + + protected final ResolveSession resolveSession; + + protected ElementResolver(@NotNull ResolveSession session) { + resolveSession = session; + } + + @NotNull + public BindingContext getElementAdditionalResolve(@NotNull JetElement jetElement) { + return elementAdditionalResolve(jetElement); + } + + @NotNull + public BindingContext resolveToElement(@NotNull JetElement jetElement) { + @SuppressWarnings("unchecked") JetElement elementOfAdditionalResolve = (JetElement) JetPsiUtil.getTopmostParentOfTypes( + jetElement, + JetNamedFunction.class, + JetClassInitializer.class, + JetProperty.class, + JetParameter.class, + JetDelegationSpecifierList.class, + JetImportDirective.class, + JetAnnotationEntry.class, + JetTypeParameter.class, + JetTypeConstraint.class, + JetPackageDirective.class, + JetCodeFragment.class); + + if (elementOfAdditionalResolve != null && !(elementOfAdditionalResolve instanceof JetParameter)) { + if (elementOfAdditionalResolve instanceof JetPackageDirective) { + elementOfAdditionalResolve = jetElement; + } + + return getElementAdditionalResolve(elementOfAdditionalResolve); + } + + JetParameter parameter = (JetParameter) elementOfAdditionalResolve; + if (parameter != null) { + JetClass klass = PsiTreeUtil.getParentOfType(parameter, JetClass.class); + if (klass != null && parameter.getParent() == klass.getPrimaryConstructorParameterList()) { + return getElementAdditionalResolve(klass); + } + + // Parameters for function literal could be met inside other parameters. We can't make resolveToDescriptors for internal elements. + jetElement = parameter; + } + + JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetElement, JetDeclaration.class, false); + if (declaration != null) { + // Activate descriptor resolution + resolveSession.resolveToDescriptor(declaration); + } + + return resolveSession.getBindingContext(); + } + + @NotNull + protected BindingContext elementAdditionalResolve(@NotNull JetElement resolveElement) { + // All additional resolve should be done to separate trace + BindingTrace trace = resolveSession.getStorageManager().createSafeTrace( + new DelegatingBindingTrace(resolveSession.getBindingContext(), "trace to resolve element", resolveElement)); + + JetFile file = resolveElement.getContainingJetFile(); + + if (resolveElement instanceof JetNamedFunction) { + functionAdditionalResolve(resolveSession, (JetNamedFunction) resolveElement, trace, file); + } + else if (resolveElement instanceof JetClassInitializer) { + initializerAdditionalResolve(resolveSession, (JetClassInitializer) resolveElement, trace, file); + } + else if (resolveElement instanceof JetProperty) { + propertyAdditionalResolve(resolveSession, (JetProperty) resolveElement, trace, file); + } + else if (resolveElement instanceof JetDelegationSpecifierList) { + delegationSpecifierAdditionalResolve(resolveSession, (JetDelegationSpecifierList) resolveElement, trace, file); + } + else if (resolveElement instanceof JetImportDirective) { + JetImportDirective importDirective = (JetImportDirective) resolveElement; + LazyImportScope scope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(importDirective.getContainingJetFile()); + scope.forceResolveAllContents(); + } + else if (resolveElement instanceof JetAnnotationEntry) { + annotationAdditionalResolve(resolveSession, (JetAnnotationEntry) resolveElement); + } + else if (resolveElement instanceof JetClass) { + constructorAdditionalResolve(resolveSession, (JetClass) resolveElement, trace, file); + } + else if (resolveElement instanceof JetTypeParameter) { + typeParameterAdditionalResolve(resolveSession, (JetTypeParameter) resolveElement); + } + else if (resolveElement instanceof JetTypeConstraint) { + typeConstraintAdditionalResolve(resolveSession, (JetTypeConstraint) resolveElement); + } + else if (resolveElement instanceof JetCodeFragment) { + codeFragmentAdditionalResolve(resolveSession, (JetCodeFragment) resolveElement, trace); + } + else if (PsiTreeUtil.getParentOfType(resolveElement, JetPackageDirective.class) != null) { + packageRefAdditionalResolve(resolveSession, trace, resolveElement); + } + else { + assert false : "Invalid type of the topmost parent"; + } + + new JetFlowInformationProvider(resolveElement, trace).checkDeclaration(); + + return trace.getBindingContext(); + } + + private static void packageRefAdditionalResolve(ResolveSession resolveSession, BindingTrace trace, JetElement jetElement) { + if (jetElement instanceof JetSimpleNameExpression) { + JetPackageDirective header = PsiTreeUtil.getParentOfType(jetElement, JetPackageDirective.class); + assert header != null; + + JetSimpleNameExpression packageNameExpression = (JetSimpleNameExpression) jetElement; + if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, packageNameExpression) == null) { + JetScope scope = getExpressionMemberScope(resolveSession, packageNameExpression); + if (scope != null) { + trace.record(BindingContext.RESOLUTION_SCOPE, packageNameExpression, scope); + } + } + + if (Name.isValidIdentifier(packageNameExpression.getReferencedName())) { + if (trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, packageNameExpression) == null) { + FqName fqName = header.getFqName(packageNameExpression); + PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName); + assert packageDescriptor != null: "Package descriptor should be present in session for " + fqName; + trace.record(BindingContext.REFERENCE_TARGET, packageNameExpression, packageDescriptor); + } + } + } + } + + private static void typeConstraintAdditionalResolve(KotlinCodeAnalyzer analyzer, JetTypeConstraint jetTypeConstraint) { + JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetTypeConstraint, JetDeclaration.class); + DeclarationDescriptor descriptor = analyzer.resolveToDescriptor(declaration); + + assert (descriptor instanceof ClassDescriptor); + + TypeConstructor constructor = ((ClassDescriptor) descriptor).getTypeConstructor(); + for (TypeParameterDescriptor parameterDescriptor : constructor.getParameters()) { + LazyEntity lazyEntity = (LazyEntity) parameterDescriptor; + lazyEntity.forceResolveAllContents(); + } + } + + private void codeFragmentAdditionalResolve( + ResolveSession resolveSession, + JetCodeFragment codeFragment, + BindingTrace trace + ) { + JetElement codeFragmentExpression = codeFragment.getContentElement(); + if (!(codeFragmentExpression instanceof JetExpression)) return; + + PsiElement contextElement = codeFragment.getContext(); + if (!(contextElement instanceof JetExpression)) return; + + JetExpression contextExpression = (JetExpression) contextElement; + BindingContext contextForElement = resolveToElement(contextExpression); + + JetScope scopeForContextElement = contextForElement.get(BindingContext.RESOLUTION_SCOPE, contextExpression); + if (scopeForContextElement != null) { + JetScope codeFragmentScope = resolveSession.getScopeProvider().getFileScope(codeFragment); + ChainedScope chainedScope = new ChainedScope( + scopeForContextElement.getContainingDeclaration(), + "Scope for resolve code fragment", + scopeForContextElement, + codeFragmentScope + ); + + DataFlowInfo dataFlowInfoForContextElement = contextForElement.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, contextExpression); + AnalyzerPackage.computeTypeInContext( + (JetExpression) codeFragmentExpression, + chainedScope, + trace, + dataFlowInfoForContextElement == null ? DataFlowInfo.EMPTY : dataFlowInfoForContextElement, + TypeUtils.NO_EXPECTED_TYPE, + resolveSession.getModuleDescriptor() + ); + } + } + + private static void annotationAdditionalResolve(ResolveSession resolveSession, JetAnnotationEntry jetAnnotationEntry) { + JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetAnnotationEntry, JetDeclaration.class); + if (declaration != null) { + Annotated descriptor = resolveSession.resolveToDescriptor(declaration); + + AnnotationResolver.resolveAnnotationsArguments( + descriptor, + resolveSession.getTrace() + ); + + ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations()); + } + } + + private static void typeParameterAdditionalResolve(KotlinCodeAnalyzer analyzer, JetTypeParameter typeParameter) { + DeclarationDescriptor descriptor = analyzer.resolveToDescriptor(typeParameter); + assert descriptor instanceof LazyEntity; + + LazyEntity parameterDescriptor = (LazyEntity) descriptor; + parameterDescriptor.forceResolveAllContents(); + } + + private static void delegationSpecifierAdditionalResolve( + ResolveSession resolveSession, + JetDelegationSpecifierList specifier, BindingTrace trace, JetFile file) { + + JetClassOrObject classOrObject = (JetClassOrObject) specifier.getParent(); + LazyClassDescriptor descriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject); + + // Activate resolving of supertypes + descriptor.getTypeConstructor().getSupertypes(); + + BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); + bodyResolver.resolveDelegationSpecifierList(createEmptyContext(resolveSession), classOrObject, descriptor, + descriptor.getUnsubstitutedPrimaryConstructor(), + descriptor.getScopeForClassHeaderResolution(), + descriptor.getScopeForMemberDeclarationResolution()); + } + + private static void propertyAdditionalResolve(final ResolveSession resolveSession, final JetProperty jetProperty, BindingTrace trace, JetFile file) { + JetScope propertyResolutionScope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(jetProperty); + + BodyResolveContextForLazy bodyResolveContext = new BodyResolveContextForLazy( + createParameters(resolveSession), + new Function() { + @Override + public JetScope apply(JetDeclaration declaration) { + assert declaration.getParent() == jetProperty : "Must be called only for property accessors, but called for " + + declaration; + return resolveSession.getScopeProvider().getResolutionScopeForDeclaration(declaration); + } + }); + BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); + PropertyDescriptor descriptor = (PropertyDescriptor) resolveSession.resolveToDescriptor(jetProperty); + + JetExpression propertyInitializer = jetProperty.getInitializer(); + if (propertyInitializer != null) { + bodyResolver.resolvePropertyInitializer(bodyResolveContext, jetProperty, descriptor, propertyInitializer, propertyResolutionScope); + } + + JetExpression propertyDelegate = jetProperty.getDelegateExpression(); + if (propertyDelegate != null) { + bodyResolver.resolvePropertyDelegate(bodyResolveContext, jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope); + } + + bodyResolver.resolvePropertyAccessors(bodyResolveContext, jetProperty, descriptor); + + for (JetPropertyAccessor accessor : jetProperty.getAccessors()) { + new JetFlowInformationProvider(accessor, trace).checkDeclaration(); + } + } + + private static void functionAdditionalResolve( + ResolveSession resolveSession, + JetNamedFunction namedFunction, + BindingTrace trace, + JetFile file + ) { + JetScope scope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(namedFunction); + FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction); + + BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); + bodyResolver.resolveFunctionBody(createEmptyContext(resolveSession), trace, namedFunction, functionDescriptor, scope); + } + + private static void constructorAdditionalResolve( + ResolveSession resolveSession, + JetClass klass, + BindingTrace trace, + JetFile file + ) { + JetScope scope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(klass); + + ClassDescriptor classDescriptor = (ClassDescriptor) resolveSession.resolveToDescriptor(klass); + ConstructorDescriptor constructorDescriptor = classDescriptor.getUnsubstitutedPrimaryConstructor(); + assert constructorDescriptor != null; + + BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); + bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(createEmptyContext(resolveSession), trace, klass, + constructorDescriptor, scope); + } + + private static boolean initializerAdditionalResolve( + ResolveSession resolveSession, + JetClassInitializer classInitializer, + BindingTrace trace, + JetFile file + ) { + JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class); + LazyClassDescriptor classOrObjectDescriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject); + + BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); + bodyResolver.resolveAnonymousInitializer(createEmptyContext(resolveSession), classInitializer, classOrObjectDescriptor); + + return true; + } + + private static BodyResolver createBodyResolver(ResolveSession resolveSession, BindingTrace trace, JetFile file) { + InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve( + file.getProject(), + createParameters(resolveSession), + trace, + resolveSession.getModuleDescriptor() + ); + return bodyResolve.getBodyResolver(); + } + + private static TopDownAnalysisParameters createParameters(@NotNull ResolveSession resolveSession) { + return TopDownAnalysisParameters.createForLocalDeclarations( + resolveSession.getStorageManager(), resolveSession.getExceptionTracker(), + Predicates.alwaysTrue()); + } + + @NotNull + private static BodyResolveContextForLazy createEmptyContext(@NotNull ResolveSession resolveSession) { + return new BodyResolveContextForLazy(createParameters(resolveSession), Functions.constant(null)); + } + + private static JetScope getExpressionResolutionScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { + ScopeProvider provider = resolveSession.getScopeProvider(); + JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class); + if (parentDeclaration == null) { + return provider.getFileScope(expression.getContainingJetFile()); + } + return provider.getResolutionScopeForDeclaration(parentDeclaration); + } + + private static JetScope getExpressionMemberScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { + BindingTrace trace = resolveSession.getStorageManager().createSafeTrace(new DelegatingBindingTrace( + resolveSession.getBindingContext(), "trace to resolve a member scope of expression", expression)); + + if (BindingContextUtils.isExpressionWithValidReference(expression, resolveSession.getBindingContext())) { + QualifiedExpressionResolver qualifiedExpressionResolver = resolveSession.getQualifiedExpressionResolver(); + + // In some type declaration + if (expression.getParent() instanceof JetUserType) { + JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier(); + if (qualifier != null) { + Collection descriptors = qualifiedExpressionResolver + .lookupDescriptorsForUserType(qualifier, getExpressionResolutionScope(resolveSession, expression), trace); + + for (DeclarationDescriptor descriptor : descriptors) { + if (descriptor instanceof LazyPackageDescriptor) { + return ((LazyPackageDescriptor) descriptor).getMemberScope(); + } + } + } + } + + // Inside import + if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) { + PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT); + assert rootPackage != null; + + if (expression.getParent() instanceof JetDotQualifiedExpression) { + JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression(); + FqName fqName = expression.getContainingJetFile().getPackageFqName(); + + PackageViewDescriptor filePackage = resolveSession.getModuleDescriptor().getPackage(fqName); + assert filePackage != null : "File package should be already resolved and be found"; + + JetScope scope = filePackage.getMemberScope(); + Collection descriptors; + + if (element instanceof JetDotQualifiedExpression) { + descriptors = qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression( + (JetDotQualifiedExpression) element, rootPackage.getMemberScope(), scope, trace, + QualifiedExpressionResolver.LookupMode.EVERYTHING, false); + } + else { + descriptors = qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference( + (JetSimpleNameExpression) element, rootPackage.getMemberScope(), scope, trace, + QualifiedExpressionResolver.LookupMode.EVERYTHING, false, false); + } + + for (DeclarationDescriptor descriptor : descriptors) { + if (descriptor instanceof PackageViewDescriptor) { + return ((PackageViewDescriptor) descriptor).getMemberScope(); + } + } + } + else { + return rootPackage.getMemberScope(); + } + } + + // Inside package declaration + JetPackageDirective packageDirective = PsiTreeUtil.getParentOfType(expression, JetPackageDirective.class, false); + if (packageDirective != null) { + PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage( + packageDirective.getFqName((JetSimpleNameExpression) expression).parent()); + if (packageDescriptor != null) { + return packageDescriptor.getMemberScope(); + } + } + } + + return null; + } + + private static class BodyResolveContextForLazy implements BodiesResolveContext { + + private final Function declaringScopes; + private final TopDownAnalysisParameters topDownAnalysisParameters; + + private BodyResolveContextForLazy( + @NotNull TopDownAnalysisParameters parameters, + @NotNull Function declaringScopes + ) { + this.topDownAnalysisParameters = parameters; + this.declaringScopes = declaringScopes; + } + + @NotNull + @Override + public StorageManager getStorageManager() { + return topDownAnalysisParameters.getStorageManager(); + } + + @NotNull + @Override + public ExceptionTracker getExceptionTracker() { + return topDownAnalysisParameters.getExceptionTracker(); + } + + @Override + public Collection getFiles() { + return Collections.emptySet(); + } + + @Override + public Map getDeclaredClasses() { + return Collections.emptyMap(); + } + + @Override + public Map getAnonymousInitializers() { + return Collections.emptyMap(); + } + + @Override + public Map getProperties() { + return Collections.emptyMap(); + } + + @Override + public Map getFunctions() { + return Collections.emptyMap(); + } + + @Override + public Function getDeclaringScopes() { + //noinspection unchecked + return (Function) declaringScopes; + } + + @Override + public Map getScripts() { + return Collections.emptyMap(); + } + + @Override + public DataFlowInfo getOuterDataFlowInfo() { + return DataFlowInfo.EMPTY; + } + + @NotNull + @Override + public TopDownAnalysisParameters getTopDownAnalysisParameters() { + return topDownAnalysisParameters; + } + + @Override + public boolean completeAnalysisNeeded(@NotNull PsiElement element) { + return true; + } + } +} diff --git a/idea/idea-analysis/idea-analysis.iml b/idea/idea-analysis/idea-analysis.iml index eeab4ecf0f3..9533d1a34a3 100644 --- a/idea/idea-analysis/idea-analysis.iml +++ b/idea/idea-analysis/idea-analysis.iml @@ -32,6 +32,7 @@ + diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java index 757ee954bc3..2d11b159de7 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java @@ -16,48 +16,26 @@ package org.jetbrains.jet.plugin.project; -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Predicates; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.util.*; +import com.intellij.psi.util.CachedValue; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiModificationTracker; import kotlin.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.analyzer.AnalyzerPackage; -import org.jetbrains.jet.di.InjectorForBodyResolve; -import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.descriptors.annotations.Annotated; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.*; -import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; -import org.jetbrains.jet.lang.resolve.lazy.*; -import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor; -import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor; -import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.ChainedScope; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.TypeConstructor; -import org.jetbrains.jet.lang.types.TypeUtils; -import org.jetbrains.jet.storage.ExceptionTracker; +import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.lazy.ElementResolver; +import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; import org.jetbrains.jet.storage.LazyResolveStorageManager; import org.jetbrains.jet.storage.MemoizedFunctionToNotNull; -import org.jetbrains.jet.storage.StorageManager; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -public class ResolveElementCache { +public class ResolveElementCache extends ElementResolver { private final CachedValue> additionalResolveCache; - private final ResolveSession resolveSession; public ResolveElementCache(ResolveSession resolveSession, Project project) { - this.resolveSession = resolveSession; + super(resolveSession); // Recreate internal cache after change of modification count this.additionalResolveCache = @@ -84,469 +62,8 @@ public class ResolveElementCache { } @NotNull - public BindingContext resolveToElement(@NotNull JetElement jetElement) { - @SuppressWarnings("unchecked") JetElement elementOfAdditionalResolve = (JetElement) JetPsiUtil.getTopmostParentOfTypes( - jetElement, - JetNamedFunction.class, - JetClassInitializer.class, - JetProperty.class, - JetParameter.class, - JetDelegationSpecifierList.class, - JetImportDirective.class, - JetAnnotationEntry.class, - JetTypeParameter.class, - JetTypeConstraint.class, - JetPackageDirective.class, - JetCodeFragment.class); - - if (elementOfAdditionalResolve != null && !(elementOfAdditionalResolve instanceof JetParameter)) { - if (elementOfAdditionalResolve instanceof JetPackageDirective) { - elementOfAdditionalResolve = jetElement; - } - - return additionalResolveCache.getValue().invoke(elementOfAdditionalResolve); - } - - JetParameter parameter = (JetParameter) elementOfAdditionalResolve; - if (parameter != null) { - JetClass klass = PsiTreeUtil.getParentOfType(parameter, JetClass.class); - if (klass != null && parameter.getParent() == klass.getPrimaryConstructorParameterList()) { - return additionalResolveCache.getValue().invoke(klass); - } - - // Parameters for function literal could be met inside other parameters. We can't make resolveToDescriptors for internal elements. - jetElement = parameter; - } - - JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetElement, JetDeclaration.class, false); - if (declaration != null) { - // Activate descriptor resolution - resolveSession.resolveToDescriptor(declaration); - } - - return resolveSession.getBindingContext(); - } - - @NotNull - private BindingContext elementAdditionalResolve(@NotNull JetElement resolveElement) { - // All additional resolve should be done to separate trace - BindingTrace trace = resolveSession.getStorageManager().createSafeTrace( - new DelegatingBindingTrace(resolveSession.getBindingContext(), "trace to resolve element", resolveElement)); - - JetFile file = resolveElement.getContainingJetFile(); - - if (resolveElement instanceof JetNamedFunction) { - functionAdditionalResolve(resolveSession, (JetNamedFunction) resolveElement, trace, file); - } - else if (resolveElement instanceof JetClassInitializer) { - initializerAdditionalResolve(resolveSession, (JetClassInitializer) resolveElement, trace, file); - } - else if (resolveElement instanceof JetProperty) { - propertyAdditionalResolve(resolveSession, (JetProperty) resolveElement, trace, file); - } - else if (resolveElement instanceof JetDelegationSpecifierList) { - delegationSpecifierAdditionalResolve(resolveSession, (JetDelegationSpecifierList) resolveElement, trace, file); - } - else if (resolveElement instanceof JetImportDirective) { - JetImportDirective importDirective = (JetImportDirective) resolveElement; - LazyImportScope scope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(importDirective.getContainingJetFile()); - scope.forceResolveAllContents(); - } - else if (resolveElement instanceof JetAnnotationEntry) { - annotationAdditionalResolve(resolveSession, (JetAnnotationEntry) resolveElement); - } - else if (resolveElement instanceof JetClass) { - constructorAdditionalResolve(resolveSession, (JetClass) resolveElement, trace, file); - } - else if (resolveElement instanceof JetTypeParameter) { - typeParameterAdditionalResolve(resolveSession, (JetTypeParameter) resolveElement); - } - else if (resolveElement instanceof JetTypeConstraint) { - typeConstraintAdditionalResolve(resolveSession, (JetTypeConstraint) resolveElement); - } - else if (resolveElement instanceof JetCodeFragment) { - codeFragmentAdditionalResolve(resolveSession, (JetCodeFragment) resolveElement, trace); - } - else if (PsiTreeUtil.getParentOfType(resolveElement, JetPackageDirective.class) != null) { - packageRefAdditionalResolve(resolveSession, trace, resolveElement); - } - else { - assert false : "Invalid type of the topmost parent"; - } - - new JetFlowInformationProvider(resolveElement, trace).checkDeclaration(); - - return trace.getBindingContext(); - } - - private static void packageRefAdditionalResolve(ResolveSession resolveSession, BindingTrace trace, JetElement jetElement) { - if (jetElement instanceof JetSimpleNameExpression) { - JetPackageDirective header = PsiTreeUtil.getParentOfType(jetElement, JetPackageDirective.class); - assert header != null; - - JetSimpleNameExpression packageNameExpression = (JetSimpleNameExpression) jetElement; - if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, packageNameExpression) == null) { - JetScope scope = getExpressionMemberScope(resolveSession, packageNameExpression); - if (scope != null) { - trace.record(BindingContext.RESOLUTION_SCOPE, packageNameExpression, scope); - } - } - - if (Name.isValidIdentifier(packageNameExpression.getReferencedName())) { - if (trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, packageNameExpression) == null) { - FqName fqName = header.getFqName(packageNameExpression); - PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName); - assert packageDescriptor != null: "Package descriptor should be present in session for " + fqName; - trace.record(BindingContext.REFERENCE_TARGET, packageNameExpression, packageDescriptor); - } - } - } - } - - private static void typeConstraintAdditionalResolve(KotlinCodeAnalyzer analyzer, JetTypeConstraint jetTypeConstraint) { - JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetTypeConstraint, JetDeclaration.class); - DeclarationDescriptor descriptor = analyzer.resolveToDescriptor(declaration); - - assert (descriptor instanceof ClassDescriptor); - - TypeConstructor constructor = ((ClassDescriptor) descriptor).getTypeConstructor(); - for (TypeParameterDescriptor parameterDescriptor : constructor.getParameters()) { - LazyEntity lazyEntity = (LazyEntity) parameterDescriptor; - lazyEntity.forceResolveAllContents(); - } - } - - private void codeFragmentAdditionalResolve( - ResolveSession resolveSession, - JetCodeFragment codeFragment, - BindingTrace trace - ) { - JetElement codeFragmentExpression = codeFragment.getContentElement(); - if (!(codeFragmentExpression instanceof JetExpression)) return; - - PsiElement contextElement = codeFragment.getContext(); - if (!(contextElement instanceof JetExpression)) return; - - JetExpression contextExpression = (JetExpression) contextElement; - BindingContext contextForElement = resolveToElement(contextExpression); - - JetScope scopeForContextElement = contextForElement.get(BindingContext.RESOLUTION_SCOPE, contextExpression); - if (scopeForContextElement != null) { - JetScope codeFragmentScope = resolveSession.getScopeProvider().getFileScope(codeFragment); - ChainedScope chainedScope = new ChainedScope( - scopeForContextElement.getContainingDeclaration(), - "Scope for resolve code fragment", - scopeForContextElement, - codeFragmentScope - ); - - DataFlowInfo dataFlowInfoForContextElement = contextForElement.get(BindingContext.EXPRESSION_DATA_FLOW_INFO, contextExpression); - AnalyzerPackage.computeTypeInContext( - (JetExpression) codeFragmentExpression, - chainedScope, - trace, - dataFlowInfoForContextElement == null ? DataFlowInfo.EMPTY : dataFlowInfoForContextElement, - TypeUtils.NO_EXPECTED_TYPE, - resolveSession.getModuleDescriptor() - ); - } - } - - private static void annotationAdditionalResolve(ResolveSession resolveSession, JetAnnotationEntry jetAnnotationEntry) { - JetDeclaration declaration = PsiTreeUtil.getParentOfType(jetAnnotationEntry, JetDeclaration.class); - if (declaration != null) { - Annotated descriptor = resolveSession.resolveToDescriptor(declaration); - - AnnotationResolver.resolveAnnotationsArguments( - descriptor, - resolveSession.getTrace() - ); - - ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations()); - } - } - - private static void typeParameterAdditionalResolve(KotlinCodeAnalyzer analyzer, JetTypeParameter typeParameter) { - DeclarationDescriptor descriptor = analyzer.resolveToDescriptor(typeParameter); - assert descriptor instanceof LazyEntity; - - LazyEntity parameterDescriptor = (LazyEntity) descriptor; - parameterDescriptor.forceResolveAllContents(); - } - - private static void delegationSpecifierAdditionalResolve( - ResolveSession resolveSession, - JetDelegationSpecifierList specifier, BindingTrace trace, JetFile file) { - - JetClassOrObject classOrObject = (JetClassOrObject) specifier.getParent(); - LazyClassDescriptor descriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject); - - // Activate resolving of supertypes - descriptor.getTypeConstructor().getSupertypes(); - - BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); - bodyResolver.resolveDelegationSpecifierList(createEmptyContext(resolveSession), classOrObject, descriptor, - descriptor.getUnsubstitutedPrimaryConstructor(), - descriptor.getScopeForClassHeaderResolution(), - descriptor.getScopeForMemberDeclarationResolution()); - } - - private static void propertyAdditionalResolve(final ResolveSession resolveSession, final JetProperty jetProperty, BindingTrace trace, JetFile file) { - JetScope propertyResolutionScope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(jetProperty); - - BodyResolveContextForLazy bodyResolveContext = new BodyResolveContextForLazy( - createParameters(resolveSession), - new Function() { - @Override - public JetScope apply(JetDeclaration declaration) { - assert declaration.getParent() == jetProperty : "Must be called only for property accessors, but called for " + - declaration; - return resolveSession.getScopeProvider().getResolutionScopeForDeclaration(declaration); - } - }); - BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); - PropertyDescriptor descriptor = (PropertyDescriptor) resolveSession.resolveToDescriptor(jetProperty); - - JetExpression propertyInitializer = jetProperty.getInitializer(); - if (propertyInitializer != null) { - bodyResolver.resolvePropertyInitializer(bodyResolveContext, jetProperty, descriptor, propertyInitializer, propertyResolutionScope); - } - - JetExpression propertyDelegate = jetProperty.getDelegateExpression(); - if (propertyDelegate != null) { - bodyResolver.resolvePropertyDelegate(bodyResolveContext, jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope); - } - - bodyResolver.resolvePropertyAccessors(bodyResolveContext, jetProperty, descriptor); - - for (JetPropertyAccessor accessor : jetProperty.getAccessors()) { - new JetFlowInformationProvider(accessor, trace).checkDeclaration(); - } - } - - private static void functionAdditionalResolve( - ResolveSession resolveSession, - JetNamedFunction namedFunction, - BindingTrace trace, - JetFile file - ) { - JetScope scope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(namedFunction); - FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction); - - BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); - bodyResolver.resolveFunctionBody(createEmptyContext(resolveSession), trace, namedFunction, functionDescriptor, scope); - } - - private static void constructorAdditionalResolve( - ResolveSession resolveSession, - JetClass klass, - BindingTrace trace, - JetFile file - ) { - JetScope scope = resolveSession.getScopeProvider().getResolutionScopeForDeclaration(klass); - - ClassDescriptor classDescriptor = (ClassDescriptor) resolveSession.resolveToDescriptor(klass); - ConstructorDescriptor constructorDescriptor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - assert constructorDescriptor != null; - - BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); - bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(createEmptyContext(resolveSession), trace, klass, - constructorDescriptor, scope); - } - - private static boolean initializerAdditionalResolve( - ResolveSession resolveSession, - JetClassInitializer classInitializer, - BindingTrace trace, - JetFile file - ) { - JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class); - LazyClassDescriptor classOrObjectDescriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject); - - BodyResolver bodyResolver = createBodyResolver(resolveSession, trace, file); - bodyResolver.resolveAnonymousInitializer(createEmptyContext(resolveSession), classInitializer, classOrObjectDescriptor); - - return true; - } - - private static BodyResolver createBodyResolver(ResolveSession resolveSession, BindingTrace trace, JetFile file) { - InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve( - file.getProject(), - createParameters(resolveSession), - trace, - resolveSession.getModuleDescriptor() - ); - return bodyResolve.getBodyResolver(); - } - - private static TopDownAnalysisParameters createParameters(@NotNull ResolveSession resolveSession) { - return TopDownAnalysisParameters.createForLocalDeclarations( - resolveSession.getStorageManager(), resolveSession.getExceptionTracker(), - Predicates.alwaysTrue()); - } - - @NotNull - private static BodyResolveContextForLazy createEmptyContext(@NotNull ResolveSession resolveSession) { - return new BodyResolveContextForLazy(createParameters(resolveSession), Functions.constant(null)); - } - - private static JetScope getExpressionResolutionScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { - ScopeProvider provider = resolveSession.getScopeProvider(); - JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class); - if (parentDeclaration == null) { - return provider.getFileScope(expression.getContainingJetFile()); - } - return provider.getResolutionScopeForDeclaration(parentDeclaration); - } - - private static JetScope getExpressionMemberScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { - BindingTrace trace = resolveSession.getStorageManager().createSafeTrace(new DelegatingBindingTrace( - resolveSession.getBindingContext(), "trace to resolve a member scope of expression", expression)); - - if (BindingContextUtils.isExpressionWithValidReference(expression, resolveSession.getBindingContext())) { - QualifiedExpressionResolver qualifiedExpressionResolver = resolveSession.getQualifiedExpressionResolver(); - - // In some type declaration - if (expression.getParent() instanceof JetUserType) { - JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier(); - if (qualifier != null) { - Collection descriptors = qualifiedExpressionResolver - .lookupDescriptorsForUserType(qualifier, getExpressionResolutionScope(resolveSession, expression), trace); - - for (DeclarationDescriptor descriptor : descriptors) { - if (descriptor instanceof LazyPackageDescriptor) { - return ((LazyPackageDescriptor) descriptor).getMemberScope(); - } - } - } - } - - // Inside import - if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) { - PackageViewDescriptor rootPackage = resolveSession.getModuleDescriptor().getPackage(FqName.ROOT); - assert rootPackage != null; - - if (expression.getParent() instanceof JetDotQualifiedExpression) { - JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression(); - FqName fqName = expression.getContainingJetFile().getPackageFqName(); - - PackageViewDescriptor filePackage = resolveSession.getModuleDescriptor().getPackage(fqName); - assert filePackage != null : "File package should be already resolved and be found"; - - JetScope scope = filePackage.getMemberScope(); - Collection descriptors; - - if (element instanceof JetDotQualifiedExpression) { - descriptors = qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression( - (JetDotQualifiedExpression) element, rootPackage.getMemberScope(), scope, trace, - QualifiedExpressionResolver.LookupMode.EVERYTHING, false); - } - else { - descriptors = qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference( - (JetSimpleNameExpression) element, rootPackage.getMemberScope(), scope, trace, - QualifiedExpressionResolver.LookupMode.EVERYTHING, false, false); - } - - for (DeclarationDescriptor descriptor : descriptors) { - if (descriptor instanceof PackageViewDescriptor) { - return ((PackageViewDescriptor) descriptor).getMemberScope(); - } - } - } - else { - return rootPackage.getMemberScope(); - } - } - - // Inside package declaration - JetPackageDirective packageDirective = PsiTreeUtil.getParentOfType(expression, JetPackageDirective.class, false); - if (packageDirective != null) { - PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage( - packageDirective.getFqName((JetSimpleNameExpression) expression).parent()); - if (packageDescriptor != null) { - return packageDescriptor.getMemberScope(); - } - } - } - - return null; - } - - private static class BodyResolveContextForLazy implements BodiesResolveContext { - - private final Function declaringScopes; - private final TopDownAnalysisParameters topDownAnalysisParameters; - - private BodyResolveContextForLazy( - @NotNull TopDownAnalysisParameters parameters, - @NotNull Function declaringScopes - ) { - this.topDownAnalysisParameters = parameters; - this.declaringScopes = declaringScopes; - } - - @NotNull - @Override - public StorageManager getStorageManager() { - return topDownAnalysisParameters.getStorageManager(); - } - - @NotNull - @Override - public ExceptionTracker getExceptionTracker() { - return topDownAnalysisParameters.getExceptionTracker(); - } - - @Override - public Collection getFiles() { - return Collections.emptySet(); - } - - @Override - public Map getDeclaredClasses() { - return Collections.emptyMap(); - } - - @Override - public Map getAnonymousInitializers() { - return Collections.emptyMap(); - } - - @Override - public Map getProperties() { - return Collections.emptyMap(); - } - - @Override - public Map getFunctions() { - return Collections.emptyMap(); - } - - @Override - public Function getDeclaringScopes() { - //noinspection unchecked - return (Function) declaringScopes; - } - - @Override - public Map getScripts() { - return Collections.emptyMap(); - } - - @Override - public DataFlowInfo getOuterDataFlowInfo() { - return DataFlowInfo.EMPTY; - } - - @NotNull - @Override - public TopDownAnalysisParameters getTopDownAnalysisParameters() { - return topDownAnalysisParameters; - } - - @Override - public boolean completeAnalysisNeeded(@NotNull PsiElement element) { - return true; - } + @Override + public BindingContext getElementAdditionalResolve(@NotNull JetElement jetElement) { + return additionalResolveCache.getValue().invoke(jetElement); } }