Inline Variable: Inline string template entries
#KT-7654 Fixed
This commit is contained in:
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtNodeType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
|
||||
|
||||
public abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtExpression {
|
||||
|
||||
@@ -38,14 +39,33 @@ public abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtE
|
||||
val parent = expression.getParent()
|
||||
|
||||
if (newElement is KtExpression) {
|
||||
when (parent) {
|
||||
is KtExpression -> {
|
||||
when {
|
||||
parent is KtStringTemplateEntryWithExpression &&
|
||||
newElement is KtStringTemplateExpression &&
|
||||
// Do not mix raw and non-raw templates
|
||||
parent.parent.firstChild.text == newElement.firstChild.text -> {
|
||||
val entriesToAdd = newElement.entries
|
||||
val templateExpression = parent.parent as KtStringTemplateExpression
|
||||
if (entriesToAdd.size > 0) {
|
||||
templateExpression.addRangeBefore(entriesToAdd.first(), entriesToAdd.last(), parent)
|
||||
val lastNewEntry = parent.prevSibling
|
||||
val nextElement = parent.nextSibling
|
||||
if (lastNewEntry is KtSimpleNameStringTemplateEntry &&
|
||||
lastNewEntry.expression != null &&
|
||||
!canPlaceAfterSimpleNameEntry(nextElement)) {
|
||||
lastNewEntry.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(lastNewEntry.expression!!))
|
||||
}
|
||||
}
|
||||
parent.delete()
|
||||
}
|
||||
|
||||
parent is KtExpression -> {
|
||||
if (KtPsiUtil.areParenthesesNecessary(newElement, expression, parent)) {
|
||||
return rawReplaceHandler(KtPsiFactory(expression).createExpressionByPattern("($0)", newElement))
|
||||
}
|
||||
}
|
||||
|
||||
is KtSimpleNameStringTemplateEntry -> {
|
||||
parent is KtSimpleNameStringTemplateEntry -> {
|
||||
if (newElement !is KtSimpleNameExpression) {
|
||||
val newEntry = parent.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
|
||||
return newEntry.getExpression()!!
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.text.Regex
|
||||
|
||||
// NOTE: in this file we collect only Kotlin-specific methods working with PSI and not modifying it
|
||||
|
||||
@@ -423,4 +424,11 @@ public fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression {
|
||||
}?.first as KtExpression? ?: this
|
||||
}
|
||||
|
||||
public fun PsiElement.isFunctionalExpression(): Boolean = this is KtNamedFunction && nameIdentifier == null
|
||||
public fun PsiElement.isFunctionalExpression(): Boolean = this is KtNamedFunction && nameIdentifier == null
|
||||
|
||||
private val BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN = Regex("[a-zA-Z0-9_].*")
|
||||
|
||||
fun canPlaceAfterSimpleNameEntry(element: PsiElement?): Boolean {
|
||||
val entryText = element?.text ?: return true
|
||||
return !BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN.matches(entryText)
|
||||
}
|
||||
+2
-7
@@ -23,15 +23,14 @@ import org.jetbrains.kotlin.psi.KtBlockStringTemplateEntry
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
|
||||
import java.util.regex.Pattern
|
||||
import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
|
||||
|
||||
public class RemoveCurlyBracesFromTemplateInspection : IntentionBasedInspection<KtBlockStringTemplateEntry>(RemoveCurlyBracesFromTemplateIntention())
|
||||
|
||||
public class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBlockStringTemplateEntry>(javaClass(), "Remove curly braces") {
|
||||
override fun isApplicableTo(element: KtBlockStringTemplateEntry): Boolean {
|
||||
if (element.getExpression() !is KtNameReferenceExpression) return false
|
||||
val nextSiblingText = element.getNextSibling()?.getText()
|
||||
return nextSiblingText == null || !pattern.matcher(nextSiblingText).matches()
|
||||
return canPlaceAfterSimpleNameEntry(element.nextSibling)
|
||||
}
|
||||
|
||||
override fun applyTo(element: KtBlockStringTemplateEntry, editor: Editor) {
|
||||
@@ -43,8 +42,4 @@ public class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndepen
|
||||
val newEntry = KtPsiFactory(element).createSimpleNameStringTemplateEntry(name)
|
||||
return element.replaced(newEntry)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val pattern = Pattern.compile("[a-zA-Z0-9_].*")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val <caret>x = " $a"
|
||||
val y = "x=${x}_"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val y = "x= ${a}_"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val <caret>x = "_$a:${a + 1}_"
|
||||
val y = "__x=${x}__"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val y = "__x=_$a:${a + 1}___"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val <caret>x = ""
|
||||
val y = "!!x=$x!!"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val y = "!!x=!!"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val <caret>x = "_$a:${a + 1}_"
|
||||
val y = "!!x=$x!!"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val y = "!!x=_$a:${a + 1}_!!"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val <caret>x = "ab\nc"
|
||||
val y = """x=$x"""
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fun foo() {
|
||||
val y = """x=${"ab\nc"}"""
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val <caret>x = """_
|
||||
$a:${a + 1}
|
||||
_"""
|
||||
val y = """!!x=$x!!"""
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
fun foo() {
|
||||
val a = 1
|
||||
val y = """!!x=_
|
||||
$a:${a + 1}
|
||||
_!!"""
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo() {
|
||||
val <caret>x = """ab
|
||||
c"""
|
||||
val y = "x=$x"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
fun foo() {
|
||||
val y = "x=${"""ab
|
||||
c"""}"
|
||||
}
|
||||
@@ -484,4 +484,55 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/refactoring/inline/stringTemplates")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class StringTemplates extends AbstractInlineTest {
|
||||
@TestMetadata("addBraces.kt")
|
||||
public void testAddBraces() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/addBraces.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInStringTemplates() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/inline/stringTemplates"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("blockEntry.kt")
|
||||
public void testBlockEntry() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/blockEntry.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("empty.kt")
|
||||
public void testEmpty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/empty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nonEmpty.kt")
|
||||
public void testNonEmpty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/nonEmpty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nonRawToRaw.kt")
|
||||
public void testNonRawToRaw() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/nonRawToRaw.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("rawString.kt")
|
||||
public void testRawString() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/rawString.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("rawToNonRaw.kt")
|
||||
public void testRawToNonRaw() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/stringTemplates/rawToNonRaw.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user