---
title: Golang の静的解析に入門する
tags:  #開発効率化 #golang  
author: [HireRoo](https://www.docswell.com/user/hireroo)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/DEYGLGXNEM.jpg?width=480
description: 弊社のサービス開発において、 Golang の静的解析を導入し始めたので、簡単に静的解析の実装方法を説明します。  Golang の場合は、環境が整っているので誰でも簡単に導入できます。ぜひ試してみてください。
published: June 07, 24
canonical: https://www.docswell.com/s/hireroo/KLLW6G-golang-static-code-analysis
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/DEYGLGXNEM.jpg)

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


# Page. 2

![Page Image](https://bcdn.docswell.com/page/VJNG4G1V78.jpg)

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


# Page. 3

![Page Image](https://bcdn.docswell.com/page/YE9WQW5VE3.jpg)

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


# Page. 4

![Page Image](https://bcdn.docswell.com/page/GE8NGNY47D.jpg)

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


# Page. 5

![Page Image](https://bcdn.docswell.com/page/LELPGP4V7R.jpg)

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


# Page. 6

![Page Image](https://bcdn.docswell.com/page/4JM4Q4KN7W.jpg)

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


# Page. 7

![Page Image](https://bcdn.docswell.com/page/PJRW8WX479.jpg)

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(), &quot;function %s must not return interface %s, but struct&quot;,
n.Name.Name, typeExpr)
}
// ...
戻り値として interface を返している場合はレポートする
7


# Page. 8

![Page Image](https://bcdn.docswell.com/page/PEXP8P6Z7X.jpg)

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


# Page. 9

![Page Image](https://bcdn.docswell.com/page/3EKDKD1VJD.jpg)

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


