diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/extendedResolutionApi.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/extendedResolutionApi.kt new file mode 100644 index 00000000000..8a3365ba5a5 --- /dev/null +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/extendedResolutionApi.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.idea.caches.resolve + +import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException + +/** + * This function throws exception when resolveToDescriptorIfAny returns null, otherwise works equivalently. + */ +fun KtDeclaration.unsafeResolveToDescriptor( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL +): DeclarationDescriptor = + resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) ?: throw NoDescriptorForDeclarationException(this) + + +/** + * This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent), + * and then takes the relevant descriptor from binding context. + * The exact set of declarations to resolve depends on bodyResolveMode + */ +fun KtDeclaration.resolveToDescriptorIfAny( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): DeclarationDescriptor? { + //TODO: BodyResolveMode.PARTIAL is not quite safe! + val context = analyze(resolutionFacade, bodyResolveMode) + return if (this is KtParameter && hasValOrVar()) { + context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this) + } else { + context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this) + } +} + +fun KtClassOrObject.resolveToDescriptorIfAny( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): ClassDescriptor? { + return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? ClassDescriptor +} + +fun KtNamedFunction.resolveToDescriptorIfAny( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): FunctionDescriptor? { + return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? FunctionDescriptor +} + +fun KtProperty.resolveToDescriptorIfAny( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): VariableDescriptor? { + return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? VariableDescriptor +} + +fun KtParameter.resolveToParameterDescriptorIfAny( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): ValueParameterDescriptor? { + val context = analyze(resolutionFacade, bodyResolveMode) + return context.get(BindingContext.VALUE_PARAMETER, this) as? ValueParameterDescriptor +} + +fun KtElement.resolveToCall( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): ResolvedCall? = + getResolvedCall(analyze(resolutionFacade, bodyResolveMode)) + + +@JvmOverloads +fun KtElement.analyze( + resolutionFacade: ResolutionFacade, + bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL +): BindingContext = + resolutionFacade.analyze(this, bodyResolveMode) + +fun KtElement.analyzeAndGetResult(resolutionFacade: ResolutionFacade): AnalysisResult { + return AnalysisResult.success(resolutionFacade.analyze(this), resolutionFacade.moduleDescriptor) +} + +// This function is used on declarations to make analysis not only declaration itself but also it content: +// body for declaration with body, initializer & accessors for properties +fun KtDeclaration.analyzeWithContent(resolutionFacade: ResolutionFacade): BindingContext = + resolutionFacade.analyzeWithAllCompilerChecks(listOf(this)).bindingContext + +// This function is used to make full analysis of declaration container. +// All its declarations, including their content (see above), are analyzed. +inline fun T.analyzeWithContent(resolutionFacade: ResolutionFacade): BindingContext where T : KtDeclarationContainer, T : KtElement = + resolutionFacade.analyzeWithAllCompilerChecks(listOf(this)).bindingContext + diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt index b89e0e7080a..24f69ebf324 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/caches/resolve/resolutionApi.kt @@ -28,64 +28,74 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTraceContext import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException fun KtElement.getResolutionFacade(): ResolutionFacade = - KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this)) + KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this)) /** * For local declarations is equivalent to unsafeResolveToDescriptor(bodyResolveMode) * * But for non-local declarations it ignores bodyResolveMode and uses LazyDeclarationResolver directly */ -@Deprecated(message = "This function has unclear semantics. Please use either unsafeResolveToDescriptor or resolveToDescriptorIfAny instead", - replaceWith = ReplaceWith("unsafeResolveToDescriptor")) +@Deprecated( + message = "This function has unclear semantics. Please use either unsafeResolveToDescriptor or resolveToDescriptorIfAny instead", + replaceWith = ReplaceWith("unsafeResolveToDescriptor") +) fun KtDeclaration.resolveToDescriptor(bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor = - getResolutionFacade().resolveToDescriptor(this, bodyResolveMode) + getResolutionFacade().resolveToDescriptor(this, bodyResolveMode) /** * This function throws exception when resolveToDescriptorIfAny returns null, otherwise works equivalently. + * + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** */ -fun KtDeclaration.unsafeResolveToDescriptor(bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor = - resolveToDescriptorIfAny(bodyResolveMode) ?: throw NoDescriptorForDeclarationException(this) +fun KtDeclaration.unsafeResolveToDescriptor( + bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL +): DeclarationDescriptor = + unsafeResolveToDescriptor(getResolutionFacade(), bodyResolveMode) /** * This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent), * and then takes the relevant descriptor from binding context. * The exact set of declarations to resolve depends on bodyResolveMode + * + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** */ -fun KtDeclaration.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): DeclarationDescriptor? { - //TODO: BodyResolveMode.PARTIAL is not quite safe! - val context = analyze(bodyResolveMode) - return if (this is KtParameter && hasValOrVar()) { - context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this) - } else { - context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this) - } -} +fun KtDeclaration.resolveToDescriptorIfAny( + bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL +): DeclarationDescriptor? = + resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode) -fun KtClassOrObject.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): ClassDescriptor? { - return (this as KtDeclaration).resolveToDescriptorIfAny(bodyResolveMode) as? ClassDescriptor -} +/** + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** + */ +fun KtClassOrObject.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) = + resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode) -fun KtNamedFunction.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): FunctionDescriptor? { - return (this as KtDeclaration).resolveToDescriptorIfAny(bodyResolveMode) as? FunctionDescriptor -} +/** + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** + */ +fun KtNamedFunction.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) = + resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode) -fun KtProperty.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): VariableDescriptor? { - return (this as KtDeclaration).resolveToDescriptorIfAny(bodyResolveMode) as? VariableDescriptor -} +/** + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** + */ +fun KtProperty.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) = + resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode) -fun KtParameter.resolveToParameterDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): ValueParameterDescriptor? { - val context = analyze(bodyResolveMode) - return context.get(BindingContext.VALUE_PARAMETER, this) as? ValueParameterDescriptor -} +/** + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** + */ +fun KtParameter.resolveToParameterDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) = + resolveToParameterDescriptorIfAny(getResolutionFacade(), bodyResolveMode) -fun KtElement.resolveToCall(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL): ResolvedCall? = - getResolvedCall(analyze(bodyResolveMode)) +/** + * **Please, use overload with providing resolutionFacade for stable results of subsequent calls** + */ +fun KtElement.resolveToCall(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) = + resolveToCall(getResolutionFacade(), bodyResolveMode) fun KtFile.resolveImportReference(fqName: FqName): Collection { val facade = getResolutionFacade() @@ -111,26 +121,39 @@ fun KtFile.resolveImportReference(fqName: FqName): Collection T.analyzeWithContent(): BindingContext where T : KtDeclarationContainer, T : KtElement = - getResolutionFacade().analyzeWithAllCompilerChecks(listOf(this)).bindingContext + analyzeWithContent(getResolutionFacade()) /** * This function is expected to produce the same result as compiler for the whole file content (including diagnostics,