Code inliner: keep main property if it can have side effects
So #KT-24165 Fixed
This commit is contained in:
@@ -76,6 +76,7 @@ class CodeInliner<TCallElement : KtElement>(
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -35,7 +35,8 @@ import org.jetbrains.kotlin.psi.KtExpression
|
||||
class CodeToInline(
|
||||
val mainExpression: KtExpression?,
|
||||
val statementsBefore: List<KtExpression>,
|
||||
val fqNamesToImport: Collection<FqName>
|
||||
val fqNamesToImport: Collection<FqName>,
|
||||
val alwaysKeepMainExpression: Boolean
|
||||
) {
|
||||
companion object {
|
||||
val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE")
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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<KtExpression>,
|
||||
val fqNamesToImport: MutableCollection<FqName>
|
||||
var mainExpression: KtExpression?,
|
||||
val statementsBefore: MutableList<KtExpression>,
|
||||
val fqNamesToImport: MutableCollection<FqName>,
|
||||
val alwaysKeepMainExpression: Boolean
|
||||
) {
|
||||
fun <TElement : KtElement> 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 <reified T : PsiElement> MutableCodeToInline.collectDescendantsOfType(noinline predicate: (T) -> Boolean = { true }): List<T> {
|
||||
|
||||
+8
@@ -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<caret>()
|
||||
}
|
||||
Vendored
+8
@@ -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
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'bar'" "true"
|
||||
|
||||
val bar get() = 1
|
||||
@Deprecated("use property instead", ReplaceWith("bar"))
|
||||
fun foo() = 1
|
||||
fun test(){
|
||||
foo<caret>()
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'bar'" "true"
|
||||
|
||||
val bar get() = 1
|
||||
@Deprecated("use property instead", ReplaceWith("bar"))
|
||||
fun foo() = 1
|
||||
fun test(){
|
||||
bar
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Replace with 'FOO'" "true"
|
||||
|
||||
const val FOO = 1
|
||||
@Deprecated("always const", ReplaceWith("FOO"))
|
||||
fun foo() = 1
|
||||
fun test(){
|
||||
foo<caret>()
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Replace with 'FOO'" "true"
|
||||
|
||||
const val FOO = 1
|
||||
@Deprecated("always const", ReplaceWith("FOO"))
|
||||
fun foo() = 1
|
||||
fun test(){
|
||||
}
|
||||
+13
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user