当使用-analysis标志调用时,godoc 会对它索引的 Go 包执行静态分析,并在源代码和包视图中显示结果。本文档简要介绍了这些功能。

类型分析功能

godoc -analysis=type执行类似于编译器执行的静态检查:它检测格式错误的程序,将每个标识符解析为它表示的实体,计算每个表达式的类型和每个类型的函数集,并确定哪些类型可以分配给每个接口类型。类型分析速度相对较快,例如,对于标准库的 200 多个包,大约需要 10 秒。

编译器错误

如果任何源文件包含编译错误,则源代码视图将以红色突出显示错误位置。将鼠标悬停在上面会显示错误消息。


标识符解析

在源代码视图中,每个引用标识符都带有有关其引用的语言实体的信息:包、常量、变量、类型、函数或语句标签。将鼠标悬停在标识符上会显示实体的种类和类型(例如var x intfunc f func(int) string)。



单击链接将带您到实体的定义。


类型信息:大小/对齐方式、方法集、接口

单击定义命名类型的标识符会导致一个面板出现,显示有关命名类型的信息,包括其大小和对齐方式(以字节为单位)、其方法集以及其实现关系:类型 T 的集合,这些类型可以分配给或来自此类型 U,其中 T 或 U 中至少有一个是接口。此示例显示了有关net/rpc.methodType的信息。

方法集不仅包括类型的声明方法,还包括从结构体的匿名字段“提升”的任何方法,例如此示例中的sync.Mutex。此外,接收器类型会显示为*TT,具体取决于它是否需要接收器值的地址或副本。

方法集和实现关系也可以通过包视图获得。

指针分析功能

godoc -analysis=pointer此外还执行精确的全程序指针分析。换句话说,它近似于每个引用可能引用的内存位置集——不仅是*T类型的变量,还有[]Tfuncmapchaninterface。此信息揭示了每个动态调用(通过func变量或接口方法)的可能目标,以及同一通道上发送和接收操作之间的关系。

与类型分析相比,指针分析需要更多的时间和内存,并且对于超过一百万行代码的代码库而言是不切实际的。

调用图导航

指针分析完成后,源代码视图会使用调用者被调用者信息对代码进行注释:调用者信息与声明函数的func关键字相关联,被调用者信息与函数调用的左括号'('相关联。

在此示例中,将鼠标悬停在rot13函数(在strings/strings_test.go中定义)的声明上会显示它恰好在一个地方被调用。

单击链接将导航到唯一的调用者。(如果有多个调用者,则首先会显示一个选择列表。)

请注意,将鼠标悬停在此调用上会显示在此站点有 19 个可能的被调用者,其中我们的rot13函数只是其中之一:这是通过func(rune) rune类型变量进行的动态调用。单击调用会显示所有 19 个潜在被调用者的列表(显示为截断)。其中许多是匿名函数。

与基于类型的技术相比,指针分析提供了非常精确的调用图近似值。例如,下一个示例显示了testing包中负责调用所有名为ExampleXYZ的用户定义函数的动态调用。

回想一下,所有此类函数的类型都是func(),即没有参数也没有结果。基于类型的近似值只能得出结论,即此调用可能会分派到与该类型匹配的任何函数——并且在大多数程序中这些函数非常多——但指针分析可以跟踪特定func值在testing包中的流向。作为其精度的指示,结果仅包含名称以Example开头的函数。

包内调用图

包视图中以非常不同的方式呈现了相同的调用图信息。对于每个包,交互式树视图允许探索与该包相关的调用图;省略了来自其他包的所有函数。树的根是包的外部入口点:不仅是其导出的函数,还有从包外部(动态)调用的任何未导出或匿名函数。

此示例显示了path/filepath包的入口点,并扩展了Glob的调用图几个级别

请注意,Glob 和 Join 的节点出现了多次:树是循环图的部分展开;完全展开通常是无限的。

对于包视图中记录的每个函数,另一个交互式树视图允许探索从该函数开始的相同图。这是net/http.ListenAndServe的内部图的一部分。

通道对等体(发送↔接收)

由于并发 Go 程序使用通道不仅传递值,还传递不同 goroutine 之间的控制权,因此在阅读 Go 代码时,自然会希望从通道发送导航到相应的接收,以便了解事件序列。

Godoc 为每个通道操作(创建、发送、范围、接收、关闭)添加了一个链接,该链接指向一个面板,其中显示有关可能与同一通道具有别名的其他操作的信息。

此示例来自net/http的测试,显示了对chan bool的发送操作。

单击<-发送操作器会显示此通道在唯一位置(第 332 行)创建,并且有三个接收操作可能会读取此值。几乎不必指出某些通道元素类型被广泛使用(例如 struct{}、bool、int、interface{}),并且典型的 Go 程序可能包含数十个对chan bool类型值的接收操作;然而,指针分析能够以比仅基于其类型更精细的精度区分通道上的操作。

另请注意,发送发生在与包含make和接收操作的外部函数不同的(匿名)函数中。

这是另一个对不同chan bool的发送示例,也在net/http包中

分析仅找到一个可能从该通道接收的接收操作,在对此功能的测试中。

已知问题

所有分析结果都与一种配置(例如 amd64 linux)完全相关。基于不同平台或构建标记有条件编译的文件对分析不可见。

import "C"的文件需要由 cgo 工具进行预处理。预处理后的文件偏移量与未预处理的文件不一致,因此标记未对齐。

文件不会定期重新分析。如果文件在运行的服务器下发生更改,则显示的标记将未对齐。

其他问题列在tools/godoc/analysis/README中。