Goの`golang.org/x/tools/go/analysis`ドキュメントは、モジュール化された静的解析のためのインターフェースを定義しています。各アナライザーは一度に1つのGoパッケージを調べ、診断を報告し、共通のAPIを通じて結果をやり取りできます。このフレームワークは、同じアナライザーを`vet`のようなコマンドラインツール、エディター、IDE、ビルドシステム、テストフレームワーク、コードレビューツール、さらに大規模なバッチ処理パイプラインへ組み込めるように設計されています。

Goプログラミング言語の公式ロゴ
Goのロゴ。ここで取り上げる解析APIが対象とする言語を示している。Go project / pkg.go.dev

冒頭ではGo向けのパッケージ解析インターフェースを紹介しているため、この公式ロゴが対象言語を示している。pkg.go.devには出典:pkg.go.dev。

アナライザーは`Analyzer`値として表され、名前、ドキュメント、フラグ、依存関係、Factの型、実行関数を記述します。ドライバーは1つのパッケージに対する`Pass`を受け取り、構文情報と型情報を提供し、必要なアナライザーを先に実行してから、その結果を`Pass.ResultOf`を通じて公開します。その後、アナライザーはパスを使って、ソースコード上の位置を示す診断を報告します。この分離により、ツール開発者は、特定のインターフェース向けに各チェッカーを書き直さずに、実行するチェックを選択できます。

このフレームワークの中核にある拡張性に関する考え方は、`Fact`です。Factとは、それ自体だけでは開発者にとって必ずしも有用とは限らないものの、別の解析が結論に到達するのを助けられる中間結果です。ドキュメントでは、`printf`チェッカーを例として挙げています。このチェッカーは関数を`printf`ラッパーとして特定し、そのFactをエクスポートできます。これにより、後続のパッケージ解析では、ラッパーを介して委譲する呼び出しに対して、より厳格なチェックを適用できます。

Factは、名前付きのオブジェクト、またはパッケージ全体に関連付けることができます。ドライバーは、依存パッケージのFactを生成し、個別のプロセス間を含むパッケージの境界を越えて伝播する責任を負います。Factはビルド成果物に保存される可能性があるため、このAPIは決定論的なgobシリアライゼーションを要求します。また、アナライザーの作者には、コンテンツアドレス指定型ビルドキャッシュで不要なミスが発生しないよう、Factをステートレスに保つことが推奨されています。

この設計では、診断の重大度を意図的にコアの`Diagnostic`型から除外しています。ドキュメントによれば、重大度に関する設定はユーザーやツールによって異なるため、ドライバーは、診断を生成したアナライザーとその任意のカテゴリに基づいて、フィルタリングと優先順位付けを提供すべきです。この選択により、アナライザーのインターフェースは比較的小さく保たれます。一方で、チェッカーの出力が、欠陥を重要度順に並べた一覧として自動的に扱われるわけではないことも意味します。

実際には制約もあります。ドキュメントが説明しているBazelおよびBlazeベースのドライバーをはじめ、一部のドライバー実装は、現在、Go標準ライブラリのパッケージを解析していません。そのため、`printf`チェッカーには`log.Printf`用の組み込みFactが含まれており、標準ライブラリのパッケージが解析されなかった場合でも、その呼び出しを調べられます。これは明示的な回避策であり、すべてのドライバーが同じパッケージカバレッジを提供している証拠ではありません。

ドキュメントは、型付き構文木を調べるアナライザーと、生のソースコードやGo以外のファイルを読み取るアナライザーも区別しています。`asmdecl`や`buildtag`などの例は、このフレームワークが通常の型情報を超える対象にも到達できることを示しています。ただし、チェッカーが何を調べ、どのように解析結果を報告するかを定義する責任は、引き続きアナライザーの作者にあります。このAPIは契約を提供するものの、あらゆるプログラムの性質を健全に推論できることを保証するものではありません。

テストには、`analysistest`サブパッケージを使用します。これはフィクスチャパッケージを対象にアナライザーを実行し、`// want`コメントで指定された診断とFactが期待どおりであることを確認します。単体ツールとして利用する場合は、`singlechecker`と`multichecker`が、それぞれ1つのアナライザーまたはアナライザー一式のエントリーポイントを提供します。これらの機能により、フレームワークは単一の社内ツールを超えて利用できます。ただし、アナライザーの前提条件と依存関係グラフを依然として検証する必要があります。

より広い重要性は、構成可能性にあります。チームは、既存のドライバーに登録されたアナライザーの一覧へチェッカーを追加するだけで、そのチェッカーを組み込めます。一方、ツール開発者は、さまざまな環境でアナライザーを再利用できます。確認できる根拠が示しているのは、文書化されたインターフェース、例、ドライバーに課された責務です。採用率、性能ベンチマーク、あるいはGoのツールチェーン環境全体がすべて同じ方法でこのフレームワークを実装していることまでは、示していません。