Refactor: merge ElementResolver into ResolveElementCache

This is a bit questionable since there are plans to use it in eclipse plugin, but we do it for now
It's possible that we can come up with a better abstraction later
This commit is contained in:
Pavel V. Talanov
2015-07-30 15:07:00 +03:00
parent 0a40b375a1
commit 7cbac51018
2 changed files with 411 additions and 440 deletions
@@ -1,427 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.resolve.lazy
import org.jetbrains.kotlin.analyzer.computeTypeInContext
import org.jetbrains.kotlin.cfg.JetFlowInformationProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.SimpleGlobalContext
import org.jetbrains.kotlin.context.withModule
import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.frontend.di.createContainerForBodyResolve
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.util.getScopeAndDataFlowForAnalyzeFragment
import org.jetbrains.kotlin.types.TypeUtils
public abstract class ElementResolver protected constructor(
public val resolveSession: ResolveSession
) {
protected open fun getElementAdditionalResolve(resolveElement: JetElement, contextElement: JetElement, bodyResolveMode: BodyResolveMode): BindingContext {
return performElementAdditionalResolve(resolveElement, resolveElement, bodyResolveMode).first
}
protected open fun probablyNothingCallableNames(): ProbablyNothingCallableNames
= throw UnsupportedOperationException("Cannot use partial body resolve with no Nothing-functions index");
public fun resolveToElement(element: JetElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext {
var contextElement = element
val elementOfAdditionalResolve = findElementOfAdditionalResolve(contextElement)
if (elementOfAdditionalResolve is JetParameter) {
// Parameters for function literal could be met inside other parameters. We can't make resolveToDescriptors for internal elements.
contextElement = elementOfAdditionalResolve
}
else if (elementOfAdditionalResolve != null) {
return getElementAdditionalResolve(elementOfAdditionalResolve, contextElement, bodyResolveMode)
}
val declaration = contextElement.getParentOfType<JetDeclaration>(false)
if (declaration != null && declaration !is JetClassInitializer) {
// Activate descriptor resolution
resolveSession.resolveToDescriptor(declaration)
}
return resolveSession.getBindingContext()
}
private fun findElementOfAdditionalResolve(element: JetElement): JetElement? {
val elementOfAdditionalResolve = JetPsiUtil.getTopmostParentOfTypes(
element,
javaClass<JetNamedFunction>(),
javaClass<JetClassInitializer>(),
javaClass<JetSecondaryConstructor>(),
javaClass<JetProperty>(),
javaClass<JetParameter>(),
javaClass<JetDelegationSpecifierList>(),
javaClass<JetInitializerList>(),
javaClass<JetImportList>(),
javaClass<JetAnnotationEntry>(),
javaClass<JetTypeParameter>(),
javaClass<JetTypeConstraint>(),
javaClass<JetPackageDirective>(),
javaClass<JetCodeFragment>()) as JetElement?
when (elementOfAdditionalResolve) {
null -> {
// Case of JetAnnotationEntry on top level class
if (element is JetAnnotationEntry) {
return element
}
return null
}
is JetPackageDirective -> return element
is JetParameter -> {
val klass = elementOfAdditionalResolve.getParentOfType<JetClass>(strict = true)
if (klass != null && elementOfAdditionalResolve.getParent() == klass.getPrimaryConstructorParameterList()) {
return klass
}
return elementOfAdditionalResolve
}
else -> return elementOfAdditionalResolve
}
}
protected fun performElementAdditionalResolve(resolveElement: JetElement, contextElement: JetElement, bodyResolveMode: BodyResolveMode): Pair<BindingContext, StatementFilter> {
val file = resolveElement.getContainingJetFile()
var statementFilterUsed = StatementFilter.NONE
fun createStatementFilter(): StatementFilter {
assert(resolveElement is JetDeclaration)
if (bodyResolveMode != BodyResolveMode.FULL) {
statementFilterUsed = PartialBodyResolveFilter(
contextElement,
resolveElement as JetDeclaration,
probablyNothingCallableNames(),
bodyResolveMode == BodyResolveMode.PARTIAL_FOR_COMPLETION)
}
return statementFilterUsed
}
val trace: BindingTrace = when (resolveElement) {
is JetNamedFunction -> functionAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetClassInitializer -> initializerAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetSecondaryConstructor -> secondaryConstructorAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetProperty -> propertyAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetDelegationSpecifierList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as JetClassOrObject, file)
is JetInitializerList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as JetEnumEntry, file)
is JetImportList -> {
val scope = resolveSession.getFileScopeProvider().getFileScope(resolveElement.getContainingJetFile())
scope.forceResolveAllImports()
resolveSession.getTrace()
}
is JetAnnotationEntry -> annotationAdditionalResolve(resolveSession, resolveElement)
is JetClass -> constructorAdditionalResolve(resolveSession, resolveElement, file)
is JetTypeParameter -> typeParameterAdditionalResolve(resolveSession, resolveElement)
is JetTypeConstraint -> typeConstraintAdditionalResolve(resolveSession, resolveElement)
is JetCodeFragment -> codeFragmentAdditionalResolve(resolveSession, resolveElement, bodyResolveMode)
else -> {
if (resolveElement.getParentOfType<JetPackageDirective>(true) != null) {
packageRefAdditionalResolve(resolveSession, resolveElement)
}
else {
error("Invalid type of the topmost parent: $resolveElement\n${resolveElement.getElementTextWithContext()}")
}
}
}
val controlFlowTrace = DelegatingBindingTrace(trace.getBindingContext(), "Element control flow resolve", resolveElement)
JetFlowInformationProvider(resolveElement, controlFlowTrace).checkDeclaration()
controlFlowTrace.addOwnDataTo(trace, null, false)
return Pair(trace.getBindingContext(), statementFilterUsed)
}
private fun packageRefAdditionalResolve(resolveSession: ResolveSession, jetElement: JetElement): BindingTrace {
val trace = createDelegatingTrace(jetElement)
if (jetElement is JetSimpleNameExpression) {
val header = jetElement.getParentOfType<JetPackageDirective>(true)!!
if (trace.getBindingContext()[BindingContext.RESOLUTION_SCOPE, jetElement] == null) {
val scope = resolveSession.getModuleDescriptor().getPackage(header.getFqName(jetElement).parent()).memberScope
trace.record(BindingContext.RESOLUTION_SCOPE, jetElement, scope)
}
if (Name.isValidIdentifier(jetElement.getReferencedName())) {
if (trace.getBindingContext()[BindingContext.REFERENCE_TARGET, jetElement] == null) {
val fqName = header.getFqName(jetElement)
val packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName)
trace.record(BindingContext.REFERENCE_TARGET, jetElement, packageDescriptor)
}
}
}
return trace
}
private fun typeConstraintAdditionalResolve(analyzer: KotlinCodeAnalyzer, jetTypeConstraint: JetTypeConstraint): BindingTrace {
val declaration = jetTypeConstraint.getParentOfType<JetDeclaration>(true)!!
val descriptor = analyzer.resolveToDescriptor(declaration) as ClassDescriptor
for (parameterDescriptor in descriptor.getTypeConstructor().getParameters()) {
ForceResolveUtil.forceResolveAllContents<TypeParameterDescriptor>(parameterDescriptor)
}
return resolveSession.getTrace()
}
private fun codeFragmentAdditionalResolve(resolveSession: ResolveSession, codeFragment: JetCodeFragment, bodyResolveMode: BodyResolveMode): BindingTrace {
val trace = createDelegatingTrace(codeFragment)
val codeFragmentExpression = codeFragment.getContentElement() as? JetExpression ?: return trace
val (scopeForContextElement, dataFlowInfoForContextElement) = codeFragment.getScopeAndDataFlowForAnalyzeFragment(resolveSession) {
val contextResolveMode = if (bodyResolveMode == BodyResolveMode.PARTIAL)
BodyResolveMode.PARTIAL_FOR_COMPLETION
else
bodyResolveMode
resolveToElement(it, contextResolveMode)
} ?: return trace
codeFragmentExpression.computeTypeInContext(scopeForContextElement, trace, dataFlowInfoForContextElement,
TypeUtils.NO_EXPECTED_TYPE, resolveSession.getModuleDescriptor())
return trace
}
private fun annotationAdditionalResolve(resolveSession: ResolveSession, jetAnnotationEntry: JetAnnotationEntry): BindingTrace {
val modifierList = jetAnnotationEntry.getParentOfType<JetModifierList>(true)
val declaration = modifierList?.getParentOfType<JetDeclaration>(true)
if (declaration != null) {
doResolveAnnotations(getAnnotationsByDeclaration(resolveSession, modifierList!!, declaration))
}
else {
val fileAnnotationList = jetAnnotationEntry.getParentOfType<JetFileAnnotationList>(true)
if (fileAnnotationList != null) {
doResolveAnnotations(resolveSession.getFileAnnotations(fileAnnotationList.getContainingJetFile()))
}
if (modifierList != null && modifierList.getParent() is JetFile) {
doResolveAnnotations(resolveSession.getDanglingAnnotations(modifierList.getContainingJetFile()))
}
}
return resolveSession.getTrace()
}
private fun doResolveAnnotations(annotations: Annotations) {
ForceResolveUtil.forceResolveAllContents(annotations)
}
private fun getAnnotationsByDeclaration(resolveSession: ResolveSession, modifierList: JetModifierList, declaration: JetDeclaration): Annotations {
var descriptor = resolveSession.resolveToDescriptor(declaration)
if (declaration is JetClass) {
if (modifierList == declaration.getPrimaryConstructorModifierList()) {
descriptor = (descriptor as ClassDescriptor).getUnsubstitutedPrimaryConstructor()
?: error("No constructor found: ${declaration.getText()}")
}
}
if (declaration is JetClassOrObject && modifierList.getParent() == declaration.getBody() && descriptor is LazyClassDescriptor) {
return descriptor.getDanglingAnnotations()
}
return descriptor.getAnnotations()
}
private fun typeParameterAdditionalResolve(analyzer: KotlinCodeAnalyzer, typeParameter: JetTypeParameter): BindingTrace {
val descriptor = analyzer.resolveToDescriptor(typeParameter)
ForceResolveUtil.forceResolveAllContents(descriptor)
return resolveSession.getTrace()
}
private fun delegationSpecifierAdditionalResolve(resolveSession: ResolveSession, jetElement: JetElement, classOrObject: JetClassOrObject, file: JetFile): BindingTrace {
val trace = createDelegatingTrace(jetElement)
val descriptor = resolveSession.resolveToDescriptor(classOrObject) as LazyClassDescriptor
// Activate resolving of supertypes
ForceResolveUtil.forceResolveAllContents(descriptor.getTypeConstructor().getSupertypes())
val bodyResolver = createBodyResolver(resolveSession, trace, file, StatementFilter.NONE)
bodyResolver.resolveDelegationSpecifierList(DataFlowInfo.EMPTY,
classOrObject,
descriptor,
descriptor.getUnsubstitutedPrimaryConstructor(),
descriptor.getScopeForClassHeaderResolution(),
descriptor.getScopeForMemberDeclarationResolution())
return trace
}
private fun propertyAdditionalResolve(resolveSession: ResolveSession, jetProperty: JetProperty, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(jetProperty)
val propertyResolutionScope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(jetProperty)
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
val descriptor = resolveSession.resolveToDescriptor(jetProperty) as PropertyDescriptor
ForceResolveUtil.forceResolveAllContents(descriptor)
val propertyInitializer = jetProperty.getInitializer()
if (propertyInitializer != null) {
bodyResolver.resolvePropertyInitializer(DataFlowInfo.EMPTY, jetProperty, descriptor, propertyInitializer, propertyResolutionScope)
}
val propertyDelegate = jetProperty.getDelegateExpression()
if (propertyDelegate != null) {
bodyResolver.resolvePropertyDelegate(DataFlowInfo.EMPTY, jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope)
}
val bodyResolveContext = BodyResolveContextForLazy(TopDownAnalysisMode.LocalDeclarations, { declaration ->
assert(declaration.getParent() == jetProperty) { "Must be called only for property accessors, but called for $declaration" }
resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(declaration)
})
bodyResolver.resolvePropertyAccessors(bodyResolveContext, jetProperty, descriptor)
for (accessor in jetProperty.getAccessors()) {
JetFlowInformationProvider(accessor, trace).checkDeclaration()
}
return trace
}
private fun functionAdditionalResolve(resolveSession: ResolveSession, namedFunction: JetNamedFunction, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(namedFunction)
val scope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(namedFunction)
val functionDescriptor = resolveSession.resolveToDescriptor(namedFunction) as FunctionDescriptor
ForceResolveUtil.forceResolveAllContents(functionDescriptor)
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveFunctionBody(DataFlowInfo.EMPTY, trace, namedFunction, functionDescriptor, scope)
return trace
}
private fun secondaryConstructorAdditionalResolve(resolveSession: ResolveSession, constructor: JetSecondaryConstructor, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(constructor)
val scope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(constructor)
val constructorDescriptor = resolveSession.resolveToDescriptor(constructor) as ConstructorDescriptor
ForceResolveUtil.forceResolveAllContents(constructorDescriptor)
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveSecondaryConstructorBody(DataFlowInfo.EMPTY, trace, constructor, constructorDescriptor, scope)
return trace
}
private fun constructorAdditionalResolve(resolveSession: ResolveSession, klass: JetClass, file: JetFile): BindingTrace {
val trace = createDelegatingTrace(klass)
val scope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(klass)
val classDescriptor = resolveSession.resolveToDescriptor(klass) as ClassDescriptor
val constructorDescriptor = classDescriptor.getUnsubstitutedPrimaryConstructor()
?: error("Can't get primary constructor for descriptor '$classDescriptor' in from class '${klass.getElementTextWithContext()}'")
val bodyResolver = createBodyResolver(resolveSession, trace, file, StatementFilter.NONE)
bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(DataFlowInfo.EMPTY, trace, klass, constructorDescriptor, scope)
return trace
}
private fun initializerAdditionalResolve(resolveSession: ResolveSession, classInitializer: JetClassInitializer, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(classInitializer)
val classOrObject = classInitializer.getParentOfType<JetClassOrObject>(true)!!
val classOrObjectDescriptor = resolveSession.resolveToDescriptor(classOrObject) as LazyClassDescriptor
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveAnonymousInitializer(DataFlowInfo.EMPTY, classInitializer, classOrObjectDescriptor)
return trace
}
private fun createBodyResolver(
resolveSession: ResolveSession,
trace: BindingTrace,
file: JetFile,
statementFilter: StatementFilter
): BodyResolver {
val globalContext = SimpleGlobalContext(resolveSession.getStorageManager(), resolveSession.getExceptionTracker())
val module = resolveSession.getModuleDescriptor()
return createContainerForBodyResolve(
globalContext.withProject(file.getProject()).withModule(module),
trace,
getTargetPlatform(file),
statementFilter
).get<BodyResolver>()
}
// All additional resolve should be done to separate trace
private fun createDelegatingTrace(resolveElement: JetElement): BindingTrace {
return resolveSession.getStorageManager().createSafeTrace(
DelegatingBindingTrace(resolveSession.getBindingContext(), "trace to resolve element", resolveElement))
}
protected abstract fun getTargetPlatform(file: JetFile): TargetPlatform
private class BodyResolveContextForLazy(
private val topDownAnalysisMode: TopDownAnalysisMode,
private val declaringScopes: Function1<JetDeclaration, JetScope?>
) : BodiesResolveContext {
override fun getFiles(): Collection<JetFile> = setOf()
override fun getDeclaredClasses(): MutableMap<JetClassOrObject, ClassDescriptorWithResolutionScopes> = hashMapOf()
override fun getAnonymousInitializers(): MutableMap<JetClassInitializer, ClassDescriptorWithResolutionScopes> = hashMapOf()
override fun getSecondaryConstructors(): MutableMap<JetSecondaryConstructor, ConstructorDescriptor> = hashMapOf()
override fun getProperties(): MutableMap<JetProperty, PropertyDescriptor> = hashMapOf()
override fun getFunctions(): MutableMap<JetNamedFunction, SimpleFunctionDescriptor> = hashMapOf()
override fun getDeclaringScope(declaration: JetDeclaration): JetScope? = declaringScopes(declaration)
override fun getScripts(): MutableMap<JetScript, ScriptDescriptor> = hashMapOf()
override fun getOuterDataFlowInfo(): DataFlowInfo = DataFlowInfo.EMPTY
override fun getTopDownAnalysisMode() = topDownAnalysisMode
}
}
@@ -22,18 +22,38 @@ import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.analyzer.computeTypeInContext
import org.jetbrains.kotlin.asJava.KotlinCodeBlockModificationListener
import org.jetbrains.kotlin.cfg.JetFlowInformationProvider
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.SimpleGlobalContext
import org.jetbrains.kotlin.context.withModule
import org.jetbrains.kotlin.context.withProject
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.frontend.di.createContainerForBodyResolve
import org.jetbrains.kotlin.idea.stubindex.JetProbablyNothingFunctionShortNameIndex
import org.jetbrains.kotlin.idea.stubindex.JetProbablyNothingPropertyShortNameIndex
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BodyResolveCache
import org.jetbrains.kotlin.resolve.StatementFilter
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.util.getScopeAndDataFlowForAnalyzeFragment
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
public class ResolveElementCache(resolveSession: ResolveSession, private val project: Project) : ElementResolver(resolveSession), BodyResolveCache {
public class ResolveElementCache(
private val resolveSession: ResolveSession,
private val project: Project
) : BodyResolveCache {
private class CachedFullResolve(val bindingContext: BindingContext, resolveElement: JetElement) {
private val modificationStamp: Long? = modificationStamp(resolveElement)
@@ -84,7 +104,21 @@ public class ResolveElementCache(resolveSession: ResolveSession, private val pro
},
false)
override fun getElementAdditionalResolve(resolveElement: JetElement, contextElement: JetElement, bodyResolveMode: BodyResolveMode): BindingContext {
private fun getTargetPlatform(file: JetFile): TargetPlatform = TargetPlatformDetector.getPlatform(file)
private fun probablyNothingCallableNames(): ProbablyNothingCallableNames {
return object : ProbablyNothingCallableNames {
override fun functionNames() = JetProbablyNothingFunctionShortNameIndex.getInstance().getAllKeys(project)
override fun propertyNames() = JetProbablyNothingPropertyShortNameIndex.getInstance().getAllKeys(project)
}
}
override fun resolveFunctionBody(function: JetNamedFunction)
= getElementAdditionalResolve(function, function, BodyResolveMode.FULL)
fun getElementAdditionalResolve(resolveElement: JetElement, contextElement: JetElement, bodyResolveMode: BodyResolveMode): BindingContext {
// check if full additional resolve already performed and is up-to-date
val fullResolveMap = fullResolveCache.value
val cachedFullResolve = fullResolveMap[resolveElement]
@@ -146,16 +180,380 @@ public class ResolveElementCache(resolveSession: ResolveSession, private val pro
}
}
override fun getTargetPlatform(file: JetFile): TargetPlatform = TargetPlatformDetector.getPlatform(file)
public fun resolveToElement(element: JetElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext {
var contextElement = element
override fun probablyNothingCallableNames(): ProbablyNothingCallableNames {
return object : ProbablyNothingCallableNames {
override fun functionNames() = JetProbablyNothingFunctionShortNameIndex.getInstance().getAllKeys(project)
override fun propertyNames() = JetProbablyNothingPropertyShortNameIndex.getInstance().getAllKeys(project)
val elementOfAdditionalResolve = findElementOfAdditionalResolve(contextElement)
if (elementOfAdditionalResolve is JetParameter) {
// Parameters for function literal could be met inside other parameters. We can't make resolveToDescriptors for internal elements.
contextElement = elementOfAdditionalResolve
}
else if (elementOfAdditionalResolve != null) {
return getElementAdditionalResolve(elementOfAdditionalResolve, contextElement, bodyResolveMode)
}
val declaration = contextElement.getParentOfType<JetDeclaration>(false)
if (declaration != null && declaration !is JetClassInitializer) {
// Activate descriptor resolution
resolveSession.resolveToDescriptor(declaration)
}
return resolveSession.getBindingContext()
}
private fun findElementOfAdditionalResolve(element: JetElement): JetElement? {
val elementOfAdditionalResolve = JetPsiUtil.getTopmostParentOfTypes(
element,
javaClass<JetNamedFunction>(),
javaClass<JetClassInitializer>(),
javaClass<JetSecondaryConstructor>(),
javaClass<JetProperty>(),
javaClass<JetParameter>(),
javaClass<JetDelegationSpecifierList>(),
javaClass<JetInitializerList>(),
javaClass<JetImportList>(),
javaClass<JetAnnotationEntry>(),
javaClass<JetTypeParameter>(),
javaClass<JetTypeConstraint>(),
javaClass<JetPackageDirective>(),
javaClass<JetCodeFragment>()) as JetElement?
when (elementOfAdditionalResolve) {
null -> {
// Case of JetAnnotationEntry on top level class
if (element is JetAnnotationEntry) {
return element
}
return null
}
is JetPackageDirective -> return element
is JetParameter -> {
val klass = elementOfAdditionalResolve.getParentOfType<JetClass>(strict = true)
if (klass != null && elementOfAdditionalResolve.getParent() == klass.getPrimaryConstructorParameterList()) {
return klass
}
return elementOfAdditionalResolve
}
else -> return elementOfAdditionalResolve
}
}
override fun resolveFunctionBody(function: JetNamedFunction)
= getElementAdditionalResolve(function, function, BodyResolveMode.FULL)
private fun performElementAdditionalResolve(resolveElement: JetElement, contextElement: JetElement, bodyResolveMode: BodyResolveMode): Pair<BindingContext, StatementFilter> {
val file = resolveElement.getContainingJetFile()
var statementFilterUsed = StatementFilter.NONE
fun createStatementFilter(): StatementFilter {
assert(resolveElement is JetDeclaration)
if (bodyResolveMode != BodyResolveMode.FULL) {
statementFilterUsed = PartialBodyResolveFilter(
contextElement,
resolveElement as JetDeclaration,
probablyNothingCallableNames(),
bodyResolveMode == BodyResolveMode.PARTIAL_FOR_COMPLETION)
}
return statementFilterUsed
}
val trace: BindingTrace = when (resolveElement) {
is JetNamedFunction -> functionAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetClassInitializer -> initializerAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetSecondaryConstructor -> secondaryConstructorAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetProperty -> propertyAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
is JetDelegationSpecifierList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as JetClassOrObject, file)
is JetInitializerList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as JetEnumEntry, file)
is JetImportList -> {
val scope = resolveSession.getFileScopeProvider().getFileScope(resolveElement.getContainingJetFile())
scope.forceResolveAllImports()
resolveSession.getTrace()
}
is JetAnnotationEntry -> annotationAdditionalResolve(resolveSession, resolveElement)
is JetClass -> constructorAdditionalResolve(resolveSession, resolveElement, file)
is JetTypeParameter -> typeParameterAdditionalResolve(resolveSession, resolveElement)
is JetTypeConstraint -> typeConstraintAdditionalResolve(resolveSession, resolveElement)
is JetCodeFragment -> codeFragmentAdditionalResolve(resolveSession, resolveElement, bodyResolveMode)
else -> {
if (resolveElement.getParentOfType<JetPackageDirective>(true) != null) {
packageRefAdditionalResolve(resolveSession, resolveElement)
}
else {
error("Invalid type of the topmost parent: $resolveElement\n${resolveElement.getElementTextWithContext()}")
}
}
}
val controlFlowTrace = DelegatingBindingTrace(trace.getBindingContext(), "Element control flow resolve", resolveElement)
JetFlowInformationProvider(resolveElement, controlFlowTrace).checkDeclaration()
controlFlowTrace.addOwnDataTo(trace, null, false)
return Pair(trace.getBindingContext(), statementFilterUsed)
}
private fun packageRefAdditionalResolve(resolveSession: ResolveSession, jetElement: JetElement): BindingTrace {
val trace = createDelegatingTrace(jetElement)
if (jetElement is JetSimpleNameExpression) {
val header = jetElement.getParentOfType<JetPackageDirective>(true)!!
if (trace.getBindingContext()[BindingContext.RESOLUTION_SCOPE, jetElement] == null) {
val scope = resolveSession.getModuleDescriptor().getPackage(header.getFqName(jetElement).parent()).memberScope
trace.record(BindingContext.RESOLUTION_SCOPE, jetElement, scope)
}
if (Name.isValidIdentifier(jetElement.getReferencedName())) {
if (trace.getBindingContext()[BindingContext.REFERENCE_TARGET, jetElement] == null) {
val fqName = header.getFqName(jetElement)
val packageDescriptor = resolveSession.getModuleDescriptor().getPackage(fqName)
trace.record(BindingContext.REFERENCE_TARGET, jetElement, packageDescriptor)
}
}
}
return trace
}
private fun typeConstraintAdditionalResolve(analyzer: KotlinCodeAnalyzer, jetTypeConstraint: JetTypeConstraint): BindingTrace {
val declaration = jetTypeConstraint.getParentOfType<JetDeclaration>(true)!!
val descriptor = analyzer.resolveToDescriptor(declaration) as ClassDescriptor
for (parameterDescriptor in descriptor.getTypeConstructor().getParameters()) {
ForceResolveUtil.forceResolveAllContents<TypeParameterDescriptor>(parameterDescriptor)
}
return resolveSession.getTrace()
}
private fun codeFragmentAdditionalResolve(resolveSession: ResolveSession, codeFragment: JetCodeFragment, bodyResolveMode: BodyResolveMode): BindingTrace {
val trace = createDelegatingTrace(codeFragment)
val codeFragmentExpression = codeFragment.getContentElement() as? JetExpression ?: return trace
val (scopeForContextElement, dataFlowInfoForContextElement) = codeFragment.getScopeAndDataFlowForAnalyzeFragment(resolveSession) {
val contextResolveMode = if (bodyResolveMode == BodyResolveMode.PARTIAL)
BodyResolveMode.PARTIAL_FOR_COMPLETION
else
bodyResolveMode
resolveToElement(it, contextResolveMode)
} ?: return trace
codeFragmentExpression.computeTypeInContext(scopeForContextElement, trace, dataFlowInfoForContextElement,
TypeUtils.NO_EXPECTED_TYPE, resolveSession.getModuleDescriptor())
return trace
}
private fun annotationAdditionalResolve(resolveSession: ResolveSession, jetAnnotationEntry: JetAnnotationEntry): BindingTrace {
val modifierList = jetAnnotationEntry.getParentOfType<JetModifierList>(true)
val declaration = modifierList?.getParentOfType<JetDeclaration>(true)
if (declaration != null) {
doResolveAnnotations(getAnnotationsByDeclaration(resolveSession, modifierList!!, declaration))
}
else {
val fileAnnotationList = jetAnnotationEntry.getParentOfType<JetFileAnnotationList>(true)
if (fileAnnotationList != null) {
doResolveAnnotations(resolveSession.getFileAnnotations(fileAnnotationList.getContainingJetFile()))
}
if (modifierList != null && modifierList.getParent() is JetFile) {
doResolveAnnotations(resolveSession.getDanglingAnnotations(modifierList.getContainingJetFile()))
}
}
return resolveSession.getTrace()
}
private fun doResolveAnnotations(annotations: Annotations) {
ForceResolveUtil.forceResolveAllContents(annotations)
}
private fun getAnnotationsByDeclaration(resolveSession: ResolveSession, modifierList: JetModifierList, declaration: JetDeclaration): Annotations {
var descriptor = resolveSession.resolveToDescriptor(declaration)
if (declaration is JetClass) {
if (modifierList == declaration.getPrimaryConstructorModifierList()) {
descriptor = (descriptor as ClassDescriptor).getUnsubstitutedPrimaryConstructor()
?: error("No constructor found: ${declaration.getText()}")
}
}
if (declaration is JetClassOrObject && modifierList.getParent() == declaration.getBody() && descriptor is LazyClassDescriptor) {
return descriptor.getDanglingAnnotations()
}
return descriptor.getAnnotations()
}
private fun typeParameterAdditionalResolve(analyzer: KotlinCodeAnalyzer, typeParameter: JetTypeParameter): BindingTrace {
val descriptor = analyzer.resolveToDescriptor(typeParameter)
ForceResolveUtil.forceResolveAllContents(descriptor)
return resolveSession.getTrace()
}
private fun delegationSpecifierAdditionalResolve(resolveSession: ResolveSession, jetElement: JetElement, classOrObject: JetClassOrObject, file: JetFile): BindingTrace {
val trace = createDelegatingTrace(jetElement)
val descriptor = resolveSession.resolveToDescriptor(classOrObject) as LazyClassDescriptor
// Activate resolving of supertypes
ForceResolveUtil.forceResolveAllContents(descriptor.getTypeConstructor().getSupertypes())
val bodyResolver = createBodyResolver(resolveSession, trace, file, StatementFilter.NONE)
bodyResolver.resolveDelegationSpecifierList(DataFlowInfo.EMPTY,
classOrObject,
descriptor,
descriptor.getUnsubstitutedPrimaryConstructor(),
descriptor.getScopeForClassHeaderResolution(),
descriptor.getScopeForMemberDeclarationResolution())
return trace
}
private fun propertyAdditionalResolve(resolveSession: ResolveSession, jetProperty: JetProperty, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(jetProperty)
val propertyResolutionScope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(jetProperty)
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
val descriptor = resolveSession.resolveToDescriptor(jetProperty) as PropertyDescriptor
ForceResolveUtil.forceResolveAllContents(descriptor)
val propertyInitializer = jetProperty.getInitializer()
if (propertyInitializer != null) {
bodyResolver.resolvePropertyInitializer(DataFlowInfo.EMPTY, jetProperty, descriptor, propertyInitializer, propertyResolutionScope)
}
val propertyDelegate = jetProperty.getDelegateExpression()
if (propertyDelegate != null) {
bodyResolver.resolvePropertyDelegate(DataFlowInfo.EMPTY, jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope)
}
val bodyResolveContext = BodyResolveContextForLazy(TopDownAnalysisMode.LocalDeclarations, { declaration ->
assert(declaration.getParent() == jetProperty) { "Must be called only for property accessors, but called for $declaration" }
resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(declaration)
})
bodyResolver.resolvePropertyAccessors(bodyResolveContext, jetProperty, descriptor)
for (accessor in jetProperty.getAccessors()) {
JetFlowInformationProvider(accessor, trace).checkDeclaration()
}
return trace
}
private fun functionAdditionalResolve(resolveSession: ResolveSession, namedFunction: JetNamedFunction, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(namedFunction)
val scope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(namedFunction)
val functionDescriptor = resolveSession.resolveToDescriptor(namedFunction) as FunctionDescriptor
ForceResolveUtil.forceResolveAllContents(functionDescriptor)
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveFunctionBody(DataFlowInfo.EMPTY, trace, namedFunction, functionDescriptor, scope)
return trace
}
private fun secondaryConstructorAdditionalResolve(resolveSession: ResolveSession, constructor: JetSecondaryConstructor, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(constructor)
val scope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(constructor)
val constructorDescriptor = resolveSession.resolveToDescriptor(constructor) as ConstructorDescriptor
ForceResolveUtil.forceResolveAllContents(constructorDescriptor)
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveSecondaryConstructorBody(DataFlowInfo.EMPTY, trace, constructor, constructorDescriptor, scope)
return trace
}
private fun constructorAdditionalResolve(resolveSession: ResolveSession, klass: JetClass, file: JetFile): BindingTrace {
val trace = createDelegatingTrace(klass)
val scope = resolveSession.getDeclarationScopeProvider().getResolutionScopeForDeclaration(klass)
val classDescriptor = resolveSession.resolveToDescriptor(klass) as ClassDescriptor
val constructorDescriptor = classDescriptor.getUnsubstitutedPrimaryConstructor()
?: error("Can't get primary constructor for descriptor '$classDescriptor' in from class '${klass.getElementTextWithContext()}'")
val bodyResolver = createBodyResolver(resolveSession, trace, file, StatementFilter.NONE)
bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(DataFlowInfo.EMPTY, trace, klass, constructorDescriptor, scope)
return trace
}
private fun initializerAdditionalResolve(resolveSession: ResolveSession, classInitializer: JetClassInitializer, file: JetFile, statementFilter: StatementFilter): BindingTrace {
val trace = createDelegatingTrace(classInitializer)
val classOrObject = classInitializer.getParentOfType<JetClassOrObject>(true)!!
val classOrObjectDescriptor = resolveSession.resolveToDescriptor(classOrObject) as LazyClassDescriptor
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
bodyResolver.resolveAnonymousInitializer(DataFlowInfo.EMPTY, classInitializer, classOrObjectDescriptor)
return trace
}
private fun createBodyResolver(
resolveSession: ResolveSession,
trace: BindingTrace,
file: JetFile,
statementFilter: StatementFilter
): BodyResolver {
val globalContext = SimpleGlobalContext(resolveSession.getStorageManager(), resolveSession.getExceptionTracker())
val module = resolveSession.getModuleDescriptor()
return createContainerForBodyResolve(
globalContext.withProject(file.getProject()).withModule(module),
trace,
getTargetPlatform(file),
statementFilter
).get<BodyResolver>()
}
// All additional resolve should be done to separate trace
private fun createDelegatingTrace(resolveElement: JetElement): BindingTrace {
return resolveSession.getStorageManager().createSafeTrace(
DelegatingBindingTrace(resolveSession.getBindingContext(), "trace to resolve element", resolveElement))
}
private class BodyResolveContextForLazy(
private val topDownAnalysisMode: TopDownAnalysisMode,
private val declaringScopes: Function1<JetDeclaration, JetScope?>
) : BodiesResolveContext {
override fun getFiles(): Collection<JetFile> = setOf()
override fun getDeclaredClasses(): MutableMap<JetClassOrObject, ClassDescriptorWithResolutionScopes> = hashMapOf()
override fun getAnonymousInitializers(): MutableMap<JetClassInitializer, ClassDescriptorWithResolutionScopes> = hashMapOf()
override fun getSecondaryConstructors(): MutableMap<JetSecondaryConstructor, ConstructorDescriptor> = hashMapOf()
override fun getProperties(): MutableMap<JetProperty, PropertyDescriptor> = hashMapOf()
override fun getFunctions(): MutableMap<JetNamedFunction, SimpleFunctionDescriptor> = hashMapOf()
override fun getDeclaringScope(declaration: JetDeclaration): JetScope? = declaringScopes(declaration)
override fun getScripts(): MutableMap<JetScript, ScriptDescriptor> = hashMapOf()
override fun getOuterDataFlowInfo(): DataFlowInfo = DataFlowInfo.EMPTY
override fun getTopDownAnalysisMode() = topDownAnalysisMode
}
}