Skip to content

マクロ定義名が識別子として登録される #92

Description

@TwoSquirrels

現象

src/library/identifiers.rscollect_definitions/collect_leaf は、宣言ノードの name/declarator フィールドを型で場合分けせず一律に辿るため、プリプロセッサのマクロ定義 (#define FOO ... / #define FOO(x) ...) もそのマクロ名を「定義識別子」として tags.jsonfiles に記録してしまう。

なぜ無意味な過剰検出と言えるか

  • バンドル時の識別子検出 (detect.rs) は -E でプリプロセスしたの、<file> 由来の行だけを見る。オブジェクト形式マクロ (#define FOO 42) はトークンが現れた時点で必ず展開されるため、FOO という生の識別子がユーザーコード側に残ることはない。
  • 関数形式マクロ (#define REP(i, n) ...) も同様に、REP(...) の形で呼び出せば展開される。「間接的にリネームして ( を伴わず参照すれば展開を逃れるのでは」という仮説も検証したが、プリプロセッサの再走査 (rescanning) により #define MYREP REP 経由でも最終的に REP( として再展開されるため成立しない。

影響

過剰検出自体は risundle の「取りこぼしより過剰検出を優先する」設計方針の範囲内であり、正しさには影響しない (architecture.md の「tree-shaking は過剰検出側に倒す」参照)。実害は次の 2 点のみ:

  • tags.jsonfiles にマクロ名が無駄に混ざり、レコードが肥大化する。
  • risundle library show <id> -v の出力がマクロ名で埋まり、実際の型・関数名を確認する際のノイズになる。

原因: tree-sitter-cpp がプリプロセッサ指令に宣言と同じフィールド名を使っている

tree-sitter-cppnode-types.json を確認すると:

preproc_def          -> ['name', 'value']
preproc_function_def -> ['name', 'parameters', 'value']

プリプロセッサのマクロ定義ノードが、C++ の宣言ノードと同じ name フィールド名を使っている。risundle 側が「宣言ノードは name/declarator を持つ」という規約に一律で乗っかっているのは正当だが、C++ の宣言とは別の文法層であるプリプロセッサ指令にまで同じフィールド名を流用しているのは tree-sitter-cpp の設計であり、risundle の走査ロジックが雑というわけではない。

提案

risundle にはすでに SKIP_DESCENT (降りても C++ の定義が得られないノードを除外する既存のリスト。compound_statement 等) がある。preproc_defpreproc_function_def をこのリストに加えるだけで解決できる。これは「単純さを崩す特別扱いの追加」ではなく、「そもそも C++ の宣言ではないものを対象外にする、既存機構の本来の適用範囲に収める」変更であり、新しい分岐ロジックは増えない。

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    Kind/EnhancementImprove existing functionalityModule: LibraryThe library registration domainPriority/LowThe priority is lowQuick FixFix is obvious and small in scope

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions