From 84a582c6189c2801d645a065e4e9bf05c523f88a Mon Sep 17 00:00:00 2001 From: Igor Yakovlev Date: Sat, 9 May 2020 01:36:12 +0300 Subject: [PATCH] Fix escaping const string literals in UL Fixed #KT-38247 --- .../kotlin/asJava/classes/ultraLightUtils.kt | 25 ++++++++++++++++--- .../asJava/ultraLightClasses/properties.kt | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index 09bfe23c479..6286ad643f8 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -18,6 +18,7 @@ import com.intellij.psi.impl.compiled.StubBuildingVisitor import com.intellij.psi.impl.light.* import com.intellij.psi.util.TypeConversionUtil import com.intellij.util.BitUtil.isSet +import com.intellij.util.IncorrectOperationException import com.intellij.util.containers.ContainerUtil import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.UltraLightClassModifierExtension @@ -364,14 +365,32 @@ private fun toQualifiedName(userType: KtUserType): FqName? { internal fun ConstantValue<*>.createPsiLiteral(parent: PsiElement): PsiExpression? { val asString = asStringForPsiLiteral(parent) - val instance = PsiElementFactory.SERVICE.getInstance(parent.project) - return instance.createExpressionFromText(asString, parent) + val instance = PsiElementFactory.getInstance(parent.project) + return try { + instance.createExpressionFromText(asString, parent) + } catch (_: IncorrectOperationException) { + null + } +} + +private fun escapeString(str: String): String = buildString { + str.forEach { char -> + val escaped = when (char) { + '\n' -> "\\n" + '\r' -> "\\r" + '\t' -> "\\t" + '\"' -> "\\\"" + '\\' -> "\\\\" + else -> "$char" + } + append(escaped) + } } private fun ConstantValue<*>.asStringForPsiLiteral(parent: PsiElement): String = when (this) { is NullValue -> "null" - is StringValue -> "\"$value\"" + is StringValue -> "\"${escapeString(value)}\"" is KClassValue -> { val value = (value as KClassValue.Value.NormalClass).value val arrayPart = "[]".repeat(value.arrayNestedness) diff --git a/compiler/testData/asJava/ultraLightClasses/properties.kt b/compiler/testData/asJava/ultraLightClasses/properties.kt index ad7305f6259..f64f76df32b 100644 --- a/compiler/testData/asJava/ultraLightClasses/properties.kt +++ b/compiler/testData/asJava/ultraLightClasses/properties.kt @@ -26,6 +26,8 @@ class Foo(a: Int, val b:Foo, var c:Boolean, private val d: List, protected val e const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" + const val CONSTANT_WITH_ESCAPES = "A\tB\nC\rD\'E\"F\\G\$H" + var counter = 0 set(value) { if (value >= 0) field = value