From fbb37f0154bb54f21e5879b34c67160ca0686330 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 26 Aug 2015 19:19:01 +0300 Subject: [PATCH] Refactored ReferenceVariantsHelper to allow specifying receiver --- .../codeInsight/ReferenceVariantsHelper.kt | 32 +++++++------ .../idea/util/ShadowedDeclarationsFilter.kt | 46 +++++++++++-------- .../idea/completion/CompletionSession.kt | 3 +- .../smart/SmartCompletionSession.kt | 6 +-- .../kotlin/idea/core/KotlinIndicesHelper.kt | 9 ++-- .../JetFunctionParameterInfoHandler.java | 6 ++- 6 files changed, 60 insertions(+), 42 deletions(-) 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 29f93228dea..38448fe55e6 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 @@ -43,14 +43,18 @@ import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.checker.JetTypeChecker import org.jetbrains.kotlin.utils.addIfNotNull -import java.util.HashSet -import java.util.LinkedHashSet +import java.util.* public class ReferenceVariantsHelper( private val context: BindingContext, private val resolutionFacade: ResolutionFacade, private val visibilityFilter: (DeclarationDescriptor) -> Boolean ) { + public data class ExplicitReceiverData( + val expression: JetExpression, + val callType: CallType + ) + public data class ReceiversData( public val receivers: Collection, public val callType: CallType @@ -60,18 +64,20 @@ public class ReferenceVariantsHelper( } } + @jvmOverloads public fun getReferenceVariants( expression: JetSimpleNameExpression, kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean, + explicitReceiverData: ExplicitReceiverData? = getExplicitReceiverData(expression), filterOutJavaGettersAndSetters: Boolean = false, useRuntimeReceiverType: Boolean = false ): Collection { var variants: Collection - = getReferenceVariantsNoVisibilityFilter(expression, kindFilter, useRuntimeReceiverType, nameFilter) + = getReferenceVariantsNoVisibilityFilter(expression, kindFilter, nameFilter, explicitReceiverData, useRuntimeReceiverType) .filter(visibilityFilter) - variants = ShadowedDeclarationsFilter(context, resolutionFacade).filter(variants, expression) + variants = ShadowedDeclarationsFilter(context, resolutionFacade, expression, explicitReceiverData).filter(variants) if (filterOutJavaGettersAndSetters) { val accessorMethodsToRemove = HashSet() @@ -91,8 +97,9 @@ public class ReferenceVariantsHelper( private fun getReferenceVariantsNoVisibilityFilter( expression: JetSimpleNameExpression, kindFilter: DescriptorKindFilter, - useRuntimeReceiverType: Boolean, - nameFilter: (Name) -> Boolean + nameFilter: (Name) -> Boolean, + explicitReceiverData: ExplicitReceiverData?, + useRuntimeReceiverType: Boolean ): Collection { val parent = expression.getParent() val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return listOf() @@ -115,9 +122,8 @@ public class ReferenceVariantsHelper( smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(it.value, context, containingDeclaration, dataFlowInfo) }.toSet() - val pair = getExplicitReceiverData(expression) - if (pair != null) { - val (receiverExpression, callType) = pair + if (explicitReceiverData != null) { + val (receiverExpression, callType) = explicitReceiverData val qualifier = context[BindingContext.QUALIFIER, receiverExpression] if (qualifier != null) { @@ -247,9 +253,9 @@ public class ReferenceVariantsHelper( public fun getReferenceVariantsReceivers(expression: JetSimpleNameExpression): ReceiversData { val receiverData = getExplicitReceiverData(expression) if (receiverData != null) { - val receiverExpression = receiverData.first + val receiverExpression = receiverData.expression val expressionType = context.getType(receiverExpression) ?: return ReceiversData.Empty - return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.second) + return ReceiversData(listOf(ExpressionReceiver(receiverExpression, expressionType)), receiverData.callType) } else { val resolutionScope = context[BindingContext.RESOLUTION_SCOPE, expression] ?: return ReceiversData.Empty @@ -275,7 +281,7 @@ public class ReferenceVariantsHelper( } companion object { - public fun getExplicitReceiverData(expression: JetSimpleNameExpression): Pair? { + public fun getExplicitReceiverData(expression: JetSimpleNameExpression): ExplicitReceiverData? { val receiverExpression = expression.getReceiverExpression() ?: return null val parent = expression.getParent() val callType = when (parent) { @@ -299,7 +305,7 @@ public class ReferenceVariantsHelper( else -> return null } - return receiverExpression to callType + return ExplicitReceiverData(receiverExpression, callType) } } } 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 f1efe16f65b..7f75741e52a 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 @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.idea.util import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.frontendService @@ -25,53 +26,54 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DelegatingBindingTrace import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.calls.CallResolver -import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.context.ContextDependency -import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall import org.jetbrains.kotlin.resolve.scopes.ChainedScope import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution -import java.util.ArrayList -import java.util.HashSet +import java.util.* public class ShadowedDeclarationsFilter( private val bindingContext: BindingContext, - private val resolutionFacade: ResolutionFacade + private val resolutionFacade: ResolutionFacade, + private val context: JetExpression, + explicitReceiverData: ReferenceVariantsHelper.ExplicitReceiverData? ) { private val psiFactory = JetPsiFactory(resolutionFacade.project) private val dummyExpressionFactory = DummyExpressionFactory(psiFactory) - public fun filter(declarations: Collection, expression: JetSimpleNameExpression): Collection { - val call = expression.getCall(bindingContext) ?: return declarations + private val explicitReceiverValue = explicitReceiverData?.let { + val type = bindingContext.getType(it.expression) ?: return@let null + ExpressionReceiver(it.expression, type) + } ?: ReceiverValue.NO_RECEIVER + public fun filter(declarations: Collection): Collection { return declarations .groupBy { signature(it) } .values() - .flatMap { group -> filterEqualSignatureGroup(group, call) } + .flatMap { group -> filterEqualSignatureGroup(group) } } public fun filterNonImported( declarations: Collection, - importedDeclarations: Collection, - expression: JetSimpleNameExpression + importedDeclarations: Collection ): Collection { val importedDeclarationsSet = importedDeclarations.toSet() val nonImportedDeclarations = declarations.filter { it !in importedDeclarationsSet } val importedDeclarationsBySignature = importedDeclarationsSet.groupBy { signature(it) } - val call = expression.getCall(bindingContext) ?: return nonImportedDeclarations - val notShadowed = HashSet() // same signature non-imported declarations from different packages do not shadow each other for ((pair, group) in nonImportedDeclarations.groupBy { signature(it) to packageName(it) }) { val imported = importedDeclarationsBySignature[pair.first] val all = if (imported != null) group + imported else group - notShadowed.addAll(filterEqualSignatureGroup(all, call, descriptorsToImport = group)) + notShadowed.addAll(filterEqualSignatureGroup(all, descriptorsToImport = group)) } return declarations.filter { it in notShadowed } } @@ -88,7 +90,6 @@ public class ShadowedDeclarationsFilter( private fun filterEqualSignatureGroup( descriptors: Collection, - call: Call, descriptorsToImport: Collection = emptyList() ): Collection { if (descriptors.size() == 1) return descriptors @@ -135,7 +136,7 @@ public class ShadowedDeclarationsFilter( arguments.add(DummyArgument(i)) } - val newCall = object : DelegatingCall(call) { + val newCall = object : Call { //TODO: compiler crash (KT-8011) //val arguments = parameters.indices.map { DummyArgument(it) } val callee = psiFactory.createExpressionByPattern("$0", name) @@ -151,17 +152,26 @@ public class ShadowedDeclarationsFilter( override fun getTypeArguments() = emptyList() override fun getTypeArgumentList() = null + + override fun getDispatchReceiver() = ReceiverValue.NO_RECEIVER + + override fun getCallOperationNode() = null + + override fun getExplicitReceiver() = explicitReceiverValue + + override fun getCallElement() = callee + + override fun getCallType() = Call.CallType.DEFAULT } - val calleeExpression = call.getCalleeExpression() ?: return descriptors - var resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return descriptors + var resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] ?: return descriptors if (descriptorsToImport.isNotEmpty()) { resolutionScope = ChainedScope(resolutionScope.getContainingDeclaration(), "Scope with explicitly imported descriptors", ExplicitImportsScope(descriptorsToImport), resolutionScope) } - val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression) + val dataFlowInfo = bindingContext.getDataFlowInfo(context) val context = BasicCallResolutionContext.create(bindingTrace, resolutionScope, newCall, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CallChecker.DoNothing, false) 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 623edc671e2..2bb27ce77c2 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 @@ -328,7 +328,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC } private fun Collection.filterShadowedNonImported(): Collection { - return ShadowedDeclarationsFilter(bindingContext, resolutionFacade).filterNonImported(this, referenceVariants, nameExpression!!) + val explicitReceiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression!!) + return ShadowedDeclarationsFilter(bindingContext, resolutionFacade, nameExpression, explicitReceiverData).filterNonImported(this, referenceVariants) } protected fun addAllClasses(kindFilter: (ClassKind) -> Boolean) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt index 27bbd1703a6..45df742588f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt @@ -90,9 +90,9 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para // special completion for outside parenthesis lambda argument private fun addFunctionLiteralArgumentCompletions() { if (nameExpression != null) { - val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) - if (receiverData != null && receiverData.second == CallType.INFIX) { - val call = receiverData.first.getCall(bindingContext) + val (receiverExpression, callType) = ReferenceVariantsHelper.getExplicitReceiverData(nameExpression) ?: return + if (callType == CallType.INFIX) { + val call = receiverExpression.getCall(bindingContext) if (call != null && call.getFunctionLiteralArguments().isEmpty()) { val dummyArgument = object : FunctionLiteralArgument { override fun getFunctionLiteral() = throw UnsupportedOperationException() diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index c53e88541e2..199f9c2a141 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -45,8 +45,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList -import java.util.HashSet -import java.util.LinkedHashSet +import java.util.* public class KotlinIndicesHelper( private val resolutionFacade: ResolutionFacade, @@ -133,9 +132,9 @@ public class KotlinIndicesHelper( } private fun receiverValues(expression: JetSimpleNameExpression, bindingContext: BindingContext): Collection> { - val receiverPair = ReferenceVariantsHelper.getExplicitReceiverData(expression) - if (receiverPair != null) { - val (receiverExpression, callType) = receiverPair + val receiverData = ReferenceVariantsHelper.getExplicitReceiverData(expression) + if (receiverData != null) { + val (receiverExpression, callType) = receiverData val expressionType = bindingContext.getType(receiverExpression) if (expressionType == null || expressionType.isError()) return emptyList() diff --git a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java index 01bf92079bd..7c6fb58c258 100644 --- a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java +++ b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/JetFunctionParameterInfoHandler.java @@ -413,8 +413,10 @@ public class JetFunctionParameterInfoHandler implements ParameterInfoHandlerWith } }; Collection variants = new ReferenceVariantsHelper(bindingContext, resolutionFacade, visibilityFilter).getReferenceVariants( - callNameExpression, new DescriptorKindFilter(DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK, - Collections.emptyList()), nameFilter, false, false); + callNameExpression, + new DescriptorKindFilter(DescriptorKindFilter.FUNCTIONS_MASK | DescriptorKindFilter.CLASSIFIERS_MASK, Collections.emptyList()), + nameFilter + ); Collection> itemsToShow = new ArrayList>(); for (DeclarationDescriptor variant : variants) {