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