在像这样的 Kotlin 表达式中
fun main() {
throw throw throw RuntimeException("boom")
}
或
fun main() {
throw throw return
}
语法正确
我理解它背后的想法,但我想知道为什么在写这种废话时没有警告(至少在 Itellij 中)。
最佳答案
这在 KT-22621 "throw throw Exception()": False negative UNREACHABLE_CODE warning 中被报告为一个小问题.需要注意的是,如果你加上括号,无法访问的代码会被警告:
throw (throw Exception())
// or
throw (return)
此外,return throws Exception()
也会给出警告。
不幸的是,4 年后它仍然是一个悬而未决的问题。
看了一点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)
}
考虑 throw throw Exception()
。当访问第一个 throw
时,generateInstructions(thrownExpression)
生成与 throw Exception()
对应的 CFG 部分。这会导致访问第二个 throw
,为 throw Exception()
生成正确的 CFG。
当 builder.getValue(thrownExpression)
被调用时,问题就来了。这从表示抛出值的 CFG 构建器获取一个 PseudoValue
。但是,(我怀疑)这会返回 nil 并且 builder.throwException
不会被调用。这是因为在为 throw Exception()
构建 CFG 时,没有绑定(bind)任何值。将此与 visitParenthesizedExpression
中发生的情况进行比较,或 visitCallExpression
,但您需要更深入地追踪。
这不会对控制流分析产生太大影响,因为为 throw Exception()
生成的 CFG 部分是正确的。 CFG 确实最终缺少一个节点来表示外部throw
,这就是builder.throwException
。会添加。该节点将被标记为不可访问并发出警告,但该节点甚至不存在,因此没有警告。
关于kotlin - Kotlin 中的 throw 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70288747/