Introduce Variable: Do not replace assignment left-hand sides
#KT-14240 Fixed
This commit is contained in:
@@ -252,6 +252,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
|
|||||||
- [`KT-14182`](https://youtrack.jetbrains.com/issue/KT-14182) Move: Show error message on applying to enum entries
|
- [`KT-14182`](https://youtrack.jetbrains.com/issue/KT-14182) Move: Show error message on applying to enum entries
|
||||||
- Extract Function: Support implicit abnormal exits via Nothing-typed expressions
|
- Extract Function: Support implicit abnormal exits via Nothing-typed expressions
|
||||||
- [`KT-14285`](https://youtrack.jetbrains.com/issue/KT-14285) Rename: Forbid on backing field reference
|
- [`KT-14285`](https://youtrack.jetbrains.com/issue/KT-14285) Rename: Forbid on backing field reference
|
||||||
|
- [`KT-14240`](https://youtrack.jetbrains.com/issue/KT-14240) Introduce Variable: Do not replace assignment left-hand sides
|
||||||
|
|
||||||
##### New features
|
##### New features
|
||||||
|
|
||||||
|
|||||||
+11
@@ -320,11 +320,18 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
|
|||||||
return commonContainer.allChildren.lastOrNull { it.textRange.contains(startOffset) } ?: return null
|
return commonContainer.allChildren.lastOrNull { it.textRange.contains(startOffset) } ?: return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun PsiElement.isAssignmentLHS(): Boolean {
|
||||||
|
return parents.any { KtPsiUtil.isAssignment(it) && (it as KtBinaryExpression).left == this }
|
||||||
|
}
|
||||||
|
|
||||||
private fun KtExpression.findOccurrences(occurrenceContainer: PsiElement): List<KtExpression> {
|
private fun KtExpression.findOccurrences(occurrenceContainer: PsiElement): List<KtExpression> {
|
||||||
return toRange()
|
return toRange()
|
||||||
.match(occurrenceContainer, KotlinPsiUnifier.DEFAULT)
|
.match(occurrenceContainer, KotlinPsiUnifier.DEFAULT)
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
val candidate = it.range.elements.first()
|
val candidate = it.range.elements.first()
|
||||||
|
|
||||||
|
if (candidate.isAssignmentLHS()) return@mapNotNull null
|
||||||
|
|
||||||
when (candidate) {
|
when (candidate) {
|
||||||
is KtExpression -> candidate
|
is KtExpression -> candidate
|
||||||
is KtStringTemplateEntryWithExpression -> candidate.expression
|
is KtStringTemplateEntryWithExpression -> candidate.expression
|
||||||
@@ -694,6 +701,10 @@ object KotlinIntroduceVariableHandler : RefactoringActionHandler {
|
|||||||
val expression = expressionToExtract?.let { KtPsiUtil.safeDeparenthesize(it) }
|
val expression = expressionToExtract?.let { KtPsiUtil.safeDeparenthesize(it) }
|
||||||
?: return showErrorHint(project, editor, KotlinRefactoringBundle.message("cannot.refactor.no.expression"))
|
?: return showErrorHint(project, editor, KotlinRefactoringBundle.message("cannot.refactor.no.expression"))
|
||||||
|
|
||||||
|
if (expression.isAssignmentLHS()) {
|
||||||
|
return showErrorHint(project, editor, KotlinRefactoringBundle.message("cannot.refactor.no.expression"))
|
||||||
|
}
|
||||||
|
|
||||||
val physicalExpression = expression.substringContextOrThis
|
val physicalExpression = expression.substringContextOrThis
|
||||||
|
|
||||||
val resolutionFacade = physicalExpression.getResolutionFacade()
|
val resolutionFacade = physicalExpression.getResolutionFacade()
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: IntArray)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(IntArray(1) { 1 })
|
||||||
|
println(<selection>foo.bar</selection>)
|
||||||
|
foo.bar[0] = foo.bar[0] + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: IntArray)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(IntArray(1) { 1 })
|
||||||
|
val message = foo.bar
|
||||||
|
println(message)
|
||||||
|
message[0] = message[0] + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(1)
|
||||||
|
println(foo.bar)
|
||||||
|
<selection>foo.bar</selection> = foo.bar + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Cannot perform refactoring without an expression
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: Bar)
|
||||||
|
class Bar(var baz: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(Bar(1))
|
||||||
|
println(<selection>foo.bar</selection>)
|
||||||
|
foo.bar.baz = foo.bar.baz + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: Bar)
|
||||||
|
class Bar(var baz: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(Bar(1))
|
||||||
|
val message = foo.bar
|
||||||
|
println(message)
|
||||||
|
message.baz = message.baz + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(1)
|
||||||
|
println(<selection>foo.bar</selection>)
|
||||||
|
foo.bar = foo.bar + 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
class Foo(var bar: Int)
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
val foo = Foo(1)
|
||||||
|
val message = foo.bar
|
||||||
|
println(message)
|
||||||
|
foo.bar = message + 1
|
||||||
|
}
|
||||||
+24
@@ -43,6 +43,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
|
|||||||
doIntroduceVariableTest(fileName);
|
doIntroduceVariableTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("arrayAssignment.kt")
|
||||||
|
public void testArrayAssignment() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/arrayAssignment.kt");
|
||||||
|
doIntroduceVariableTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("callUnderSmartCast.kt")
|
@TestMetadata("callUnderSmartCast.kt")
|
||||||
public void testCallUnderSmartCast() throws Exception {
|
public void testCallUnderSmartCast() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/callUnderSmartCast.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/callUnderSmartCast.kt");
|
||||||
@@ -337,6 +343,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
|
|||||||
doIntroduceVariableTest(fileName);
|
doIntroduceVariableTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("onAssignmentLHS.kt")
|
||||||
|
public void testOnAssignmentLHS() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/onAssignmentLHS.kt");
|
||||||
|
doIntroduceVariableTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("OneExplicitReceiver.kt")
|
@TestMetadata("OneExplicitReceiver.kt")
|
||||||
public void testOneExplicitReceiver() throws Exception {
|
public void testOneExplicitReceiver() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/OneExplicitReceiver.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/OneExplicitReceiver.kt");
|
||||||
@@ -367,6 +379,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
|
|||||||
doIntroduceVariableTest(fileName);
|
doIntroduceVariableTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("selectorAssignment.kt")
|
||||||
|
public void testSelectorAssignment() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/selectorAssignment.kt");
|
||||||
|
doIntroduceVariableTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Simple.kt")
|
@TestMetadata("Simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/Simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/Simple.kt");
|
||||||
@@ -385,6 +403,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest {
|
|||||||
doIntroduceVariableTest(fileName);
|
doIntroduceVariableTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("skipUsageInAssignmentLHS.kt")
|
||||||
|
public void testSkipUsageInAssignmentLHS() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/skipUsageInAssignmentLHS.kt");
|
||||||
|
doIntroduceVariableTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("StringInjection.kt")
|
@TestMetadata("StringInjection.kt")
|
||||||
public void testStringInjection() throws Exception {
|
public void testStringInjection() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/StringInjection.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/StringInjection.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user