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 the value to be inlined is not used and has no side effects we may drop it
|
||||||
if (codeToInline.mainExpression != null
|
if (codeToInline.mainExpression != null
|
||||||
|
&& !codeToInline.alwaysKeepMainExpression
|
||||||
&& assignment == null
|
&& assignment == null
|
||||||
&& elementToBeReplaced is KtExpression
|
&& elementToBeReplaced is KtExpression
|
||||||
&& !elementToBeReplaced.isUsedAsExpression(bindingContext)
|
&& !elementToBeReplaced.isUsedAsExpression(bindingContext)
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ import org.jetbrains.kotlin.psi.KtExpression
|
|||||||
class CodeToInline(
|
class CodeToInline(
|
||||||
val mainExpression: KtExpression?,
|
val mainExpression: KtExpression?,
|
||||||
val statementsBefore: List<KtExpression>,
|
val statementsBefore: List<KtExpression>,
|
||||||
val fqNamesToImport: Collection<FqName>
|
val fqNamesToImport: Collection<FqName>,
|
||||||
|
val alwaysKeepMainExpression: Boolean
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE")
|
val PARAMETER_USAGE_KEY: Key<Name> = Key("PARAMETER_USAGE")
|
||||||
|
|||||||
@@ -16,9 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.codeInliner
|
package org.jetbrains.kotlin.idea.codeInliner
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.asExpression
|
import org.jetbrains.kotlin.idea.core.asExpression
|
||||||
@@ -59,7 +57,17 @@ class CodeToInlineBuilder(
|
|||||||
): CodeToInline {
|
): CodeToInline {
|
||||||
var bindingContext = analyze()
|
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)
|
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")
|
private val POST_INSERTION_ACTION: Key<(KtElement) -> Unit> = Key("POST_INSERTION_ACTION")
|
||||||
|
|
||||||
internal class MutableCodeToInline(
|
internal class MutableCodeToInline(
|
||||||
var mainExpression: KtExpression?,
|
var mainExpression: KtExpression?,
|
||||||
val statementsBefore: MutableList<KtExpression>,
|
val statementsBefore: MutableList<KtExpression>,
|
||||||
val fqNamesToImport: MutableCollection<FqName>
|
val fqNamesToImport: MutableCollection<FqName>,
|
||||||
|
val alwaysKeepMainExpression: Boolean
|
||||||
) {
|
) {
|
||||||
fun <TElement : KtElement> addPostInsertionAction(element: TElement, action: (TElement) -> Unit) {
|
fun <TElement : KtElement> addPostInsertionAction(element: TElement, action: (TElement) -> Unit) {
|
||||||
assert(element in this)
|
assert(element in this)
|
||||||
@@ -82,13 +83,15 @@ internal class MutableCodeToInline(
|
|||||||
|
|
||||||
internal fun CodeToInline.toMutable(): MutableCodeToInline {
|
internal fun CodeToInline.toMutable(): MutableCodeToInline {
|
||||||
return MutableCodeToInline(
|
return MutableCodeToInline(
|
||||||
mainExpression?.copied(),
|
mainExpression?.copied(),
|
||||||
statementsBefore.map { it.copied() }.toMutableList(),
|
statementsBefore.map { it.copied() }.toMutableList(),
|
||||||
fqNamesToImport.toMutableSet())
|
fqNamesToImport.toMutableSet(),
|
||||||
|
alwaysKeepMainExpression
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun MutableCodeToInline.toNonMutable(): CodeToInline {
|
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> {
|
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")
|
@TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/typeAliases")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@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")
|
@TestMetadata("idea/testData/quickfix/deprecatedSymbolUsage/publishedApi")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user