From 498e7466892250ebd10e82c6012452a4b9dec91f Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 25 Jun 2015 11:00:59 +0200 Subject: [PATCH] KT-8169 Strange exception when replacing function call to its only argument #KT-8169 Fixed --- .../quickfix/DeprecatedSymbolUsageFixBase.kt | 33 +++++++++++-------- .../replaceCallWithArgument.kt | 7 ++++ .../replaceCallWithArgument.kt.after | 7 ++++ .../replaceCallWithReceiver.kt | 9 +++++ .../replaceCallWithReceiver.kt.after | 9 +++++ .../idea/quickfix/QuickFixTestGenerated.java | 12 +++++++ 6 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt index b486972817f..cdf441821dd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/DeprecatedSymbolUsageFixBase.kt @@ -153,21 +153,21 @@ public abstract class DeprecatedSymbolUsageFixBase( receiver?.mark(RECEIVER_VALUE_KEY) + val wrapper = ConstructedExpressionWrapper(replacement.expression, expressionToBeReplaced, bindingContext) + //TODO: this@ for (thisExpression in replacement.expression.collectDescendantsOfType()) { if (receiver != null) { - thisExpression.replace(receiver) + wrapper.replaceExpression(thisExpression, receiver) } else { thisExpression.mark(RECEIVER_VALUE_KEY) } } - val introduceValuesForParameters = processValueParameterUsages(resolvedCall, replacement, bindingContext, project) + val introduceValuesForParameters = wrapper.processValueParameterUsages(resolvedCall, project) - processTypeParameterUsages(resolvedCall, replacement) - - val wrapper = ConstructedExpressionWrapper(replacement.expression, expressionToBeReplaced, bindingContext) + wrapper.processTypeParameterUsages(resolvedCall) if (qualifiedExpression is JetSafeQualifiedExpression) { wrapper.wrapExpressionForSafeCall(receiver!!, receiverType) @@ -209,10 +209,8 @@ public abstract class DeprecatedSymbolUsageFixBase( return resultRange.last as JetExpression } - private fun processValueParameterUsages( + private fun ConstructedExpressionWrapper.processValueParameterUsages( resolvedCall: ResolvedCall, - replacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression, - bindingContext: BindingContext, project: Project ): Collection { val introduceValuesForParameters = ArrayList() @@ -225,7 +223,7 @@ public abstract class DeprecatedSymbolUsageFixBase( argument.expression.put(PARAMETER_VALUE_KEY, parameter) val parameterName = parameter.getName() - val usages = replacement.expression.collectDescendantsOfType { + val usages = expression.collectDescendantsOfType { it[ReplaceWithAnnotationAnalyzer.PARAMETER_USAGE_KEY] == parameterName } usages.forEach { @@ -236,7 +234,7 @@ public abstract class DeprecatedSymbolUsageFixBase( if (argument.isDefaultValue) { usageArgument?.mark(DEFAULT_PARAMETER_VALUE_KEY) } - it.replace(argument.expression) + replaceExpression(it, argument.expression) } //TODO: sometimes we need to add explicit type arguments here because we don't have expected type in the new context @@ -254,7 +252,7 @@ public abstract class DeprecatedSymbolUsageFixBase( val value: JetExpression, val valueType: JetType?) - private fun processTypeParameterUsages(resolvedCall: ResolvedCall, replacement: ReplaceWithAnnotationAnalyzer.ReplacementExpression) { + private fun ConstructedExpressionWrapper.processTypeParameterUsages(resolvedCall: ResolvedCall) { val typeParameters = resolvedCall.getResultingDescriptor().getOriginal().getTypeParameters() val callElement = resolvedCall.getCall().getCallElement() @@ -264,7 +262,7 @@ public abstract class DeprecatedSymbolUsageFixBase( for ((index, typeParameter) in typeParameters.withIndex()) { val parameterName = typeParameter.getName() - val usages = replacement.expression.collectDescendantsOfType { + val usages = expression.collectDescendantsOfType { it[ReplaceWithAnnotationAnalyzer.TYPE_PARAMETER_USAGE_KEY] == parameterName } @@ -285,7 +283,7 @@ public abstract class DeprecatedSymbolUsageFixBase( } else { //TODO: tests for this? - usage.replace(JetPsiFactory(usage).createExpression(typeElement.getText())) + replaceExpression(usage, JetPsiFactory(usage).createExpression(typeElement.getText())) } } } @@ -639,6 +637,15 @@ public abstract class DeprecatedSymbolUsageFixBase( val psiFactory = JetPsiFactory(expressionToBeReplaced) + public fun replaceExpression(oldExpression: JetExpression, newExpression: JetExpression): JetExpression { + assert(expression.isAncestor(oldExpression)) + val result = oldExpression.replace(newExpression) as JetExpression + if (oldExpression == expression) { + expression = result + } + return result + } + public fun introduceValue( value: JetExpression, valueType: JetType?, diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt new file mode 100644 index 00000000000..f3144f105f7 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt @@ -0,0 +1,7 @@ +// "Replace with 'p'" "true" +deprecated("", ReplaceWith("p")) +fun oldFun(p: Int): Int = p + +fun foo() { + oldFun(0) +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt.after new file mode 100644 index 00000000000..5d92cd44375 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt.after @@ -0,0 +1,7 @@ +// "Replace with 'p'" "true" +deprecated("", ReplaceWith("p")) +fun oldFun(p: Int): Int = p + +fun foo() { + 0 +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt new file mode 100644 index 00000000000..03ec5421885 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt @@ -0,0 +1,9 @@ +// "Replace with 'this'" "true" +class C { + deprecated("", ReplaceWith("this")) + fun oldFun(): C = this +} + +fun foo() { + C().oldFun() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt.after new file mode 100644 index 00000000000..d7beb3636de --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt.after @@ -0,0 +1,9 @@ +// "Replace with 'this'" "true" +class C { + deprecated("", ReplaceWith("this")) + fun oldFun(): C = this +} + +fun foo() { + C() +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index ff89a107b7b..30de46d17d2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -3034,6 +3034,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("replaceCallWithArgument.kt") + public void testReplaceCallWithArgument() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithArgument.kt"); + doTest(fileName); + } + + @TestMetadata("replaceCallWithReceiver.kt") + public void testReplaceCallWithReceiver() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/replaceCallWithReceiver.kt"); + doTest(fileName); + } + @TestMetadata("shortenReferences.kt") public void testShortenReferences() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/deprecatedSymbolUsage/shortenReferences.kt");