Go 分析框架:Go 团队开发的模块化静态分析

Go 分析框架:Go 团队开发的模块化静态分析

Hacker News 摘要

原标题:Go Analysis Framework: modular static analysis by go team

golang.org/x/tools/go/analysis 包定义了模块化静态分析工具与分析驱动程序之间的接口。

核心概念与背景

静态分析是检查 Go 代码包并报告诊断结果(通常是代码错误)的过程,也可能产生重构建议或其他事实数据。报告错误的分析工具通俗地被称为 checker。例如,printf 检查器专门报告 fmt.Printf 格式字符串中的错误。

模块化分析是指一次只检查一个包,但可以保存低层级包的信息,并在检查高层级包时使用这些信息,这类似于工具链中的独立编译。通过实现通用接口,不同来源的检查器可以轻松集成到各种驱动程序中,包括命令行工具(如 vet)、文本编辑器、集成开发环境(IDE)、构建系统(如 go buildBazel)、代码审查工具和文档查看器等。

核心类型:Analyzer

Analyzer 类型是该 API 的核心,它静态地描述了一个分析函数,包括其名称、文档、标志位、与其他分析器的关系以及执行逻辑。

Analyzer 的主要字段包括:

Name:分析器的名称,必须是一个合法的 Go 标识符。

Doc:文档说明,首行通常是简短摘要。

Flags:定义分析器接受的命令行标志。

Run:在包上执行分析的核心函数。它接收一个 Pass 参数,并返回结果或错误。

Requires:该分析器依赖的其他分析器列表。驱动程序会先运行依赖项,并将其结果提供给当前分析器。这建立了同包内不同分析器之间的水平依赖。

ResultType:分析函数返回值的类型,供依赖它的其他分析器使用。

FactTypes:分析器导入或导出的事实类型,用于跨包的垂直依赖。

RunDespiteErrors:即使包中存在语法错误或类型错误,是否仍运行该分析。

该包提供的 Validate 函数可以对 Analyzer 进行健全性检查,例如确保依赖图无环、事实类型唯一以及名称合法。

分析运行单元:Pass

Pass 类型代表了一个具体的工作单元,即在一个特定的 Go 包上应用一个特定的 Analyzer。它为 Run 函数提供所需的信息,并提供向驱动程序报告诊断信息的手段。

Pass 包含的关键信息有:

FsetFilesPkgTypesInfo:提供单个 Go 包的语法树、类型信息和源码位置。

OtherFilesIgnoredFiles:提供包内非 Go 文件(如汇编文件)或被忽略的源文件名称。

ResultOf:包含当前分析器所依赖的其他分析器的计算结果。

Report:用于发布 Diagnostic(诊断信息)。

Diagnostic 结构体包含位置信息(Pos 和可选的 End)、类别标签(Category)和消息内容(Message)。它不包含严重程度字段,因为设计者认为严重程度应由用户根据偏好在驱动程序中配置。此外,诊断信息还可以包含 SuggestedFixes(建议修复)和 Related(关联的辅助位置信息)。

模块化分析与事实(Facts)

为了提高效率和可扩展性,该框架支持模块化分析。某些分析结果(称为 Fact)可以从依赖包传递到当前包。

Fact(事实)是与包中声明的对象或包本身相关联的中间分析结论。例如,printf 检查器会记录某个函数是否是 printf 的包装函数。这些事实会被序列化(使用 gob 编码)并保存,以便在分析依赖该包的其他代码时使用。

Pass 提供了导入和导出事实的方法:

ExportObjectFactImportObjectFact:关联或检索特定对象(如函数或变量)的事实。

ExportPackageFactImportPackageFact:关联或检索整个包的事实。

分析器只能导出当前包及其对象的事实,但可以导入任何直接依赖包的事实。

测试分析器

analysistest 子包提供了用于测试分析器的工具。开发者可以编写带有 // want ... 注释的测试代码,测试框架会自动运行分析器并验证报告的诊断信息和事实是否符合预期。

独立命令

虽然分析器通常作为包被驱动程序导入,但也可以轻松创建独立的命令行工具。该框架提供了 singlechecker(用于单个分析器)和 multichecker(用于多个分析器)子包,帮助开发者快速构建符合标准的命令行界面。例如,只需在 main 函数中调用 singlechecker.Main(Analyzer) 即可生成一个完整的工具。

子目录说明

该路径下还包含多个相关的子包:

analysistest:测试工具。

checker:基于包加载结果的分析驱动程序。

multichecker:多分析器驱动的主函数定义。

passes:包含各种标准的分析实现。

singlechecker:单分析器驱动的主函数定义。

unitchecker:用于构建系统中分析单个编译单元的驱动程序。


原文:https://pkg.go.dev/golang.org/x/tools/go/analysis

评论:https://news.ycombinator.com/item?id=49057398

Report Page