go の学び直し 静的解析編
23時に寝て2時に起きて5時ぐらいにも起きて7時に起きた。昨日は podcast 収録でたくさん話して疲れてしまってそのまま帰ってすぐ寝た。すぐ起きるんだけど。
ストレッチ⌗
今日の開脚幅は開始前157cmで、ストレッチ後159cmだった。朝出かける前に開脚のストレッチしたら数値よくなるかな?と思ってやってみたらいつもより少しよくなった。ストレッチはいつも通りとも言えるし、腰の張りがまだまだ残っていることも確認できた。疲労が溜まっているんよな。毎週ストレッチしているからこの程度の疲労で済んでいるとも思える。お正月に実家から戻ってきてから1月の東京出張と35日は終えた。来週はまた2月の東京出張とその週末に49日がある。ここまで体力がもてばその次の法要は初盆なので少し空く。体力的に第4四半期の山場と言えるかもしれない。ただがんばる。
go の学び直し⌗
Gopher塾 #3 - 静的解析を使ったGoの開発ツール制作 入門編 - DAY 1 に参加した。
過去にも Python とマクロ、インポートフックと抽象構文木 や Java のアノテーションプロセッサを試す など、メタプログラミングのアプローチやコード生成などを実務で使ってきたので静的解析にも関心がある。講義内容の詳細は書かないけど、静的解析のような難しい話題に対して4時間という短い時間でとてもよい講義になっていたと思う。go の静的解析の要点や提供されているツールなどを一通り学ぶことができた。もちろん、実用するには試行錯誤や習熟を必要とするけど、取っ掛かりとして十分な内容に思えた。
skeleton というツールを使って静的解析のための analyzer プロジェクトのひな形を作る。
$ go install github.com/gostaticanalysis/skeleton/v2@latest
$ skeleton myanalyzer
$ tree myanalyzer
myanalyzer
├── cmd
│ └── myanalyzer
│ └── main.go
├── go.mod
├── myanalyzer.go
├── myanalyzer_test.go
└── testdata
└── src
└── a
├── a.go
└── go.mod
意図的にテストが落ちるようになっていてすぐ動作確認できる。
$ go mod tidy
$ go test
--- FAIL: TestAnalyzer (0.05s)
analysistest.go:448: a/a.go:5:6: diagnostic "identifier is gopher" does not match pattern "pattern"
analysistest.go:512: a/a.go:5: no diagnostic was reported matching "pattern"
FAIL
exit status 1
FAIL myanalyzer 0.349s
いろいろ説明を端折るけど、試しに FuncDecl の ast ノードに対して関数の行数をカウントする処理を実装してみた。analysis パッケージの Pass を使うと便利なユーティリティが提供されていて、静的解析をするときに面倒な処理をショートカットできて簡単に実装できることが理解できた。ここで作った analyzer は go vet で実行できるそうなのでプロジェクトの独自ルールを analyzer で実装して ci でチェックするといった運用もできる。応用範囲は広そう。
case *ast.FuncDecl:
fmt.Println(n.Name, n.Pos(), n.End())
start := pass.Fset.Position(n.Pos()).Line
end := pass.Fset.Position(n.End()).Line
fmt.Println("the number of lines:", end-start)