From 59fa639ab462851832278b82f09508b36857e24e Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Mon, 26 Oct 2015 18:04:57 +0300 Subject: [PATCH] Refactored ReferenceVariantsHelper to not require KtSimpleNameExpression --- .../kotlin/resolve/BindingContextUtils.kt | 10 ++- .../codeInsight/ReferenceVariantsHelper.kt | 66 +++++++++++-------- .../idea/util/ShadowedDeclarationsFilter.kt | 5 +- .../idea/completion/CompletionSession.kt | 2 +- .../org/jetbrains/kotlin/idea/core/Utils.kt | 2 +- 5 files changed, 51 insertions(+), 34 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt index 687edbb990c..c0c82b4d5f7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.resolve.bindingContextUtil +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.* import org.jetbrains.kotlin.resolve.BindingTrace @@ -75,8 +77,12 @@ public fun BindingTrace.recordScope(scope: LexicalScope, element: KtElement?) { } } -public fun BindingContext.getDataFlowInfo(expression: KtExpression?): DataFlowInfo = - expression?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it]?.dataFlowInfo } ?: DataFlowInfo.EMPTY +public fun BindingContext.getDataFlowInfo(position: PsiElement): DataFlowInfo { + for (element in position.parentsWithSelf) { + (element as? KtExpression)?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it] }?.let { return it.dataFlowInfo } + } + return DataFlowInfo.EMPTY +} public fun KtExpression.isUnreachableCode(context: BindingContext): Boolean = context[BindingContext.UNREACHABLE_CODE, this]!! diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index 2973204b1c3..a512b588b89 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.idea.codeInsight +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.frontendService @@ -47,25 +48,34 @@ import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* -public class ReferenceVariantsHelper( - private val context: BindingContext, +class ReferenceVariantsHelper( + private val bindingContext: BindingContext, private val resolutionFacade: ResolutionFacade, private val visibilityFilter: (DeclarationDescriptor) -> Boolean ) { - @JvmOverloads - public fun getReferenceVariants( + fun getReferenceVariants( expression: KtSimpleNameExpression, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, - callTypeAndReceiver: CallTypeAndReceiver<*, *> = CallTypeAndReceiver.detect(expression), + filterOutJavaGettersAndSetters: Boolean = false, + useRuntimeReceiverType: Boolean = false + ): Collection + = getReferenceVariants(expression, CallTypeAndReceiver.detect(expression), + kindFilter, nameFilter, filterOutJavaGettersAndSetters, useRuntimeReceiverType) + + fun getReferenceVariants( + contextElement: PsiElement, + callTypeAndReceiver: CallTypeAndReceiver<*, *>, + kindFilter: DescriptorKindFilter, + nameFilter: (Name) -> Boolean, filterOutJavaGettersAndSetters: Boolean = false, useRuntimeReceiverType: Boolean = false ): Collection { var variants: Collection - = getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType) + = getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useRuntimeReceiverType) .filter { !it.isAnnotatedAsHidden() && visibilityFilter(it) } - ShadowedDeclarationsFilter.create(context, resolutionFacade, expression, callTypeAndReceiver)?.let { + ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let { variants = it.filter(variants) } @@ -79,14 +89,14 @@ public class ReferenceVariantsHelper( } } - variants = variants.filter { it.original !in accessorMethodsToRemove } + variants = variants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove } } return variants } private fun getReferenceVariantsNoVisibilityFilter( - expression: KtSimpleNameExpression, + contextElement: PsiElement, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, callTypeAndReceiver: CallTypeAndReceiver<*, *>, @@ -108,15 +118,15 @@ public class ReferenceVariantsHelper( } is CallTypeAndReceiver.TYPE -> { - return getVariantsForUserType(callTypeAndReceiver.receiver, expression, kindFilter, nameFilter) + return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter) } is CallTypeAndReceiver.ANNOTATION -> { - return getVariantsForUserType(callTypeAndReceiver.receiver, expression, kindFilter, nameFilter) + return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter) } is CallTypeAndReceiver.CALLABLE_REFERENCE -> { - val resolutionScope = expression.getResolutionScope(context, resolutionFacade) + val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade) return getVariantsForCallableReference(callTypeAndReceiver.receiver, resolutionScope, kindFilter, nameFilter) } @@ -129,19 +139,19 @@ public class ReferenceVariantsHelper( else -> throw RuntimeException() //TODO: see KT-9394 } - val resolutionScope = expression.getResolutionScope(context, resolutionFacade) - val dataFlowInfo = context.getDataFlowInfo(expression) + val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade) + val dataFlowInfo = bindingContext.getDataFlowInfo(contextElement) val containingDeclaration = resolutionScope.ownerDescriptor val smartCastManager = resolutionFacade.frontendService() val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance().flatMap { - smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo) + smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, bindingContext, containingDeclaration, dataFlowInfo) }.toSet() val descriptors = LinkedHashSet() if (receiverExpression != null) { - val qualifier = context[BindingContext.QUALIFIER, receiverExpression] + val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] if (qualifier != null) { descriptors.addAll(qualifier.scope.getDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.Extensions, nameFilter)) } @@ -149,11 +159,11 @@ public class ReferenceVariantsHelper( val expressionType = if (useRuntimeReceiverType) getQualifierRuntimeType(receiverExpression) else - context.getType(receiverExpression) + bindingContext.getType(receiverExpression) if (expressionType != null && !expressionType.isError()) { val receiverValue = ExpressionReceiver(receiverExpression, expressionType) val explicitReceiverTypes = smartCastManager - .getSmartCastVariantsWithLessSpecificExcluded(receiverValue, context, containingDeclaration, dataFlowInfo) + .getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, containingDeclaration, dataFlowInfo) descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter) } @@ -170,16 +180,16 @@ public class ReferenceVariantsHelper( private fun getVariantsForUserType( receiverExpression: KtExpression?, - expression: KtSimpleNameExpression, + contextElement: PsiElement, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean ): Collection { if (receiverExpression != null) { - val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList() + val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList() return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter) } else { - val scope = expression.getResolutionScope(context, resolutionFacade) + val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade) return scope.collectDescriptorsFiltered(kindFilter, nameFilter) } } @@ -192,7 +202,7 @@ public class ReferenceVariantsHelper( ): Collection { val descriptors = LinkedHashSet() if (qualifierTypeRef != null) { - val type = context[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList() + val type = bindingContext[BindingContext.TYPE, qualifierTypeRef] ?: return emptyList() descriptors.addNonExtensionMembers(listOf(type), kindFilter, nameFilter, constructorFilter = { true }) @@ -211,7 +221,7 @@ public class ReferenceVariantsHelper( nameFilter: (Name) -> Boolean ): Collection { if (receiverExpression != null) { - val qualifier = context[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList() + val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList() return qualifier.scope.getDescriptorsFiltered(kindFilter, nameFilter) } else { @@ -285,7 +295,7 @@ public class ReferenceVariantsHelper( } private fun MutableSet.addScopeAndSyntheticExtensions( - resolutionScope: LexicalScope, + scope: LexicalScope, receiverTypes: Collection, callType: CallType<*>, kindFilter: DescriptorKindFilter, @@ -299,26 +309,26 @@ public class ReferenceVariantsHelper( } } - for (descriptor in resolutionScope.collectDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.NonExtensions, nameFilter)) { + for (descriptor in scope.collectDescriptorsFiltered(kindFilter exclude DescriptorKindExclude.NonExtensions, nameFilter)) { // todo: sometimes resolution scope here is LazyJavaClassMemberScope. see ea.jetbrains.com/browser/ea_problems/72572 process(descriptor as CallableDescriptor) } if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) { - for (extension in resolutionScope.collectSyntheticExtensionProperties(receiverTypes)) { + for (extension in scope.collectSyntheticExtensionProperties(receiverTypes)) { process(extension) } } if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) { - for (extension in resolutionScope.collectSyntheticExtensionFunctions(receiverTypes)) { + for (extension in scope.collectSyntheticExtensionFunctions(receiverTypes)) { process(extension) } } } private fun getQualifierRuntimeType(receiver: KtExpression): KotlinType? { - val type = context.getType(receiver) + val type = bindingContext.getType(receiver) if (type != null && TypeUtils.canHaveSubtypes(KotlinTypeChecker.DEFAULT, type)) { val evaluator = receiver.getContainingFile().getCopyableUserData(KtCodeFragment.RUNTIME_TYPE_EVALUATOR) val runtimeType = evaluator?.invoke(receiver) diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt index d3ed6b41b74..eb1dde048cf 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/ShadowedDeclarationsFilter.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.idea.util +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.resolve.ResolutionFacade @@ -40,14 +41,14 @@ import java.util.* public class ShadowedDeclarationsFilter private constructor( private val bindingContext: BindingContext, private val resolutionFacade: ResolutionFacade, - private val context: KtExpression, + private val context: PsiElement, private val explicitReceiverValue: ReceiverValue ) { companion object { fun create( bindingContext: BindingContext, resolutionFacade: ResolutionFacade, - context: KtExpression, + context: PsiElement, callTypeAndReceiver: CallTypeAndReceiver<*, *> ): ShadowedDeclarationsFilter? { val receiverExpression = when (callTypeAndReceiver) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index d22d01a39dc..4c792d9fd96 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -316,7 +316,7 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC private fun createLookupElementFactory(callType: CallType<*>?, receiverTypes: Collection?): LookupElementFactory { val contextVariablesProvider = { nameExpression?.let { - referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, CallTypeAndReceiver.DEFAULT) + referenceVariantsHelper.getReferenceVariants(it, CallTypeAndReceiver.DEFAULT, DescriptorKindFilter.VARIABLES, nameFilter = { true }) .map { it as VariableDescriptor } } ?: emptyList() } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/Utils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/Utils.kt index fc13afcc4a2..d80e9cf02b5 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/Utils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/Utils.kt @@ -112,7 +112,7 @@ public fun Call.resolveCandidates( val resolutionScope = callElement.getResolutionScope(bindingContext, resolutionFacade) val inDescriptor = resolutionScope.ownerDescriptor - val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression) + val dataFlowInfo = bindingContext.getDataFlowInfo(callElement) val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace") val callResolutionContext = BasicCallResolutionContext.create( bindingTrace, resolutionScope, this, expectedType, dataFlowInfo,