diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/copyConcatenatedStringToClipboard/ConcatenatedStringGenerator.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/copyConcatenatedStringToClipboard/ConcatenatedStringGenerator.kt index a52d281a34f..9a78fdce058 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/copyConcatenatedStringToClipboard/ConcatenatedStringGenerator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/copyConcatenatedStringToClipboard/ConcatenatedStringGenerator.kt @@ -16,8 +16,11 @@ package org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall class ConcatenatedStringGenerator { fun create(element: KtBinaryExpression): String { @@ -37,7 +40,7 @@ class ConcatenatedStringGenerator { is KtBinaryExpression -> this.appendTo(sb) is KtConstantExpression -> sb.append(text) is KtStringTemplateExpression -> this.appendTo(sb) - else -> sb.append("?") + else -> sb.append(convertToValueIfCompileTimeConstant() ?: "?") } } @@ -47,8 +50,15 @@ class ConcatenatedStringGenerator { when (stringTemplate) { is KtLiteralStringTemplateEntry -> sb.append(stringTemplate.text) is KtEscapeStringTemplateEntry -> sb.append(stringTemplate.unescapedValue) - else -> sb.append("?") + else -> sb.append(stringTemplate.expression?.convertToValueIfCompileTimeConstant() ?: "?") } } } + + private fun KtExpression.convertToValueIfCompileTimeConstant(): String? { + val resolvedCall = getResolvedCall(analyzeFully()) ?: return null + val propertyDescriptor = resolvedCall.resultingDescriptor as? PropertyDescriptor ?: return null + return propertyDescriptor.compileTimeInitializer?.value?.toString() + } + } \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/constants.kt b/idea/testData/concatenatedStringGenerator/constants.kt index 136bbe32160..b08db7c66aa 100644 --- a/idea/testData/concatenatedStringGenerator/constants.kt +++ b/idea/testData/concatenatedStringGenerator/constants.kt @@ -1 +1 @@ -"" + 1 + 1.1 + "foo" \ No newline at end of file +val test = "" + 1 + 1.1 + "foo" \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/constants2.kt b/idea/testData/concatenatedStringGenerator/constants2.kt new file mode 100644 index 00000000000..155d05ee082 --- /dev/null +++ b/idea/testData/concatenatedStringGenerator/constants2.kt @@ -0,0 +1,2 @@ +val b = 1 +val test = "" + b + "foo" \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/constants2.kt.result b/idea/testData/concatenatedStringGenerator/constants2.kt.result new file mode 100644 index 00000000000..f2b9efe7121 --- /dev/null +++ b/idea/testData/concatenatedStringGenerator/constants2.kt.result @@ -0,0 +1 @@ +1foo \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/simple.kt b/idea/testData/concatenatedStringGenerator/simple.kt index 8c4c39a8813..d39ac498d9d 100644 --- a/idea/testData/concatenatedStringGenerator/simple.kt +++ b/idea/testData/concatenatedStringGenerator/simple.kt @@ -1 +1 @@ -"foo" + "bar" \ No newline at end of file +val test = "foo" + "bar" \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/stringtemplate.kt b/idea/testData/concatenatedStringGenerator/stringtemplate.kt index b7403f4871a..b8d13a63383 100644 --- a/idea/testData/concatenatedStringGenerator/stringtemplate.kt +++ b/idea/testData/concatenatedStringGenerator/stringtemplate.kt @@ -1 +1,7 @@ -"foo$foo$bar" + "${bar}${bar2()}bar" \ No newline at end of file +// WITH_RUNTIME + +var foo = "aaa" +var bar = "bbb" +fun bar2() = "will be ignored" + +val test = "foo$foo$bar" + "${bar}${bar2()}bar" \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt b/idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt new file mode 100644 index 00000000000..4956662820f --- /dev/null +++ b/idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt @@ -0,0 +1,7 @@ +// WITH_RUNTIME + +val foo = "aaa" +val bar = "bbb" +fun bar2() = "will be ignored" + +val test = "foo$foo$bar" + "${bar}${bar2()}bar" \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt.result b/idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt.result new file mode 100644 index 00000000000..50281aa1636 --- /dev/null +++ b/idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt.result @@ -0,0 +1 @@ +fooaaabbbbbb?bar \ No newline at end of file diff --git a/idea/testData/concatenatedStringGenerator/variables.kt b/idea/testData/concatenatedStringGenerator/variables.kt index 5c92a735c5c..796de5d9b15 100644 --- a/idea/testData/concatenatedStringGenerator/variables.kt +++ b/idea/testData/concatenatedStringGenerator/variables.kt @@ -1 +1,2 @@ -"" + b + "foo" \ No newline at end of file +var b = 1 +val test = "" + b + "foo" \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractConcatenatedStringGeneratorTest.kt b/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractConcatenatedStringGeneratorTest.kt index fe64deae07a..af9bc45df63 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractConcatenatedStringGeneratorTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/AbstractConcatenatedStringGeneratorTest.kt @@ -16,24 +16,52 @@ package org.jetbrains.kotlin.idea.intentions +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.psi.PsiDocumentManager +import com.intellij.testFramework.PlatformTestUtil import junit.framework.TestCase import org.jetbrains.kotlin.idea.intentions.copyConcatenatedStringToClipboard.ConcatenatedStringGenerator +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.KotlinCodeInsightTestCase +import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType +import org.jetbrains.kotlin.test.InTextDirectivesUtils import java.io.File +/** + * Compare xxx.kt.result file with the result of ConcatenatedStringGenerator().create(KtBinaryExpression) where KtBinaryExpression is the last KtBinaryExpression of xxx.kt file + */ abstract class AbstractConcatenatedStringGeneratorTest : KotlinCodeInsightTestCase() { @Throws(Exception::class) protected fun doTest(path: String) { val mainFile = File(path) - val readText = mainFile.readText() + val fileText = mainFile.readText() val resultFile = File("$path.result") val expectedText = resultFile.readText() - val expression = KtPsiFactory(project).createExpression(readText) as? KtBinaryExpression - TestCase.assertNotNull("Invalid expression: $readText", expression) - val generatedString = ConcatenatedStringGenerator().create(expression!!) - TestCase.assertEquals("mismatch '$expectedText' - '$generatedString'", expectedText, generatedString) + + val vFile = LocalFileSystem.getInstance().findFileByPath(path) ?: return + val document = FileDocumentManager.getInstance().getDocument(vFile) ?: return + val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document) ?: return + + val isWithRuntime = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// WITH_RUNTIME") != null + + try { + if (isWithRuntime) ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, PluginTestCaseBase.mockJdk()) + ConfigLibraryUtil.configureLibrariesByDirective(module, PlatformTestUtil.getCommunityPath(), fileText) + + val ktFile = KtPsiFactory(project).createAnalyzableFile("dummy.kt", fileText, psiFile) + val expression = ktFile.collectDescendantsOfType().lastOrNull() + TestCase.assertNotNull("No binary expression found: $path", expression) + val generatedString = ConcatenatedStringGenerator().create(expression!!) + TestCase.assertEquals("mismatch '$expectedText' - '$generatedString'", expectedText, generatedString) + } + finally { + ConfigLibraryUtil.unconfigureLibrariesByDirective(myModule, fileText) + if (isWithRuntime) ConfigLibraryUtil.unConfigureKotlinRuntimeAndSdk(module, testProjectJdk) + } } } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/ConcatenatedStringGeneratorTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/ConcatenatedStringGeneratorTestGenerated.java index dfb9a31ee2b..e5557f0d6ef 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/ConcatenatedStringGeneratorTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/ConcatenatedStringGeneratorTestGenerated.java @@ -42,6 +42,12 @@ public class ConcatenatedStringGeneratorTestGenerated extends AbstractConcatenat doTest(fileName); } + @TestMetadata("constants2.kt") + public void testConstants2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/constants2.kt"); + doTest(fileName); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/simple.kt"); @@ -54,6 +60,12 @@ public class ConcatenatedStringGeneratorTestGenerated extends AbstractConcatenat doTest(fileName); } + @TestMetadata("stringtemplateWithConstant.kt") + public void testStringtemplateWithConstant() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/stringtemplateWithConstant.kt"); + doTest(fileName); + } + @TestMetadata("variables.kt") public void testVariables() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/concatenatedStringGenerator/variables.kt");