为何IntelliJ IDEA代码存在ENQ/ESA Unicode字符时会误报多字符字面量错误?
问题描述
我当时正在尝试修复异常的PDF Unicode重映射问题,遇到了该故障:代码任意位置加入ENQ Unicode字符后无法编译,IDE会弹出我认为属于误报的错误提示。
我们以这段完全合法的Kotlin代码为例,将其称为程序A。遗憾的是你无法在这里看到单引号之间的实际字符,但请相信引号内确实存在一个字符(你可以将代码复制到本地IDE中查看字符)。
package yamin fun main() { val foo = mutableListOf('') //val bar = mutableListOf('') println(foo) }
你可以在下图中看到这些字符:
但如果你尝试编译这段代码,IDE会编译失败,提示第4行存在Too many characters in a character literal(字符字面量包含过多字符)错误。
值得注意的是,即使ENQ字符仅出现在注释行中,也会导致IDE编译失败。如果你删除第5行、移除ENQ字符,代码就可以正常编译,我们将其称为程序B,如下图所示:
如果你删除程序A的第4行,取消注释第5行,代码同样可以正常编译,我们将其称为程序C:
综上,程序A无法编译,报错指向第4行,但删除带ENQ字符的第5行得到的程序B可正常编译,程序C的表现也符合该规律。请问这是什么原因导致的?
问题原因
这个问题是IntelliJ IDEA内置Kotlin语法解析器的已知bug导致的,触发逻辑如下:
- ENQ(U+0005)属于ASCII C0控制字符,旧版本Kotlin插件的词法分析器解析单行注释时,碰到ENQ字符会错误地提前终止单行注释的作用范围,导致
//之后ENQ字符后的内容被当成正常代码解析。 - 程序A的第5行注释内容为
//val bar = mutableListOf(''),两个单引号中间是ENQ字符。词法分析器扫描到ENQ时误以为单行注释结束,后面的单引号就被识别为正常的字符字面量起始标记。 - 此时词法分析器会错误地将第4行字符字面量的起始单引号,和第5行ENQ之后的单引号配对,中间跨两行的所有内容都被算成字符字面量的内容,自然字符数远大于1,就抛出了第4行“字符字面量包含过多字符”的错误。
- 删除第5行后,第4行的单引号配对逻辑恢复正常,所以程序B可以正常编译;删除第4行、取消第5行注释时,第5行的单引号配对没有异常,所以程序C也可以正常运行。
解决方案
- 所有C0控制字符不要直接写在代码中,统一使用Unicode转义序列表示,比如ENQ字符写成
'\u0005',即可完全规避该问题。 - 升级IntelliJ IDEA以及Kotlin插件到最新正式版,该解析bug已经在后续版本中被修复。
内容的提问来源于stack exchange,提问作者Yamin Siahmargooei
相关产品推荐
相关产品推荐

