staticcheck

Table of Contents

  1. 解決する問題
  2. 設定
  3. オプション
  4. 主要なチェックカテゴリ
    1. SA: 静的解析(バグ検出)
    2. S: コード簡略化
    3. ST: スタイル
    4. QF: クイックフィックス
  5. サンプル
    1. 検出例
    2. 修正例
  6. 注意点
  7. 参考リンク

staticcheck は Go コードの広範な静的解析を行うツールです。バグの検出、非推奨 API の使用、コードの簡略化提案など多岐にわたるチェックを提供します。

解決する問題

go vet だけでは検出できないバグや非効率なコードパターンが数多く存在します。staticcheck は 150 以上のチェックを備え、到達不能コード、非推奨 API の使用、不正な正規表現、不要なコード、パフォーマンス改善の余地などを検出します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Before: staticcheck が検出する問題

func example() {
// SA1000: 不正な正規表現
re := regexp.MustCompile("[invalid")

// SA4003: 常に true になる比較(uint >= 0)
var u uint
if u >= 0 {
fmt.Println("always true")
}

// SA1019: 非推奨の関数
io.ReadAll(strings.NewReader("test")) // Go 1.16 以前の io/ioutil.ReadAll が非推奨
_ = re
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// After: 修正後
func example() {
re := regexp.MustCompile(`[a-z]+`)

var u uint
if u > 0 {
fmt.Println("positive")
}

data, _ := io.ReadAll(strings.NewReader("test"))
_ = re
_ = data
}

設定

公式ドキュメント

1
2
3
4
5
6
7
8
9
10
11
12
# .golangci.yml 設定例
version: "2"

linters:
enable:
- staticcheck
settings:
staticcheck:
checks:
- all
- "-ST1000" # パッケージコメントのチェックを無効化
- "-ST1003" # 命名規則のチェックを無効化

オプション

オプション デフォルト 説明
checks []string [all, -ST1000, -ST1003, -ST1016, -ST1020, -ST1021, -ST1022] 有効化するチェックのリスト。all で全有効化し、- プレフィックスで個別に無効化
initialisms []string [ACL, API, ASCII, ...] イニシャリズムとして扱う単語のリスト
dot-import-whitelist []string [] ドットインポートを許可するパッケージ
http-status-code-whitelist []string [200, 400, 404, 500] マジックナンバーチェックから除外する HTTP ステータスコード

主要なチェックカテゴリ

SA: 静的解析(バグ検出)

チェック 検出内容
SA1000 不正な正規表現
SA1006 Printf に動的な第一引数を渡している
SA1012 nil の context.Context を渡している
SA1019 非推奨の関数・変数・定数の使用
SA2000 sync.WaitGroup.Add がゴルーチン内で呼ばれている
SA4003 常に true/false になる比較
SA4006 代入した値が使われていない
SA4010 *append の結果が使われていない
SA5001 defer 内で Body.Close が呼ばれているがエラーチェック前
SA6005 strings.ToLower で比較する代わりに strings.EqualFold を使うべき
SA9003 空の分岐

S: コード簡略化

チェック 検出内容
S1000 単一ケースの select を使うべき
S1001 for + copy の代わりに copy を使うべき
S1005 不要な _ 代入
S1007 正規表現の raw string 使用を推奨
S1025 fmt.Sprintf("%s", x) の不要な使用
S1028 errors.New(fmt.Sprintf(...)) の代わりに fmt.Errorf を使うべき

ST: スタイル

チェック 検出内容
ST1000 パッケージコメントがない
ST1003 命名規則(MixedCaps)に違反
ST1005 エラー文字列が大文字で始まっている
ST1006 レシーバ名が不適切
ST1008 error が最後の戻り値でない

QF: クイックフィックス

チェック 検出内容
QF1001 if-elseswitch に変換可能
QF1003 if-elsestrings.EqualFold に変換可能
QF1011 冗長な型変換

サンプル

検出例

1
2
3
4
5
6
7
8
9
10
11
12
// SA1019: 非推奨の関数
data, _ := ioutil.ReadAll(resp.Body) // ioutil は Go 1.16 で非推奨

// S1028: fmt.Errorf を使うべき
err := errors.New(fmt.Sprintf("user %s not found", id))

// SA4006: 代入した値が未使用
result, err := fetchData()
result = nil // result に再代入したが使われていない

// ST1005: エラー文字列は小文字で始めるべき
return fmt.Errorf("User not found") // "user not found" にすべき

修正例

1
2
3
4
5
6
7
8
data, _ := io.ReadAll(resp.Body)

err := fmt.Errorf("user %s not found", id)

result, err := fetchData()
_ = result // 使わない場合はブランク識別子

return fmt.Errorf("user not found")

注意点

  • golangci-lint の standard デフォルトセットに含まれている。明示的に有効化しなくてもデフォルトで動作する
  • デフォルトで一部の ST(スタイル)チェックが無効化されている。厳格にするなら checks: [all] で全有効化する
  • GL_DEBUG=staticcheck golangci-lint run --enable=staticcheck で有効なチェックの一覧を確認できる
  • staticcheck は独自の設定ファイル(staticcheck.conf)も持つが、golangci-lint 経由では .golangci.yml 内で設定する

参考リンク