Inline Variable: Inline string template entries

#KT-7654 Fixed
This commit is contained in:
Alexey Sedunov
2015-12-02 17:46:42 +03:00
parent 0af2243245
commit b2bdb8ed02
18 changed files with 148 additions and 11 deletions
@@ -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)
}
@@ -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);
}
}
}