Skip to main content

libperl_macrogen/
macro_infer.rs

1//! マクロ型推論エンジン
2//!
3//! マクロ定義から型情報を推論するためのモジュール。
4//! ExprId を活用し、複数ソースからの型制約を収集・管理する。
5
6use std::collections::{HashMap, HashSet};
7
8use crate::apidoc::ApidocDict;
9use crate::apidoc_patches::ApidocPatchSet;
10use crate::ast::{AssertKind, BlockItem, Expr, ExprKind};
11use crate::c_fn_decl::CFnDeclDict;
12use crate::fields_dict::FieldsDict;
13use crate::inline_fn::InlineFnDict;
14use crate::intern::{InternedStr, StringInterner};
15use crate::macro_def::{MacroDef, MacroKind, MacroTable};
16use crate::parser::{
17    parse_expression_from_tokens_ref_with_stats,
18    parse_expression_from_tokens_ref_with_generic_params,
19    parse_statement_from_tokens_ref_with_stats,
20    parse_statement_from_tokens_ref_with_generic_params,
21    parse_block_items_from_tokens_ref_with_stats,
22    parse_block_items_from_tokens_ref_with_generic_params,
23    ParseStats,
24};
25use crate::rust_decl::RustDeclDict;
26use crate::semantic::SemanticAnalyzer;
27use crate::preprocessor::Preprocessor;
28use crate::source::FileRegistry;
29use crate::token::{Token, TokenKind};
30use crate::type_env::{TypeConstraint, TypeEnv};
31use crate::type_repr::TypeRepr;
32
33// use std::io;
34// use crate::SexpPrinter;
35
36/// 展開を抑制するマクロシンボル
37///
38/// これらのマクロは展開せずに AST に関数呼び出しとして残す。
39/// パターン検出(SvANY)や特殊処理(assert)に使用。
40#[derive(Debug, Clone, Copy)]
41pub struct NoExpandSymbols {
42    /// assert マクロ
43    pub assert: InternedStr,
44    /// assert_ マクロ(Perl 独自)
45    pub assert_: InternedStr,
46}
47
48impl NoExpandSymbols {
49    /// 新しい NoExpandSymbols を作成
50    pub fn new(interner: &mut StringInterner) -> Self {
51        Self {
52            assert: interner.intern("assert"),
53            assert_: interner.intern("assert_"),
54        }
55    }
56
57    /// 全シンボルをイテレート
58    pub fn iter(&self) -> impl Iterator<Item = InternedStr> {
59        [self.assert, self.assert_].into_iter()
60    }
61}
62
63/// 明示的に展開するマクロのシンボル
64///
65/// `preserve_function_macros` モードで展開対象となるマクロ。
66/// これらは単純なフィールドアクセスや `__builtin_expect` ラッパーなので、
67/// インライン展開した方が効率的。
68#[derive(Debug, Clone, Copy)]
69pub struct ExplicitExpandSymbols {
70    /// SvANY マクロ(sv->sv_any に展開)
71    pub sv_any: InternedStr,
72    /// SvFLAGS マクロ(sv->sv_flags に展開)
73    pub sv_flags: InternedStr,
74    /// CvFLAGS マクロ(cv->sv_flags に展開、CV 用)
75    pub cv_flags: InternedStr,
76    /// HEK_FLAGS マクロ(hek->hek_flags に展開)
77    pub hek_flags: InternedStr,
78    /// EXPECT マクロ(__builtin_expect のラッパー)
79    pub expect: InternedStr,
80    /// LIKELY マクロ(__builtin_expect(cond, 1) のラッパー)
81    pub likely: InternedStr,
82    /// UNLIKELY マクロ(__builtin_expect(cond, 0) のラッパー)
83    pub unlikely: InternedStr,
84    /// cBOOL マクロ(条件を bool に変換)
85    pub cbool: InternedStr,
86    /// __ASSERT_ マクロ(DEBUGGING 時のアサーション)
87    pub assert_underscore_: InternedStr,
88    /// STR_WITH_LEN マクロ(文字列リテラルと長さのペア)
89    pub str_with_len: InternedStr,
90    /// ASSERT_IS_LITERAL マクロ(`("" x "")` の literal-only assert、
91    /// 5.36+ の STR_WITH_LEN が使用。意味的には identity なので展開し、
92    /// パーサの隣接文字列連結還元で `x` に潰す)
93    pub assert_is_literal: InternedStr,
94    /// INT2PTR マクロ(整数からポインタへのキャスト)
95    pub int2ptr: InternedStr,
96    /// assert_not_ROK マクロ(assert_ ラッパー)
97    pub assert_not_rok: InternedStr,
98    /// assert_not_glob マクロ(assert_ ラッパー)
99    pub assert_not_glob: InternedStr,
100    /// MUTABLE_PTR マクロ(identity キャスト)
101    pub mutable_ptr: InternedStr,
102}
103
104impl ExplicitExpandSymbols {
105    /// 新しい ExplicitExpandSymbols を作成
106    pub fn new(interner: &mut StringInterner) -> Self {
107        Self {
108            sv_any: interner.intern("SvANY"),
109            sv_flags: interner.intern("SvFLAGS"),
110            cv_flags: interner.intern("CvFLAGS"),
111            hek_flags: interner.intern("HEK_FLAGS"),
112            expect: interner.intern("EXPECT"),
113            likely: interner.intern("LIKELY"),
114            unlikely: interner.intern("UNLIKELY"),
115            cbool: interner.intern("cBOOL"),
116            assert_underscore_: interner.intern("__ASSERT_"),
117            str_with_len: interner.intern("STR_WITH_LEN"),
118            assert_is_literal: interner.intern("ASSERT_IS_LITERAL"),
119            int2ptr: interner.intern("INT2PTR"),
120            assert_not_rok: interner.intern("assert_not_ROK"),
121            assert_not_glob: interner.intern("assert_not_glob"),
122            mutable_ptr: interner.intern("MUTABLE_PTR"),
123        }
124    }
125
126    /// 全シンボルをイテレート
127    ///
128    /// 注: `mutable_ptr` は含めない。MUTABLE_PTR をインライン展開すると
129    /// `MUTABLE_SV(p)` 等の本体が `((SV*)({void*p_=(p);p_;}))` になり、
130    /// identity StmtExpr 越しに外側キャストがパラメータへ逆伝播して
131    /// `p: *mut SV` に狭まる (SAVECOMPPAD 等の呼び出し側で型不一致)。
132    /// 呼び出しとして保存すれば `MUTABLE_PTR(p: *mut c_void)` の引数制約から
133    /// `p: *mut c_void` が正しく付き、呼び出し側は cast_arg_syn_if_needed が
134    /// `as *mut c_void` を挿す。
135    pub fn iter(&self) -> impl Iterator<Item = InternedStr> {
136        [
137            self.sv_any,
138            self.sv_flags,
139            self.cv_flags,
140            self.hek_flags,
141            self.expect,
142            self.likely,
143            self.unlikely,
144            self.cbool,
145            self.assert_underscore_,
146            self.str_with_len,
147            self.assert_is_literal,
148            self.int2ptr,
149            self.assert_not_rok,
150            self.assert_not_glob,
151        ].into_iter()
152    }
153}
154
155/// マクロのパース結果
156#[derive(Debug, Clone)]
157pub enum ParseResult {
158    /// 式としてパース成功
159    Expression(Box<Expr>),
160    /// 文としてパース成功
161    Statement(Vec<BlockItem>),
162    /// パース不能(エラーメッセージ付き)
163    Unparseable(Option<String>),
164}
165
166// ============================================================================
167// MacroAst: マクロの AST 表現(パラメータ情報付き)
168// ============================================================================
169
170/// マクロパラメータの AST 表現
171///
172/// 各パラメータは `Expr` として表現され、固有の `ExprId` を持つ。
173/// これにより、パラメータの型制約も `expr_constraints` に統一的に格納できる。
174#[derive(Debug, Clone)]
175pub struct MacroParam {
176    /// パラメータ名
177    pub name: InternedStr,
178    /// パラメータを表す Expr(ExprKind::Ident を持つ)
179    pub expr: Expr,
180}
181
182impl MacroParam {
183    /// 新しい MacroParam を作成
184    pub fn new(name: InternedStr, loc: crate::source::SourceLocation) -> Self {
185        Self {
186            name,
187            expr: Expr::new(ExprKind::Ident(name), loc),
188        }
189    }
190
191    /// パラメータの ExprId を取得
192    pub fn expr_id(&self) -> crate::ast::ExprId {
193        self.expr.id
194    }
195}
196
197/// 推論状態
198#[derive(Debug, Clone, Copy, PartialEq, Eq)]
199pub enum InferStatus {
200    /// 未処理
201    Pending,
202    /// 全ての型が確定
203    TypeComplete,
204    /// 一部の型が未確定
205    TypeIncomplete,
206    /// 型推論不能
207    TypeUnknown,
208}
209
210impl Default for InferStatus {
211    fn default() -> Self {
212        Self::Pending
213    }
214}
215
216/// apidoc からリテラル文字列パラメータを収集
217///
218/// `"..."` 形式の引数を持つパラメータを記録する。
219fn collect_literal_string_params(entry: &crate::apidoc::ApidocEntry, info: &mut MacroInferInfo) {
220    use crate::apidoc::ApidocEntry;
221
222    for (i, arg) in entry.args.iter().enumerate() {
223        if ApidocEntry::is_literal_string_keyword(&arg.ty) {
224            info.literal_string_params.insert(i);
225        }
226    }
227}
228
229/// apidoc からジェネリック型パラメータを収集
230///
231/// `type` や `cast` キーワードを持つパラメータをジェネリック型として扱う。
232fn collect_generic_params(entry: &crate::apidoc::ApidocEntry, info: &mut MacroInferInfo) {
233    use crate::apidoc::ApidocEntry;
234
235    const PARAM_NAMES: [char; 7] = ['T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
236    let mut param_idx = 0;
237
238    // パラメータの type/cast を収集
239    for (i, arg) in entry.args.iter().enumerate() {
240        if ApidocEntry::is_type_param_keyword(&arg.ty) {
241            if param_idx < PARAM_NAMES.len() {
242                let name = PARAM_NAMES[param_idx].to_string();
243                info.generic_type_params.insert(i as i32, name);
244                param_idx += 1;
245            }
246        }
247    }
248
249    // 戻り値型の type/cast を収集
250    if entry.returns_type_param() {
251        // 最初のパラメータの type と同じ場合は同じ名前を使う
252        // (NUM2PTR のように戻り値型とパラメータの type が同じ場合)
253        let name = if let Some(first_name) = info.generic_type_params.get(&0) {
254            first_name.clone()
255        } else if param_idx < PARAM_NAMES.len() {
256            PARAM_NAMES[param_idx].to_string()
257        } else {
258            "T".to_string()
259        };
260        info.generic_type_params.insert(-1, name); // -1 = return type
261    }
262}
263
264/// マクロの型推論情報
265#[derive(Debug, Clone)]
266pub struct MacroInferInfo {
267    /// マクロ名
268    pub name: InternedStr,
269    /// ターゲットマクロかどうか
270    pub is_target: bool,
271    /// マクロ本体にトークンがあるかどうか
272    pub has_body: bool,
273    /// 関数形式マクロかどうか
274    pub is_function: bool,
275
276    /// このマクロが使用する他のマクロ(def-use 関係)
277    pub uses: HashSet<InternedStr>,
278    /// このマクロを使用するマクロ(use-def 関係)
279    pub used_by: HashSet<InternedStr>,
280
281    /// THX 依存(aTHX, tTHX, my_perl を含む)
282    pub is_thx_dependent: bool,
283
284    /// トークン連結 (##) を含む(推移的)
285    pub has_token_pasting: bool,
286
287    /// パラメータリスト(各パラメータは ExprId を持つ)
288    pub params: Vec<MacroParam>,
289
290    /// パース結果
291    pub parse_result: ParseResult,
292
293    /// 型環境(収集された型制約)
294    pub type_env: TypeEnv,
295
296    /// 引数の型推論状態
297    pub args_infer_status: InferStatus,
298
299    /// 戻り値の型推論状態
300    pub return_infer_status: InferStatus,
301
302    /// ジェネリック型パラメータ情報
303    ///
304    /// apidoc で `type` や `cast` として宣言されたパラメータは、
305    /// Rust のジェネリック型パラメータとして扱う。
306    /// key: パラメータインデックス(-1 は戻り値型)
307    /// value: 型パラメータ名 ("T", "U", etc.)
308    pub generic_type_params: HashMap<i32, String>,
309
310    /// リテラル文字列パラメータのインデックス集合
311    ///
312    /// apidoc で `"..."` 形式の引数として宣言されたパラメータ。
313    /// Rust では `&str` 型として出力する。
314    pub literal_string_params: HashSet<usize>,
315
316    /// 関数呼び出しの数(パース時に検出)
317    pub function_call_count: usize,
318    /// ポインタデリファレンスの数(パース時に検出)
319    pub deref_count: usize,
320
321    /// 呼び出される関数名の集合(マクロ以外の関数呼び出し)
322    pub called_functions: HashSet<InternedStr>,
323    /// 利用不可関数の呼び出しを含む(直接または推移的)
324    pub calls_unavailable: bool,
325    /// apidoc patches / skip-list で skip_codegen 指定された対象自身か
326    ///
327    /// 直接の skip 対象にしか立てない。伝播では `is_unavailable_for_codegen()`
328    /// で `calls_unavailable` と OR を取って参照する。
329    pub apidoc_suppressed: bool,
330    /// apidoc 戻り値型が `pair` (カンマ式で複数値を返す) のマクロか。
331    /// 単一の戻り値を持つ Rust 関数に落とせないため codegen 対象外にする
332    /// (STR_WITH_LEN 等。doc/plan/skip-pair-return-type-macros.md Step 1)。
333    pub pair_return: bool,
334
335    // ── Phase 2 確定型(resolve_param_and_return_types で設定)──
336
337    /// パラメータの確定型(Rust 型文字列)
338    pub resolved_param_types: Vec<String>,
339
340    /// 戻り値の確定型(Rust 型文字列)
341    pub resolved_return_type: Option<String>,
342
343    /// ポインタパラメータの const 位置集合
344    pub const_pointer_positions: HashSet<usize>,
345
346    /// bool を返すマクロか(依存順解析で確定)
347    pub is_bool_return: bool,
348
349    /// Statement 本体が Rust fn として表現できない要素を含む:
350    /// ローカル宣言 (BlockItem::Decl — fn 内に落としても無意味) や、
351    /// typedef 名を値として使う式 (dTHXa 等の宣言マクロの誤パース跡)。
352    /// これが立っている場合は Statement 確定 (= fn 生成) を行わない。
353    pub stmt_unrepresentable: bool,
354
355    /// Phase 2 の名前使用解析 (mut 必要性 / 未使用 / 代入前 AddrOf)。
356    /// analyze_all_macros で設定し、Phase 3 は読むだけ (GH #16/#22/#23)
357    pub local_usage: Option<crate::local_usage::LocalUsageAnalysis>,
358}
359
360impl MacroInferInfo {
361    /// 新しい MacroInferInfo を作成
362    pub fn new(name: InternedStr) -> Self {
363        Self {
364            name,
365            is_target: false,
366            has_body: false,
367            is_function: false,
368            uses: HashSet::new(),
369            used_by: HashSet::new(),
370            is_thx_dependent: false,
371            has_token_pasting: false,
372            params: Vec::new(),
373            parse_result: ParseResult::Unparseable(None),
374            type_env: TypeEnv::new(),
375            args_infer_status: InferStatus::Pending,
376            return_infer_status: InferStatus::Pending,
377            generic_type_params: HashMap::new(),
378            literal_string_params: HashSet::new(),
379            function_call_count: 0,
380            deref_count: 0,
381            called_functions: HashSet::new(),
382            calls_unavailable: false,
383            apidoc_suppressed: false,
384            pair_return: false,
385            resolved_param_types: Vec::new(),
386            resolved_return_type: None,
387            const_pointer_positions: HashSet::new(),
388            is_bool_return: false,
389            stmt_unrepresentable: false,
390            local_usage: None,
391        }
392    }
393
394    /// unsafe 操作を含むか
395    pub fn has_unsafe_ops(&self) -> bool {
396        self.function_call_count > 0 || self.deref_count > 0
397    }
398
399    /// 出力可否の総合判定
400    ///
401    /// `calls_unavailable`(不在関数を呼ぶ/推移的)または
402    /// `apidoc_suppressed`(自分が skip_codegen 対象)のいずれかが立っていれば
403    /// codegen 対象外。propagation や cascade 検査ではこのヘルパーを使う。
404    ///
405    /// 注意: `pair_return` はここに **含めない**。pair マクロは caller 側で
406    /// トークン展開されて消えるのが通常で (newSVpvs → STR_WITH_LEN 等)、
407    /// used_by (= `uses`) 経由の伝播に乗せると展開済みの caller まで
408    /// 巻き添えになる。fn 生成の抑止は Phase 3 の pair_return 分岐、
409    /// AST 呼び出しが残った caller の降格は check_function_availability の
410    /// called_functions 検査が担う。
411    pub fn is_unavailable_for_codegen(&self) -> bool {
412        self.calls_unavailable || self.apidoc_suppressed
413    }
414
415    /// パラメータ名から対応する ExprId を検索
416    pub fn find_param_expr_id(&self, name: InternedStr) -> Option<crate::ast::ExprId> {
417        self.params.iter()
418            .find(|p| p.name == name)
419            .map(|p| p.expr_id())
420    }
421
422    /// 引数と戻り値の両方が確定しているか
423    pub fn is_fully_confirmed(&self) -> bool {
424        self.args_infer_status == InferStatus::TypeComplete
425            && self.return_infer_status == InferStatus::TypeComplete
426    }
427
428    /// 使用するマクロを追加
429    pub fn add_use(&mut self, used_macro: InternedStr) {
430        self.uses.insert(used_macro);
431    }
432
433    /// 使用されるマクロを追加
434    pub fn add_used_by(&mut self, user_macro: InternedStr) {
435        self.used_by.insert(user_macro);
436    }
437
438    /// パース結果が式かどうか
439    pub fn is_expression(&self) -> bool {
440        matches!(self.parse_result, ParseResult::Expression(_))
441    }
442
443    /// パース結果が文かどうか
444    pub fn is_statement(&self) -> bool {
445        matches!(self.parse_result, ParseResult::Statement(_))
446    }
447
448    /// パース可能かどうか
449    pub fn is_parseable(&self) -> bool {
450        !matches!(self.parse_result, ParseResult::Unparseable(_))
451    }
452
453    /// マクロの戻り値型を取得
454    ///
455    /// 1. return_constraints があればそれを使用
456    /// 2. 式マクロの場合、ルート式の型制約を使用
457    pub fn get_return_type(&self) -> Option<&crate::type_repr::TypeRepr> {
458        // return_constraints とルート式制約の両方から、
459        // Tier ベースで最高確度の制約を選択
460        let mut best: Option<(&crate::type_repr::TypeRepr, u8)> = None;
461
462        // return_constraints (apidoc 由来等)
463        for c in &self.type_env.return_constraints {
464            let tier = c.ty.confidence_tier();
465            if best.is_none() || tier < best.unwrap().1 {
466                best = Some((&c.ty, tier));
467            }
468        }
469
470        // 式マクロの場合、ルート式の制約も候補に
471        if let ParseResult::Expression(ref expr) = self.parse_result {
472            if let Some(constraints) = self.type_env.get_expr_constraints(expr.id) {
473                for c in constraints {
474                    let tier = c.ty.confidence_tier();
475                    if best.is_none() || tier < best.unwrap().1 {
476                        best = Some((&c.ty, tier));
477                    }
478                }
479            }
480        }
481
482        best.map(|(ty, _)| ty)
483    }
484
485    /// 複数文マクロで、全パラメータに型制約が集まっているか。
486    ///
487    /// Statement マクロの戻り値は定義上 `()` なので、ルート式の型制約
488    /// (Expression マクロの確定根拠) は存在しない。代わりに「引数側の
489    /// 制約が揃っていること」を確定条件にする (PAD_SET_CUR_NOSAVE 等)。
490    /// 制約の無いパラメータが残るものは従来どおり未確定に落とし、
491    /// `/* unknown */` 型のまま fn を emit してしまう事故を防ぐ。
492    pub fn is_statement_with_resolvable_params(&self) -> bool {
493        !self.stmt_unrepresentable
494            && matches!(self.parse_result, ParseResult::Statement(_))
495            && self.params.iter().all(|p| {
496                self.type_env.param_constraints.contains_key(&p.name)
497                    || self
498                        .type_env
499                        .param_to_exprs
500                        .get(&p.name)
501                        .is_some_and(|ids| {
502                            ids.iter()
503                                .any(|id| self.type_env.expr_constraints.contains_key(id))
504                        })
505            })
506    }
507}
508
509/// マクロ型推論コンテキスト
510///
511/// 全マクロの型推論を管理する。
512pub struct MacroInferContext {
513    /// マクロ名 → 推論情報
514    pub macros: HashMap<InternedStr, MacroInferInfo>,
515
516    /// 型確定済みマクロ
517    pub confirmed: HashSet<InternedStr>,
518
519    /// 型未確定マクロ
520    pub unconfirmed: HashSet<InternedStr>,
521
522    /// 型推論不能マクロ
523    pub unknown: HashSet<InternedStr>,
524
525    /// デバッグ対象マクロ名(文字列)
526    pub debug_macros: HashSet<String>,
527
528    /// 確定済みマクロのパラメータ型キャッシュ
529    /// マクロ名 → [(パラメータ名, 型文字列)]
530    /// ネストしたマクロ呼び出しからの型伝播に使用
531    pub macro_param_types: HashMap<String, Vec<(String, String)>>,
532
533    /// apidoc_patches の return_type_override が当たっている名前の集合。
534    /// これらの apidoc 戻り値制約は手書き修正なので PatchOverride source
535    /// (Tier 0) を与え、callee 伝播 (Tier 1) にも勝たせる (GH #15 AvFILL)
536    pub return_override_names: HashSet<InternedStr>,
537}
538
539impl MacroInferContext {
540    /// 新しいコンテキストを作成
541    pub fn new() -> Self {
542        Self {
543            macros: HashMap::new(),
544            confirmed: HashSet::new(),
545            unconfirmed: HashSet::new(),
546            unknown: HashSet::new(),
547            debug_macros: HashSet::new(),
548            macro_param_types: HashMap::new(),
549            return_override_names: HashSet::new(),
550        }
551    }
552
553    /// デバッグ対象マクロを設定
554    pub fn set_debug_macros(&mut self, macros: impl IntoIterator<Item = String>) {
555        self.debug_macros = macros.into_iter().collect();
556    }
557
558    /// マクロがデバッグ対象かどうか
559    pub fn is_debug_target(&self, name: &str) -> bool {
560        self.debug_macros.contains(name)
561    }
562
563    /// マクロ情報を登録
564    pub fn register(&mut self, info: MacroInferInfo) {
565        let name = info.name;
566        self.macros.insert(name, info);
567    }
568
569    /// マクロ情報を取得
570    pub fn get(&self, name: InternedStr) -> Option<&MacroInferInfo> {
571        self.macros.get(&name)
572    }
573
574    /// マクロ情報を可変で取得
575    pub fn get_mut(&mut self, name: InternedStr) -> Option<&mut MacroInferInfo> {
576        self.macros.get_mut(&name)
577    }
578
579    /// apidoc skip_codegen を `apidoc_suppressed` フラグに反映
580    ///
581    /// `patches.skip_codegen` の各エントリ名を interner で解決し、
582    /// 該当するマクロが見つかれば `info.apidoc_suppressed = true` を立てる。
583    /// マッチしたマクロ数を返す(インライン関数側のマッチは
584    /// `InlineFnDict::apply_apidoc_suppressions` が別途扱う)。
585    pub fn apply_apidoc_suppressions(
586        &mut self,
587        patches: &ApidocPatchSet,
588        interner: &StringInterner,
589    ) -> usize {
590        let mut count = 0usize;
591        for name_str in patches.skip_codegen.keys() {
592            if let Some(interned) = interner.lookup(name_str) {
593                if let Some(info) = self.macros.get_mut(&interned) {
594                    info.apidoc_suppressed = true;
595                    count += 1;
596                }
597            }
598        }
599        count
600    }
601
602    /// def-use 関係を構築
603    ///
604    /// 各マクロの uses 情報から used_by を逆引きで構築する。
605    pub fn build_use_relations(&mut self) {
606        // まず uses 情報を収集
607        let use_pairs: Vec<(InternedStr, InternedStr)> = self
608            .macros
609            .iter()
610            .flat_map(|(user, info)| {
611                info.uses
612                    .iter()
613                    .map(move |used| (*user, *used))
614            })
615            .collect();
616
617        // used_by を設定
618        for (user, used) in use_pairs {
619            if let Some(used_info) = self.macros.get_mut(&used) {
620                used_info.add_used_by(user);
621            }
622        }
623    }
624
625    /// 初期分類を行う
626    ///
627    /// 各マクロの状態に基づいて confirmed/unconfirmed/unknown に分類する。
628    pub fn classify_initial(&mut self) {
629        for (name, info) in &self.macros {
630            if info.is_fully_confirmed() {
631                self.confirmed.insert(*name);
632            } else if info.args_infer_status == InferStatus::TypeUnknown
633                || info.return_infer_status == InferStatus::TypeUnknown
634            {
635                self.unknown.insert(*name);
636            } else {
637                self.unconfirmed.insert(*name);
638            }
639        }
640    }
641
642    /// 推論候補を取得
643    ///
644    /// 未確定マクロのうち、使用するマクロが全て確定済みのものを返す。
645    /// 使用マクロ数の少ない順にソート。
646    pub fn get_inference_candidates(&self) -> Vec<InternedStr> {
647        let mut candidates: Vec<_> = self
648            .unconfirmed
649            .iter()
650            .filter(|name| {
651                if let Some(info) = self.macros.get(name) {
652                    // 使用するマクロが全て confirmed に含まれているか
653                    info.uses.iter().all(|used| {
654                        self.confirmed.contains(used) || !self.macros.contains_key(used)
655                    })
656                } else {
657                    false
658                }
659            })
660            .copied()
661            .collect();
662
663        // 使用マクロ数でソート。第2キーに InternedStr (intern 順) を使い、
664        // HashSet 由来の順序揺れを排除する — 確定順が揺れると
665        // param_types_cache の内容が変わり、生成コードが run ごとに揺れる。
666        candidates.sort_by_key(|name| {
667            (
668                self.macros
669                    .get(name)
670                    .map(|info| info.uses.len())
671                    .unwrap_or(0),
672                *name,
673            )
674        });
675
676        candidates
677    }
678
679    /// マクロを確定済みに移動
680    pub fn mark_confirmed(&mut self, name: InternedStr) {
681        self.unconfirmed.remove(&name);
682        self.confirmed.insert(name);
683        if let Some(info) = self.macros.get_mut(&name) {
684            info.args_infer_status = InferStatus::TypeComplete;
685            info.return_infer_status = InferStatus::TypeComplete;
686        }
687    }
688
689    /// マクロのパラメータ型をキャッシュに保存
690    ///
691    /// ネストしたマクロ呼び出しからの型伝播に使用される。
692    /// `mark_confirmed` の後に呼び出す。
693    pub fn cache_param_types(&mut self, name: InternedStr, interner: &StringInterner) {
694        let mut temp_cache = HashMap::new();
695        self.cache_param_types_to(name, interner, &mut temp_cache);
696        self.macro_param_types.extend(temp_cache);
697    }
698
699    /// パラメータ型を外部キャッシュに保存
700    pub fn cache_param_types_to(
701        &self,
702        name: InternedStr,
703        interner: &StringInterner,
704        cache: &mut HashMap<String, Vec<(String, String)>>,
705    ) {
706        let info = match self.macros.get(&name) {
707            Some(info) => info,
708            None => return,
709        };
710
711        let macro_name = interner.get(name).to_string();
712        let mut param_types = Vec::new();
713
714        for param in &info.params {
715            let param_name = interner.get(param.name).to_string();
716
717            // パラメータの型を取得(param_to_exprs 経由)
718            let type_str = if let Some(expr_ids) = info.type_env.param_to_exprs.get(&param.name) {
719                // 非 void 制約のうち最も確度の高い (tier 最小) ものを使用。
720                // 「最初に見つかったもの」だと symbol lookup (tier 4) が
721                // apidoc/コールサイト由来 (tier ≤ 3) を覆い隠し、伝播先の
722                // マクロが誤った型 (例: PADLIST 値渡し) を継承してしまう。
723                let mut best: Option<(&crate::type_repr::TypeRepr, u8)> = None;
724                for expr_id in expr_ids {
725                    if let Some(constraints) = info.type_env.expr_constraints.get(expr_id) {
726                        for c in constraints {
727                            if c.ty.is_void() {
728                                continue;
729                            }
730                            let tier = c.ty.confidence_tier();
731                            if best.is_none() || tier < best.unwrap().1 {
732                                best = Some((&c.ty, tier));
733                            }
734                        }
735                    }
736                }
737                best.map(|(ty, _)| ty.to_rust_string(interner))
738            } else {
739                // フォールバック: param.expr の ExprId から取得
740                let expr_id = param.expr_id();
741                info.type_env.expr_constraints.get(&expr_id)
742                    .and_then(|constraints| constraints.first())
743                    .map(|c| c.ty.to_rust_string(interner))
744            };
745
746            if let Some(ty) = type_str {
747                param_types.push((param_name, ty));
748            }
749        }
750
751        if !param_types.is_empty() {
752            cache.insert(macro_name, param_types);
753        }
754    }
755
756    /// マクロのパラメータ型キャッシュを取得
757    pub fn get_macro_param_types(&self) -> &HashMap<String, Vec<(String, String)>> {
758        &self.macro_param_types
759    }
760
761    /// マクロを未知に移動(引数側)
762    pub fn mark_args_unknown(&mut self, name: InternedStr) {
763        if let Some(info) = self.macros.get_mut(&name) {
764            info.args_infer_status = InferStatus::TypeUnknown;
765        }
766    }
767
768    /// マクロを未知に移動(戻り値側)
769    pub fn mark_return_unknown(&mut self, name: InternedStr) {
770        if let Some(info) = self.macros.get_mut(&name) {
771            info.return_infer_status = InferStatus::TypeUnknown;
772        }
773    }
774
775    /// マクロを unknown 集合に移動
776    pub fn move_to_unknown(&mut self, name: InternedStr) {
777        self.unconfirmed.remove(&name);
778        self.unknown.insert(name);
779    }
780
781    /// 統計情報を取得
782    pub fn stats(&self) -> MacroInferStats {
783        let mut args_unknown = 0;
784        let mut return_unknown = 0;
785        for info in self.macros.values() {
786            if info.args_infer_status == InferStatus::TypeUnknown {
787                args_unknown += 1;
788            }
789            if info.return_infer_status == InferStatus::TypeUnknown {
790                return_unknown += 1;
791            }
792        }
793        MacroInferStats {
794            total: self.macros.len(),
795            confirmed: self.confirmed.len(),
796            unconfirmed: self.unconfirmed.len(),
797            args_unknown,
798            return_unknown,
799        }
800    }
801
802    /// Phase 1: MacroInferInfo の初期構築(パースまで、型推論なし)
803    ///
804    /// 返り値: (info, has_pasting_direct, has_thx_direct)
805    /// - has_pasting_direct: マクロ本体に直接 ## が含まれるか
806    /// - has_thx_direct: マクロ本体に直接 aTHX/tTHX/my_perl が含まれるか
807    pub fn build_macro_info(
808        &self,
809        def: &MacroDef,
810        pp: &mut Preprocessor,
811        typedefs: &HashSet<InternedStr>,
812        thx_symbols: (InternedStr, InternedStr, InternedStr),
813        no_expand: NoExpandSymbols,
814        perl_build_mode: crate::perl_config::PerlBuildMode,
815    ) -> (MacroInferInfo, bool, bool) {
816        let mut info = MacroInferInfo::new(def.name);
817        info.is_target = def.is_target;
818        info.has_body = !def.body.is_empty();
819        info.is_function = matches!(def.kind, MacroKind::Function { .. });
820
821        // パラメータ名を取得
822        let params: Vec<InternedStr> = if let MacroKind::Function { params, .. } = &def.kind {
823            for &param_name in params {
824                info.params.push(MacroParam::new(param_name, crate::source::SourceLocation::default()));
825            }
826            params.clone()
827        } else {
828            Vec::new()
829        };
830
831        // 直接 ## を含むかチェック
832        let has_pasting_direct = def.body.iter().any(|t| matches!(t.kind, TokenKind::HashHash));
833
834        // マクロ本体を展開(Preprocessor を使用)
835        // no_expand マクロを skip_expand_macros に一時的に追加
836        for sym in no_expand.iter() {
837            pp.add_skip_expand_macro(sym);
838        }
839
840        let mut in_progress = HashSet::new();
841        in_progress.insert(def.name); // 自己参照防止
842
843        let (expanded_tokens, called_macros) = match pp.expand_macro_body_for_inference(
844            &def.body,
845            &params,
846            &[], // 引数なし(マクロ定義の解析なので)
847            &mut in_progress,
848        ) {
849            Ok(result) => result,
850            Err(_) => {
851                // 展開に失敗した場合は元のトークンを使用
852                (def.body.clone(), HashSet::new())
853            }
854        };
855
856        // _CANNOT を含むマクロは生成抑制(fakesdio.h/nostdio.h 由来)
857        let has_cannot = expanded_tokens.iter().any(|t| {
858            matches!(&t.kind, TokenKind::StringLit(s) if s == b"CANNOT")
859        });
860        if has_cannot {
861            info.calls_unavailable = true;
862            return (info, has_pasting_direct, false);
863        }
864
865        // assert_(cond) の後にカンマを注入(パースエラー防止)
866        let expanded_tokens = inject_comma_after_assert_underscore(
867            &expanded_tokens,
868            &no_expand,
869        );
870
871        // def-use 関係を収集(呼び出されたマクロの集合から)
872        self.collect_uses_from_called(&called_macros, &mut info);
873
874        // THX 判定: 展開されたマクロに aTHX, tTHX が含まれるか、
875        // または展開後トークンに my_perl が含まれるかをチェック。
876        // 非 threaded perl では aTHX_ / pTHX_ が空展開され、my_perl も
877        // 存在しないので、検出自体を短絡させて常に false にする。
878        let (sym_athx, sym_tthx, sym_my_perl) = thx_symbols;
879        let has_thx = if perl_build_mode.is_threaded() {
880            let has_thx_from_uses = info.uses.contains(&sym_athx) || info.uses.contains(&sym_tthx);
881            let has_my_perl = expanded_tokens.iter().any(|t| {
882                matches!(t.kind, TokenKind::Ident(id) if id == sym_my_perl)
883            });
884            has_thx_from_uses || has_my_perl
885        } else {
886            false
887        };
888
889        // 初期値を設定(後で propagate で上書きされる可能性あり)
890        info.has_token_pasting = has_pasting_direct;
891        info.is_thx_dependent = has_thx;
892
893        // パースを試行(pp から interner と files を取得)
894        let interner = pp.interner();
895        let files = pp.files();
896
897        // 関数マクロの場合、全仮引数を generic_params として渡す
898        let generic_params: HashMap<InternedStr, usize> = params.iter()
899            .enumerate()
900            .map(|(i, &name)| (name, i))
901            .collect();
902
903        let (parse_result, stats, detected_type_params) = self.try_parse_tokens(
904            &expanded_tokens, interner, files, typedefs, generic_params,
905        );
906        info.parse_result = parse_result;
907
908        // 本体が Rust fn として表現できないか判定:
909        // - ローカル宣言 (fn 内に落ちても呼び出し側に届かず無意味)
910        // - typedef 名を値として使う式 — `PerlInterpreter *my_perl = (a)` の
911        //   ような宣言マクロ (dTHXa 等) が乗算/代入式に誤パースされた跡。
912        //   Expression としてパースされた場合 (セミコロンなし) も同様。
913        match &info.parse_result {
914            ParseResult::Statement(items) => {
915                info.stmt_unrepresentable = items.iter().any(|it| match it {
916                    BlockItem::Decl(_) => true,
917                    BlockItem::Stmt(crate::ast::Stmt::Expr(Some(e), _)) => {
918                        Self::expr_uses_typedef_as_value(e, typedefs)
919                    }
920                    BlockItem::Stmt(_) => false,
921                });
922            }
923            ParseResult::Expression(e) => {
924                info.stmt_unrepresentable = Self::expr_uses_typedef_as_value(e, typedefs);
925            }
926            ParseResult::Unparseable(_) => {}
927        }
928        info.function_call_count = stats.function_call_count;
929        info.deref_count = stats.deref_count;
930
931        // 検出された型パラメータを generic_type_params にマッピング
932        if !detected_type_params.is_empty() {
933            let param_names = ['T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
934            let mut idx = 0;
935            for (i, param) in params.iter().enumerate() {
936                if detected_type_params.contains(param) && idx < param_names.len() {
937                    info.generic_type_params.insert(i as i32, param_names[idx].to_string());
938                    idx += 1;
939                }
940            }
941        }
942
943        // パース成功した場合、assert 呼び出しを Assert 式に変換
944        match &mut info.parse_result {
945            ParseResult::Expression(expr) => {
946                convert_assert_calls(expr, interner);
947            }
948            ParseResult::Statement(items) => {
949                for item in items {
950                    if let BlockItem::Stmt(stmt) = item {
951                        convert_assert_calls_in_stmt(stmt, interner);
952                    }
953                }
954            }
955            ParseResult::Unparseable(_) => {}
956        }
957
958        // パース成功した場合、関数呼び出しを収集
959        match &info.parse_result {
960            ParseResult::Expression(expr) => {
961                Self::collect_function_calls_from_expr(expr, &mut info.called_functions);
962            }
963            ParseResult::Statement(block_items) => {
964                Self::collect_function_calls_from_block_items(block_items, &mut info.called_functions);
965            }
966            ParseResult::Unparseable(_) => {}
967        }
968
969        (info, has_pasting_direct, has_thx)
970    }
971
972    /// Phase 2: 型推論の適用
973    ///
974    /// 既に登録済みの MacroInferInfo に対して型制約を収集する
975    /// `return_types_cache` は確定済みマクロの戻り値型キャッシュ
976    /// `param_types_cache` は確定済みマクロのパラメータ型キャッシュ
977    pub fn infer_macro_types<'a>(
978        &mut self,
979        name: InternedStr,
980        params: &[InternedStr],
981        interner: &'a StringInterner,
982        files: &'a FileRegistry,
983        apidoc: Option<&'a ApidocDict>,
984        fields_dict: Option<&'a FieldsDict>,
985        rust_decl_dict: Option<&'a RustDeclDict>,
986        inline_fn_dict: Option<&'a InlineFnDict>,
987        typedefs: &'a HashSet<InternedStr>,
988        return_types_cache: &HashMap<String, String>,
989        param_types_cache: &HashMap<String, Vec<(String, String)>>,
990    ) {
991        let macro_name_str = interner.get(name);
992        let is_debug = self.is_debug_target(macro_name_str);
993        // self.macros の可変借用より前に読む (PatchOverride Tier 0 付与用)
994        let is_return_override = self.return_override_names.contains(&name);
995
996        if is_debug {
997            eprintln!("\n[DEBUG infer_macro_types] macro={}", macro_name_str);
998            eprintln!("  params: {:?}", params.iter().map(|p| interner.get(*p)).collect::<Vec<_>>());
999        }
1000
1001        let info = match self.macros.get_mut(&name) {
1002            Some(info) => info,
1003            None => return,
1004        };
1005
1006        // パース成功した場合、型制約を収集
1007        if let ParseResult::Expression(ref expr) = info.parse_result {
1008            let mut analyzer = SemanticAnalyzer::with_rust_decl_dict(
1009                interner,
1010                apidoc,
1011                fields_dict,
1012                rust_decl_dict,
1013                inline_fn_dict,
1014            );
1015
1016            // 確定済みマクロの戻り値型を設定(キャッシュへの参照を渡す)
1017            analyzer.set_macro_return_types(return_types_cache);
1018
1019            // 確定済みマクロのパラメータ型を設定(ネストしたマクロ呼び出しからの型伝播用)
1020            analyzer.set_macro_param_types(param_types_cache);
1021
1022            // apidoc 型情報付きでパラメータをシンボルテーブルに登録
1023            analyzer.register_macro_params_from_apidoc(name, params, files, typedefs);
1024
1025            // 全式の型制約を収集
1026            analyzer.collect_expr_constraints(expr, &mut info.type_env);
1027
1028            // デバッグ出力: 型制約の内容
1029            if is_debug {
1030                eprintln!("  [type_env after collect_expr_constraints]");
1031                for (expr_id, constraints) in &info.type_env.expr_constraints {
1032                    for c in constraints {
1033                        eprintln!("    expr_id={:?}: {} ({})", expr_id, c.ty.to_display_string(interner), c.context);
1034                    }
1035                }
1036                eprintln!("  [param_constraints]");
1037                for (param_id, constraints) in &info.type_env.param_constraints {
1038                    for c in constraints {
1039                        eprintln!("    param={}: {} ({})", interner.get(*param_id), c.ty.to_display_string(interner), c.context);
1040                    }
1041                }
1042                eprintln!("  [param_to_exprs]");
1043                for (param, expr_ids) in &info.type_env.param_to_exprs {
1044                    eprintln!("    param={}: {:?}", interner.get(*param), expr_ids);
1045                }
1046            }
1047
1048            // マクロ自体の戻り値型を制約として追加
1049            if let Some(apidoc_dict) = apidoc {
1050                let macro_name_str = interner.get(name);
1051                if let Some(entry) = apidoc_dict.get(macro_name_str) {
1052                    if let Some(ref return_type) = entry.return_type {
1053                        let mut type_repr = TypeRepr::from_c_type_string(return_type, interner, files, typedefs);
1054                        // return_type_override 由来なら手書き修正として
1055                        // PatchOverride source (Tier 0) を与え、callee 伝播
1056                        // (Tier 1) にも勝たせる (GH #15 AvFILL)
1057                        if is_return_override {
1058                            if let TypeRepr::CType { ref mut source, .. } = type_repr {
1059                                *source = crate::type_repr::CTypeSource::PatchOverride {
1060                                    raw: return_type.clone(),
1061                                };
1062                            }
1063                        }
1064                        info.type_env.add_return_constraint(TypeConstraint::new(
1065                            expr.id,
1066                            type_repr,
1067                            format!("return type of macro {}", macro_name_str),
1068                        ));
1069                    }
1070
1071                    // ジェネリック型パラメータを収集
1072                    collect_generic_params(entry, info);
1073
1074                    // リテラル文字列パラメータを収集
1075                    collect_literal_string_params(entry, info);
1076                }
1077            }
1078        }
1079
1080        // Statement の場合も型制約を収集
1081        if let ParseResult::Statement(ref block_items) = info.parse_result {
1082            let mut analyzer = SemanticAnalyzer::with_rust_decl_dict(
1083                interner,
1084                apidoc,
1085                fields_dict,
1086                rust_decl_dict,
1087                inline_fn_dict,
1088            );
1089
1090            // 確定済みマクロの戻り値型を設定(キャッシュへの参照を渡す)
1091            analyzer.set_macro_return_types(return_types_cache);
1092
1093            // 確定済みマクロのパラメータ型を設定(ネストしたマクロ呼び出しからの型伝播用)
1094            analyzer.set_macro_param_types(param_types_cache);
1095
1096            // apidoc 型情報付きでパラメータをシンボルテーブルに登録
1097            analyzer.register_macro_params_from_apidoc(name, params, files, typedefs);
1098
1099            // 各 BlockItem について型制約を収集
1100            for item in block_items {
1101                if let BlockItem::Stmt(stmt) = item {
1102                    analyzer.collect_stmt_constraints(stmt, &mut info.type_env);
1103                }
1104            }
1105
1106            // デバッグ出力: 型制約の内容 (Expression 分岐と同等)
1107            if is_debug {
1108                eprintln!("  [type_env after collect_stmt_constraints]");
1109                // (自身の apidoc param 制約は後段で追加される)
1110                for (expr_id, constraints) in &info.type_env.expr_constraints {
1111                    for c in constraints {
1112                        eprintln!("    expr_id={:?}: {} ({})", expr_id, c.ty.to_display_string(interner), c.context);
1113                    }
1114                }
1115                eprintln!("  [param_constraints]");
1116                for (param_id, constraints) in &info.type_env.param_constraints {
1117                    for c in constraints {
1118                        eprintln!("    param={}: {} ({})", interner.get(*param_id), c.ty.to_display_string(interner), c.context);
1119                    }
1120                }
1121                eprintln!("  [param_to_exprs]");
1122                for (param, expr_ids) in &info.type_env.param_to_exprs {
1123                    eprintln!("    param={}: {:?}", interner.get(*param), expr_ids);
1124                }
1125            }
1126        }
1127
1128        // マクロ自身の apidoc パラメータ宣言を Tier 3 の param 制約として登録。
1129        // symbol table 経由 (symbol lookup, Tier 4) だけだと、呼び出し先マクロの
1130        // apidoc 由来制約 (Tier 3) との競合に負ける (例: HvFILL の hv が
1131        // MUTABLE_HV の void* に引きずられて型消失する)。
1132        // apidoc の誤りは apidoc_patches (arg_type_override) 側で正す前提。
1133        if let Some(apidoc_dict) = apidoc {
1134            if let Some(entry) = apidoc_dict.get(macro_name_str) {
1135                if let Some(info) = self.macros.get_mut(&name) {
1136                    let decls: Vec<(InternedStr, crate::ast::ExprId, String)> = info
1137                        .params
1138                        .iter()
1139                        .enumerate()
1140                        .filter_map(|(i, mp)| {
1141                            entry
1142                                .args
1143                                .get(i)
1144                                .filter(|a| !a.ty.is_empty())
1145                                .map(|a| (mp.name, mp.expr_id(), a.ty.clone()))
1146                        })
1147                        .collect();
1148                    for (pname, expr_id, ty_str) in decls {
1149                        // from_apidoc_string の簡易パーサは "HV *const" (postfix
1150                        // const) 等を Void に潰すため、本パーサ経由で読み、
1151                        // 出所だけ Apidoc (Tier 3) に付け替える。
1152                        let mut tr =
1153                            TypeRepr::from_c_type_string(&ty_str, interner, files, typedefs);
1154                        if let TypeRepr::CType { source, .. } = &mut tr {
1155                            *source = crate::type_repr::CTypeSource::Apidoc {
1156                                raw: ty_str.clone(),
1157                            };
1158                        }
1159                        if tr.is_void() {
1160                            continue; // パース不能 (可変長引数 "..." 等) は登録しない
1161                        }
1162                        if is_debug {
1163                            eprintln!(
1164                                "  [apidoc param decl] {}: {:?} (from {:?})",
1165                                interner.get(pname), tr, ty_str
1166                            );
1167                        }
1168                        info.type_env.add_param_constraint(
1169                            pname,
1170                            TypeConstraint::new(
1171                                expr_id,
1172                                tr,
1173                                format!("apidoc param decl of {}", macro_name_str),
1174                            ),
1175                        );
1176                    }
1177                }
1178            }
1179        }
1180    }
1181
1182    /// マクロの戻り値型を取得(キャッシュ更新用)
1183    pub fn get_macro_return_type(&self, name: InternedStr, interner: &StringInterner) -> Option<(String, String)> {
1184        self.macros.get(&name).and_then(|info| {
1185            info.get_return_type().map(|ty| {
1186                (interner.get(name).to_string(), ty.to_rust_string(interner))
1187            })
1188        })
1189    }
1190
1191    /// トークン列から使用するマクロ/関数を収集
1192    /// 呼び出されたマクロを uses に追加
1193    ///
1194    /// TokenExpander が呼び出したマクロの集合(no_expand を含む)から、自分自身を除いて uses に追加する。
1195    fn collect_uses_from_called(
1196        &self,
1197        called_macros: &HashSet<InternedStr>,
1198        info: &mut MacroInferInfo,
1199    ) {
1200        for &id in called_macros {
1201            if id != info.name {
1202                info.add_use(id);
1203            }
1204        }
1205    }
1206
1207    /// トークン列のトップレベル(括弧の外側)にセミコロンがあるか判定
1208    fn has_toplevel_semicolon(tokens: &[Token]) -> bool {
1209        let mut depth = 0;
1210        for t in tokens {
1211            match t.kind {
1212                TokenKind::LParen | TokenKind::LBrace | TokenKind::LBracket => depth += 1,
1213                TokenKind::RParen | TokenKind::RBrace | TokenKind::RBracket => {
1214                    if depth > 0 { depth -= 1; }
1215                }
1216                TokenKind::Semi if depth == 0 => return true,
1217                _ => {}
1218            }
1219        }
1220        false
1221    }
1222
1223    /// 複数文パース結果から空文 (`;` 単体 = Stmt::Expr(None)) を除く。
1224    /// 空定義マクロ (非 DEBUGGING の DEBUG_Xv 等) の呼び出しを
1225    /// preprocessor が消した跡に残るセミコロン対策。
1226    fn strip_empty_stmts(items: Vec<BlockItem>) -> Vec<BlockItem> {
1227        use crate::ast::Stmt;
1228        items
1229            .into_iter()
1230            .filter(|it| !matches!(it, BlockItem::Stmt(Stmt::Expr(None, _))))
1231            .collect()
1232    }
1233
1234    /// トークン列を式または文としてパース試行
1235    ///
1236    /// # Returns
1237    /// (パース結果, 関数呼び出しを含むか)
1238    fn try_parse_tokens(
1239        &self,
1240        tokens: &[crate::token::Token],
1241        interner: &StringInterner,
1242        files: &FileRegistry,
1243        typedefs: &HashSet<InternedStr>,
1244        generic_params: HashMap<InternedStr, usize>,
1245    ) -> (ParseResult, ParseStats, HashSet<InternedStr>) {
1246        if tokens.is_empty() {
1247            return (ParseResult::Unparseable(Some("empty token sequence".to_string())), ParseStats::default(), HashSet::new());
1248        }
1249
1250        // 空白・改行をスキップして最初の有効なトークンを探す
1251        let first_significant = tokens.iter().find(|t| {
1252            !matches!(t.kind, TokenKind::Space | TokenKind::Newline)
1253        });
1254
1255        // 先頭トークンが KwDo または KwIf なら文としてパース試行
1256        let is_statement_start = first_significant
1257            .is_some_and(|t| matches!(t.kind, TokenKind::KwDo | TokenKind::KwIf));
1258        if is_statement_start {
1259            if generic_params.is_empty() {
1260                match parse_statement_from_tokens_ref_with_stats(tokens.to_vec(), interner, files, typedefs) {
1261                    Ok((stmt, stats)) => {
1262                        return (
1263                            ParseResult::Statement(vec![BlockItem::Stmt(stmt)]),
1264                            stats,
1265                            HashSet::new(),
1266                        );
1267                    }
1268                    Err(_) => {} // フォールスルーして式としてパース
1269                }
1270            } else {
1271                match parse_statement_from_tokens_ref_with_generic_params(tokens.to_vec(), interner, files, typedefs, generic_params.clone()) {
1272                    Ok((stmt, stats, detected)) => {
1273                        return (
1274                            ParseResult::Statement(vec![BlockItem::Stmt(stmt)]),
1275                            stats,
1276                            detected,
1277                        );
1278                    }
1279                    Err(_) => {} // フォールスルーして式としてパース
1280                }
1281            }
1282        }
1283
1284        // トップレベルにセミコロンがあれば複数文パースを試行
1285        if Self::has_toplevel_semicolon(tokens) {
1286            if generic_params.is_empty() {
1287                match parse_block_items_from_tokens_ref_with_stats(tokens.to_vec(), interner, files, typedefs) {
1288                    Ok((items, stats)) => {
1289                        return (
1290                            ParseResult::Statement(Self::strip_empty_stmts(items)),
1291                            stats,
1292                            HashSet::new(),
1293                        );
1294                    }
1295                    Err(_) => {} // フォールスルーして式としてパース
1296                }
1297            } else {
1298                match parse_block_items_from_tokens_ref_with_generic_params(tokens.to_vec(), interner, files, typedefs, generic_params.clone()) {
1299                    Ok((items, stats, detected)) => {
1300                        return (
1301                            ParseResult::Statement(Self::strip_empty_stmts(items)),
1302                            stats,
1303                            detected,
1304                        );
1305                    }
1306                    Err(_) => {} // フォールスルーして式としてパース
1307                }
1308            }
1309        }
1310
1311        // 式としてパースを試行
1312        if generic_params.is_empty() {
1313            match parse_expression_from_tokens_ref_with_stats(tokens.to_vec(), interner, files, typedefs) {
1314                Ok((expr, stats)) => (
1315                    ParseResult::Expression(Box::new(expr)),
1316                    stats,
1317                    HashSet::new(),
1318                ),
1319                Err(err) => (ParseResult::Unparseable(Some(err.format_with_files(files))), ParseStats::default(), HashSet::new()),
1320            }
1321        } else {
1322            match parse_expression_from_tokens_ref_with_generic_params(tokens.to_vec(), interner, files, typedefs, generic_params) {
1323                Ok((expr, stats, detected)) => (
1324                    ParseResult::Expression(Box::new(expr)),
1325                    stats,
1326                    detected,
1327                ),
1328                Err(err) => (ParseResult::Unparseable(Some(err.format_with_files(files))), ParseStats::default(), HashSet::new()),
1329            }
1330        }
1331    }
1332
1333    /// 全ターゲットマクロを解析
1334    ///
1335    /// MacroTable 内の全ターゲットマクロに対して analyze_macro を実行し、
1336    /// def-use 関係を構築して初期分類を行う。
1337    pub fn analyze_all_macros<'a>(
1338        &mut self,
1339        pp: &mut Preprocessor,
1340        apidoc: Option<&'a ApidocDict>,
1341        apidoc_patches: Option<&'a ApidocPatchSet>,
1342        fields_dict: Option<&'a FieldsDict>,
1343        rust_decl_dict: Option<&'a RustDeclDict>,
1344        mut inline_fn_dict: Option<&'a mut InlineFnDict>,
1345        c_fn_decl_dict: Option<&'a CFnDeclDict>,
1346        typedefs: &HashSet<InternedStr>,
1347        thx_symbols: (InternedStr, InternedStr, InternedStr),
1348        no_expand: NoExpandSymbols,
1349        perl_build_mode: crate::perl_config::PerlBuildMode,
1350    ) {
1351        // Step 1: 全マクロの初期構築(パースのみ、型推論なし)
1352        let mut thx_initial = HashSet::new();
1353        let mut pasting_initial = HashSet::new();
1354
1355        // マクロ定義のリストを事前に収集(借用の問題を回避)
1356        let target_macros: Vec<MacroDef> = pp.macros().iter_target_macros().cloned().collect();
1357
1358        for def in &target_macros {
1359            let (mut info, has_pasting, has_thx) = self.build_macro_info(
1360                def, pp, typedefs, thx_symbols, no_expand, perl_build_mode
1361            );
1362            // 名前使用解析 (mut 必要性 / 未使用 / 代入前 AddrOf)。
1363            // Phase 3 はこの結果を読むだけにする (GH #16/#22/#23)
1364            info.local_usage = Some(crate::local_usage::analyze_macro(
1365                &info.parse_result, &info.params));
1366            if has_pasting {
1367                pasting_initial.insert(def.name);
1368            }
1369            if has_thx {
1370                thx_initial.insert(def.name);
1371            }
1372            self.register(info);
1373        }
1374
1375        // Step 1.5: called_functions を CFnDeclDict と照合して THX 依存を追加検出
1376        if let Some(c_fn_dict) = c_fn_decl_dict {
1377            for (name, info) in &self.macros {
1378                // 呼び出す関数が THX 依存かチェック
1379                let has_thx_from_fn_calls = info.called_functions.iter().any(|fn_name| {
1380                    c_fn_dict.is_thx_dependent(*fn_name)
1381                });
1382                if has_thx_from_fn_calls && !thx_initial.contains(name) {
1383                    thx_initial.insert(*name);
1384                }
1385            }
1386        }
1387
1388        // Step 1.7: inline 関数の名前使用解析 (local_usage) を実行
1389        // (dict はこの時点で構築済み。Phase 3 は結果を読むだけ)
1390        if let Some(ref mut ifd) = inline_fn_dict {
1391            ifd.analyze_local_usage();
1392        }
1393
1394        // Step 2: used_by を構築
1395        self.build_use_relations();
1396
1397        // Step 3: THX の推移閉包を計算(used_by 経由)
1398        self.propagate_flag_via_used_by(&thx_initial, true);
1399
1400        // Step 4: ## の推移閉包を計算(used_by 経由)
1401        self.propagate_flag_via_used_by(&pasting_initial, false);
1402
1403        // Step 4.4: apidoc skip_codegen を apidoc_suppressed フラグに反映
1404        // (Step 4.5 / 4.6 / 4.7 で is_unavailable_for_codegen() 経由で
1405        //   伝播の起点として扱うため、availability チェックの前に立てる)
1406        if let Some(patches) = apidoc_patches {
1407            let interner = pp.interner();
1408            // return_type_override が当たる名前を控える (Tier 0 付与用)
1409            self.return_override_names = patches
1410                .return_overrides
1411                .keys()
1412                .filter_map(|n| interner.lookup(n))
1413                .collect();
1414            let macro_hits = self.apply_apidoc_suppressions(patches, interner);
1415            let inline_hits = inline_fn_dict
1416                .as_mut()
1417                .map(|ifd| ifd.apply_apidoc_suppressions(patches, interner))
1418                .unwrap_or(0);
1419            let total = patches.skip_codegen.len();
1420            let unmatched = total.saturating_sub(macro_hits + inline_hits);
1421            eprintln!(
1422                "[apidoc-suppress] skip_codegen reflected: {} macro(s) + {} inline fn(s); \
1423                 {} of {} entries unmatched (no such macro/inline; possibly stale skip-list)",
1424                macro_hits, inline_hits, unmatched, total,
1425            );
1426        }
1427
1428        // Step 4.45: apidoc 戻り値型 `pair` のマクロを codegen 対象外に
1429        // (STR_WITH_LEN 等。カンマ式で複数値を返すため単一戻り値の Rust fn に
1430        //   落とせない。caller 側でトークン展開されて消えるのが通常のため
1431        //   used_by 伝播には乗せず、AST 呼び出しが残った caller だけを
1432        //   Step 4.5 の called_functions 検査で降格する)
1433        if let Some(apidoc_dict) = apidoc {
1434            let interner = pp.interner();
1435            let mut pair_names: Vec<&str> = Vec::new();
1436            for (name, info) in self.macros.iter_mut() {
1437                let name_str = interner.get(*name);
1438                if let Some(entry) = apidoc_dict.get(name_str) {
1439                    if entry.return_type.as_deref() == Some("pair") {
1440                        info.pair_return = true;
1441                        pair_names.push(name_str);
1442                    }
1443                }
1444            }
1445            if !pair_names.is_empty() {
1446                eprintln!(
1447                    "[apidoc-suppress] pair-return macro(s) excluded from codegen: {}",
1448                    pair_names.join(", "),
1449                );
1450            }
1451        }
1452
1453        // Step 4.5: マクロの利用不可関数呼び出しチェック
1454        {
1455            let interner = pp.interner();
1456            self.check_function_availability(
1457                rust_decl_dict,
1458                inline_fn_dict.as_deref(),
1459                interner,
1460            );
1461        }
1462
1463        // Step 4.6: inline 関数の利用不可関数呼び出しチェック
1464        if let Some(ref mut ifd) = inline_fn_dict {
1465            let interner = pp.interner();
1466            self.check_inline_fn_availability(ifd, rust_decl_dict, interner);
1467        }
1468
1469        // Step 4.7: クロスドメイン推移閉包の計算(macro↔inline)
1470        if let Some(ref mut ifd) = inline_fn_dict {
1471            self.propagate_unavailable_cross_domain(ifd);
1472        } else {
1473            self.propagate_unavailable_via_used_by();
1474        }
1475
1476        // Step 5: 全マクロを unconfirmed に
1477        for name in self.macros.keys().copied().collect::<Vec<_>>() {
1478            self.unconfirmed.insert(name);
1479        }
1480
1481        // Step 6: 依存順に型推論
1482        {
1483            let macro_table = pp.macros();
1484            let interner = pp.interner();
1485            let files = pp.files();
1486            self.infer_types_in_dependency_order(
1487                macro_table, interner, files, apidoc, fields_dict, rust_decl_dict,
1488                inline_fn_dict.as_deref(), typedefs
1489            );
1490        }
1491    }
1492
1493    /// used_by を辿ってフラグを推移的に伝播
1494    ///
1495    /// is_thx が true の場合は is_thx_dependent を、false の場合は has_token_pasting を設定
1496    fn propagate_flag_via_used_by(&mut self, initial_set: &HashSet<InternedStr>, is_thx: bool) {
1497        // 初期集合のフラグを設定
1498        for name in initial_set {
1499            if let Some(info) = self.macros.get_mut(name) {
1500                if is_thx {
1501                    info.is_thx_dependent = true;
1502                } else {
1503                    info.has_token_pasting = true;
1504                }
1505            }
1506        }
1507
1508        // used_by を辿って伝播
1509        let mut to_propagate: Vec<InternedStr> = initial_set.iter().copied().collect();
1510
1511        while let Some(name) = to_propagate.pop() {
1512            let used_by_list: Vec<InternedStr> = self.macros
1513                .get(&name)
1514                .map(|info| info.used_by.iter().copied().collect())
1515                .unwrap_or_default();
1516
1517            for user in used_by_list {
1518                if let Some(user_info) = self.macros.get_mut(&user) {
1519                    let flag = if is_thx {
1520                        &mut user_info.is_thx_dependent
1521                    } else {
1522                        &mut user_info.has_token_pasting
1523                    };
1524                    if !*flag {
1525                        *flag = true;
1526                        to_propagate.push(user);
1527                    }
1528                }
1529            }
1530        }
1531    }
1532
1533    /// 関数呼び出しの利用可能性をチェック
1534    ///
1535    /// 各マクロの `called_functions` を調べ、bindings.rs にもマクロにも
1536    /// 存在しない関数を呼び出している場合、`calls_unavailable = true` を設定
1537    fn check_function_availability(
1538        &mut self,
1539        rust_decl_dict: Option<&RustDeclDict>,
1540        inline_fn_dict: Option<&InlineFnDict>,
1541        interner: &StringInterner,
1542    ) {
1543        // bindings.rs の関数名を収集
1544        let bindings_fns: std::collections::HashSet<&str> = rust_decl_dict
1545            .map(|d| d.fns.keys().map(|s| s.as_str()).collect())
1546            .unwrap_or_default();
1547
1548        // ビルトイン関数
1549        let builtin_fns: std::collections::HashSet<&str> = [
1550            "__builtin_expect",
1551            "__builtin_offsetof",
1552            "offsetof",
1553            "__builtin_types_compatible_p",
1554            "__builtin_constant_p",
1555            "__builtin_choose_expr",
1556            "__builtin_unreachable",
1557            "__builtin_trap",
1558            "__builtin_assume",
1559            "__builtin_bswap16",
1560            "__builtin_bswap32",
1561            "__builtin_bswap64",
1562            "__builtin_popcount",
1563            "__builtin_clz",
1564            "__builtin_ctz",
1565            "pthread_mutex_lock",
1566            "pthread_mutex_unlock",
1567            "pthread_rwlock_rdlock",
1568            "pthread_rwlock_wrlock",
1569            "pthread_rwlock_unlock",
1570            "memchr",
1571            "memcpy",
1572            "memmove",
1573            "memset",
1574            "strlen",
1575            "strcmp",
1576            "strncmp",
1577            "strcpy",
1578            "strncpy",
1579            "ASSERT_IS_LITERAL",
1580            "ASSERT_IS_PTR",
1581            "ASSERT_NOT_PTR",
1582        ].into_iter().collect();
1583
1584        // マクロ名の集合
1585        let macro_names: HashSet<InternedStr> = self.macros.keys().copied().collect();
1586
1587        // 各マクロの関数呼び出しをチェック
1588        let macro_names_list: Vec<InternedStr> = self.macros.keys().copied().collect();
1589        for name in macro_names_list {
1590            let called_functions: Vec<InternedStr> = self.macros
1591                .get(&name)
1592                .map(|info| info.called_functions.iter().copied().collect())
1593                .unwrap_or_default();
1594
1595            let mut has_unavailable = false;
1596            for called_fn in called_functions {
1597                let fn_name = interner.get(called_fn);
1598
1599                // pair 戻り値マクロ (STR_WITH_LEN 等) は fn を生成しないため、
1600                // AST 上の呼び出しとして残っている caller は利用不可
1601                if self.macros.get(&called_fn).is_some_and(|i| i.pair_return) {
1602                    has_unavailable = true;
1603                    break;
1604                }
1605
1606                // マクロとして存在する場合はOK
1607                if macro_names.contains(&called_fn) {
1608                    continue;
1609                }
1610
1611                // bindings.rs に存在する場合はOK
1612                if bindings_fns.contains(fn_name) {
1613                    continue;
1614                }
1615
1616                // インライン関数として存在する場合はOK
1617                if let Some(inline_fns) = inline_fn_dict {
1618                    if inline_fns.get(called_fn).is_some() {
1619                        continue;
1620                    }
1621                }
1622
1623                // ビルトイン関数の場合はOK
1624                if builtin_fns.contains(fn_name) {
1625                    continue;
1626                }
1627
1628                // それ以外は利用不可
1629                has_unavailable = true;
1630                break;
1631            }
1632
1633            if has_unavailable {
1634                if let Some(info) = self.macros.get_mut(&name) {
1635                    info.calls_unavailable = true;
1636                }
1637            }
1638        }
1639    }
1640
1641    /// calls_unavailable を used_by 経由で伝播
1642    ///
1643    /// 初期集合は `is_unavailable_for_codegen()`(= `calls_unavailable` または
1644    /// `apidoc_suppressed`)が立っているマクロ。伝播時は caller に
1645    /// `calls_unavailable = true` を立てる(`apidoc_suppressed` は直接の skip
1646    /// 対象自身にしか立てないため)。
1647    fn propagate_unavailable_via_used_by(&mut self) {
1648        // 初期集合: 直接利用不可関数を呼び出すか、apidoc_suppressed なマクロ
1649        let initial_set: HashSet<InternedStr> = self.macros
1650            .iter()
1651            .filter(|(_, info)| info.is_unavailable_for_codegen())
1652            .map(|(name, _)| *name)
1653            .collect();
1654
1655        // used_by を辿って伝播
1656        let mut to_propagate: Vec<InternedStr> = initial_set.into_iter().collect();
1657
1658        while let Some(name) = to_propagate.pop() {
1659            let used_by_list: Vec<InternedStr> = self.macros
1660                .get(&name)
1661                .map(|info| info.used_by.iter().copied().collect())
1662                .unwrap_or_default();
1663
1664            for user in used_by_list {
1665                if let Some(user_info) = self.macros.get_mut(&user) {
1666                    if !user_info.calls_unavailable {
1667                        user_info.calls_unavailable = true;
1668                        to_propagate.push(user);
1669                    }
1670                }
1671            }
1672        }
1673    }
1674
1675    /// inline 関数の利用可能性をチェック
1676    ///
1677    /// 各 inline 関数の `called_functions` を調べ、bindings.rs にもマクロにも
1678    /// inline 関数にも存在しない関数を呼び出している場合、unavailable を設定
1679    fn check_inline_fn_availability(
1680        &self,
1681        inline_fn_dict: &mut InlineFnDict,
1682        rust_decl_dict: Option<&RustDeclDict>,
1683        interner: &StringInterner,
1684    ) {
1685        // bindings.rs の関数名を収集
1686        let bindings_fns: HashSet<&str> = rust_decl_dict
1687            .map(|d| d.fns.keys().map(|s| s.as_str()).collect())
1688            .unwrap_or_default();
1689
1690        // ビルトイン関数(check_function_availability と同じリスト)
1691        let builtin_fns: HashSet<&str> = [
1692            "__builtin_expect",
1693            "__builtin_offsetof",
1694            "offsetof",
1695            "__builtin_types_compatible_p",
1696            "__builtin_constant_p",
1697            "__builtin_choose_expr",
1698            "__builtin_unreachable",
1699            "__builtin_trap",
1700            "__builtin_assume",
1701            "__builtin_bswap16",
1702            "__builtin_bswap32",
1703            "__builtin_bswap64",
1704            "__builtin_popcount",
1705            "__builtin_clz",
1706            "__builtin_ctz",
1707            "pthread_mutex_lock",
1708            "pthread_mutex_unlock",
1709            "pthread_rwlock_rdlock",
1710            "pthread_rwlock_wrlock",
1711            "pthread_rwlock_unlock",
1712            "memchr",
1713            "memcpy",
1714            "memmove",
1715            "memset",
1716            "strlen",
1717            "strcmp",
1718            "strncmp",
1719            "strcpy",
1720            "strncpy",
1721            "ASSERT_IS_LITERAL",
1722            "ASSERT_IS_PTR",
1723            "ASSERT_NOT_PTR",
1724        ].into_iter().collect();
1725
1726        // マクロ名の集合
1727        let macro_names: HashSet<InternedStr> = self.macros.keys().copied().collect();
1728
1729        // inline 関数の called_functions をチェック
1730        let entries: Vec<(InternedStr, Vec<InternedStr>)> = inline_fn_dict
1731            .called_functions_iter()
1732            .map(|(name, calls)| (*name, calls.iter().copied().collect()))
1733            .collect();
1734
1735        for (name, called_fns) in entries {
1736            let mut has_unavailable = false;
1737            for called_fn in called_fns {
1738                let fn_name = interner.get(called_fn);
1739
1740                // pair 戻り値マクロの呼び出しが AST に残っている場合は利用不可
1741                // (check_function_availability と同じ理由)
1742                if self.macros.get(&called_fn).is_some_and(|i| i.pair_return) {
1743                    has_unavailable = true;
1744                    break;
1745                }
1746
1747                if macro_names.contains(&called_fn) { continue; }
1748                if bindings_fns.contains(fn_name) { continue; }
1749                if inline_fn_dict.get(called_fn).is_some() { continue; }
1750                if builtin_fns.contains(fn_name) { continue; }
1751
1752                has_unavailable = true;
1753                break;
1754            }
1755
1756            if has_unavailable {
1757                inline_fn_dict.set_calls_unavailable(name);
1758            }
1759        }
1760    }
1761
1762    /// マクロ↔inline 関数のクロスドメイン推移閉包を計算
1763    ///
1764    /// macro→macro, inline→inline, macro→inline, inline→macro の
1765    /// 全方向の利用不可伝播を fixpoint ループで実行する。
1766    ///
1767    /// 被呼び出し先の判定は `is_unavailable_for_codegen()` を使う
1768    /// (`calls_unavailable` または `apidoc_suppressed` のいずれか)。
1769    /// caller に立てるフラグは常に `calls_unavailable = true`
1770    /// (`apidoc_suppressed` は直接の skip 対象自身にしか立てない)。
1771    fn propagate_unavailable_cross_domain(
1772        &mut self,
1773        inline_fn_dict: &mut InlineFnDict,
1774    ) {
1775        loop {
1776            let mut changed = false;
1777
1778            // (a) macro → macro: used_by 経由の伝播
1779            let macro_names: Vec<InternedStr> = self.macros.keys().copied().collect();
1780            for name in &macro_names {
1781                if !self.macros.get(name)
1782                    .map(|i| i.is_unavailable_for_codegen())
1783                    .unwrap_or(false)
1784                {
1785                    continue;
1786                }
1787                let used_by_list: Vec<InternedStr> = self.macros
1788                    .get(name)
1789                    .map(|info| info.used_by.iter().copied().collect())
1790                    .unwrap_or_default();
1791                for user in used_by_list {
1792                    if let Some(user_info) = self.macros.get_mut(&user) {
1793                        if !user_info.calls_unavailable {
1794                            user_info.calls_unavailable = true;
1795                            changed = true;
1796                        }
1797                    }
1798                }
1799            }
1800
1801            // (b) inline → inline: inline の called_functions が
1802            //     unavailable な inline を含む場合、自身も unavailable
1803            let inline_entries: Vec<(InternedStr, Vec<InternedStr>)> = inline_fn_dict
1804                .called_functions_iter()
1805                .map(|(name, calls)| (*name, calls.iter().copied().collect()))
1806                .collect();
1807            for (name, calls) in &inline_entries {
1808                if inline_fn_dict.is_calls_unavailable(*name) {
1809                    continue;
1810                }
1811                let has_unavailable_inline = calls.iter().any(|called| {
1812                    inline_fn_dict.get(*called).is_some()
1813                        && inline_fn_dict.is_unavailable_for_codegen(*called)
1814                });
1815                if has_unavailable_inline {
1816                    inline_fn_dict.set_calls_unavailable(*name);
1817                    changed = true;
1818                }
1819            }
1820
1821            // (c) macro → inline: マクロの called_functions が
1822            //     unavailable な inline を含む場合、マクロも unavailable
1823            for name in &macro_names {
1824                if self.macros.get(name)
1825                    .map(|i| i.calls_unavailable)
1826                    .unwrap_or(false)
1827                {
1828                    continue;
1829                }
1830                let called_fns: Vec<InternedStr> = self.macros
1831                    .get(name)
1832                    .map(|info| info.called_functions.iter().copied().collect())
1833                    .unwrap_or_default();
1834                let has_unavailable_inline = called_fns.iter().any(|called| {
1835                    inline_fn_dict.get(*called).is_some()
1836                        && inline_fn_dict.is_unavailable_for_codegen(*called)
1837                });
1838                if has_unavailable_inline {
1839                    if let Some(info) = self.macros.get_mut(name) {
1840                        info.calls_unavailable = true;
1841                        changed = true;
1842                    }
1843                }
1844            }
1845
1846            // (d) inline → macro: inline の called_functions が
1847            //     unavailable なマクロを含む場合、inline も unavailable
1848            for (name, calls) in &inline_entries {
1849                if inline_fn_dict.is_calls_unavailable(*name) {
1850                    continue;
1851                }
1852                let has_unavailable_macro = calls.iter().any(|called| {
1853                    self.macros.get(called)
1854                        .map(|info| info.is_unavailable_for_codegen())
1855                        .unwrap_or(false)
1856                });
1857                if has_unavailable_macro {
1858                    inline_fn_dict.set_calls_unavailable(*name);
1859                    changed = true;
1860                }
1861            }
1862
1863            if !changed {
1864                break;
1865            }
1866        }
1867    }
1868
1869    /// 依存順に型推論を実行
1870    fn infer_types_in_dependency_order<'a>(
1871        &mut self,
1872        macro_table: &MacroTable,
1873        interner: &'a StringInterner,
1874        files: &FileRegistry,
1875        apidoc: Option<&'a ApidocDict>,
1876        fields_dict: Option<&'a FieldsDict>,
1877        rust_decl_dict: Option<&'a RustDeclDict>,
1878        inline_fn_dict: Option<&'a InlineFnDict>,
1879        typedefs: &HashSet<InternedStr>,
1880    ) {
1881        // 確定済みマクロの戻り値型キャッシュ(O(N²) を避けるため)
1882        let mut return_types_cache: HashMap<String, String> = HashMap::new();
1883        // 確定済みマクロのパラメータ型キャッシュ(ネストしたマクロ呼び出しからの型伝播用)
1884        let mut param_types_cache: HashMap<String, Vec<(String, String)>> = HashMap::new();
1885
1886        loop {
1887            let candidates = self.get_inference_candidates();
1888            if candidates.is_empty() {
1889                // 残りの未確定マクロにも型推論を実行(apidoc 情報を適用するため)。
1890                // HashSet 順序の揺れを排除するためソートする (決定的生成)。
1891                let mut remaining: Vec<_> = self.unconfirmed.iter().copied().collect();
1892                remaining.sort();
1893                for name in remaining {
1894                    // パラメータを取得
1895                    let params: Vec<InternedStr> = macro_table
1896                        .get(name)
1897                        .map(|def| match &def.kind {
1898                            MacroKind::Function { params, .. } => params.clone(),
1899                            MacroKind::Object => vec![],
1900                        })
1901                        .unwrap_or_default();
1902
1903                    // 型推論を実行(apidoc 型情報を適用)
1904                    self.infer_macro_types(
1905                        name, &params, interner, files, apidoc, fields_dict, rust_decl_dict, inline_fn_dict, typedefs,
1906                        &return_types_cache, &param_types_cache,
1907                    );
1908
1909                    // apidoc から型が確定した場合は confirmed に。
1910                    // Statement マクロは戻り値 () 固定なので、引数制約が
1911                    // 揃っていれば確定とする。
1912                    // 本体が Rust fn として表現不能 (宣言マクロ等) なら確定させない。
1913                    let is_confirmed = self.macros.get(&name)
1914                        .map(|info| {
1915                            !info.stmt_unrepresentable
1916                                && (info.get_return_type().is_some()
1917                                    || info.is_statement_with_resolvable_params())
1918                        })
1919                        .unwrap_or(false);
1920
1921                    if is_confirmed {
1922                        if let Some((macro_name, return_type)) = self.get_macro_return_type(name, interner) {
1923                            return_types_cache.insert(macro_name, return_type);
1924                        }
1925                        self.mark_confirmed(name);
1926                        self.cache_param_types_to(name, interner, &mut param_types_cache);
1927                    } else {
1928                        self.move_to_unknown(name);
1929                    }
1930                }
1931                break;
1932            }
1933
1934            for name in candidates {
1935                // パラメータを取得
1936                let params: Vec<InternedStr> = macro_table
1937                    .get(name)
1938                    .map(|def| match &def.kind {
1939                        MacroKind::Function { params, .. } => params.clone(),
1940                        MacroKind::Object => vec![],
1941                    })
1942                    .unwrap_or_default();
1943
1944                // 型推論を実行(キャッシュを渡す)
1945                self.infer_macro_types(
1946                    name, &params, interner, files, apidoc, fields_dict, rust_decl_dict, inline_fn_dict, typedefs,
1947                    &return_types_cache, &param_types_cache,
1948                );
1949
1950                // 推論結果に基づいて分類
1951                let is_confirmed = self.macros.get(&name)
1952                    .map(|info| {
1953                        // 戻り値型が決まっていれば confirmed とする
1954                        // MacroInferInfo::get_return_type() を使用(ルート式の型も考慮)。
1955                        // Statement マクロは戻り値 () 固定なので、引数制約が
1956                        // 揃っていれば確定とする。
1957                        // 本体が Rust fn として表現不能 (宣言マクロ等) なら確定させない。
1958                        !info.stmt_unrepresentable
1959                            && (info.get_return_type().is_some()
1960                                || info.is_statement_with_resolvable_params())
1961                    })
1962                    .unwrap_or(false);
1963
1964                if is_confirmed {
1965                    // キャッシュに戻り値型を追加
1966                    if let Some((macro_name, return_type)) = self.get_macro_return_type(name, interner) {
1967                        return_types_cache.insert(macro_name, return_type);
1968                    }
1969                    self.mark_confirmed(name);
1970                    self.cache_param_types_to(name, interner, &mut param_types_cache);
1971                } else {
1972                    self.move_to_unknown(name);
1973                }
1974            }
1975        }
1976
1977        // ローカルキャッシュを self.macro_param_types に同期
1978        self.macro_param_types = param_types_cache;
1979    }
1980
1981    /// 式が typedef 名を「値」として参照しているか (再帰)。
1982    ///
1983    /// `sizeof(T)` / キャストの型部は値使用ではないので走査しない。
1984    /// collect_uses_from_expr と同じ走査形だが、目的が異なるので分ける。
1985    pub fn expr_uses_typedef_as_value(expr: &Expr, typedefs: &HashSet<InternedStr>) -> bool {
1986        match &expr.kind {
1987            ExprKind::Ident(name) => typedefs.contains(name),
1988            ExprKind::Call { func, args } => {
1989                // 関数位置の Ident は値使用とみなさない (呼び出し名)
1990                let func_hit = match &func.kind {
1991                    ExprKind::Ident(_) => false,
1992                    _ => Self::expr_uses_typedef_as_value(func, typedefs),
1993                };
1994                func_hit || args.iter().any(|a| Self::expr_uses_typedef_as_value(a, typedefs))
1995            }
1996            ExprKind::Binary { lhs, rhs, .. }
1997            | ExprKind::Assign { lhs, rhs, .. }
1998            | ExprKind::Comma { lhs, rhs } => {
1999                Self::expr_uses_typedef_as_value(lhs, typedefs)
2000                    || Self::expr_uses_typedef_as_value(rhs, typedefs)
2001            }
2002            ExprKind::Cast { expr: inner, .. }
2003            | ExprKind::PreInc(inner)
2004            | ExprKind::PreDec(inner)
2005            | ExprKind::PostInc(inner)
2006            | ExprKind::PostDec(inner)
2007            | ExprKind::AddrOf(inner)
2008            | ExprKind::Deref(inner)
2009            | ExprKind::UnaryPlus(inner)
2010            | ExprKind::UnaryMinus(inner)
2011            | ExprKind::BitNot(inner)
2012            | ExprKind::LogNot(inner) => Self::expr_uses_typedef_as_value(inner, typedefs),
2013            ExprKind::Index { expr: base, index } => {
2014                Self::expr_uses_typedef_as_value(base, typedefs)
2015                    || Self::expr_uses_typedef_as_value(index, typedefs)
2016            }
2017            ExprKind::Member { expr: base, .. } | ExprKind::PtrMember { expr: base, .. } => {
2018                Self::expr_uses_typedef_as_value(base, typedefs)
2019            }
2020            ExprKind::Conditional { cond, then_expr, else_expr } => {
2021                Self::expr_uses_typedef_as_value(cond, typedefs)
2022                    || Self::expr_uses_typedef_as_value(then_expr, typedefs)
2023                    || Self::expr_uses_typedef_as_value(else_expr, typedefs)
2024            }
2025            _ => false,
2026        }
2027    }
2028
2029    /// 式から使用される関数/マクロを再帰的に収集
2030    pub fn collect_uses_from_expr(
2031        expr: &Expr,
2032        uses: &mut HashSet<InternedStr>,
2033    ) {
2034        match &expr.kind {
2035            ExprKind::Call { func, args } => {
2036                // 関数名を収集
2037                if let ExprKind::Ident(name) = &func.kind {
2038                    uses.insert(*name);
2039                }
2040                Self::collect_uses_from_expr(func, uses);
2041                for arg in args {
2042                    Self::collect_uses_from_expr(arg, uses);
2043                }
2044            }
2045            ExprKind::Ident(name) => {
2046                uses.insert(*name);
2047            }
2048            ExprKind::Binary { lhs, rhs, .. } => {
2049                Self::collect_uses_from_expr(lhs, uses);
2050                Self::collect_uses_from_expr(rhs, uses);
2051            }
2052            ExprKind::Cast { expr: inner, .. }
2053            | ExprKind::PreInc(inner)
2054            | ExprKind::PreDec(inner)
2055            | ExprKind::PostInc(inner)
2056            | ExprKind::PostDec(inner)
2057            | ExprKind::AddrOf(inner)
2058            | ExprKind::Deref(inner)
2059            | ExprKind::UnaryPlus(inner)
2060            | ExprKind::UnaryMinus(inner)
2061            | ExprKind::BitNot(inner)
2062            | ExprKind::LogNot(inner)
2063            | ExprKind::Sizeof(inner) => {
2064                Self::collect_uses_from_expr(inner, uses);
2065            }
2066            ExprKind::Index { expr: base, index } => {
2067                Self::collect_uses_from_expr(base, uses);
2068                Self::collect_uses_from_expr(index, uses);
2069            }
2070            ExprKind::Member { expr: base, .. } | ExprKind::PtrMember { expr: base, .. } => {
2071                Self::collect_uses_from_expr(base, uses);
2072            }
2073            ExprKind::Conditional { cond, then_expr, else_expr } => {
2074                Self::collect_uses_from_expr(cond, uses);
2075                Self::collect_uses_from_expr(then_expr, uses);
2076                Self::collect_uses_from_expr(else_expr, uses);
2077            }
2078            ExprKind::Assign { lhs, rhs, .. } => {
2079                Self::collect_uses_from_expr(lhs, uses);
2080                Self::collect_uses_from_expr(rhs, uses);
2081            }
2082            ExprKind::Comma { lhs, rhs } => {
2083                Self::collect_uses_from_expr(lhs, uses);
2084                Self::collect_uses_from_expr(rhs, uses);
2085            }
2086            ExprKind::BuiltinCall { args, .. } => {
2087                for arg in args {
2088                    if let crate::ast::BuiltinArg::Expr(e) = arg {
2089                        Self::collect_uses_from_expr(e, uses);
2090                    }
2091                }
2092            }
2093            ExprKind::Assert { condition, .. } => {
2094                Self::collect_uses_from_expr(condition, uses);
2095            }
2096            _ => {}
2097        }
2098    }
2099
2100    /// 式から関数呼び出しのみを再帰的に収集(識別子は含めない)
2101    pub fn collect_function_calls_from_expr(
2102        expr: &Expr,
2103        calls: &mut HashSet<InternedStr>,
2104    ) {
2105        match &expr.kind {
2106            ExprKind::Call { func, args } => {
2107                // 関数名を収集(直接呼び出しの場合のみ)
2108                if let ExprKind::Ident(name) = &func.kind {
2109                    calls.insert(*name);
2110                }
2111                Self::collect_function_calls_from_expr(func, calls);
2112                for arg in args {
2113                    Self::collect_function_calls_from_expr(arg, calls);
2114                }
2115            }
2116            ExprKind::Binary { lhs, rhs, .. } => {
2117                Self::collect_function_calls_from_expr(lhs, calls);
2118                Self::collect_function_calls_from_expr(rhs, calls);
2119            }
2120            ExprKind::Cast { expr: inner, .. }
2121            | ExprKind::PreInc(inner)
2122            | ExprKind::PreDec(inner)
2123            | ExprKind::PostInc(inner)
2124            | ExprKind::PostDec(inner)
2125            | ExprKind::AddrOf(inner)
2126            | ExprKind::Deref(inner)
2127            | ExprKind::UnaryPlus(inner)
2128            | ExprKind::UnaryMinus(inner)
2129            | ExprKind::BitNot(inner)
2130            | ExprKind::LogNot(inner)
2131            | ExprKind::Sizeof(inner) => {
2132                Self::collect_function_calls_from_expr(inner, calls);
2133            }
2134            ExprKind::Index { expr: base, index } => {
2135                Self::collect_function_calls_from_expr(base, calls);
2136                Self::collect_function_calls_from_expr(index, calls);
2137            }
2138            ExprKind::Member { expr: base, .. } | ExprKind::PtrMember { expr: base, .. } => {
2139                Self::collect_function_calls_from_expr(base, calls);
2140            }
2141            ExprKind::Conditional { cond, then_expr, else_expr } => {
2142                Self::collect_function_calls_from_expr(cond, calls);
2143                Self::collect_function_calls_from_expr(then_expr, calls);
2144                Self::collect_function_calls_from_expr(else_expr, calls);
2145            }
2146            ExprKind::Assign { lhs, rhs, .. } => {
2147                Self::collect_function_calls_from_expr(lhs, calls);
2148                Self::collect_function_calls_from_expr(rhs, calls);
2149            }
2150            ExprKind::Comma { lhs, rhs } => {
2151                Self::collect_function_calls_from_expr(lhs, calls);
2152                Self::collect_function_calls_from_expr(rhs, calls);
2153            }
2154            ExprKind::StmtExpr(compound) => {
2155                Self::collect_function_calls_from_block_items(&compound.items, calls);
2156            }
2157            ExprKind::BuiltinCall { args, .. } => {
2158                for arg in args {
2159                    if let crate::ast::BuiltinArg::Expr(e) = arg {
2160                        Self::collect_function_calls_from_expr(e, calls);
2161                    }
2162                }
2163            }
2164            ExprKind::Assert { condition, .. } => {
2165                Self::collect_function_calls_from_expr(condition, calls);
2166            }
2167            _ => {}
2168        }
2169    }
2170
2171    /// ブロックアイテムから関数呼び出しを収集
2172    pub fn collect_function_calls_from_block_items(
2173        items: &[BlockItem],
2174        calls: &mut HashSet<InternedStr>,
2175    ) {
2176        for item in items {
2177            match item {
2178                BlockItem::Stmt(stmt) => {
2179                    Self::collect_function_calls_from_stmt(stmt, calls);
2180                }
2181                BlockItem::Decl(decl) => {
2182                    Self::collect_function_calls_from_decl(decl, calls);
2183                }
2184            }
2185        }
2186    }
2187
2188    /// 宣言の初期化子から関数呼び出しを収集
2189    fn collect_function_calls_from_decl(
2190        decl: &crate::ast::Declaration,
2191        calls: &mut HashSet<InternedStr>,
2192    ) {
2193        for init_decl in &decl.declarators {
2194            if let Some(init) = &init_decl.init {
2195                Self::collect_function_calls_from_initializer(init, calls);
2196            }
2197        }
2198    }
2199
2200    /// 初期化子から関数呼び出しを収集
2201    fn collect_function_calls_from_initializer(
2202        init: &crate::ast::Initializer,
2203        calls: &mut HashSet<InternedStr>,
2204    ) {
2205        match init {
2206            crate::ast::Initializer::Expr(expr) => {
2207                Self::collect_function_calls_from_expr(expr, calls);
2208            }
2209            crate::ast::Initializer::List(items) => {
2210                for item in items {
2211                    Self::collect_function_calls_from_initializer(&item.init, calls);
2212                }
2213            }
2214        }
2215    }
2216
2217    /// 文から関数呼び出しを収集
2218    fn collect_function_calls_from_stmt(
2219        stmt: &crate::ast::Stmt,
2220        calls: &mut HashSet<InternedStr>,
2221    ) {
2222        use crate::ast::{Stmt, ForInit};
2223        match stmt {
2224            Stmt::Expr(Some(expr), _) => {
2225                Self::collect_function_calls_from_expr(expr, calls);
2226            }
2227            Stmt::If { cond, then_stmt, else_stmt, .. } => {
2228                Self::collect_function_calls_from_expr(cond, calls);
2229                Self::collect_function_calls_from_stmt(then_stmt, calls);
2230                if let Some(else_s) = else_stmt {
2231                    Self::collect_function_calls_from_stmt(else_s, calls);
2232                }
2233            }
2234            Stmt::While { cond, body, .. } => {
2235                Self::collect_function_calls_from_expr(cond, calls);
2236                Self::collect_function_calls_from_stmt(body, calls);
2237            }
2238            Stmt::DoWhile { body, cond, .. } => {
2239                Self::collect_function_calls_from_stmt(body, calls);
2240                Self::collect_function_calls_from_expr(cond, calls);
2241            }
2242            Stmt::For { init, cond, step, body, .. } => {
2243                if let Some(for_init) = init {
2244                    match for_init {
2245                        ForInit::Expr(expr) => {
2246                            Self::collect_function_calls_from_expr(expr, calls);
2247                        }
2248                        ForInit::Decl(_) => {
2249                            // 宣言内の初期化子は今回はスキップ
2250                        }
2251                    }
2252                }
2253                if let Some(cond_expr) = cond {
2254                    Self::collect_function_calls_from_expr(cond_expr, calls);
2255                }
2256                if let Some(step_expr) = step {
2257                    Self::collect_function_calls_from_expr(step_expr, calls);
2258                }
2259                Self::collect_function_calls_from_stmt(body, calls);
2260            }
2261            Stmt::Compound(compound) => {
2262                Self::collect_function_calls_from_block_items(&compound.items, calls);
2263            }
2264            Stmt::Return(Some(expr), _) => {
2265                Self::collect_function_calls_from_expr(expr, calls);
2266            }
2267            Stmt::Switch { expr, body, .. } => {
2268                Self::collect_function_calls_from_expr(expr, calls);
2269                Self::collect_function_calls_from_stmt(body, calls);
2270            }
2271            Stmt::Label { stmt, .. } | Stmt::Case { stmt, .. } | Stmt::Default { stmt, .. } => {
2272                Self::collect_function_calls_from_stmt(stmt, calls);
2273            }
2274            _ => {}
2275        }
2276    }
2277
2278    // ========================================================================
2279    // Phase 2: パラメータ/戻り値型の確定
2280    // ========================================================================
2281
2282    /// 全マクロのパラメータ型・戻り値型・const/mut・bool を確定する。
2283    /// `infer_types_in_dependency_order()` の後に呼ぶ。
2284    pub fn resolve_param_and_return_types(
2285        &mut self,
2286        interner: &mut StringInterner,
2287        rust_decl_dict: Option<&crate::rust_decl::RustDeclDict>,
2288        inline_fn_dict: &crate::inline_fn::InlineFnDict,
2289    ) {
2290        // ── 戻り値型の topological 伝播 ──
2291        // build_macro_info 時には callee マクロの戻り値型が未確定のため、
2292        // `cond ? HEK_KEY(...) : NULL` のような式は then ブランチ型不明で
2293        // void * にフォールバックしていた。ここで依存順に再評価し、
2294        // 各マクロの type_env に return_constraint として追加する。
2295        // 後段の const/mut/bool 推論より前に行う必要はない (独立) が、
2296        // 同じ topological 結果を 2 回計算しないよう先に走らせる。
2297        self.propagate_macro_return_types(interner);
2298
2299        // 依存順にソート(リーフマクロ先頭)
2300        let sorted = self.topological_sort_for_resolve();
2301
2302        // 外部関数の const パラメータ情報を収集
2303        let mut callee_const_params: HashMap<InternedStr, HashSet<usize>> = HashMap::new();
2304        Self::seed_callee_const(interner, rust_decl_dict, inline_fn_dict, &mut callee_const_params);
2305
2306        // 外部関数の bool 戻り値情報を収集
2307        let mut bool_return_set: HashSet<InternedStr> = HashSet::new();
2308        Self::seed_bool_returns(interner, rust_decl_dict, inline_fn_dict, &mut bool_return_set);
2309
2310        // 依存順で解析
2311        for name in &sorted {
2312            let info = match self.macros.get(name) {
2313                Some(info) => info,
2314                None => continue,
2315            };
2316            if !info.is_parseable() || info.calls_unavailable || !info.is_function {
2317                continue;
2318            }
2319
2320            // ── const/mut 推論 ──
2321            let must_mut = crate::rust_codegen::collect_must_mut_pointer_params(
2322                &info.parse_result,
2323                &info.params,
2324                &callee_const_params,
2325            );
2326            let mut const_positions = HashSet::new();
2327            for (i, param) in info.params.iter().enumerate() {
2328                if !must_mut.contains(&param.name) {
2329                    // param_to_exprs 経由で型がポインタか確認
2330                    if Self::param_has_pointer_type_static(&info.type_env, param) {
2331                        const_positions.insert(i);
2332                    }
2333                }
2334            }
2335            if !const_positions.is_empty() {
2336                callee_const_params.insert(*name, const_positions.clone());
2337            }
2338
2339            // ── bool 戻り値推論 ──
2340            let is_bool = if let ParseResult::Expression(expr) = &info.parse_result {
2341                crate::rust_codegen::is_boolean_expr_with_context(
2342                    expr, &bool_return_set, &bool_return_set,
2343                )
2344            } else {
2345                false
2346            };
2347            if is_bool {
2348                bool_return_set.insert(*name);
2349            }
2350
2351            // 結果を格納(可変参照を取り直す)
2352            let info_mut = self.macros.get_mut(name).unwrap();
2353            info_mut.const_pointer_positions = const_positions;
2354            info_mut.is_bool_return = is_bool;
2355        }
2356    }
2357
2358    /// 依存順 (リーフ先頭) で各マクロの戻り値型を構造的に伝播する。
2359    ///
2360    /// `resolve_param_and_return_types` の補助。conditional 式
2361    /// (`cond ? then : else`) の戻り値型推論は `compute_conditional_type_str`
2362    /// (semantic.rs) が build_macro_info 時に処理しているが、その時点では
2363    /// マクロ→マクロ呼出の戻り値型は不明 (`HEK_KEY` 等は他マクロから定義)
2364    /// で、`*mut c_void` (NULL ブランチ由来) にフォールバックしてしまう。
2365    ///
2366    /// 本ステップでは topological 順に各マクロの戻り値型を `macro_returns`
2367    /// に蓄積し、Call/Conditional をその情報で再評価して
2368    /// `type_env.return_constraints` に高優先度で追加する。
2369    fn propagate_macro_return_types(&mut self, _interner: &StringInterner) {
2370        let sorted = self.topological_sort_for_resolve();
2371        let mut macro_returns: HashMap<InternedStr, TypeRepr> = HashMap::new();
2372
2373        for name in &sorted {
2374            // 不変借用スコープ内で「式の id」と「再評価結果」だけ取り出し、
2375            // ブロックを抜けてから可変借用で書き戻す (borrow チェッカー対応)。
2376            let computed: Option<(crate::ast::ExprId, TypeRepr)> = {
2377                let info = match self.macros.get(name) {
2378                    Some(i) => i,
2379                    None => continue,
2380                };
2381                if !info.is_parseable() || info.calls_unavailable || !info.is_function {
2382                    continue;
2383                }
2384                let ParseResult::Expression(ref expr) = info.parse_result else {
2385                    continue;
2386                };
2387                compute_macro_return_type(expr, &info.type_env, &macro_returns)
2388                    .map(|ty| (expr.id, ty))
2389            };
2390
2391            if let Some((expr_id, ret_ty)) = computed {
2392                macro_returns.insert(*name, ret_ty.clone());
2393                let info_mut = self.macros.get_mut(name).unwrap();
2394                info_mut.type_env.add_return_constraint(TypeConstraint::new(
2395                    expr_id,
2396                    ret_ty,
2397                    "macro return propagated from callee macros",
2398                ));
2399            }
2400
2401            // 自マクロの式中の Call(callee_macro, ...) で、build_macro_info
2402            // 時に semantic.rs の stale な return_types_cache から付いた
2403            // `Parsed { raw: "*mut c_void" }` のような void pointer 制約を、
2404            // propagated の具体ポインタ型で差し替える。
2405            //
2406            // **条件付き差し替え**: stale 側が void * かつ propagated 側が
2407            // 具体ポインタの場合**のみ**、void * 制約を除去する。
2408            // これにより HvENAME (callee の cached value が `void*` で誤って
2409            // いた) は修正できる一方、apidoc が `void *` を意図して宣言している
2410            // (HeKEY 等) ケースは触らないので signature/body 整合を壊さない。
2411            let updates: Vec<(crate::ast::ExprId, TypeRepr)> = {
2412                let info = self.macros.get(name).unwrap();
2413                let mut acc = Vec::new();
2414                collect_macro_call_updates(&info.parse_result, &macro_returns, &mut acc);
2415                acc
2416            };
2417            if !updates.is_empty() {
2418                let info_mut = self.macros.get_mut(name).unwrap();
2419                for (eid, ty) in updates {
2420                    if !ty.is_concrete_pointer() {
2421                        continue;
2422                    }
2423                    if let Some(cs) = info_mut.type_env.expr_constraints.get_mut(&eid) {
2424                        let mut should_replace = false;
2425                        cs.retain(|c| {
2426                            let stale = c.context.starts_with("return type of macro ")
2427                                && c.ty.is_void_pointer();
2428                            if stale {
2429                                should_replace = true;
2430                                false
2431                            } else {
2432                                true
2433                            }
2434                        });
2435                        if should_replace {
2436                            cs.push(TypeConstraint::new(
2437                                eid,
2438                                ty,
2439                                "return type from propagated callee macro (void* override)",
2440                            ));
2441                        }
2442                    }
2443                }
2444            }
2445        }
2446    }
2447
2448    /// 解析用のトポロジカルソート(リーフ先頭)
2449    fn topological_sort_for_resolve(&self) -> Vec<InternedStr> {
2450        use std::collections::VecDeque;
2451        let target_macros: HashSet<InternedStr> = self.macros.iter()
2452            .filter(|(_, info)| info.is_target && info.has_body && info.is_function)
2453            .map(|(n, _)| *n)
2454            .collect();
2455
2456        let mut in_degree: HashMap<InternedStr, usize> = HashMap::new();
2457        for &name in &target_macros {
2458            in_degree.entry(name).or_insert(0);
2459            if let Some(info) = self.macros.get(&name) {
2460                for used in &info.uses {
2461                    if target_macros.contains(used) {
2462                        *in_degree.entry(name).or_insert(0) += 1;
2463                    }
2464                }
2465            }
2466        }
2467
2468        let mut queue: VecDeque<InternedStr> = in_degree.iter()
2469            .filter(|(_, deg)| **deg == 0)
2470            .map(|(&name, _)| name)
2471            .collect();
2472        let mut result = Vec::new();
2473        while let Some(name) = queue.pop_front() {
2474            result.push(name);
2475            if let Some(info) = self.macros.get(&name) {
2476                for user in &info.used_by {
2477                    if let Some(deg) = in_degree.get_mut(user) {
2478                        *deg = deg.saturating_sub(1);
2479                        if *deg == 0 {
2480                            queue.push_back(*user);
2481                        }
2482                    }
2483                }
2484            }
2485        }
2486        // 残り(循環)を追加
2487        for &name in &target_macros {
2488            if !result.contains(&name) {
2489                result.push(name);
2490            }
2491        }
2492        result
2493    }
2494
2495    /// パラメータがポインタ型を持つか(static 版、&self 不要)
2496    fn param_has_pointer_type_static(type_env: &crate::type_env::TypeEnv, param: &MacroParam) -> bool {
2497        if let Some(expr_ids) = type_env.param_to_exprs.get(&param.name) {
2498            for expr_id in expr_ids {
2499                if let Some(constraints) = type_env.expr_constraints.get(expr_id) {
2500                    for c in constraints {
2501                        if c.ty.has_outer_pointer() {
2502                            return true;
2503                        }
2504                    }
2505                }
2506            }
2507        }
2508        let expr_id = param.expr_id();
2509        if let Some(constraints) = type_env.expr_constraints.get(&expr_id) {
2510            for c in constraints {
2511                if c.ty.has_outer_pointer() {
2512                    return true;
2513                }
2514            }
2515        }
2516        false
2517    }
2518
2519    /// bindings.rs/inline 関数の const パラメータ情報を収集
2520    fn seed_callee_const(
2521        interner: &mut StringInterner,
2522        rust_decl_dict: Option<&crate::rust_decl::RustDeclDict>,
2523        inline_fn_dict: &crate::inline_fn::InlineFnDict,
2524        callee_const: &mut HashMap<InternedStr, HashSet<usize>>,
2525    ) {
2526        if let Some(dict) = rust_decl_dict {
2527            for (name, func) in &dict.fns {
2528                let name_id = interner.intern(name);
2529                let mut positions = HashSet::new();
2530                for (i, param) in func.params.iter().enumerate() {
2531                    // syn の出力は "* const" (スペースあり) の場合がある
2532                    let normalized = param.ty.replace(" ", "");
2533                    if normalized.contains("*const") {
2534                        positions.insert(i);
2535                    }
2536                }
2537                if !positions.is_empty() {
2538                    callee_const.insert(name_id, positions);
2539                }
2540            }
2541        }
2542        for (name_id, fn_info) in inline_fn_dict.iter() {
2543            let mut positions = HashSet::new();
2544            for dd in &fn_info.declarator.derived {
2545                if let crate::ast::DerivedDecl::Function(param_list) = dd {
2546                    for (i, param) in param_list.params.iter().enumerate() {
2547                        if let Some(ref decl) = param.declarator {
2548                            let pointer_count = decl.derived.iter().filter(|d| {
2549                                matches!(d, crate::ast::DerivedDecl::Pointer(_))
2550                            }).count();
2551                            // Rust の外側ポインタが *const になるのは
2552                            // 「指し先が const」のとき:
2553                            // - `const char *key` — const は DeclSpecs 側
2554                            //   (pointee const)。単一ポインタなら外側 = *const。
2555                            //   perl の inline fn (5.44 で hv_common_key_len 等が
2556                            //   inline 化) はほぼこの形
2557                            // - `T * const *` のような多段は中間ポインタの
2558                            //   qual に付く (従来からの検査)
2559                            // なお `char * const p` (束縛のみ const) を従来検査が
2560                            // *const 扱いする不正確さは既存挙動として維持
2561                            let has_const = (pointer_count == 1
2562                                    && param.specs.qualifiers.is_const)
2563                                || decl.derived.iter().any(|d| {
2564                                    matches!(d, crate::ast::DerivedDecl::Pointer(q) if q.is_const)
2565                                });
2566                            if has_const && pointer_count > 0 {
2567                                positions.insert(i);
2568                            }
2569                        }
2570                    }
2571                    break;
2572                }
2573            }
2574            if !positions.is_empty() {
2575                callee_const.insert(*name_id, positions);
2576            }
2577        }
2578    }
2579
2580    /// bindings.rs/inline 関数の bool 戻り値情報を収集
2581    fn seed_bool_returns(
2582        interner: &mut StringInterner,
2583        rust_decl_dict: Option<&crate::rust_decl::RustDeclDict>,
2584        inline_fn_dict: &crate::inline_fn::InlineFnDict,
2585        bool_returns: &mut HashSet<InternedStr>,
2586    ) {
2587        if let Some(dict) = rust_decl_dict {
2588            for (name, func) in &dict.fns {
2589                if func.ret_ty.as_deref() == Some("bool") {
2590                    let name_id = interner.intern(name);
2591                    bool_returns.insert(name_id);
2592                }
2593            }
2594        }
2595        for (name_id, fn_info) in inline_fn_dict.iter() {
2596            let has_bool = fn_info.specs.type_specs.iter()
2597                .any(|ts| matches!(ts, crate::ast::TypeSpec::Bool));
2598            if has_bool {
2599                bool_returns.insert(*name_id);
2600            }
2601        }
2602    }
2603}
2604
2605impl Default for MacroInferContext {
2606    fn default() -> Self {
2607        Self::new()
2608    }
2609}
2610
2611// ============================================================================
2612// Macro return type の topological 伝播 (resolve_param_and_return_types から使う)
2613// ============================================================================
2614
2615/// マクロ式の戻り値型を、既に解決済の callee マクロ群 (`macro_returns`) を
2616/// 参照しつつ構造的に再評価する。Conditional の場合は両ブランチの型を比べ、
2617/// `void *` と具体ポインタの組合せなら具体側を採用する (C 三項演算の慣例)。
2618/// マクロ M の `parse_result` を再帰 walk し、`Call(Ident(name), args)` で
2619/// `macro_returns` に登録済の callee マクロを呼んでいる箇所を集める。
2620/// 戻り値は (call 式の `ExprId`, callee の戻り値型) の列。
2621fn collect_macro_call_updates(
2622    parse_result: &ParseResult,
2623    macro_returns: &HashMap<InternedStr, TypeRepr>,
2624    acc: &mut Vec<(crate::ast::ExprId, TypeRepr)>,
2625) {
2626    match parse_result {
2627        ParseResult::Expression(e) => visit_expr_for_calls(e, macro_returns, acc),
2628        ParseResult::Statement(items) => {
2629            for it in items {
2630                if let BlockItem::Stmt(stmt) = it {
2631                    visit_stmt_for_calls(stmt, macro_returns, acc);
2632                }
2633            }
2634        }
2635        ParseResult::Unparseable(_) => {}
2636    }
2637}
2638
2639fn visit_expr_for_calls(
2640    expr: &Expr,
2641    macro_returns: &HashMap<InternedStr, TypeRepr>,
2642    acc: &mut Vec<(crate::ast::ExprId, TypeRepr)>,
2643) {
2644    if let ExprKind::Call { func, args } = &expr.kind {
2645        if let ExprKind::Ident(callee) = &func.kind {
2646            if let Some(ty) = macro_returns.get(callee) {
2647                acc.push((expr.id, ty.clone()));
2648            }
2649        }
2650        visit_expr_for_calls(func, macro_returns, acc);
2651        for a in args {
2652            visit_expr_for_calls(a, macro_returns, acc);
2653        }
2654        return;
2655    }
2656    walk_expr_children(expr, &mut |e| visit_expr_for_calls(e, macro_returns, acc));
2657}
2658
2659fn visit_stmt_for_calls(
2660    stmt: &crate::ast::Stmt,
2661    macro_returns: &HashMap<InternedStr, TypeRepr>,
2662    acc: &mut Vec<(crate::ast::ExprId, TypeRepr)>,
2663) {
2664    use crate::ast::Stmt;
2665    match stmt {
2666        Stmt::Compound(c) => {
2667            for it in &c.items {
2668                if let BlockItem::Stmt(s) = it {
2669                    visit_stmt_for_calls(s, macro_returns, acc);
2670                }
2671            }
2672        }
2673        Stmt::Expr(Some(e), _) | Stmt::Return(Some(e), _) => {
2674            visit_expr_for_calls(e, macro_returns, acc)
2675        }
2676        Stmt::If { cond, then_stmt, else_stmt, .. } => {
2677            visit_expr_for_calls(cond, macro_returns, acc);
2678            visit_stmt_for_calls(then_stmt, macro_returns, acc);
2679            if let Some(es) = else_stmt {
2680                visit_stmt_for_calls(es, macro_returns, acc);
2681            }
2682        }
2683        Stmt::While { cond, body, .. } | Stmt::DoWhile { body, cond, .. } => {
2684            visit_expr_for_calls(cond, macro_returns, acc);
2685            visit_stmt_for_calls(body, macro_returns, acc);
2686        }
2687        Stmt::For { init, cond, step, body, .. } => {
2688            if let Some(crate::ast::ForInit::Expr(e)) = init {
2689                visit_expr_for_calls(e, macro_returns, acc);
2690            }
2691            if let Some(c) = cond {
2692                visit_expr_for_calls(c, macro_returns, acc);
2693            }
2694            if let Some(s) = step {
2695                visit_expr_for_calls(s, macro_returns, acc);
2696            }
2697            visit_stmt_for_calls(body, macro_returns, acc);
2698        }
2699        Stmt::Switch { expr, body, .. } => {
2700            visit_expr_for_calls(expr, macro_returns, acc);
2701            visit_stmt_for_calls(body, macro_returns, acc);
2702        }
2703        Stmt::Case { expr, stmt, .. } => {
2704            visit_expr_for_calls(expr, macro_returns, acc);
2705            visit_stmt_for_calls(stmt, macro_returns, acc);
2706        }
2707        Stmt::Default { stmt, .. } | Stmt::Label { stmt, .. } => {
2708            visit_stmt_for_calls(stmt, macro_returns, acc);
2709        }
2710        _ => {}
2711    }
2712}
2713
2714/// `Expr` の子ノードを構造的に列挙する小ヘルパ。Call の特殊扱いは呼出側で行う前提。
2715fn walk_expr_children<F: FnMut(&Expr)>(expr: &Expr, f: &mut F) {
2716    match &expr.kind {
2717        ExprKind::Ident(_)
2718        | ExprKind::IntLit(_)
2719        | ExprKind::UIntLit(_)
2720        | ExprKind::FloatLit(_)
2721        | ExprKind::CharLit(_)
2722        | ExprKind::StringLit(_)
2723        | ExprKind::SizeofType(_)
2724        | ExprKind::Alignof(_) => {}
2725        ExprKind::Call { func, args } => {
2726            f(func);
2727            for a in args { f(a); }
2728        }
2729        ExprKind::Index { expr: e, index } => { f(e); f(index); }
2730        ExprKind::Member { expr: e, .. } | ExprKind::PtrMember { expr: e, .. } => f(e),
2731        ExprKind::PostInc(e)
2732        | ExprKind::PostDec(e)
2733        | ExprKind::PreInc(e)
2734        | ExprKind::PreDec(e)
2735        | ExprKind::AddrOf(e)
2736        | ExprKind::Deref(e)
2737        | ExprKind::UnaryPlus(e)
2738        | ExprKind::UnaryMinus(e)
2739        | ExprKind::BitNot(e)
2740        | ExprKind::LogNot(e)
2741        | ExprKind::Sizeof(e) => f(e),
2742        ExprKind::Cast { expr: e, .. } => f(e),
2743        ExprKind::Binary { lhs, rhs, .. } => { f(lhs); f(rhs); }
2744        ExprKind::Assign { lhs, rhs, .. } => { f(lhs); f(rhs); }
2745        ExprKind::Conditional { cond, then_expr, else_expr } => {
2746            f(cond); f(then_expr); f(else_expr);
2747        }
2748        ExprKind::Comma { lhs, rhs } => { f(lhs); f(rhs); }
2749        ExprKind::CompoundLit { .. } => {}
2750        ExprKind::BuiltinCall { args, .. } => {
2751            for a in args {
2752                if let crate::ast::BuiltinArg::Expr(e) = a { f(e); }
2753            }
2754        }
2755        ExprKind::StmtExpr(_) => {}
2756        ExprKind::Assert { condition, .. } => f(condition),
2757        ExprKind::MacroCall { args, expanded, .. } => {
2758            for a in args { f(a); }
2759            f(expanded);
2760        }
2761    }
2762}
2763
2764fn compute_macro_return_type(
2765    expr: &Expr,
2766    env: &TypeEnv,
2767    macro_returns: &HashMap<InternedStr, TypeRepr>,
2768) -> Option<TypeRepr> {
2769    match &expr.kind {
2770        ExprKind::Conditional { then_expr, else_expr, .. } => {
2771            let then_ty = compute_macro_return_type(then_expr, env, macro_returns)
2772                .or_else(|| existing_constraint_type(then_expr.id, env));
2773            let else_ty = compute_macro_return_type(else_expr, env, macro_returns)
2774                .or_else(|| existing_constraint_type(else_expr.id, env));
2775            resolve_conditional_branches(then_ty, else_ty)
2776        }
2777        ExprKind::Call { func, .. } => {
2778            if let ExprKind::Ident(callee_name) = &func.kind {
2779                if let Some(ty) = macro_returns.get(callee_name) {
2780                    return Some(ty.clone());
2781                }
2782            }
2783            existing_constraint_type(expr.id, env)
2784        }
2785        // 透過的に右側を採用 (`(a, b)` の値は `b`)
2786        ExprKind::Comma { rhs, .. } => {
2787            compute_macro_return_type(rhs, env, macro_returns)
2788                .or_else(|| existing_constraint_type(rhs.id, env))
2789        }
2790        // 二項演算: pointer ± integer → pointer 型を伝播する。
2791        // `RX_WRAPPED(prog) + N` (Add) のように lhs がマクロ呼出のとき、
2792        // build_macro_info 時には callee の戻り値型が未知で `void *` に
2793        // 落ちていた。ここで構造的に解決する。
2794        ExprKind::Binary { op, lhs, rhs } => {
2795            let lhs_ty = compute_macro_return_type(lhs, env, macro_returns)
2796                .or_else(|| existing_constraint_type(lhs.id, env));
2797            let rhs_ty = compute_macro_return_type(rhs, env, macro_returns)
2798                .or_else(|| existing_constraint_type(rhs.id, env));
2799            resolve_binary(op, lhs_ty, rhs_ty)
2800        }
2801        // キャスト式: 既存の constraint (キャスト先型) で十分
2802        ExprKind::Cast { .. } => existing_constraint_type(expr.id, env),
2803        // それ以外は build_macro_info 時に張られた制約をそのまま採用
2804        _ => existing_constraint_type(expr.id, env),
2805    }
2806}
2807
2808/// `expr_constraints` の先頭エントリの型を返す (見つからなければ None)。
2809fn existing_constraint_type(
2810    expr_id: crate::ast::ExprId,
2811    env: &TypeEnv,
2812) -> Option<TypeRepr> {
2813    env.expr_constraints
2814        .get(&expr_id)
2815        .and_then(|cs| cs.first())
2816        .map(|c| c.ty.clone())
2817}
2818
2819/// 二項演算の結果型を構造的に推論する:
2820/// - 比較・論理演算 → 既存の constraint に任せる (None を返して fallback)
2821/// - `pointer ± integer` → pointer 側の型
2822/// - `pointer - pointer` → 既存の constraint (isize 推定済) を維持
2823/// - それ以外 → None で fallback
2824fn resolve_binary(
2825    op: &crate::ast::BinOp,
2826    lhs_ty: Option<TypeRepr>,
2827    rhs_ty: Option<TypeRepr>,
2828) -> Option<TypeRepr> {
2829    use crate::ast::BinOp;
2830    match op {
2831        BinOp::Add | BinOp::Sub => {
2832            let lhs_is_ptr = lhs_ty.as_ref().is_some_and(|t| t.is_pointer_type());
2833            let rhs_is_ptr = rhs_ty.as_ref().is_some_and(|t| t.is_pointer_type());
2834            match (lhs_is_ptr, rhs_is_ptr) {
2835                (true, false) => lhs_ty,
2836                (false, true) => rhs_ty,
2837                _ => None, // pointer-pointer / 整数同士は既存 constraint に任せる
2838            }
2839        }
2840        _ => None,
2841    }
2842}
2843
2844/// 三項演算 / if-else の二ブランチの型を統合する。
2845/// 構造的判定 (`is_void_pointer` / `is_concrete_pointer`) のみを使い、
2846/// 文字列 contains は使わない。
2847fn resolve_conditional_branches(
2848    then_ty: Option<TypeRepr>,
2849    else_ty: Option<TypeRepr>,
2850) -> Option<TypeRepr> {
2851    match (&then_ty, &else_ty) {
2852        (Some(t), Some(e)) => {
2853            if t.is_void_pointer() && e.is_concrete_pointer() {
2854                return else_ty;
2855            }
2856            if e.is_void_pointer() && t.is_concrete_pointer() {
2857                return then_ty;
2858            }
2859            // それ以外は then 側を採用 (C のセマンティクスでは双方の昇格型だが、
2860            // 主要ユースケース (`HEK_KEY ? : NULL`) は具体型を優先する目的で
2861            // 十分。両方とも具体ポインタなら then が一般的に意味のある型)
2862            then_ty
2863        }
2864        (Some(_), None) => then_ty,
2865        (None, Some(_)) => else_ty,
2866        (None, None) => None,
2867    }
2868}
2869
2870/// `assert_(cond)` 呼び出しの後にカンマトークンを注入
2871///
2872/// C の `assert_(what)` は DEBUGGING 時に `assert(what),`(末尾カンマ付き)に展開される。
2873/// マクロ推論では `assert_` を展開せずに残すため、`assert_(c1) assert_(c2) expr` のように
2874/// カンマなしで隣接してパースエラーになる。この関数は元の意味論を再現するために
2875/// `assert_(...)` の後にカンマを注入する。
2876fn inject_comma_after_assert_underscore(
2877    tokens: &[Token],
2878    no_expand: &NoExpandSymbols,
2879) -> Vec<Token> {
2880    let assert_underscore = no_expand.assert_;
2881
2882    let mut result = Vec::with_capacity(tokens.len());
2883    let mut i = 0;
2884
2885    while i < tokens.len() {
2886        if matches!(tokens[i].kind, TokenKind::Ident(name) if name == assert_underscore) {
2887            // assert_ トークンをコピー
2888            result.push(tokens[i].clone());
2889            i += 1;
2890
2891            // 空白をスキップしつつコピー
2892            while i < tokens.len() && matches!(tokens[i].kind, TokenKind::Space | TokenKind::Newline) {
2893                result.push(tokens[i].clone());
2894                i += 1;
2895            }
2896
2897            // ( ... ) を括弧の深さを追跡しながらコピー
2898            if i < tokens.len() && matches!(tokens[i].kind, TokenKind::LParen) {
2899                let mut depth = 0;
2900                loop {
2901                    if i >= tokens.len() {
2902                        break;
2903                    }
2904                    match tokens[i].kind {
2905                        TokenKind::LParen => depth += 1,
2906                        TokenKind::RParen => {
2907                            depth -= 1;
2908                            if depth == 0 {
2909                                result.push(tokens[i].clone());
2910                                i += 1;
2911                                break;
2912                            }
2913                        }
2914                        _ => {}
2915                    }
2916                    result.push(tokens[i].clone());
2917                    i += 1;
2918                }
2919
2920                // RParen の後にカンマを注入(後続が式の開始の場合のみ)
2921                let next_significant = tokens[i..].iter()
2922                    .find(|t| !matches!(t.kind, TokenKind::Space | TokenKind::Newline));
2923                let needs_comma = next_significant
2924                    .is_some_and(|t| !matches!(t.kind,
2925                        TokenKind::Comma | TokenKind::RParen | TokenKind::Eof
2926                        | TokenKind::Semi));
2927                if needs_comma {
2928                    let loc = result.last().map(|t| t.loc.clone())
2929                        .unwrap_or_default();
2930                    result.push(Token::new(TokenKind::Comma, loc));
2931                }
2932            }
2933        } else {
2934            result.push(tokens[i].clone());
2935            i += 1;
2936        }
2937    }
2938
2939    result
2940}
2941
2942/// マクロ名がアサーションマクロかどうかを判定
2943pub fn detect_assert_kind(name: &str) -> Option<AssertKind> {
2944    match name {
2945        "assert" => Some(AssertKind::Assert),
2946        "assert_" => Some(AssertKind::AssertUnderscore),
2947        _ => None,
2948    }
2949}
2950
2951/// AST 内の assert/assert_ 呼び出しを Assert 式に変換
2952///
2953/// パース後に呼び出し、`Call { func: Ident("assert"), args }` を
2954/// `Assert { kind, condition }` に変換する。
2955pub fn convert_assert_calls(expr: &mut Expr, interner: &StringInterner) {
2956    match &mut expr.kind {
2957        ExprKind::Call { func, args } => {
2958            // 子を先に処理
2959            convert_assert_calls(func, interner);
2960            for arg in args.iter_mut() {
2961                convert_assert_calls(arg, interner);
2962            }
2963
2964            // assert/assert_ 呼び出しを検出
2965            if let ExprKind::Ident(name) = &func.kind {
2966                let name_str = interner.get(*name);
2967                if let Some(kind) = detect_assert_kind(name_str) {
2968                    if let Some(condition) = args.pop() {
2969                        expr.kind = ExprKind::Assert {
2970                            kind,
2971                            condition: Box::new(condition),
2972                        };
2973                    }
2974                }
2975            }
2976        }
2977        ExprKind::Binary { lhs, rhs, .. } => {
2978            convert_assert_calls(lhs, interner);
2979            convert_assert_calls(rhs, interner);
2980        }
2981        ExprKind::Cast { expr: inner, .. }
2982        | ExprKind::PreInc(inner)
2983        | ExprKind::PreDec(inner)
2984        | ExprKind::PostInc(inner)
2985        | ExprKind::PostDec(inner)
2986        | ExprKind::AddrOf(inner)
2987        | ExprKind::Deref(inner)
2988        | ExprKind::UnaryPlus(inner)
2989        | ExprKind::UnaryMinus(inner)
2990        | ExprKind::BitNot(inner)
2991        | ExprKind::LogNot(inner)
2992        | ExprKind::Sizeof(inner) => {
2993            convert_assert_calls(inner, interner);
2994        }
2995        ExprKind::Index { expr: base, index } => {
2996            convert_assert_calls(base, interner);
2997            convert_assert_calls(index, interner);
2998        }
2999        ExprKind::Member { expr: base, .. } | ExprKind::PtrMember { expr: base, .. } => {
3000            convert_assert_calls(base, interner);
3001        }
3002        ExprKind::Conditional { cond, then_expr, else_expr } => {
3003            convert_assert_calls(cond, interner);
3004            convert_assert_calls(then_expr, interner);
3005            convert_assert_calls(else_expr, interner);
3006        }
3007        ExprKind::Assign { lhs, rhs, .. } => {
3008            convert_assert_calls(lhs, interner);
3009            convert_assert_calls(rhs, interner);
3010        }
3011        ExprKind::Comma { lhs, rhs } => {
3012            convert_assert_calls(lhs, interner);
3013            convert_assert_calls(rhs, interner);
3014        }
3015        ExprKind::Assert { condition, .. } => {
3016            convert_assert_calls(condition, interner);
3017        }
3018        ExprKind::CompoundLit { init, .. } => {
3019            for item in init {
3020                if let crate::ast::Initializer::Expr(e) = &mut item.init {
3021                    convert_assert_calls(e, interner);
3022                }
3023            }
3024        }
3025        ExprKind::StmtExpr(compound) => {
3026            for item in &mut compound.items {
3027                if let BlockItem::Stmt(stmt) = item {
3028                    convert_assert_calls_in_stmt(stmt, interner);
3029                }
3030            }
3031        }
3032        // マクロ呼び出し(引数と展開結果の両方を処理)
3033        ExprKind::MacroCall { args, expanded, .. } => {
3034            for arg in args.iter_mut() {
3035                convert_assert_calls(arg, interner);
3036            }
3037            convert_assert_calls(expanded, interner);
3038        }
3039        ExprKind::BuiltinCall { args, .. } => {
3040            for arg in args.iter_mut() {
3041                if let crate::ast::BuiltinArg::Expr(e) = arg {
3042                    convert_assert_calls(e, interner);
3043                }
3044            }
3045        }
3046        // リテラルや識別子など、再帰不要
3047        ExprKind::Ident(_)
3048        | ExprKind::IntLit(_)
3049        | ExprKind::UIntLit(_)
3050        | ExprKind::FloatLit(_)
3051        | ExprKind::CharLit(_)
3052        | ExprKind::StringLit(_)
3053        | ExprKind::SizeofType(_)
3054        | ExprKind::Alignof(_) => {}
3055    }
3056}
3057
3058/// CompoundStmt 内の assert 呼び出しを変換
3059///
3060/// inline 関数の本体などに使用。
3061pub fn convert_assert_calls_in_compound_stmt(compound: &mut crate::ast::CompoundStmt, interner: &StringInterner) {
3062    use crate::ast::BlockItem;
3063    for item in &mut compound.items {
3064        if let BlockItem::Stmt(s) = item {
3065            convert_assert_calls_in_stmt(s, interner);
3066        }
3067    }
3068}
3069
3070/// Statement 内の assert 呼び出しを変換
3071pub fn convert_assert_calls_in_stmt(stmt: &mut crate::ast::Stmt, interner: &StringInterner) {
3072    use crate::ast::Stmt;
3073    match stmt {
3074        Stmt::Expr(Some(expr), _) => convert_assert_calls(expr, interner),
3075        Stmt::If { cond, then_stmt, else_stmt, .. } => {
3076            convert_assert_calls(cond, interner);
3077            convert_assert_calls_in_stmt(then_stmt, interner);
3078            if let Some(else_s) = else_stmt {
3079                convert_assert_calls_in_stmt(else_s, interner);
3080            }
3081        }
3082        Stmt::While { cond, body, .. } => {
3083            convert_assert_calls(cond, interner);
3084            convert_assert_calls_in_stmt(body, interner);
3085        }
3086        Stmt::DoWhile { body, cond, .. } => {
3087            convert_assert_calls_in_stmt(body, interner);
3088            convert_assert_calls(cond, interner);
3089        }
3090        Stmt::For { init, cond, step, body, .. } => {
3091            if let Some(crate::ast::ForInit::Expr(e)) = init {
3092                convert_assert_calls(e, interner);
3093            }
3094            if let Some(c) = cond {
3095                convert_assert_calls(c, interner);
3096            }
3097            if let Some(s) = step {
3098                convert_assert_calls(s, interner);
3099            }
3100            convert_assert_calls_in_stmt(body, interner);
3101        }
3102        Stmt::Switch { expr, body, .. } => {
3103            convert_assert_calls(expr, interner);
3104            convert_assert_calls_in_stmt(body, interner);
3105        }
3106        Stmt::Return(Some(expr), _) => convert_assert_calls(expr, interner),
3107        Stmt::Compound(compound) => {
3108            for item in &mut compound.items {
3109                match item {
3110                    BlockItem::Stmt(s) => convert_assert_calls_in_stmt(s, interner),
3111                    BlockItem::Decl(_) => {}
3112                }
3113            }
3114        }
3115        Stmt::Label { stmt: s, .. }
3116        | Stmt::Case { stmt: s, .. }
3117        | Stmt::Default { stmt: s, .. } => {
3118            convert_assert_calls_in_stmt(s, interner);
3119        }
3120        _ => {}
3121    }
3122}
3123
3124/// 推論統計
3125#[derive(Debug, Clone, Copy)]
3126pub struct MacroInferStats {
3127    pub total: usize,
3128    pub confirmed: usize,
3129    pub unconfirmed: usize,
3130    /// 引数の型が unknown のマクロ数
3131    pub args_unknown: usize,
3132    /// 戻り値の型が unknown のマクロ数
3133    pub return_unknown: usize,
3134}
3135
3136impl std::fmt::Display for MacroInferStats {
3137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3138        write!(
3139            f,
3140            "MacroInferStats {{ total: {}, confirmed: {}, unconfirmed: {}, args_unknown: {}, return_unknown: {} }}",
3141            self.total, self.confirmed, self.unconfirmed, self.args_unknown, self.return_unknown
3142        )
3143    }
3144}
3145
3146#[cfg(test)]
3147mod tests {
3148    use super::*;
3149    use crate::intern::StringInterner;
3150
3151    #[test]
3152    fn test_macro_infer_info_new() {
3153        let mut interner = StringInterner::new();
3154        let name = interner.intern("MY_MACRO");
3155
3156        let info = MacroInferInfo::new(name);
3157
3158        assert_eq!(info.name, name);
3159        assert!(!info.is_target);
3160        assert!(!info.is_thx_dependent);
3161        assert!(!info.has_token_pasting);
3162        assert!(info.uses.is_empty());
3163        assert!(info.used_by.is_empty());
3164        assert!(!info.is_parseable());
3165        assert_eq!(info.args_infer_status, InferStatus::Pending);
3166        assert_eq!(info.return_infer_status, InferStatus::Pending);
3167    }
3168
3169    #[test]
3170    fn test_macro_infer_context_register() {
3171        let mut interner = StringInterner::new();
3172        let name = interner.intern("FOO");
3173
3174        let mut ctx = MacroInferContext::new();
3175        let info = MacroInferInfo::new(name);
3176        ctx.register(info);
3177
3178        assert!(ctx.get(name).is_some());
3179        assert_eq!(ctx.macros.len(), 1);
3180    }
3181
3182    #[test]
3183    fn test_build_use_relations() {
3184        let mut interner = StringInterner::new();
3185        let foo = interner.intern("FOO");
3186        let bar = interner.intern("BAR");
3187        let baz = interner.intern("BAZ");
3188
3189        let mut ctx = MacroInferContext::new();
3190
3191        // FOO uses BAR
3192        let mut foo_info = MacroInferInfo::new(foo);
3193        foo_info.add_use(bar);
3194        ctx.register(foo_info);
3195
3196        // BAR uses BAZ
3197        let mut bar_info = MacroInferInfo::new(bar);
3198        bar_info.add_use(baz);
3199        ctx.register(bar_info);
3200
3201        // BAZ is standalone
3202        let baz_info = MacroInferInfo::new(baz);
3203        ctx.register(baz_info);
3204
3205        // Build relations
3206        ctx.build_use_relations();
3207
3208        // BAR should be used_by FOO
3209        assert!(ctx.get(bar).unwrap().used_by.contains(&foo));
3210        // BAZ should be used_by BAR
3211        assert!(ctx.get(baz).unwrap().used_by.contains(&bar));
3212    }
3213
3214    #[test]
3215    fn test_inference_candidates() {
3216        let mut interner = StringInterner::new();
3217        let foo = interner.intern("FOO");
3218        let bar = interner.intern("BAR");
3219        let baz = interner.intern("BAZ");
3220
3221        let mut ctx = MacroInferContext::new();
3222
3223        // FOO uses BAR
3224        let mut foo_info = MacroInferInfo::new(foo);
3225        foo_info.add_use(bar);
3226        ctx.register(foo_info);
3227
3228        // BAR uses BAZ
3229        let mut bar_info = MacroInferInfo::new(bar);
3230        bar_info.add_use(baz);
3231        ctx.register(bar_info);
3232
3233        // BAZ is standalone (confirmed)
3234        let mut baz_info = MacroInferInfo::new(baz);
3235        baz_info.args_infer_status = InferStatus::TypeComplete;
3236        baz_info.return_infer_status = InferStatus::TypeComplete;
3237        ctx.register(baz_info);
3238
3239        ctx.classify_initial();
3240
3241        // Initially, only BAZ is confirmed
3242        assert!(ctx.confirmed.contains(&baz));
3243        assert!(ctx.unconfirmed.contains(&foo));
3244        assert!(ctx.unconfirmed.contains(&bar));
3245
3246        // Candidates: BAR (uses BAZ which is confirmed)
3247        let candidates = ctx.get_inference_candidates();
3248        assert_eq!(candidates, vec![bar]);
3249
3250        // After confirming BAR
3251        ctx.mark_confirmed(bar);
3252        let candidates = ctx.get_inference_candidates();
3253        assert_eq!(candidates, vec![foo]);
3254    }
3255
3256    #[test]
3257    fn test_no_expand_symbols_new() {
3258        let mut interner = StringInterner::new();
3259        let symbols = NoExpandSymbols::new(&mut interner);
3260
3261        assert_eq!(interner.get(symbols.assert), "assert");
3262        assert_eq!(interner.get(symbols.assert_), "assert_");
3263    }
3264
3265    #[test]
3266    fn test_no_expand_symbols_iter() {
3267        let mut interner = StringInterner::new();
3268        let symbols = NoExpandSymbols::new(&mut interner);
3269
3270        let syms: Vec<_> = symbols.iter().collect();
3271        assert_eq!(syms.len(), 2);
3272        assert!(syms.contains(&symbols.assert));
3273        assert!(syms.contains(&symbols.assert_));
3274    }
3275
3276    #[test]
3277    fn test_explicit_expand_symbols_new() {
3278        let mut interner = StringInterner::new();
3279        let symbols = ExplicitExpandSymbols::new(&mut interner);
3280
3281        assert_eq!(interner.get(symbols.sv_any), "SvANY");
3282        assert_eq!(interner.get(symbols.sv_flags), "SvFLAGS");
3283        assert_eq!(interner.get(symbols.expect), "EXPECT");
3284        assert_eq!(interner.get(symbols.likely), "LIKELY");
3285        assert_eq!(interner.get(symbols.unlikely), "UNLIKELY");
3286        assert_eq!(interner.get(symbols.cbool), "cBOOL");
3287        assert_eq!(interner.get(symbols.assert_underscore_), "__ASSERT_");
3288        assert_eq!(interner.get(symbols.str_with_len), "STR_WITH_LEN");
3289        assert_eq!(interner.get(symbols.assert_not_rok), "assert_not_ROK");
3290        assert_eq!(interner.get(symbols.assert_not_glob), "assert_not_glob");
3291        assert_eq!(interner.get(symbols.mutable_ptr), "MUTABLE_PTR");
3292    }
3293
3294    #[test]
3295    fn test_explicit_expand_symbols_iter() {
3296        let mut interner = StringInterner::new();
3297        let symbols = ExplicitExpandSymbols::new(&mut interner);
3298
3299        let syms: Vec<_> = symbols.iter().collect();
3300        assert_eq!(syms.len(), 14);
3301        assert!(syms.contains(&symbols.assert_is_literal));
3302        assert!(syms.contains(&symbols.sv_any));
3303        assert!(syms.contains(&symbols.sv_flags));
3304        assert!(syms.contains(&symbols.cv_flags));
3305        assert!(syms.contains(&symbols.hek_flags));
3306        assert!(syms.contains(&symbols.expect));
3307        assert!(syms.contains(&symbols.likely));
3308        assert!(syms.contains(&symbols.unlikely));
3309        assert!(syms.contains(&symbols.cbool));
3310        assert!(syms.contains(&symbols.assert_underscore_));
3311        assert!(syms.contains(&symbols.str_with_len));
3312        assert!(syms.contains(&symbols.assert_not_rok));
3313        assert!(syms.contains(&symbols.assert_not_glob));
3314        // MUTABLE_PTR は明示展開しない (iter のコメント参照):
3315        // インライン展開すると外側キャストの逆伝播で MUTABLE_SV 系の
3316        // パラメータ型が誤って狭まるため、呼び出しとして保存する。
3317        assert!(!syms.contains(&symbols.mutable_ptr));
3318    }
3319}