From d781626201c0a88a91844ec4643fcb3778ac7551 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 30 Apr 2014 18:26:47 +0400 Subject: [PATCH] Smart completion: only overloads with all previous arguments matched are considered --- .../resolve/calls/util/resolvedCallUtil.kt | 8 ++--- .../jet/plugin/completion/ExpectedInfos.kt | 36 ++++++++++++------- ...gnore => OverloadedMethodCallArgument3.kt} | 0 .../JvmSmartCompletionTestGenerated.java | 5 +++ 4 files changed, 33 insertions(+), 16 deletions(-) rename idea/testData/completion/smart/{OverloadedMethodCallArgument3.kt.ignore => OverloadedMethodCallArgument3.kt} (100%) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt index 778c0a4836b..24e26b5148e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/resolvedCallUtil.kt @@ -24,20 +24,20 @@ import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument import org.jetbrains.jet.lang.resolve.calls.model.ArgumentMapping import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor -fun ResolvedCall.noErrorsInValueArguments(): Boolean { +public fun ResolvedCall.noErrorsInValueArguments(): Boolean { return getCall().getValueArguments().all { argument -> !getArgumentMapping(argument!!).isError() } } -fun ResolvedCall.hasUnmappedArguments(): Boolean { +public fun ResolvedCall.hasUnmappedArguments(): Boolean { return getCall().getValueArguments().any { argument -> getArgumentMapping(argument!!) == ArgumentUnmapped } } -fun ResolvedCall.hasUnmappedParameters(): Boolean { +public fun ResolvedCall.hasUnmappedParameters(): Boolean { val parameterToArgumentMap = getValueArguments() return !parameterToArgumentMap.keySet().containsAll(getResultingDescriptor().getValueParameters()) } -fun ResolvedCall.hasErrorOnParameter(parameter: ValueParameterDescriptor): Boolean { +public fun ResolvedCall.hasErrorOnParameter(parameter: ValueParameterDescriptor): Boolean { val resolvedValueArgument = getValueArguments()[parameter] if (resolvedValueArgument == null) return true diff --git a/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt b/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt index d429bb85c53..b57700ddfd4 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt @@ -46,6 +46,9 @@ import org.jetbrains.jet.lang.psi.JetIfExpression import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import org.jetbrains.jet.lang.psi.JetContainerNode import org.jetbrains.jet.plugin.completion.smart.isSubtypeOf +import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall +import org.jetbrains.jet.lang.resolve.calls.util.noErrorsInValueArguments +import org.jetbrains.jet.lang.resolve.calls.util.hasUnmappedParameters enum class Tail { COMMA @@ -57,8 +60,7 @@ data class ExpectedInfo(val `type`: JetType, val tail: Tail?) class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) { public fun calculate(expressionWithType: JetExpression): Collection? { - val forArgument = calculateForArgument(expressionWithType) - return forArgument + return calculateForArgument(expressionWithType) ?: calculateForFunctionLiteralArgument(expressionWithType) ?: calculateForEq(expressionWithType) ?: calculateForIf(expressionWithType) @@ -101,7 +103,14 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo receiver = ReceiverValue.NO_RECEIVER callOperationNode = null } - val call = CallMaker.makeCall(receiver, callOperationNode, callExpression) + var call = CallMaker.makeCall(receiver, callOperationNode, callExpression) + + if (!isFunctionLiteralArgument) { // leave only arguments before the current one + call = object : DelegatingCall(call) { + override fun getValueArguments() = super.getValueArguments().subList(0, argumentIndex) + override fun getValueArgumentList() = null + } + } val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, calleeExpression] ?: return null //TODO: discuss it @@ -120,16 +129,19 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo val expectedInfos = HashSet() for (candidate: ResolvedCall in results.getAllCandidates()!!) { - val parameters = candidate.getResultingDescriptor().getValueParameters() - if (isFunctionLiteralArgument) { - if (argumentIndex != parameters.size - 1) continue + // consider only candidates with more arguments than in the truncated call and with all arguments before the current one matched + if (candidate.noErrorsInValueArguments() && (isFunctionLiteralArgument || candidate.hasUnmappedParameters())) { + val parameters = candidate.getResultingDescriptor().getValueParameters() + if (isFunctionLiteralArgument) { + if (argumentIndex != parameters.size - 1) continue + } + else { + if (parameters.size <= argumentIndex) continue + } + val parameterDescriptor = parameters[argumentIndex] + val tail = if (isFunctionLiteralArgument) null else if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA + expectedInfos.add(ExpectedInfo(parameterDescriptor.getType(), tail)) } - else { - if (parameters.size <= argumentIndex) continue - } - val parameterDescriptor = parameters[argumentIndex] - val tail = if (isFunctionLiteralArgument) null else if (argumentIndex == parameters.size - 1) Tail.PARENTHESIS else Tail.COMMA - expectedInfos.add(ExpectedInfo(parameterDescriptor.getType(), tail)) } return expectedInfos } diff --git a/idea/testData/completion/smart/OverloadedMethodCallArgument3.kt.ignore b/idea/testData/completion/smart/OverloadedMethodCallArgument3.kt similarity index 100% rename from idea/testData/completion/smart/OverloadedMethodCallArgument3.kt.ignore rename to idea/testData/completion/smart/OverloadedMethodCallArgument3.kt diff --git a/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java index 6cdd3d48e9e..5e6acc8e415 100644 --- a/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java @@ -336,6 +336,11 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT doTest("idea/testData/completion/smart/OverloadedMethodCallArgument2.kt"); } + @TestMetadata("OverloadedMethodCallArgument3.kt") + public void testOverloadedMethodCallArgument3() throws Exception { + doTest("idea/testData/completion/smart/OverloadedMethodCallArgument3.kt"); + } + @TestMetadata("PrivateConstructorForAbstract.kt") public void testPrivateConstructorForAbstract() throws Exception { doTest("idea/testData/completion/smart/PrivateConstructorForAbstract.kt");