Skip to content

Conversation

@lemonadern
Copy link
Collaborator

@lemonadern lemonadern commented Oct 23, 2025

Summary

uroborosql-fmt にフォーマッタとは独立した lint 基盤を追加しました。
仕組みの最小構成(ルール登録、診断収集、テスト、簡易 CLI)までを今回で整備しています。実装済みルールはサンプル的位置づけで、設計が妥当か見てもらうことを目的にしています。

config 解決の仕組みなどは現状では実装していません。

基本的なアーキテクチャ

Linter は SQL をパース → 全ノードをプリオーダー走査 → ルールの target_kinds に一致したノードへ run_on_node を呼び出すという流れでで作成しています。

ルールは Rule トレイトを実装する構造体として定義し、Rule trait に生えているメソッドをを適宜実装するとエンジン側で呼び出されて実行されるという流れです。

各ルールで検出された違反は Diagnostic (診断)として LintContext が集約します。

ルールの実装イメージ

ルール作者は target_kinds() で監視したい SyntaxKind を宣言し、run_on_node() 内に対象ノードの検査処理を書きます。診断は ctx.report() を呼び出して返します。

サンプルとして以下3つのルールを実装しています:

  • no-distinct
    • SyntaxKind::DISTINCT がある場合に呼び出され、DISTINCT 使用を警告する
  • no-union-distinct
    • SyntaxKind::UNION で呼び出され、、UNION ALL でないパターンの結合であれば警告する
  • too-large-in-list
    • SyntaxKind::in_expr で呼び出され、式の個数を数えて 100 件超なら警告する

テスト

ルールごとにユニットテストを用意し、該当ルールだけ有効化した Lint を通じて単体検証を実施しています。
現状では素直に Rust のテストを使っています。

CLI について

uroborosql-lint-cli を追加しました。設定ファイルは未対応かつファイルは1つ限定です。
fmt のCLI と将来的には統合すると思いますが、まずは別で用意しています。

SQL ファイルを受け取り、診断を stdout に path:line:column: rule_id: message 形式で表示します。
現状はシンプルなテキスト出力で、ハイライトなどのリッチなアノテーションは未作成です。

@ppputtyo
Copy link
Collaborator

ppputtyo commented Oct 31, 2025

現時点ではルールが数個しかないため変更不要ですが、1点高速化案です。

現状は全てのルールでループを回し、全てのノードに対してルールに対応するか判定しているため、 $O(Rules \times Nodes)$ の計算量になっていると思います。

以下のようにすることで計算量を $O(Nodes \times AvgRulesPerKind)$に削減することができると思います。(target_kindsが指定されているルールが多いほど高速になります。)

  1. 各ルールで以下のList、Map作成
    1. 全てのノードに対して実行するルールのList (target_kindsが指定されていないルールはここに格納)
    2. ノードの種別に対してどのルールを実行するかのkeyがノード種別、valueがルールのMap (target_kindsが指定されているルールはここに格納)
  2. nodesを1度だけ走査し、以下実行
    1. 1-iで作成したListを利用して、全てのノードに対して実行するルールを実行
    2. 1-iiで作成したMapを利用して、該当するルールを全て実行

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants