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
|
||||
effectiveVisibility == Visibilities.PUBLIC -> mangledAndStable()
|
||||
|
||||
descriptor is CallableMemberDescriptor && descriptor.isOverridableOrOverrides -> mangledAndStable()
|
||||
descriptor.isOverridableOrOverrides -> mangledAndStable()
|
||||
|
||||
// Make all protected declarations of non-final public classes stable
|
||||
effectiveVisibility == Visibilities.PROTECTED &&
|
||||
@@ -346,8 +346,28 @@ class NameSuggestion {
|
||||
@JvmStatic fun sanitizeName(name: String): String {
|
||||
if (name.isEmpty()) return "_"
|
||||
|
||||
val first = name.first().let { if (java.lang.Character.isJavaIdentifierStart(it)) it else '_' }
|
||||
return first.toString() + name.drop(1).map { if (java.lang.Character.isJavaIdentifierPart(it)) it else '_' }.joinToString("")
|
||||
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||
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 {
|
||||
val `()` = "OK"
|
||||
fun `[]`() = `()`
|
||||
return `[]`()
|
||||
val `1(¢)` = "OK"
|
||||
fun `[£]`() = `1(¢)`
|
||||
return `[£]`()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
|
||||
Reference in New Issue
Block a user