From 88b0db6dd7fb5cdb65a764d77b86f9b60abb88b4 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Wed, 27 Mar 2019 19:20:43 +0700 Subject: [PATCH] ReplaceWith intention could save generic type arguments #KT-21195 Fixed --- .../ClassUsageReplacementStrategy.kt | 18 ++++++++-- .../constructorUsageWithTypeArgument.kt | 11 ++++++ .../constructorUsageWithTypeArgument.kt.after | 11 ++++++ .../constructorUsageWithTypeArgument2.kt | 11 ++++++ ...constructorUsageWithTypeArgument2.kt.after | 11 ++++++ .../constructorUsageWithTypeArgument3.kt | 11 ++++++ ...constructorUsageWithTypeArgument3.kt.after | 11 ++++++ .../classUsages/innerType.kt | 12 +++++++ .../classUsages/innerType.kt.after | 12 +++++++ .../classUsages/noMatchTypeArgument.kt | 10 ++++++ .../classUsages/noMatchTypeArgument.kt.after | 10 ++++++ .../classUsages/noMatchTypeArgument2.kt | 10 ++++++ .../classUsages/noMatchTypeArgument2.kt.after | 10 ++++++ .../typeAliases/withTypeArgument.kt | 9 +++++ .../typeAliases/withTypeArgument.kt.after | 9 +++++ .../idea/quickfix/QuickFixTestGenerated.java | 35 +++++++++++++++++++ 16 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt.after create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt create mode 100644 idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt index cba185ab60a..a81d781fdea 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/ClassUsageReplacementStrategy.kt @@ -49,9 +49,15 @@ class ClassUsageReplacementStrategy( is KtUserType -> { if (typeReplacement == null) return null return { + val oldArgumentList = parent.typeArgumentList?.copy() as? KtTypeArgumentList val replaced = parent.replaced(typeReplacement) + val newArgumentList = replaced.typeArgumentList + if (oldArgumentList != null && oldArgumentList.arguments.size == newArgumentList?.arguments?.size) { + newArgumentList.replace(oldArgumentList) + } + ShortenReferences.DEFAULT.process(replaced) - } //TODO: type arguments and type arguments of outer class are lost + } } is KtCallExpression -> { @@ -80,7 +86,15 @@ class ClassUsageReplacementStrategy( } private fun replaceConstructorCallWithOtherTypeConstruction(callExpression: KtCallExpression): KtElement { - callExpression.calleeExpression!!.replace(typeReplacement!!.referenceExpression!!) + val referenceExpression = typeReplacement?.referenceExpression ?: error("Couldn't find referenceExpression") + callExpression.calleeExpression?.replace(referenceExpression) + + val typeArgumentList = callExpression.typeArgumentList + if (typeArgumentList != null && typeReplacement.typeArguments.size != typeArgumentList.arguments.size) { + val newTypeArgumentList = typeReplacement.typeArgumentList + if (newTypeArgumentList != null) typeArgumentList.replace(newTypeArgumentList.copy()) + else typeArgumentList.delete() + } val expressionToReplace = callExpression.getQualifiedExpressionForSelectorOrThis() val newExpression = if (typeReplacementQualifierAsExpression != null) diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt new file mode 100644 index 00000000000..5d85509d3c8 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt @@ -0,0 +1,11 @@ +// "Replace with 'NewClass'" "true" +package ppp + +@Deprecated("renamed", ReplaceWith("NewClass")) +class OldClass + +class NewClass + +fun foo() { + OldClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt.after new file mode 100644 index 00000000000..b0eb3677902 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt.after @@ -0,0 +1,11 @@ +// "Replace with 'NewClass'" "true" +package ppp + +@Deprecated("renamed", ReplaceWith("NewClass")) +class OldClass + +class NewClass + +fun foo() { + NewClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt new file mode 100644 index 00000000000..d9d787b251f --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt @@ -0,0 +1,11 @@ +// "Replace with 'NewClass'" "true" +package ppp + +@Deprecated("", ReplaceWith("NewClass")) +class OldClass + +class NewClass + +fun foo() { + OldClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt.after new file mode 100644 index 00000000000..700d1dc5be5 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt.after @@ -0,0 +1,11 @@ +// "Replace with 'NewClass'" "true" +package ppp + +@Deprecated("", ReplaceWith("NewClass")) +class OldClass + +class NewClass + +fun foo() { + NewClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt new file mode 100644 index 00000000000..9535d757cdd --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt @@ -0,0 +1,11 @@ +// "Replace with 'NewClass'" "true" +package ppp + +@Deprecated("", ReplaceWith("NewClass")) +class OldClass + +class NewClass + +fun foo() { + OldClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt.after new file mode 100644 index 00000000000..259fcf5aff7 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt.after @@ -0,0 +1,11 @@ +// "Replace with 'NewClass'" "true" +package ppp + +@Deprecated("", ReplaceWith("NewClass")) +class OldClass + +class NewClass + +fun foo() { + NewClass() +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt new file mode 100644 index 00000000000..c7cf0009464 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt @@ -0,0 +1,12 @@ +// "Replace with 'B'" "true" +// WITH_RUNTIME + +@Deprecated(message = "renamed", replaceWith = ReplaceWith("B")) +typealias A = List + +abstract class B : List +class F + +fun test() { + var x: A> +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt.after new file mode 100644 index 00000000000..0d4e77f7126 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt.after @@ -0,0 +1,12 @@ +// "Replace with 'B'" "true" +// WITH_RUNTIME + +@Deprecated(message = "renamed", replaceWith = ReplaceWith("B")) +typealias A = List + +abstract class B : List +class F + +fun test() { + var x: B> +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt new file mode 100644 index 00000000000..04d7bb93796 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt @@ -0,0 +1,10 @@ +// "Replace with 'B'" "true" + +@Deprecated("", ReplaceWith("B")) +class C + +class B + +fun foo() { + var c: C +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt.after new file mode 100644 index 00000000000..8fd9340d096 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt.after @@ -0,0 +1,10 @@ +// "Replace with 'B'" "true" + +@Deprecated("", ReplaceWith("B")) +class C + +class B + +fun foo() { + var c: B +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt new file mode 100644 index 00000000000..0979ff98cb3 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt @@ -0,0 +1,10 @@ +// "Replace with 'B'" "true" + +@Deprecated("", ReplaceWith("B")) +class C + +class B + +fun foo() { + var c: C +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt.after new file mode 100644 index 00000000000..eb80e6284d3 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt.after @@ -0,0 +1,10 @@ +// "Replace with 'B'" "true" + +@Deprecated("", ReplaceWith("B")) +class C + +class B + +fun foo() { + var c: B +} diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt b/idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt new file mode 100644 index 00000000000..96f58a627c0 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt @@ -0,0 +1,9 @@ +// "Replace with 'B'" "true" +// WITH_RUNTIME + +@Deprecated(message = "renamed", replaceWith = ReplaceWith("B")) +typealias A = List + +typealias B = List + +val x: A = emptyList() diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt.after new file mode 100644 index 00000000000..776b35e41b0 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt.after @@ -0,0 +1,9 @@ +// "Replace with 'B'" "true" +// WITH_RUNTIME + +@Deprecated(message = "renamed", replaceWith = ReplaceWith("B")) +typealias A = List + +typealias B = List + +val x: B = emptyList() diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 4da562a8f2f..adcf43dfaf1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6041,6 +6041,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsage4.kt"); } + @TestMetadata("constructorUsageWithTypeArgument.kt") + public void testConstructorUsageWithTypeArgument() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument.kt"); + } + + @TestMetadata("constructorUsageWithTypeArgument2.kt") + public void testConstructorUsageWithTypeArgument2() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument2.kt"); + } + + @TestMetadata("constructorUsageWithTypeArgument3.kt") + public void testConstructorUsageWithTypeArgument3() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/constructorUsageWithTypeArgument3.kt"); + } + @TestMetadata("imports.kt") public void testImports() throws Exception { runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/imports.kt"); @@ -6081,6 +6096,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/inTypeArgument.kt"); } + @TestMetadata("innerType.kt") + public void testInnerType() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/innerType.kt"); + } + @TestMetadata("nestedClassToNestedClass.kt") public void testNestedClassToNestedClass() throws Exception { runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/nestedClassToNestedClass.kt"); @@ -6091,6 +6111,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noAnnotationConstructorUsage.kt"); } + @TestMetadata("noMatchTypeArgument.kt") + public void testNoMatchTypeArgument() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument.kt"); + } + + @TestMetadata("noMatchTypeArgument2.kt") + public void testNoMatchTypeArgument2() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/noMatchTypeArgument2.kt"); + } + @TestMetadata("qualifiedClassName.kt") public void testQualifiedClassName() throws Exception { runTest("idea/testData/quickfix/deprecatedSymbolUsage/classUsages/qualifiedClassName.kt"); @@ -6559,6 +6589,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/typeAliasWithAllGenericParams.kt"); } + @TestMetadata("withTypeArgument.kt") + public void testWithTypeArgument() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/withTypeArgument.kt"); + } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/typeAliases/wholeProject") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)