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

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

概览

Go 分析框架定义了一个通用的 Analyzer 接口,使开发者能够编写可被 vet、文本编辑器、构建系统和自定义 linter 使用的模块化静态分析。

分析器类型

分析器静态描述一个分析函数。它包括用于名称、文档、标志集、Run 函数、RunDespiteErrors、ResultType、Requires 依赖和 FactTypes 的字段。Run 函数接收一个 *Pass 并返回一个 interface{} 结果和一个错误。Validate 函数检查 Requires 图是否无环,事实和结果类型是否唯一,并且 Run 不为 nil。

Pass 类型

Pass 表示一个工作单元:将一个 Analyzer 应用于一个 Go 包。它提供文件集、语法树、类型信息以及用于报告诊断的辅助方法。ResultOf 映射保存来自所需分析器的结果。Reportf 和 ReportRangef 辅助函数创建带有位置、可选类别和消息的 Diagnostic 对象。Pass 还提供 ExportObjectFact、ImportObjectFact、ExportPackageFact 和 ImportPackageFact,用于在包之间共享事实。

事实和模块化分析

事实是分析可以附加到 types.Object 或包上的中间、可序列化的信息片段。它们使得可以进行独立编译风格的分析:一个分析器可以导出事实,随后的分析器(即使在不同的地址空间)可以通过驱动程序导入这些事实。事实类型必须是指针,并使用 gob 进行编码;它们应该是无状态且确定的,以便与内容可寻址缓存一起工作。printf 检查器通过记录哪些函数委托给 fmt.Printf 并重用该事实来检查其他包中的调用来演示这一点。

测试 Analyzer

analysistest 子包通过在 testdata 文件上运行 Analyzer 并通过源代码中的 "// want" 注释验证预期的诊断和事实来帮助测试 Analyzer。这提供了一种轻量级的方法,无需构建完整的驱动程序即可断言正确性。

独立命令

singlechecker 和 multichecker 子包简化了创建运行一个或多个分析器的命令行工具。典型的单分析器命令如下:

package main

import ( "golang.org/x/tools/go/analysis/passes/findcall" "golang.org/x/tools/go/analysis/singlechecker" )

func main() { singlechecker.Main(findcall.Analyzer) }

多检查器命令仅需将 *Analyzer 的切片传递给 multichecker.Main。

生态系统使用

评论者指出,该框架已经被许多 linter 使用(参见 golang.org/x/tools/go/analysis 的导入图)。一位用户报告称,为 SpiceDB 定义自定义分析器取得了成功,强调该框架减少了对部落知识的需求并加快了代码审查。另一位评论者询问这些原语是否可用于构建更广泛的架构 linter,表明对更高级别检查的兴趣。进一步的评论者赞赏 Go 团队在人类和代理开发两方面对工具的关注,引用了利用构建标签和 testscript 进行有针对性测试的个人项目。

这些观察表明,分析包既是现有工具(如 vet)的可重用基础,也是用户定义的检查器的基础,支持在 Go 生态系统中进行模块化、事实驱动的静态分析。

Sources