Extracted common code for detecting candidates for a Call
This commit is contained in:
@@ -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<FunctionLiteralArgument>()
|
||||
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<CallResolver>()
|
||||
val results: OverloadResolutionResults<FunctionDescriptor> = callResolver.resolveFunctionCall(callResolutionContext)
|
||||
val candidates = truncatedCall.resolveCandidates(bindingContext, resolutionFacade, callExpectedType)
|
||||
|
||||
val expectedInfos = ArrayList<ExpectedInfo>()
|
||||
|
||||
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]
|
||||
|
||||
|
||||
@@ -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<ValueArgument, ValueParameterDescriptor> {
|
||||
@@ -110,3 +120,44 @@ public fun JetImportDirective.targetDescriptors(): Collection<DeclarationDescrip
|
||||
val nameExpression = importedReference?.getQualifiedElementSelector() as? JetSimpleNameExpression ?: return emptyList()
|
||||
return nameExpression.mainReference.resolveToDescriptors(nameExpression.analyze())
|
||||
}
|
||||
|
||||
public fun Call.resolveCandidates(
|
||||
bindingContext: BindingContext,
|
||||
resolutionFacade: ResolutionFacade,
|
||||
expectedType: JetType = expectedType(this, bindingContext),
|
||||
filterOutWrongReceiver: Boolean = true,
|
||||
filterOutByVisibility: Boolean = true
|
||||
): Collection<ResolvedCall<FunctionDescriptor>> {
|
||||
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<CallResolver>()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
+5
-48
@@ -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<TArgumentList : JetElement
|
||||
val bindingContext = argumentList.analyze(BodyResolveMode.PARTIAL)
|
||||
val call = findCall(argumentList, bindingContext) ?: return null
|
||||
|
||||
val candidates = detectCandidates(call, bindingContext, file.getResolutionFacade())
|
||||
val candidates = call.resolveCandidates(bindingContext, file.getResolutionFacade())
|
||||
|
||||
context.itemsToShow = candidates.map { it.resultingDescriptor.original }.toTypedArray()
|
||||
context.itemsToShow = candidates.map { it.resultingDescriptor.original }.distinct().toTypedArray()
|
||||
return argumentList
|
||||
}
|
||||
|
||||
@@ -350,8 +335,8 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : JetElement
|
||||
}
|
||||
}
|
||||
|
||||
val candidates = detectCandidates(callToUse, bindingContext, resolutionFacade)
|
||||
val resolvedCall = candidates.singleOrNull { descriptorsEqual(it.resultingDescriptor, overload) } ?: return null
|
||||
val candidates = callToUse.resolveCandidates(bindingContext, resolutionFacade)
|
||||
val resolvedCall = candidates.firstOrNull { descriptorsEqual(it.resultingDescriptor, overload) } ?: return null
|
||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||
|
||||
fun argumentToParameter(argument: ValueArgument): ValueParameterDescriptor? {
|
||||
@@ -375,34 +360,6 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : JetElement
|
||||
private fun ValueArgument.hasError(bindingContext: BindingContext)
|
||||
= getArgumentExpression()?.let { bindingContext.getType(it) }?.isError ?: true
|
||||
|
||||
private fun detectCandidates(call: Call, bindingContext: BindingContext, resolutionFacade: ResolutionFacade): List<ResolvedCall<FunctionDescriptor>> {
|
||||
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<CallResolver>()
|
||||
|
||||
val results: OverloadResolutionResults<FunctionDescriptor> = 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
|
||||
|
||||
Reference in New Issue
Block a user