Linter

概要

Linterとは、静的にプログラムを解析するツール。プログラムにおける解析ツールの総称。実行はできるがエラーにつながる書き方をチェックしてくれたり、チームでの書き方を揃えるのに使う。

一般的にはプログラム言語が対象だが、自然言語に対するlint(TextLint)も存在する。プログラム言語それぞれでツールが存在する。

ESLint
JavaScript, TypeScriptにおけるLint
Rubocop
RubyにおけるLint。

Memo

できることの方向性

静的解析によってできることは多い。

  • 特定の書き方を検知する
  • コードの数値化
  • 自動修正
  • 静的解析を助けるメタツール
    • より深い理解につながる

TODO 14. 静的解析とコード生成 - Google Slides

メモ。

静的開発ツール開発の流れ。

flowchart LR

開始 -->|Goファイル| 字句解析
字句解析 -->|トークン| 構文解析
構文解析 -->|抽象構文木| 型チェック
構文解析 -->|抽象構文木| 自作部分
型チェック -->|型情報| 自作部分

20230226004543-H6jQpJeEsi.png

Goにおける静的解析のフェーズ。

  1. 構文解析
  2. 型チェック
  3. 静的単一代入形式
  4. ポインタ解析

言語仕様を読む。

  • 抽象構文木を扱うためにGoの構文に詳しくなる
    • 言語仕様書
    • EBNFを読む
    • 構文を深く理解すれば抽象構文木を自由に扱える
      • どういうノードで構成されているか
      • どういう情報がどういうノードから取得できるか

使い方。

  • Preorderはインターフェース型でフィルタできない
  • ast.Walkは探索アルゴリズムを切り替えるときに使う
    • visitorインターフェースがアルゴリズム部分
  • ノードの置換はApply
  • スコープを取得できる

やること

静的解析で何ができる、の勘所がないのでいくつか作ってみる。ベースがあれば、何かやっているときにひらめくだろう。14. 静的解析とコード生成 - Google Slidesを参考にしている。

  • プライベートだけどタグがついてるフィールドを探す
  • 引数をカウント
  • どこからも呼ばれてないパッケージ関数を見つける
  • どこからも呼ばれてない識別子を見つける
  • int型の式を見つける
  • 名前の短いパッケージ変数を探す
  • コンテキストを構造体に保持しているのを探す
  • サブテストでt.Parallel()を呼び出しているのに親テストで呼び出していないケースを探す
  • knifeを使ってコード生成する
  • 構造体のフィールドのgetter, setterを作る
    • タグがつけられているものだけ
  • GOSSAFUNCを指定してSSA形式を確認する
  • godump ASTとSSAのダンプを行うCLIツール
  • 使われていない引数を探す
  • 自由変数の値を変更しているコードを見つける
  • 関数が呼び出されているか

Tasks

TODO すべての式・文を使用しているかの判定ツール

  • テストで生成する用。いろは歌的にすべてのnodeが登場しているのを確かめる。
  • 学ぶ用。すべてのnodeの例を自分で書いて確かめる用

TODO ast.goを読む

気づいたところを書く。

  • interfaceのNodeは、Pos()とEnd()で構成されている。ファイルでの開始位置、終了位置
  • Nodeには3種類ある
    • Stmt node 文
    • Expr node 式
    • Decl node 定義

Reference

Archives

DONE オリジナルで作ったやつを複数走らせる方法がわからない

unitchecker.Main(trashcomment.Analyzer)
unitchecker.Main(gophersample.Analyzer)

↑だと先に定義した1つ(つまりtrashcomment)しか実行できない。

unitcheckerは引数に複数のAnalyzerを取って実行できる。

unitchecker.Main(trashcomment.Analyzer, gophersample.Analyzer)

DONE 1つオリジナルで実装してみる

無意味なコメントを検知してみる。

DONE 引数をカウントする

引数が超えると警告する。

DONE 配信方法を考える

オリジナルで作ったけど、それらをひとまとめにして簡単に利用できるようにする。1つにインポートしてまとめて、ビルドしてコンテナに入れればいい。

DONE ASTをダンプする方法を探す

よく使うのでツール化する。

DONE コンテキストを構造体に保持しているのを探す

コンテキストを探す。

  1. 構造体である
  2. フィールドの型がそれぞれcontext.Contextでないか調べる
  3. エラーを出す

インターフェースの場合は、型アサーションしないと個別の型にはアクセスできない。そりゃそう。

DONE どこからも呼ばれてない識別子を見つける

どうやってやるのだろう。unusedのコードを調べたが、完全に理解してはいない。識別子はあらゆるパターンで出てきて、それぞれを考慮するのが必要になる。大きく分けると定義か呼び出し。さらに基本型ごとにある。

DONE プライベートだけどタグがついてるフィールドを探す

タグはパブリックでないと意味がない。

  • タグは実行時に参照可能なメタ情報
  • タグ情報はリフレクション経由で取得できる

DONE 式と文をASTで出力する

ひと目でわかるようにする。

interfaceを実装している構造体を一覧で見られれば網羅できるが、調べ方を忘れた。

DONE context検知ツールの修正

自作ツールの考慮にかなり漏れがあるようだ。

を参考に修正する。

  • analysisutilの関数で一発でcontext.Contextを見つけている
  • ResultOfの使い方。なぜident.Mapで型アサーションしているか
  • グローバルに定義されてる場合、エクスポートされてる場合はスルー
  • 変数ではない・フィールドではない・無名関数の場合はスルー
  • ポインタも確認
  • インポートしたものをループで処理

テストでの未考慮が多いところに問題がある。問題があるとわかれば、調べて解決できるだろう。