Golang の静的解析に入門する

815 Views

June 07, 24

スライド概要

弊社のサービス開発において、 Golang の静的解析を導入し始めたので、簡単に静的解析の実装方法を説明します。

Golang の場合は、環境が整っているので誰でも簡単に導入できます。ぜひ試してみてください。

profile-image

HireRooは、エンジニア採用のコーディング試験サービスです。🦘エンジニアの技術力を多角的かつ定量的に評価することで、候補者と企業のミスマッチを防ぎます。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Golang の静的解析に入門する @okarin 1

2.

Golang の静的解析に入門する 自己紹介 岡部 京太 @okarin 所属 ● 株式会社ハイヤールー ○ エンジニア募集中!! エンジニアリング領域 ● バックエンド ● 認証・認可 SNS等 ● X: @okarin_dev ● GitHub: @ksrnnb 好きなもの ● ブロッコリー ● ランニング Hireroo Tech Blog Go Conference 2024 当日スタッフとして参加!! 2

3.

Golang の静的解析に入門する なぜ静的解析が必要? ● 同じレビューコメントをしたくない ● 人間がチェックすると見逃す可能性がある 静的解析で機械的にコードの品質を担保! 3

4.

Golang の静的解析に入門する 静的解析ツール作成の流れ ● 対象を決める ○ 今回は Accept interfaces, return structs を遵守するツール ● skeleton を使って雛形コードの生成 ● Analyzer の実装 ● unitchecker をつかって実行する 詳細は Tech Blog を参照 4

5.

Golang の静的解析に入門する skeleton を使って雛形コードの生成 notreturninterface.go $ skeleton github.com/xxxxxxxxx/notreturninterface package notreturninterface import ( "go/ast" ) skeleton を使うと 雛形のコードが自動で生成される 基本的に run 関数を実装するだけで良い "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/analysis/passes/inspect" "golang.org/x/tools/go/ast/inspector" const doc = "notreturninterface is ..." // Analyzer is ... var Analyzer = &analysis.Analyzer{ Name: "notreturninterface", Doc: doc, Run: run, // Analyzer.Run の実行前に Requires の Analyzer が実行される Requires: []*analysis.Analyzer{ inspect.Analyzer, }, } func run(pass *analysis.Pass) (any, error) { // ... } 5

6.

Golang の静的解析に入門する Analyzer の実装 - 1 func run(pass *analysis.Pass) (any, error) { // inspect.Analyzer の結果を利用する inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector) // AST を走査するときにフィルターする Node nodeFilter := []ast.Node{ (*ast.FuncDecl)(nil), } // 深さ優先探索の Preorder 順で走査 inspect.Preorder(nodeFilter, func(n ast.Node) { switch n := n.(type) { // 関数定義の場合 case *ast.FuncDecl: // 戻り値があるかどうかをチェック if n.Type.Results == nil || n.Type.Results.List == nil { return } // ... *inspector.Inspector をつかうと AST を走査して型情報などを調べることができる 6

7.
[beta]
Golang の静的解析に入門する

Analyzer の実装 - 2
inspect.Preorder(nodeFilter, func(n ast.Node) {
switch n := n.(type) {
case *ast.FuncDecl:
// ...
// 戻り値ごとにループ
for _, field := range n.Type.Results.List {
// 型情報の取得
typeExpr := pass.TypesInfo.TypeOf(field.Type)
if typeExpr == nil {
continue
}
// interface かどうかのチェック
if _, ok := typeExpr.Underlying().(*types.Interface); !ok {
continue
}
// TODO: Add allow list and ignore flag
pass.Reportf(n.Pos(), "function %s must not return interface %s, but struct",
n.Name.Name, typeExpr)
}
// ...

戻り値として interface を返している場合はレポートする
7

8.

Golang の静的解析に入門する unitchecker をつかって実行する cmd/notreturninterface/main.go $ go build ./cmd/notreturninterface package main $ go vet -vettool="$(pwd)/notreturninterface" \ -notreturninterface.ignore=SomeInterface \ ./... import ( "github.com/ksrnnb/notreturninterface" ) フラグを使う場合 `${Analyzer.Name}.${flagName}` で指定 unitchecker は go vet 経由でしか実行できないので注意 (multichecker を使えば直接実行できる) "golang.org/x/tools/go/analysis/unitchecker" func main() { unitchecker.Main( notreturninterface.Analyzer, ) } 8

9.

Golang の静的解析に入門する まとめ ● 静的解析を使うと同じレビューコメントをしなくて済む ● 静的解析ツールの自作は意外と簡単! (静的解析の良い学習教材があれば教えてください!) 9