Kotlin 中的 throw 语句

say*_*llo 3 exception kotlin

在 Kotlin 表达式中,例如

fun main() {
    throw throw throw RuntimeException("boom")
}
Run Code Online (Sandbox Code Playgroud)

或者

fun main() {
    throw throw return
}
Run Code Online (Sandbox Code Playgroud)

语法正确

我理解其背后的想法,但我想知道为什么在写这样的废话时没有警告(至少在 Itellij 中)。

Swe*_*per 5

这在 KT-22621“throw throw Exception()”中被报告为一个小问题:漏报 UNREACHABLE_CODE 警告。应该注意的是,如果放入括号,则会警告无法访问的代码:

throw (throw Exception())
// or
throw (return)
Run Code Online (Sandbox Code Playgroud)

另外,return throws Exception()也给出警告。

不幸的是,四年后这仍然是一个悬而未决的问题。

读了一下 Kotlin 的源代码后,我认为这是无意的。让我们考虑 ControlFlowProcessor.kt visitThrowExpression

override fun visitThrowExpression(expression: KtThrowExpression) {
    mark(expression)

    generateJumpsToCatchAndFinally()

    val thrownExpression = expression.thrownExpression ?: return
    generateInstructions(thrownExpression)

    val thrownValue = builder.getBoundValue(thrownExpression) ?: return
    builder.throwException(expression, thrownValue)
}
Run Code Online (Sandbox Code Playgroud)

考虑throw throw Exception()。当第一个throw被访问时,generateInstructions(thrownExpression)生成 CFG 中对应于 的部分throw Exception()throw这会导致访问第二个,从而为 生成正确的 CFG throw Exception()

builder.getValue(thrownExpression)当接到电话时,问题就来了。这会PseudoValue从 CFG 构建器获取表示抛出值的值。但是,(我怀疑)这会返回 nil 并且builder.throwException不会被调用。这是因为在构建 的 CFG 时throw Exception(),没有绑定任何值。将此与visitParenthesizedExpression、 或中发生的情况进行比较visitCallExpression,但您需要更深入地追踪。

这不会对控制流分析产生太大影响,因为生成的 CFG 部分throw Exception()是正确的。CFG最终确实缺少一个代表外部的节点throw,而这正是本builder.throwException应添加的节点。该节点将被标记为无法访问并发出警告,但该节点甚至不存在,因此没有警告。