Join with assignment: place the result at the assignment

#KT-21172 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-09-26 12:51:34 +03:00
committed by Mikhail Glukhikh
parent 8078c5da40
commit 40dd229021
14 changed files with 128 additions and 9 deletions
@@ -25,6 +25,7 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.canOmitDeclaredType
import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.core.unblockDocument
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.lexer.KtTokens
@@ -76,25 +77,35 @@ class JoinDeclarationAndAssignmentIntention : SelfTargetingRangeIntention<KtProp
}
override fun applyTo(element: KtProperty, editor: Editor?) {
val typeReference = element.typeReference ?: return
if (element.typeReference == null) return
val assignment = findAssignment(element) ?: return
val initializer = assignment.right ?: return
val newInitializer = element.setInitializer(initializer)!!
element.initializer = initializer
if (element.hasModifier(KtTokens.LATEINIT_KEYWORD)) element.removeModifier(KtTokens.LATEINIT_KEYWORD)
val initializerBlock = assignment.parent.parent as? KtAnonymousInitializer
assignment.delete()
if (initializerBlock != null && (initializerBlock.body as? KtBlockExpression)?.isEmpty() == true) {
initializerBlock.delete()
val grandParent = assignment.parent.parent
val initializerBlock = grandParent as? KtAnonymousInitializer
val secondaryConstructor = grandParent as? KtSecondaryConstructor
val newProperty = if (!element.isLocal && (initializerBlock != null || secondaryConstructor != null)) {
assignment.delete()
if ((initializerBlock?.body as? KtBlockExpression)?.isEmpty() == true) initializerBlock.delete()
val secondaryConstructorBlock = secondaryConstructor?.bodyBlockExpression
if (secondaryConstructorBlock?.isEmpty() == true) secondaryConstructorBlock.delete()
element
} else {
assignment.replaced(element).also {
element.delete()
}
}
val newInitializer = newProperty.initializer!!
val typeReference = newProperty.typeReference!!
editor?.apply {
unblockDocument()
if (element.canOmitDeclaredType(newInitializer, canChangeTypeToSubtype = !element.isVar)) {
val colon = element.colon!!
if (newProperty.canOmitDeclaredType(newInitializer, canChangeTypeToSubtype = !newProperty.isVar)) {
val colon = newProperty.colon!!
selectionModel.setSelection(colon.startOffset, typeReference.endOffset)
moveCaret(typeReference.endOffset, ScrollType.CENTER)
} else {
@@ -0,0 +1,9 @@
fun test(repo: Repository, commitMessage: String) {
val hash: String<caret>
repo.git("add --verbose .")
hash = repo.git("commit -m $commitMessage")
}
class Repository {
fun git(s: String) = ""
}
@@ -0,0 +1,8 @@
fun test(repo: Repository, commitMessage: String) {
repo.git("add --verbose .")
val hash<selection>: String</selection><caret> = repo.git("commit -m $commitMessage")
}
class Repository {
fun git(s: String) = ""
}
@@ -0,0 +1,9 @@
class A {
constructor() {
val foo: String<caret>
bar()
foo = ""
}
fun bar() {}
}
@@ -0,0 +1,8 @@
class A {
constructor() {
bar()
val foo<selection>: String</selection><caret> = ""
}
fun bar() {}
}
@@ -0,0 +1,9 @@
class A {
init {
val foo: String<caret>
bar()
foo = ""
}
fun bar() {}
}
@@ -0,0 +1,8 @@
class A {
init {
bar()
val foo<selection>: String</selection><caret> = ""
}
fun bar() {}
}
@@ -0,0 +1,7 @@
class A {
constructor() {
a = 1
}
val a<caret>: Int
}
@@ -0,0 +1,5 @@
class A {
constructor()
val a<selection>: Int</selection><caret> = 1
}
@@ -0,0 +1,8 @@
// DISABLE-ERRORS
class A(i: Int, j: Int) {
constructor(i: Int) : this(i, 2) {
a = 1
}
val a<caret>: Int
}
@@ -0,0 +1,6 @@
// DISABLE-ERRORS
class A(i: Int, j: Int) {
constructor(i: Int) : this(i, 2)
val a<selection>: Int</selection><caret> = 1
}
@@ -1,7 +1,10 @@
class A {
constructor() {
a = 1
foo()
}
val a<caret>: Int
fun foo() {}
}
@@ -1,6 +1,9 @@
class A {
constructor() {
foo()
}
val a<selection>: Int</selection><caret> = 1
fun foo() {}
}
@@ -10007,6 +10007,21 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/assignmentInIf.kt");
}
@TestMetadata("atAssignment.kt")
public void testAtAssignment() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/atAssignment.kt");
}
@TestMetadata("atAssignmentInConstructor.kt")
public void testAtAssignmentInConstructor() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/atAssignmentInConstructor.kt");
}
@TestMetadata("atAssignmentInInitializer.kt")
public void testAtAssignmentInInitializer() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/atAssignmentInInitializer.kt");
}
@TestMetadata("cannotRemoveType.kt")
public void testCannotRemoveType() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/cannotRemoveType.kt");
@@ -10042,6 +10057,16 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/correctConditionalAssignment.kt");
}
@TestMetadata("deleteConstructorBlock.kt")
public void testDeleteConstructorBlock() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/deleteConstructorBlock.kt");
}
@TestMetadata("deleteConstructorBlock2.kt")
public void testDeleteConstructorBlock2() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/deleteConstructorBlock2.kt");
}
@TestMetadata("deleteInitBlock.kt")
public void testDeleteInitBlock() throws Exception {
runTest("idea/testData/intentions/joinDeclarationAndAssignment/deleteInitBlock.kt");