Swift 5.9 中的调试改进
Swift 5.9 为编译器和 LLDB 调试器引入了许多新的调试功能。
以下是三项可以帮助您进行日常调试工作流程的更改。
使用 p 和 po 更快地检查变量 p and po section" href="#faster-variable-inspection-with-p-and-po">
LLDB 提供了简写命令别名 p 来检查变量,以及 po 来调用对象的 debugDescription 属性。最初,这些是相当重量级的 expression 和 expression -O 命令的别名。在 Swift 5.9 中,p 和 po 命令别名已被重新定义为新的 dwim-print 命令。
dwim-print 命令使用最用户友好的实现来打印值。“DWIM” 是 “Do What I Mean”(明白我的意思)的首字母缩写。具体来说,在打印变量时,dwim-print 将使用与 frame variable 或 v 相同的实现,而不是更昂贵的表达式求值器。
除了速度更快之外,使用 p 不再创建像 $R0 这样的持久结果变量,这些变量在调试会话中通常未使用。持久结果变量不仅会产生开销,还会保留它们包含的任何对象,这可能是程序执行的意外副作用。
偶尔需要持久结果的用户可以直接使用 expression(或唯一前缀,例如 expr)而不是 p。如果您希望每次都启用持久结果,您可以利用 LLDB 便利的别名功能,并将以下内容放入 ~/.lldbinit 文件中
command unalias p
command alias p dwim-print --persistent-result on --
dwim-print 命令还为 po 提供了新功能。po 命令现在可以打印 Swift 对象,即使只给定一个原始地址。当运行 po <object-address> 时,LLDB 的嵌入式 Swift 编译器将自动在后台评估表达式 unsafeBitCast(<object-address>, to: AnyObject.self) 以产生预期的结果。
Swift 5.9 之前
(lldb) po 0x00006000025c43d0
(Int) 105553155867600
使用 Swift 5.9
(lldb) po 0x00006000025c43d0
<MyApp.AppDelegate: 0x6000025c43d0>
在表达式中支持泛型类型参数
LLDB 现在支持在表达式求值中引用泛型类型参数。例如,给定以下代码
func use<T>(_ t: T) {
print(t) // break here
}
use(5)
use("Hello!")
当在 use 中停止时,运行 po T.self 将在第一次调用时打印 Int,在第二次调用时打印 String。
除了显示泛型的具体类型外,您还可以使用它来设置查找具体类型的条件。例如,如果您将条件 T.self == String.self 添加到上面的断点,则仅当变量 t 是 String 时,use 才会停止。(请注意,最后一个示例仅适用于 Swift 5.9 工具链的 nightly 构建。)
有关此功能实现的更多详细信息,请参阅原始的 LLDB pull request。
细粒度的作用域信息
Swift 编译器现在在调试信息中发出更精确的词法作用域,使调试器能够更好地区分不同的变量,例如以下示例中许多名为 x 的变量
func f(x: AnyObject?) {
// function parameter `x: AnyObject?`
guard let x else {}
// local variable `x: AnyObject`, which shadows the function argument `x`
...
}
在 Swift 5.9 中,编译器现在使用更准确的 ASTScope 信息在调试信息中生成词法作用域层次结构,这导致调试器中的一些行为发生变化。
在下面的示例中,局部变量 a 在 getInt() 的调用站点尚未进入作用域,并且仅在赋值后才可用。使用先前版本的 Swift 编译器生成的调试信息,调试器可能会在 getInt() 的调用站点将未初始化的内存显示为 a 的内容。在 Swift 5.9 中,变量 a 仅在初始化后才变为可见
1 func getInt() -> Int { return 42 }
2
3 func f() {
4 let a = getInt()
^
5 print(a)
6 }
(lldb) p a
error: <EXPR>:3:1: error: cannot find 'a' in scope
(lldb) n
3 func f() {
4 let a = getInt()
5 print(a)
^
6 }
(lldb) p a
42
有关更多详细信息,请参阅引入此更改的 pull request。
参与进来
如果您想了解更多关于 Swift 调试和 LLDB 的信息,提供反馈,或为工具本身做出贡献,请加入 Swift 开发论坛的 LLDB 版块。