From 6e8be8d5af7a32aa19db9af592fa1eca20bab34b Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 6 Oct 2015 20:37:54 +0300 Subject: [PATCH] Extracted common code for detecting candidates for a Call --- .../kotlin/idea/completion/ExpectedInfos.kt | 38 ++---------- .../org/jetbrains/kotlin/idea/core/Utils.kt | 61 +++++++++++++++++-- .../KotlinFunctionParameterInfoHandler.kt | 53 ++-------------- 3 files changed, 67 insertions(+), 85 deletions(-) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt index a407159982a..315ffb4a452 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt @@ -22,8 +22,8 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.completion.smart.TypesWithContainsDetector import org.jetbrains.kotlin.idea.core.IterableTypesDetection import org.jetbrains.kotlin.idea.core.mapArgumentsToParameters +import org.jetbrains.kotlin.idea.core.resolveCandidates import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.idea.resolve.ideService import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.fuzzyReturnType @@ -32,25 +32,15 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DelegatingBindingTrace -import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunctionDescriptor -import org.jetbrains.kotlin.resolve.calls.CallResolver import org.jetbrains.kotlin.resolve.calls.callUtil.allArgumentsMapped 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.model.ResolvedCall -import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults -import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.typeUtil.containsError import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable @@ -247,27 +237,18 @@ class ExpectedInfos( override fun getFunctionLiteralArguments() = emptyList() override fun getValueArgumentList() = null } - val resolutionScope = bindingContext[BindingContext.LEXICAL_SCOPE, call.calleeExpression] ?: return emptyList() //TODO: discuss it - val inDescriptor = resolutionScope.ownerDescriptor - val dataFlowInfo = bindingContext.getDataFlowInfo(call.calleeExpression) - val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for completion") - val context = BasicCallResolutionContext.create(bindingTrace, resolutionScope, truncatedCall, callExpectedType, dataFlowInfo, - ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, - CallChecker.DoNothing, false) - val callResolutionContext = context.replaceCollectAllCandidates(true) - val callResolver = resolutionFacade.frontendService() - val results: OverloadResolutionResults = callResolver.resolveFunctionCall(callResolutionContext) + val candidates = truncatedCall.resolveCandidates(bindingContext, resolutionFacade, callExpectedType) val expectedInfos = ArrayList() - for (candidate in results.allCandidates!!) { - expectedInfos.addExpectedInfoForCandidate(candidate, call, argument, argumentIndex, inDescriptor, checkPrevArgumentsMatched = true) + for (candidate in candidates) { + expectedInfos.addExpectedInfoForCandidate(candidate, call, argument, argumentIndex, checkPrevArgumentsMatched = true) } if (expectedInfos.isEmpty()) { // if no candidates have previous arguments matched, try with no type checking for them - for (candidate in results.allCandidates!!) { - expectedInfos.addExpectedInfoForCandidate(candidate, call, argument, argumentIndex, inDescriptor, checkPrevArgumentsMatched = false) + for (candidate in candidates) { + expectedInfos.addExpectedInfoForCandidate(candidate, call, argument, argumentIndex, checkPrevArgumentsMatched = false) } } @@ -279,12 +260,8 @@ class ExpectedInfos( call: Call, argument: ValueArgument, argumentIndex: Int, - inDescriptor: DeclarationDescriptor, checkPrevArgumentsMatched: Boolean ) { - val status = candidate.getStatus() - if (status == ResolutionStatus.RECEIVER_TYPE_ERROR || status == ResolutionStatus.RECEIVER_PRESENCE_ERROR) return - // check that all arguments before the current has mappings to parameters if (!candidate.allArgumentsMapped()) return @@ -294,9 +271,6 @@ class ExpectedInfos( var descriptor = candidate.getResultingDescriptor() if (descriptor.valueParameters.isEmpty()) return - val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(candidate.getDispatchReceiver(), bindingContext) - if (!Visibilities.isVisible(thisReceiver, descriptor, inDescriptor)) return - var argumentToParameter = call.mapArgumentsToParameters(descriptor) var parameter = argumentToParameter[argument] 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 db53246500c..8d9ba76cfc3 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 @@ -17,23 +17,33 @@ package org.jetbrains.kotlin.idea.core import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getFileTopLevelScope import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector +import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf 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.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.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver -import org.jetbrains.kotlin.resolve.scopes.utils.asLexicalScope +import org.jetbrains.kotlin.types.JetType +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import java.util.* public fun Call.mapArgumentsToParameters(targetDescriptor: CallableDescriptor): Map { @@ -110,3 +120,44 @@ public fun JetImportDirective.targetDescriptors(): Collection> { + val resolutionScope = callElement.getResolutionScope(bindingContext, resolutionFacade) + val inDescriptor = resolutionScope.ownerDescriptor + + val dataFlowInfo = bindingContext.getDataFlowInfo(calleeExpression) + val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace") + val callResolutionContext = BasicCallResolutionContext.create( + bindingTrace, resolutionScope, this, expectedType, dataFlowInfo, + ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, + CallChecker.DoNothing, false + ).replaceCollectAllCandidates(true) + val callResolver = resolutionFacade.frontendService() + + val results = callResolver.resolveFunctionCall(callResolutionContext) + + var candidates = results.allCandidates!! + if (filterOutWrongReceiver) { + candidates = candidates.filter { it.status != ResolutionStatus.RECEIVER_TYPE_ERROR && it.status != ResolutionStatus.RECEIVER_PRESENCE_ERROR } + } + if (filterOutByVisibility) { + candidates = candidates.filter { + val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(it.dispatchReceiver, bindingContext) + Visibilities.isVisible(thisReceiver, it.resultingDescriptor, inDescriptor) + } + } + return candidates +} + +private fun expectedType(call: Call, bindingContext: BindingContext): JetType { + return (call.callElement as? JetExpression)?.let { + bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, it.getQualifiedExpressionForSelectorOrThis()] + } ?: TypeUtils.NO_EXPECTED_TYPE +} + diff --git a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt index 2931d6e9c1f..b9eff6f99a5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/parameterInfo/KotlinFunctionParameterInfoHandler.kt @@ -27,41 +27,26 @@ import com.intellij.ui.JBColor import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.OptionalParametersHelper -import org.jetbrains.kotlin.idea.core.getResolutionScope +import org.jetbrains.kotlin.idea.core.resolveCandidates import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.idea.resolve.frontendService import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.allChildren -import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DelegatingBindingTrace import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils -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.callUtil.getResolvedCall -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.model.ArgumentMatch -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall -import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults -import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.JetType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.typeUtil.containsError import java.awt.Color import java.util.* @@ -129,9 +114,9 @@ abstract class KotlinParameterInfoWithCallHandlerBase> { - val callElement = call.callElement - val resolutionScope = callElement.getResolutionScope(bindingContext, resolutionFacade) - val inDescriptor = resolutionScope.ownerDescriptor - - val dataFlowInfo = bindingContext.getDataFlowInfo(call.calleeExpression) - val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace") - val expectedType = (callElement as? JetExpression)?.let { - bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, it.getQualifiedExpressionForSelectorOrThis()] - } ?: TypeUtils.NO_EXPECTED_TYPE - val callResolutionContext = BasicCallResolutionContext.create( - bindingTrace, resolutionScope, call, expectedType, dataFlowInfo, - ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, - CallChecker.DoNothing, false/*TODO?*/ - ).replaceCollectAllCandidates(true) - val callResolver = resolutionFacade.frontendService() - - val results: OverloadResolutionResults = callResolver.resolveFunctionCall(callResolutionContext) - - return results.allCandidates!! - .filter { it.status != ResolutionStatus.RECEIVER_TYPE_ERROR && it.status != ResolutionStatus.RECEIVER_PRESENCE_ERROR } - .filter { - val thisReceiver = ExpressionTypingUtils.normalizeReceiverValueForVisibility(it.dispatchReceiver, bindingContext) - Visibilities.isVisible(thisReceiver, it.resultingDescriptor, inDescriptor) - } - .distinctBy { it.resultingDescriptor.original } - } - // we should not compare descriptors directly because partial resolve is involved private fun descriptorsEqual(descriptor1: FunctionDescriptor, descriptor2: FunctionDescriptor): Boolean { if (descriptor1.original == descriptor2.original) return true