From 414fabb2c67375add6a5386d3e2a76b3a72eebbb Mon Sep 17 00:00:00 2001 From: xiexed Date: Fri, 22 Jun 2018 21:54:28 +0300 Subject: [PATCH] KtStringTemplateExpressionManipulator: properly works with interpolations (KT-24958) --- .../KtStringTemplateExpressionManipulator.kt | 36 ++++++++-- ...StringTemplateExpressionManipulatorTest.kt | 40 ++++++++++- ...ngTemplateExpressionManipulatorTest.kt.173 | 71 ------------------- 3 files changed, 69 insertions(+), 78 deletions(-) delete mode 100644 idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt.173 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/KtStringTemplateExpressionManipulator.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/KtStringTemplateExpressionManipulator.kt index 2085afa19f6..990570bf02f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/KtStringTemplateExpressionManipulator.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/KtStringTemplateExpressionManipulator.kt @@ -16,12 +16,17 @@ package org.jetbrains.kotlin.psi.psiUtil +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.AbstractElementManipulator +import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression import org.jetbrains.kotlin.psi.KtStringTemplateExpression +private val LOG = Logger.getInstance(KtStringTemplateExpressionManipulator::class.java) + class KtStringTemplateExpressionManipulator : AbstractElementManipulator() { override fun handleContentChange( element: KtStringTemplateExpression, @@ -29,11 +34,34 @@ class KtStringTemplateExpressionManipulator : AbstractElementManipulator + when (entry) { + is KtStringTemplateEntryWithExpression -> entry.text + else -> StringUtil.escapeStringCharacters(entry.text) + } + } + } else newContent + } else newContent + + val newKtExpression = makeKtExpressionFromText(wrapAsInOld(newContentPreprocessed)) + node.replaceAllChildrenToChildrenOf(newKtExpression.node) + return node.getPsi(KtStringTemplateExpression::class.java) } diff --git a/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt b/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt index 87b1aa754ed..1a1118e9e34 100644 --- a/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt +++ b/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt @@ -16,11 +16,12 @@ package org.jetbrains.kotlin.psi +import com.intellij.openapi.util.TextRange +import com.intellij.psi.ElementManipulators +import com.intellij.testFramework.LoggedErrorProcessor +import org.apache.log4j.Logger import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor -import com.intellij.psi.ElementManipulators -import org.junit.Assert.* -import com.intellij.openapi.util.TextRange class StringTemplateExpressionManipulatorTest : KotlinLightCodeInsightFixtureTestCase() { fun testSingleQuoted() { @@ -58,6 +59,27 @@ class StringTemplateExpressionManipulatorTest : KotlinLightCodeInsightFixtureTes fun testReplaceRange() { doTestContentChange("\"abc\"", "x", range = TextRange(2,3), expected = "\"axc\"") doTestContentChange("\"\"\"abc\"\"\"", "x", range = TextRange(4,5), expected = "\"\"\"axc\"\"\"") + doTestContentChange( + "\"
\${foo(\"\")}
\"", + "custom", range = TextRange(16, 23), + expected = "\"
\${foo(\"\")}
\"" + ) + } + + + fun testHackyReplaceRange() { + suppressFallingOnLogError { + doTestContentChange("\"a\\\"bc\"", "'", range = TextRange(0, 4), expected = "'bc\"") + } + } + + fun testTemplateWithInterpolation() { + doTestContentChange("\"
\${foo(\"\")}
\"", "

\${foo(\"\")}

", "\"

\${foo(\"\")}

\"") + doTestContentChange( + "\"
\${foo(\"\")}
\"", + "

\${foo(\"\")}

", + "\"

\${foo(\"\")}

\"" + ) } private fun doTestContentChange(original: String, newContent: String, expected: String, range: TextRange? = null) { @@ -69,3 +91,15 @@ class StringTemplateExpressionManipulatorTest : KotlinLightCodeInsightFixtureTes override fun getProjectDescriptor() = KotlinLightProjectDescriptor.INSTANCE } + +private fun suppressFallingOnLogError(call: () -> T) { + val loggedErrorProcessor = LoggedErrorProcessor.getInstance() + try { + LoggedErrorProcessor.setNewInstance(object : LoggedErrorProcessor() { + override fun processError(message: String?, t: Throwable?, details: Array?, logger: Logger) {} + }) + call() + } finally { + LoggedErrorProcessor.setNewInstance(loggedErrorProcessor) + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt.173 b/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt.173 deleted file mode 100644 index 59fd1fc77a8..00000000000 --- a/idea/tests/org/jetbrains/kotlin/psi/StringTemplateExpressionManipulatorTest.kt.173 +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.psi - -import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor -import com.intellij.psi.ElementManipulators -import org.junit.Assert.* -import com.intellij.openapi.util.TextRange - -class StringTemplateExpressionManipulatorTest : KotlinLightCodeInsightFixtureTestCase() { - fun testSingleQuoted() { - doTestContentChange("\"a\"", "b", "\"b\"") - doTestContentChange("\"\"", "b", "\"b\"") - doTestContentChange("\"a\"", "\t", "\"\\t\"") - doTestContentChange("\"a\"", "\n", "\"\\n\"") - doTestContentChange("\"a\"", "\\t", "\"\\\\t\"") - } - - fun testUnclosedQuoted() { - doTestContentChange("\"a", "b", "\"b") - doTestContentChange("\"", "b", "\"b") - doTestContentChange("\"a", "\t", "\"\\t") - doTestContentChange("\"a", "\n", "\"\\n") - doTestContentChange("\"a", "\\t", "\"\\\\t") - } - - fun testTripleQuoted() { - doTestContentChange("\"\"\"a\"\"\"", "b", "\"\"\"b\"\"\"") - doTestContentChange("\"\"\"\"\"\"", "b", "\"\"\"b\"\"\"") - doTestContentChange("\"\"\"a\"\"\"", "\t", "\"\"\"\t\"\"\"") - doTestContentChange("\"\"\"a\"\"\"", "\n", "\"\"\"\n\"\"\"") - doTestContentChange("\"\"\"a\"\"\"", "\\t", "\"\"\"\\t\"\"\"") - } - - fun testUnclosedTripleQuoted() { - doTestContentChange("\"\"\"a", "b", "\"\"\"b") - doTestContentChange("\"\"\"", "b", "\"\"\"b") - doTestContentChange("\"\"\"a", "\t", "\"\"\"\t") - doTestContentChange("\"\"\"a", "\n", "\"\"\"\n") - doTestContentChange("\"\"\"a", "\\t", "\"\"\"\\t") - } - - fun testReplaceRange() { - doTestContentChange("\"abc\"", "x", range = TextRange(2,3), expected = "\"axc\"") - doTestContentChange("\"\"\"abc\"\"\"", "x", range = TextRange(4,5), expected = "\"\"\"axc\"\"\"") - } - - private fun doTestContentChange(original: String, newContent: String, expected: String, range: TextRange? = null) { - val expression = KtPsiFactory(project).createExpression(original) as KtStringTemplateExpression - val manipulator = ElementManipulators.getNotNullManipulator(expression) - val newExpression = if (range == null) manipulator.handleContentChange(expression, newContent) else manipulator.handleContentChange(expression, range, newContent) - assertEquals(expected, newExpression.text) - } - - override fun getProjectDescriptor() = KotlinLightProjectDescriptor.INSTANCE -}