Upgrade to Pro — share decks privately, control downloads, hide ads and more …

go vetのprintf.Analyzerの挙動を追え! - tenntenn Conference 2022

go vetのprintf.Analyzerの挙動を追え! - tenntenn Conference 2022

この資料はtenntenn Conference 2022にて発表を行った際に用いた資料です。

■ tenntenn Conferenceとは
tenntenn Conferenceはtenntennが主催し、そしてすべてのセッションがtenntennによる登壇のカンファレンスです。

イベントページ:https://tenntenn.connpass.com/event/226562/
ハッシュタグ:#tennconn
資料(Googleスライド):https://tenn.in/printf
動画:https://tenn.in/printf-video
再生リスト:https://tenn.in/conn22-videolist

■ 内容
このセッションでは公式の静的解析ツールであるgo vetに含まれるfmt.Printfなどの使い方を調べる解析器(printf.Analyzer)の挙動を解説します。簡単そうに見えますが、実は裏では細かなところまで解析できるように実装されています。go vetはgo testを動かすと実行される身近なツールです。このセッションはそんな身近なツールの実装を見てみるよい機会になります。

・go vet
・printf.Analyzer
・analysis.Fact

■ 登壇者&主催者

・名前:tenntenn / 上田拓也
・HP:https://tenntenn.dev
・Twitter:https://twitter.com/tenntenn

メルカリ/メルペイ所属。バックエンドエンジニアとして日々Goを書いている。Google Developer Expert (Go)。一般社団法人Gophers Japan代表。Go Conference主催者。大学時代にGoに出会い、それ以来のめり込む。人類をGopherにしたいと考え、Goの普及に取り組んでいる。複数社でGoに関する技術アドバイザーをしている。マスコットのGopherの絵を描くのも好き。

■ Gopher道場 自習室

https://gopherdojo.org/studyroom/

Gopher道場とは、実践的なGoを体系的に学べる場です。
Gopher道場 自習室では、以下のようなコンテンツや学びの場を提供します。

・Gopher道場の講義を録画した動画(10時間以上分)
・Slackにおける受講者同士のコミュニティ
・Gopher道場卒業生による課題のレビュー(ボランティアでご協力頂いているのでベストエフォートです)

■ Meety(カジュアル面談)

・ソフトウェアエンジニアの地方移住ってどうなの?:https://meety.net/matches/jyZgDkEEwmMk
・メルカリグループにおけるGoの使いどころ:https://meety.net/matches/LbeVbIACxLqk
・地方からの技術コミュニティへの貢献:https://meety.net/matches/gVeMtImLkWJE

■ お仕事の依頼について

副業にて技術顧問やアドバイザーなどを行っています。過去の実績や問い合わせフォームは以下のURLからご確認ください。
https://tenntenn.dev/ja/job/

#golang #tenntenn #tennconn #Go言語

tenntenn - Takuya Ueda

January 15, 2022
Tweet

More Decks by tenntenn - Takuya Ueda

Other Decks in Programming

Transcript

  1. The Go gopher was designed by Renée French. The gopher

    stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license. go vetのprintf.Analyzer の挙動を追え! 2022/01/15(土) tenntenn Conference 2022 資料:https://tenn.in/printf 動画:https://tenn.in/printf-video
  2. 上田拓也 Go ビギナーズ
 Go Conference
 @tenntenn tenntenn.dev Google Developer Expert

    (Go) 一般社団法人 Gophers Japan 代表理事 Experts Team
  3. go vetとは? ▪ 標準の静的解析ツール • コンパイラでは発見できないバグを見つける • go testを走らせれば自動で実行される(Go1.10から) •

    The Go Playgroundでも実行される ◦ go.dev/playでは実行されなくなった! 参考:14. 静的解析とコード生成 - プログラミング言語Go完全入門
  4. printfパッケージ ▪ printf系の関数の使い方をチェックする • printf.Analyzerを提供 • ラッパーでも指摘する! package main import

    "fmt" func main() { fmt.Printf("%s\n", 100) } Playgroundで動かす %sなのに数値が渡されている
  5. Factの設定 ▪ analysis.Analyzer型のFactTypesフィールドに設定 • 型が分かれば十分 • FactはGobでシリアライズされる 11 type Analyzer

    struct { /* 略 */ // インポートまたはエクスポートするFact(型情報が必要) // 要素はポインタである必要がある FactTypes []Fact }
  6. Factのエクスポート ▪ analysis.Pass型のフィールドからエクスポート 12 type Pass struct { /* 略

    */ // オブジェクトに関連付けられたFactをエクスポートする // 第2引数に渡す具象型の値はポインタである必要がある // スレッドセーフではない ExportObjectFact func(obj types.Object, fact Fact) // パッケージに関連付けられたFactをエクスポートする // 他の挙動はExportObjectFactと同じ ExportPackageFact func(fact Fact) }
  7. Factのインポート ▪ analysis.Pass型のフィールドからインポート 13 type Pass struct { /* 略

    */ // オブジェクトに関連付けられたFactをインポートする // 第2引数に渡す具象型の値はポインタである必要がある // Factを満たす場合はインポートした値を // 第2引数で渡したポインタが指す先に代入 // スレッドセーフではない ImportObjectFact func(obj types.Object, fact Fact) bool // パッケージに関連付けられたFactをインポートする // 他の挙動はImportObjectFactと同じ ImportPackageFact func(pkg *types.Package, fact Fact) bool }
  8. Factを使った解析 ▪ 依存するパッケージもすべて解析対象になる • analysis.Analyzer型のFactTypesフィールドがnilじゃない場合 • importしているパッケージにもRunフィールドの関数を適用 ◦ Factを使ってない場合はimportしているパッケージは対象外 •

    FactはGobでシリアライズされる 14 ドライバー go vet, goplz 静的解析ツール unitchecker.Main パッケージ1 実行 解析 静的解析ツール unitchecker.Main 静的解析ツール unitchecker.Main パッケージ2 解析 パッケージ3 解析 Fact Fact Gob Export Export Import import "pkg1" import "pkg2"
  9. Factの利用例 15 ▪ x/tools/go/analysis/passes/printfパッケージ • go vetの中で使われているAnalyzerを定義している • printf系の関数をラップしているかどうかを表すFactを定義している •

    importしているパッケージも対象として解析ができる type isWrapper struct{ Kind Kind } func (f *isWrapper) AFact() {} func (f *isWrapper) String() string { switch f.Kind { case KindPrintf: return "printfWrapper" case KindPrint: return "printWrapper" case KindErrorf: return "errorfWrapper" default: return "unknownWrapper" } }