Smart completion: only overloads with all previous arguments matched are considered
This commit is contained in:
@@ -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.resolve.calls.model.ArgumentMapping
|
||||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
|
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor
|
||||||
|
|
||||||
fun <D : CallableDescriptor> ResolvedCall<D>.noErrorsInValueArguments(): Boolean {
|
public fun <D : CallableDescriptor> ResolvedCall<D>.noErrorsInValueArguments(): Boolean {
|
||||||
return getCall().getValueArguments().all { argument -> !getArgumentMapping(argument!!).isError() }
|
return getCall().getValueArguments().all { argument -> !getArgumentMapping(argument!!).isError() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedArguments(): Boolean {
|
public fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedArguments(): Boolean {
|
||||||
return getCall().getValueArguments().any { argument -> getArgumentMapping(argument!!) == ArgumentUnmapped }
|
return getCall().getValueArguments().any { argument -> getArgumentMapping(argument!!) == ArgumentUnmapped }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedParameters(): Boolean {
|
public fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedParameters(): Boolean {
|
||||||
val parameterToArgumentMap = getValueArguments()
|
val parameterToArgumentMap = getValueArguments()
|
||||||
return !parameterToArgumentMap.keySet().containsAll(getResultingDescriptor().getValueParameters())
|
return !parameterToArgumentMap.keySet().containsAll(getResultingDescriptor().getValueParameters())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> ResolvedCall<D>.hasErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
|
public fun <D : CallableDescriptor> ResolvedCall<D>.hasErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
|
||||||
val resolvedValueArgument = getValueArguments()[parameter]
|
val resolvedValueArgument = getValueArguments()[parameter]
|
||||||
if (resolvedValueArgument == null) return true
|
if (resolvedValueArgument == null) return true
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ import org.jetbrains.jet.lang.psi.JetIfExpression
|
|||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||||
import org.jetbrains.jet.lang.psi.JetContainerNode
|
import org.jetbrains.jet.lang.psi.JetContainerNode
|
||||||
import org.jetbrains.jet.plugin.completion.smart.isSubtypeOf
|
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 {
|
enum class Tail {
|
||||||
COMMA
|
COMMA
|
||||||
@@ -57,8 +60,7 @@ data class ExpectedInfo(val `type`: JetType, val tail: Tail?)
|
|||||||
|
|
||||||
class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) {
|
class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: ModuleDescriptor) {
|
||||||
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
public fun calculate(expressionWithType: JetExpression): Collection<ExpectedInfo>? {
|
||||||
val forArgument = calculateForArgument(expressionWithType)
|
return calculateForArgument(expressionWithType)
|
||||||
return forArgument
|
|
||||||
?: calculateForFunctionLiteralArgument(expressionWithType)
|
?: calculateForFunctionLiteralArgument(expressionWithType)
|
||||||
?: calculateForEq(expressionWithType)
|
?: calculateForEq(expressionWithType)
|
||||||
?: calculateForIf(expressionWithType)
|
?: calculateForIf(expressionWithType)
|
||||||
@@ -101,7 +103,14 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo
|
|||||||
receiver = ReceiverValue.NO_RECEIVER
|
receiver = ReceiverValue.NO_RECEIVER
|
||||||
callOperationNode = null
|
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
|
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<ExpectedInfo>()
|
val expectedInfos = HashSet<ExpectedInfo>()
|
||||||
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
|
for (candidate: ResolvedCall<FunctionDescriptor> in results.getAllCandidates()!!) {
|
||||||
val parameters = candidate.getResultingDescriptor().getValueParameters()
|
// consider only candidates with more arguments than in the truncated call and with all arguments before the current one matched
|
||||||
if (isFunctionLiteralArgument) {
|
if (candidate.noErrorsInValueArguments() && (isFunctionLiteralArgument || candidate.hasUnmappedParameters())) {
|
||||||
if (argumentIndex != parameters.size - 1) continue
|
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
|
return expectedInfos
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,6 +336,11 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
|
|||||||
doTest("idea/testData/completion/smart/OverloadedMethodCallArgument2.kt");
|
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")
|
@TestMetadata("PrivateConstructorForAbstract.kt")
|
||||||
public void testPrivateConstructorForAbstract() throws Exception {
|
public void testPrivateConstructorForAbstract() throws Exception {
|
||||||
doTest("idea/testData/completion/smart/PrivateConstructorForAbstract.kt");
|
doTest("idea/testData/completion/smart/PrivateConstructorForAbstract.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user