gocritic は診断・スタイル・パフォーマンスなど幅広いカテゴリの約 100 個のチェックを提供する包括的な Linter です。
解決する問題
Go のコードには、コンパイルは通るが非効率だったり、バグの温床になるパターンが多数存在します。gocritic は単一の Linter で広範なチェックを行い、コードの品質・パフォーマンス・一貫性を総合的に向上させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func process(items []Item) { for _, item := range items { fmt.Println(item.Name) }
if x == 1 { doA() } else if x == 2 { doB() } else if x == 3 { doC() } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| func process(items []Item) { for i := range items { fmt.Println(items[i].Name) }
switch x { case 1: doA() case 2: doB() case 3: doC() } }
|
設定
公式ドキュメント
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| version: "2"
linters: enable: - gocritic settings: gocritic: enabled-tags: - diagnostic - style - performance disabled-checks: - hugeParam - rangeValCopy
|
オプション
タグによる一括設定
| タグ |
説明 |
デフォルト |
diagnostic |
バグや論理エラーの検出 |
有効 |
style |
コードスタイルの一貫性 |
有効 |
performance |
パフォーマンスの最適化 |
有効 |
experimental |
開発中のチェック(誤検知の可能性あり) |
無効 |
opinionated |
好みが分かれるチェック |
無効 |
設定パラメータ
| オプション |
型 |
説明 |
enabled-tags |
[]string |
有効にするタグ |
disabled-tags |
[]string |
無効にするタグ |
enabled-checks |
[]string |
個別に有効にするチェック |
disabled-checks |
[]string |
個別に無効にするチェック |
settings |
map |
各チェックの詳細設定 |
チェック固有の設定例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| linters: settings: gocritic: enabled-tags: - diagnostic - style - performance settings: rangeValCopy: sizeThreshold: 128 hugeParam: sizeThreshold: 256 captLocal: paramsOnly: true
|
主要なチェック
diagnostic(バグ検出)
| チェック |
検出内容 |
appendAssign |
append の結果を別の変数に代入 |
badCond |
常に true/false になる条件式 |
nilValReturn |
nil チェック後に nil を返す |
sloppyReassign |
不要な再代入 |
weakCond |
弱い条件(意図しない部分一致など) |
style(コードスタイル)
| チェック |
検出内容 |
ifElseChain |
switch に置き換え可能な if-else チェーン |
singleCaseSwitch |
case が 1 つだけの switch |
typeAssertChain |
switch に置き換え可能な型アサーションチェーン |
unslice |
不要なスライス操作 s[:] |
paramTypeCombine |
同じ型のパラメータをまとめられる |
| チェック |
検出内容 |
rangeValCopy |
range ループで大きな構造体のコピー |
rangeExprCopy |
range 式の不要なコピー |
hugeParam |
大きな値のパラメータ渡し |
indexAlloc |
不要なインデックスアロケーション |
サンプル
検出例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
func example1(a []int) { b := append(a, 1) _ = b }
func example2(x int) { switch x { case 1: doSomething() } }
func example3(s []int) []int { return s[:] }
func example4(a string, b string) { fmt.Println(a, b) }
|
修正例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func example1(a []int) { a = append(a, 1) _ = a }
func example2(x int) { if x == 1 { doSomething() } }
func example3(s []int) []int { return s }
func example4(a, b string) { fmt.Println(a, b) }
|
注意点
- デフォルトで
diagnostic、style、performance タグが有効。experimental と opinionated は明示的に有効化が必要
enabled-tags と disabled-checks を組み合わせて、タグ単位で有効化しつつ特定チェックを除外するのが一般的
rangeValCopy や hugeParam は sizeThreshold で閾値を調整できる。プロジェクトの構造体サイズに合わせて設定する
- 約 100 個のチェックがあるため、有効なチェックの確認は
GL_DEBUG=gocritic golangci-lint run で確認できる
参考リンク