Fix handling non-ES5 identifiers in JS
When a Kotlin identifiers contains non-ES5 chars, JS BE either reports error (for published declarations) or mangles name (for non-published ones). The old approach relied on wrong assuption that Java identifier = ES identifier. However, that's not true. This commit introduces functions that check identifiers according to ES5.1 spec rather than using Character.isIdentifierStart[Part] See KT-17476
This commit is contained in:
committed by
Alexey Andreev
parent
24c0a1e7ce
commit
a0ddbf0e9b
@@ -294,7 +294,7 @@ class NameSuggestion {
|
|||||||
// Make all public declarations stable
|
// Make all public declarations stable
|
||||||
effectiveVisibility == Visibilities.PUBLIC -> mangledAndStable()
|
effectiveVisibility == Visibilities.PUBLIC -> mangledAndStable()
|
||||||
|
|
||||||
descriptor is CallableMemberDescriptor && descriptor.isOverridableOrOverrides -> mangledAndStable()
|
descriptor.isOverridableOrOverrides -> mangledAndStable()
|
||||||
|
|
||||||
// Make all protected declarations of non-final public classes stable
|
// Make all protected declarations of non-final public classes stable
|
||||||
effectiveVisibility == Visibilities.PROTECTED &&
|
effectiveVisibility == Visibilities.PROTECTED &&
|
||||||
@@ -346,8 +346,28 @@ class NameSuggestion {
|
|||||||
@JvmStatic fun sanitizeName(name: String): String {
|
@JvmStatic fun sanitizeName(name: String): String {
|
||||||
if (name.isEmpty()) return "_"
|
if (name.isEmpty()) return "_"
|
||||||
|
|
||||||
val first = name.first().let { if (java.lang.Character.isJavaIdentifierStart(it)) it else '_' }
|
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||||
return first.toString() + name.drop(1).map { if (java.lang.Character.isJavaIdentifierPart(it)) it else '_' }.joinToString("")
|
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See ES 5.1 spec: https://www.ecma-international.org/ecma-262/5.1/#sec-7.6
|
||||||
|
private fun Char.isES5IdentifierStart() =
|
||||||
|
Character.isLetter(this) || // Lu | Ll | Lt | Lm | Lo
|
||||||
|
Character.getType(this).toByte() == Character.LETTER_NUMBER ||
|
||||||
|
// Nl which is missing in Character.isLetter, but present in UnicodeLetter in spec
|
||||||
|
this == '_' ||
|
||||||
|
this == '$'
|
||||||
|
|
||||||
|
private fun Char.isES5IdentifierPart() =
|
||||||
|
isES5IdentifierStart() ||
|
||||||
|
when (Character.getType(this).toByte()) {
|
||||||
|
Character.NON_SPACING_MARK,
|
||||||
|
Character.COMBINING_SPACING_MARK,
|
||||||
|
Character.DECIMAL_DIGIT_NUMBER,
|
||||||
|
Character.CONNECTOR_PUNCTUATION -> true
|
||||||
|
else -> false
|
||||||
|
} ||
|
||||||
|
this == '\u200C' || // Zero-width non-joiner
|
||||||
|
this == '\u200D' // Zero-width joiner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ fun test3(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun test4(): String {
|
fun test4(): String {
|
||||||
val `()` = "OK"
|
val `1(¢)` = "OK"
|
||||||
fun `[]`() = `()`
|
fun `[£]`() = `1(¢)`
|
||||||
return `[]`()
|
return `[£]`()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user