返回

文章详情

Go 分析框架:由 Go 团队提供的模块化静态分析

Hacker News2026年7月26日 12:21

包分析定义了模块化静态分析与分析驱动程序之间的接口。 背景 ¶ 静态分析是一个检查 Go 代码包并报告一组诊断(通常是代码中的错误)的功能,并可能还会产生其他结果,例如建议重构或其他事实。报告错误的分析通常被非正式地称为 "检查器"。例如,printf 检查器报告 fmt.Printf 格式字符串中的错误。"模块化" 分析是一种一次检查一个包,但可以保存来自低级包的信息并在检查更高级包时使用的分析,类似于工具链中的单独编译。printf 检查器是模块化的:当它发现某个函数(如 log.Fatalf)委托给 fmt.Printf 时,它记录下这个事实,并检查对该函数的调用,包括来自另一个包的调用。 通过实现一个通用接口,可以轻松地选择、整合和重用来自各种来源的检查器,广泛应用于包括命令行工具(如 vet)、文本编辑器和集成开发环境(IDEs)、构建和测试系统(如 go build、Bazel 或 Buck)、测试框架、代码审查工具、代码库索引器(如 SourceGraph)、文档查看器(如 godoc)、大型代码库的批处理管道等各类驱动程序。 分析器 ¶ API 中的主要类型是 Analyzer。Analyzer 静态描述一个分析功能:它的名称、文档、标志、与其他分析器的关系,以及当然,还有它的逻辑。要定义一个分析,用户声明一个类型为 Analyzer 的(逻辑上常量)变量。以下是来自 go/analysis/passes/ 子目录的一个典型示例: ```go package unusedresult var Analyzer = &analysis.Analyzer{ Name: "unusedresult", Doc: "检查某些函数调用的未使用结果", Run: run, ... } func run(pass *analysis.Pass) (interface{}, error) { ... } ``` 分析驱动程序是如 vet 这样的程序,它运行一系列分析并打印它们报告的诊断。驱动程序必须导入所需的 Analyzer 列表。通常每个 Analyzer 都位于一个单独的包中。要将新的 Analyzer 添加到现有驱动程序,只需在列表中添加另一个项: ```go import ( "unusedresult"; "nilness"; "printf" ) var analyses = []*analysis.Analyzer{ unusedresult.Analyzer, nilness.Analyzer, printf.Analyzer, } ``` 驱动程序可以使用名称、标志和文档提供在线帮助,以描述它执行的分析。文档注释包含简要的一句话总结,后面可以跟随段落解释。Analyzer 类型除了上面显示的字段外还有更多字段: ```go type Analyzer struct { Name string Doc string Flags flag.FlagSet Run func(*Pass) (interface{}, error) RunDespiteErrors bool ResultType reflect.Type Requires []*Analyzer FactTypes []Fact } ``` Flags 字段声明了一组命名的(全局)标志变量,用于控制分析行为。与 vet 不同,分析标志不会直接在命令行 FlagSet 中声明;设置标志变量由驱动程序负责。单个分析 a 的驱动程序可能会直接在命令行上暴露其标志 f,如 -f,而多个分析的驱动程序可能会使用分析名称作为前缀(-a.f)来避免歧义。IDE 可能通过图形界面暴露标志,而批处理管道可能从配置文件中配置它们。请参见 "findcall" 分析器以获取旗帜实际应用的示例。 RunDespiteErrors 标志指示分析是否能够处理类型错误的代码。如果不能,则如果存在解析或类型错误,驱动程序将跳过分析。可选的 ResultType 字段指定由此分析计算的结果值的类型,并提供给其他分析。Requires 字段指定一个分析依赖于的分析列表及其结果可能被访问的分析,并约束了驱动程序运行分析的顺序。FactTypes 字段将在模块性部分讨论。分析包提供一个 Validate 函数,对 Analyzer 进行基本的合理性检查,例如其 Requires 图是否为无环图,其事实和结果类型是否唯一,等等。最后,Run 字段包含一个函数,由驱动程序调用以对单个包执行分析。驱动程序将 Pass 类型的实例传递给它。 Pass ¶ Pass 描述一个单独的工作单元:将特定分析应用于特定 Go 代码包。Pass 为 Analyzer 的 Run 函数提供有关正在分析的包的信息,并为 Run 函数提供将诊断和其他信息反馈给驱动程序的操作。 ```go type Pass struct { Fset *token.FileSet Files []*ast.File OtherFiles []string IgnoredFiles []string Pkg *types.Package TypesInfo *types.Info ResultOf map[*Analyzer]interface{} Report func(Diagnostic) ... } ``` Fset、Files、Pkg 和 TypesInfo 字段提供了语法

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡