diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt index 77a93483c56..6338e2eb7a5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeInliner.kt @@ -76,6 +76,7 @@ class CodeInliner( // if the value to be inlined is not used and has no side effects we may drop it if (codeToInline.mainExpression != null + && !codeToInline.alwaysKeepMainExpression && assignment == null && elementToBeReplaced is KtExpression && !elementToBeReplaced.isUsedAsExpression(bindingContext) diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInline.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInline.kt index cab5c426200..03c67a5b35c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInline.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInline.kt @@ -35,7 +35,8 @@ import org.jetbrains.kotlin.psi.KtExpression class CodeToInline( val mainExpression: KtExpression?, val statementsBefore: List, - val fqNamesToImport: Collection + val fqNamesToImport: Collection, + val alwaysKeepMainExpression: Boolean ) { companion object { val PARAMETER_USAGE_KEY: Key = Key("PARAMETER_USAGE") diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt index bc808c06ff1..4c34881a5c9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt @@ -16,9 +16,7 @@ package org.jetbrains.kotlin.idea.codeInliner -import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.asExpression @@ -59,7 +57,17 @@ class CodeToInlineBuilder( ): CodeToInline { var bindingContext = analyze() - val codeToInline = MutableCodeToInline(mainExpression, statementsBefore.toMutableList(), mutableSetOf()) + val descriptor = mainExpression.getResolvedCall(bindingContext)?.resultingDescriptor + val alwaysKeepMainExpression = when (descriptor) { + is PropertyDescriptor -> descriptor.getter?.isDefault == false + else -> false + } + val codeToInline = MutableCodeToInline( + mainExpression, + statementsBefore.toMutableList(), + mutableSetOf(), + alwaysKeepMainExpression + ) bindingContext = insertExplicitTypeArguments(codeToInline, bindingContext, analyze) diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt index 5b490ebde66..f7097996ba2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/MutableCodeToInline.kt @@ -29,9 +29,10 @@ import org.jetbrains.kotlin.psi.psiUtil.isAncestor private val POST_INSERTION_ACTION: Key<(KtElement) -> Unit> = Key("POST_INSERTION_ACTION") internal class MutableCodeToInline( - var mainExpression: KtExpression?, - val statementsBefore: MutableList, - val fqNamesToImport: MutableCollection + var mainExpression: KtExpression?, + val statementsBefore: MutableList, + val fqNamesToImport: MutableCollection, + val alwaysKeepMainExpression: Boolean ) { fun addPostInsertionAction(element: TElement, action: (TElement) -> Unit) { assert(element in this) @@ -82,13 +83,15 @@ internal class MutableCodeToInline( internal fun CodeToInline.toMutable(): MutableCodeToInline { return MutableCodeToInline( - mainExpression?.copied(), - statementsBefore.map { it.copied() }.toMutableList(), - fqNamesToImport.toMutableSet()) + mainExpression?.copied(), + statementsBefore.map { it.copied() }.toMutableList(), + fqNamesToImport.toMutableSet(), + alwaysKeepMainExpression + ) } internal fun MutableCodeToInline.toNonMutable(): CodeToInline { - return CodeToInline(mainExpression, statementsBefore, fqNamesToImport) + return CodeToInline(mainExpression, statementsBefore, fqNamesToImport, alwaysKeepMainExpression) } internal inline fun MutableCodeToInline.collectDescendantsOfType(noinline predicate: (T) -> Boolean = { true }): List { diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt new file mode 100644 index 00000000000..a511e1c3cb6 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt @@ -0,0 +1,8 @@ +// "Replace with 'FOO'" "true" + +const val FOO = 1 +@Deprecated("always const", ReplaceWith("FOO")) +fun foo() = 1 +fun test(){ + val x = foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt.after new file mode 100644 index 00000000000..3fd5bae5241 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt.after @@ -0,0 +1,8 @@ +// "Replace with 'FOO'" "true" + +const val FOO = 1 +@Deprecated("always const", ReplaceWith("FOO")) +fun foo() = 1 +fun test(){ + val x = FOO +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt new file mode 100644 index 00000000000..fa5639b2320 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt @@ -0,0 +1,8 @@ +// "Replace with 'bar'" "true" + +val bar get() = 1 +@Deprecated("use property instead", ReplaceWith("bar")) +fun foo() = 1 +fun test(){ + foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt.after new file mode 100644 index 00000000000..74aa46707c9 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt.after @@ -0,0 +1,8 @@ +// "Replace with 'bar'" "true" + +val bar get() = 1 +@Deprecated("use property instead", ReplaceWith("bar")) +fun foo() = 1 +fun test(){ + bar +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt new file mode 100644 index 00000000000..96d8b49e2d3 --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt @@ -0,0 +1,8 @@ +// "Replace with 'FOO'" "true" + +const val FOO = 1 +@Deprecated("always const", ReplaceWith("FOO")) +fun foo() = 1 +fun test(){ + foo() +} \ No newline at end of file diff --git a/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt.after b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt.after new file mode 100644 index 00000000000..c6e4b21025f --- /dev/null +++ b/idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt.after @@ -0,0 +1,7 @@ +// "Replace with 'FOO'" "true" + +const val FOO = 1 +@Deprecated("always const", ReplaceWith("FOO")) +fun foo() = 1 +fun test(){ +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index d3ed1aecb15..9014ea164be 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -2353,6 +2353,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/properties") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Properties extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInProperties() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/properties"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java.172 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java.172 index 4630defc4fd..88b23dccf11 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java.172 +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java.172 @@ -1578,6 +1578,97 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/keepComments") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class KeepComments extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInKeepComments() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/keepComments"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class KeepLineBreaks extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInKeepLineBreaks() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/keepLineBreaks"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/operatorCalls") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class OperatorCalls extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInOperatorCalls() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/operatorCalls"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/optionalParameters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class OptionalParameters extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInOptionalParameters() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/optionalParameters"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/properties") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Properties extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInProperties() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/properties"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class PublishedApi extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInPublishedApi() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/safeCall") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SafeCall extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInSafeCall() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/safeCall"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/typeAliases") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index b45a0a2ad1c..ff0082a3022 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -5653,6 +5653,34 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/properties") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Properties extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInProperties() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/deprecatedSymbolUsage/properties"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("callInAssignmentToProperty.kt") + public void testCallInAssignmentToProperty() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/properties/callInAssignmentToProperty.kt"); + } + + @TestMetadata("callToCustomProperty.kt") + public void testCallToCustomProperty() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/properties/callToCustomProperty.kt"); + } + + @TestMetadata("callToProperty.kt") + public void testCallToProperty() throws Exception { + runTest("idea/testData/quickfix/deprecatedSymbolUsage/properties/callToProperty.kt"); + } + } + @TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)