diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt index ca57fc56852..c5a7d506bc0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/changeSignature/JetParameterInfo.kt @@ -57,6 +57,19 @@ public class JetParameterInfo( defaultValueForCall!!.accept( object : JetTreeVisitorVoid() { + private fun selfParameterOrNull(parameter: DeclarationDescriptor?): ValueParameterDescriptor? { + return if (parameter is ValueParameterDescriptor && + parameter.getContainingDeclaration() == functionDescriptor) parameter else null + } + + private fun selfReceiverOrNull(receiver: ThisReceiver?): DeclarationDescriptor? { + return when (receiver) { + functionDescriptor.getExtensionReceiverParameter()?.getValue(), + functionDescriptor.getDispatchReceiverParameter()?.getValue()-> receiver?.getDeclarationDescriptor() + else -> null + } + } + private fun getRelevantDescriptor( expression: JetSimpleNameExpression, ref: JetReference @@ -64,18 +77,24 @@ public class JetParameterInfo( val context = expression.analyze(BodyResolveMode.PARTIAL) val descriptor = ref.resolveToDescriptors(context).singleOrNull() - if (descriptor is ValueParameterDescriptor) return descriptor + if (descriptor is ValueParameterDescriptor) return selfParameterOrNull(descriptor) if (descriptor is PropertyDescriptor && functionDescriptor is ConstructorDescriptor) { val parameter = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) as? JetParameter - return parameter?.let { context[BindingContext.VALUE_PARAMETER, it] } + return parameter?.let { selfParameterOrNull(context[BindingContext.VALUE_PARAMETER, it]) } } val resolvedCall = expression.getResolvedCall(context) ?: return null - (resolvedCall.getResultingDescriptor() as? ReceiverParameterDescriptor)?.let { return it } + (resolvedCall.getResultingDescriptor() as? ReceiverParameterDescriptor)?.let { + return when (it) { + functionDescriptor.getDispatchReceiverParameter(), + functionDescriptor.getExtensionReceiverParameter() -> it + else -> null + } + } - (resolvedCall.getExtensionReceiver() as? ThisReceiver)?.let { return it.getDeclarationDescriptor() } - (resolvedCall.getDispatchReceiver() as? ThisReceiver)?.let { return it.getDeclarationDescriptor() } + selfReceiverOrNull(resolvedCall.getExtensionReceiver() as? ThisReceiver)?.let { return it } + selfReceiverOrNull(resolvedCall.getDispatchReceiver() as? ThisReceiver)?.let { return it } return null } diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt index 90e74d08dfb..7a8af5d3ed3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceParameter/KotlinIntroduceParameterHandler.kt @@ -120,7 +120,11 @@ fun IntroduceParameterDescriptor.performRefactoring() { return originalDescriptor.modify { methodDescriptor -> if (!withDefaultValue) { val parameters = callable.getValueParameters() - parametersToRemove.map { parameters.indexOf(it) }.sortDescending().forEach { methodDescriptor.removeParameter(it) } + val withReceiver = methodDescriptor.receiver != null + parametersToRemove + .map { parameters.indexOf(it) + if (withReceiver) 1 else 0 } + .sortDescending() + .forEach { methodDescriptor.removeParameter(it) } } val parameterInfo = JetParameterInfo(functionDescriptor = callableDescriptor, diff --git a/idea/testData/refactoring/introduceParameter/foreignParameterRef.kt b/idea/testData/refactoring/introduceParameter/foreignParameterRef.kt new file mode 100644 index 00000000000..f13dd81da4e --- /dev/null +++ b/idea/testData/refactoring/introduceParameter/foreignParameterRef.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// WITH_DEFAULT_VALUE: false +fun a() { + 1.b(2) +} + +fun Int.foo(f: Int.(Int) -> Int) = this + +fun Int.b(n: Int) = n.foo { it + this + n + this@b } + 1 \ No newline at end of file diff --git a/idea/testData/refactoring/introduceParameter/foreignParameterRef.kt.after b/idea/testData/refactoring/introduceParameter/foreignParameterRef.kt.after new file mode 100644 index 00000000000..8e16e0089ec --- /dev/null +++ b/idea/testData/refactoring/introduceParameter/foreignParameterRef.kt.after @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// WITH_DEFAULT_VALUE: false +fun a() { + 1.b(2.foo { it + this + 2 + 1 }) +} + +fun Int.foo(f: Int.(Int) -> Int) = this + +fun Int.b(i: Int) = i + 1 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java index d2d5527da30..f02f69505d3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java @@ -2401,6 +2401,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doIntroduceSimpleParameterTest(fileName); } + @TestMetadata("foreignParameterRef.kt") + public void testForeignParameterRef() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/foreignParameterRef.kt"); + doIntroduceSimpleParameterTest(fileName); + } + @TestMetadata("fun.kt") public void testFun() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceParameter/fun.kt");