Skip to main content

libperl_macrogen/
ast.rs

1//! C言語の抽象構文木
2//!
3//! C11規格に基づくAST定義。
4
5use std::sync::atomic::{AtomicU64, Ordering};
6
7use crate::intern::InternedStr;
8use crate::source::SourceLocation;
9use crate::token::Comment;
10
11// ============================================================================
12// ExprId - 式の一意識別子
13// ============================================================================
14
15/// 式ID(一意の通し番号)
16///
17/// 各式ノードに一意のIDを付与することで、型推論結果の紐付けに使用する。
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
19pub struct ExprId(pub u64);
20
21/// ExprId 生成用のグローバルカウンター
22static EXPR_ID_COUNTER: AtomicU64 = AtomicU64::new(1); // 0 は無効値として予約
23
24impl ExprId {
25    /// 新しい一意のIDを生成
26    pub fn next() -> Self {
27        Self(EXPR_ID_COUNTER.fetch_add(1, Ordering::Relaxed))
28    }
29
30    /// 無効なID
31    pub const INVALID: Self = Self(0);
32
33    /// IDが有効かどうか
34    pub fn is_valid(&self) -> bool {
35        self.0 != 0
36    }
37}
38
39impl std::fmt::Display for ExprId {
40    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41        write!(f, "ExprId({})", self.0)
42    }
43}
44
45// ============================================================================
46// マクロ展開情報
47// ============================================================================
48
49/// 単一のマクロ呼び出し情報
50#[derive(Debug, Clone, PartialEq)]
51pub struct MacroInvocation {
52    /// マクロ名
53    pub name: InternedStr,
54    /// 呼び出し位置
55    pub call_loc: SourceLocation,
56    /// 関数マクロの場合、引数のテキスト表現
57    pub args: Option<Vec<String>>,
58}
59
60impl MacroInvocation {
61    /// 新しいマクロ呼び出し情報を作成
62    pub fn new(name: InternedStr, call_loc: SourceLocation) -> Self {
63        Self {
64            name,
65            call_loc,
66            args: None,
67        }
68    }
69
70    /// 関数マクロの呼び出し情報を作成
71    pub fn with_args(name: InternedStr, call_loc: SourceLocation, args: Vec<String>) -> Self {
72        Self {
73            name,
74            call_loc,
75            args: Some(args),
76        }
77    }
78}
79
80/// マクロ展開の履歴情報
81///
82/// ネストしたマクロ展開を追跡するためのチェーン構造を持つ。
83/// 例: A が B を含み、B が C を含む場合: [A, B, C]
84#[derive(Debug, Clone, Default, PartialEq)]
85pub struct MacroExpansionInfo {
86    /// マクロ展開のチェーン(外側から内側へ)
87    pub chain: Vec<MacroInvocation>,
88}
89
90impl MacroExpansionInfo {
91    /// 新しい空のマクロ展開情報を作成
92    pub fn new() -> Self {
93        Self { chain: Vec::new() }
94    }
95
96    /// チェーンが空かどうか
97    pub fn is_empty(&self) -> bool {
98        self.chain.is_empty()
99    }
100
101    /// マクロ呼び出しを追加
102    pub fn push(&mut self, invocation: MacroInvocation) {
103        self.chain.push(invocation);
104    }
105
106    /// 最も内側のマクロ呼び出し
107    pub fn innermost(&self) -> Option<&MacroInvocation> {
108        self.chain.last()
109    }
110
111    /// 最も外側のマクロ呼び出し
112    pub fn outermost(&self) -> Option<&MacroInvocation> {
113        self.chain.first()
114    }
115
116    /// チェーンの長さ
117    pub fn len(&self) -> usize {
118        self.chain.len()
119    }
120}
121
122/// ASTノードの共通メタデータ
123///
124/// ソース位置とオプションのマクロ展開情報を保持する。
125/// Phase 5 で各ASTノードの `loc: SourceLocation` を `info: NodeInfo` に置き換える。
126#[derive(Debug, Clone, Default, PartialEq)]
127pub struct NodeInfo {
128    /// ソース位置
129    pub loc: SourceLocation,
130    /// マクロ展開情報(マクロ展開由来の場合のみ Some)
131    pub macro_expansion: Option<Box<MacroExpansionInfo>>,
132}
133
134impl NodeInfo {
135    /// 新しいNodeInfoを作成(マクロ情報なし)
136    pub fn new(loc: SourceLocation) -> Self {
137        Self {
138            loc,
139            macro_expansion: None,
140        }
141    }
142
143    /// マクロ情報付きのNodeInfoを作成
144    ///
145    /// マクロ情報が空の場合は None として保存する。
146    pub fn with_macro_info(loc: SourceLocation, macro_info: MacroExpansionInfo) -> Self {
147        Self {
148            loc,
149            macro_expansion: if macro_info.is_empty() {
150                None
151            } else {
152                Some(Box::new(macro_info))
153            },
154        }
155    }
156
157    /// マクロ展開由来かどうか
158    pub fn is_from_macro(&self) -> bool {
159        self.macro_expansion.is_some()
160    }
161
162    /// マクロ展開情報への参照を取得
163    pub fn macro_info(&self) -> Option<&MacroExpansionInfo> {
164        self.macro_expansion.as_deref()
165    }
166}
167
168// ============================================================================
169// AST 定義
170// ============================================================================
171
172/// 翻訳単位(ファイル全体)
173#[derive(Debug, Clone)]
174pub struct TranslationUnit {
175    pub decls: Vec<ExternalDecl>,
176}
177
178/// 外部宣言
179#[derive(Debug, Clone)]
180pub enum ExternalDecl {
181    /// 関数定義
182    FunctionDef(FunctionDef),
183    /// 変数・型宣言
184    Declaration(Declaration),
185}
186
187impl ExternalDecl {
188    /// ターゲットディレクトリで定義されたかどうか
189    pub fn is_target(&self) -> bool {
190        match self {
191            ExternalDecl::FunctionDef(f) => f.is_target,
192            ExternalDecl::Declaration(d) => d.is_target,
193        }
194    }
195}
196
197/// 関数定義
198#[derive(Debug, Clone)]
199pub struct FunctionDef {
200    pub specs: DeclSpecs,
201    pub declarator: Declarator,
202    pub body: CompoundStmt,
203    pub info: NodeInfo,
204    pub comments: Vec<Comment>,
205    /// ターゲットディレクトリで定義されたかどうか
206    pub is_target: bool,
207    /// 関数本体に含まれる関数呼び出しの数(パース時に検出)
208    pub function_call_count: usize,
209    /// 関数本体に含まれるポインタデリファレンスの数(パース時に検出)
210    pub deref_count: usize,
211}
212
213impl FunctionDef {
214    /// 後方互換性のための loc アクセサ
215    pub fn loc(&self) -> &SourceLocation {
216        &self.info.loc
217    }
218}
219
220/// 宣言
221#[derive(Debug, Clone)]
222pub struct Declaration {
223    pub specs: DeclSpecs,
224    pub declarators: Vec<InitDeclarator>,
225    pub info: NodeInfo,
226    pub comments: Vec<Comment>,
227    /// ターゲットディレクトリで定義されたかどうか
228    pub is_target: bool,
229}
230
231impl Declaration {
232    /// 後方互換性のための loc アクセサ
233    pub fn loc(&self) -> &SourceLocation {
234        &self.info.loc
235    }
236}
237
238/// 宣言指定子
239#[derive(Debug, Clone, Default)]
240pub struct DeclSpecs {
241    pub storage: Option<StorageClass>,
242    pub type_specs: Vec<TypeSpec>,
243    pub qualifiers: TypeQualifiers,
244    pub is_inline: bool,
245}
246
247/// ストレージクラス
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249pub enum StorageClass {
250    Typedef,
251    Extern,
252    Static,
253    Auto,
254    Register,
255}
256
257/// 型指定子
258#[derive(Debug, Clone)]
259pub enum TypeSpec {
260    Void,
261    Char,
262    Short,
263    Int,
264    Long,
265    Float,
266    Double,
267    Signed,
268    Unsigned,
269    Bool,
270    Complex,
271    // GCC拡張浮動小数点型
272    Float16,
273    Float32,
274    Float64,
275    Float128,
276    Float32x,
277    Float64x,
278    // GCC拡張: 128ビット整数
279    Int128,
280    // GCC拡張: __typeof__(expr)
281    TypeofExpr(Box<Expr>),
282    Struct(StructSpec),
283    Union(StructSpec),
284    Enum(EnumSpec),
285    TypedefName(InternedStr),
286}
287
288/// 型修飾子
289#[derive(Debug, Clone, Default, PartialEq)]
290pub struct TypeQualifiers {
291    pub is_const: bool,
292    pub is_volatile: bool,
293    pub is_restrict: bool,
294    pub is_atomic: bool,
295}
296
297impl TypeQualifiers {
298    pub fn is_empty(&self) -> bool {
299        !self.is_const && !self.is_volatile && !self.is_restrict && !self.is_atomic
300    }
301}
302
303/// 構造体/共用体指定
304#[derive(Debug, Clone)]
305pub struct StructSpec {
306    pub name: Option<InternedStr>,
307    pub members: Option<Vec<StructMember>>,
308    pub loc: SourceLocation,
309}
310
311/// 構造体メンバー
312#[derive(Debug, Clone)]
313pub struct StructMember {
314    pub specs: DeclSpecs,
315    pub declarators: Vec<StructDeclarator>,
316}
317
318/// 構造体メンバー宣言子
319#[derive(Debug, Clone)]
320pub struct StructDeclarator {
321    pub declarator: Option<Declarator>,
322    pub bitfield: Option<Box<Expr>>,
323}
324
325/// 列挙型指定
326#[derive(Debug, Clone)]
327pub struct EnumSpec {
328    pub name: Option<InternedStr>,
329    pub enumerators: Option<Vec<Enumerator>>,
330    pub loc: SourceLocation,
331}
332
333/// 列挙子
334#[derive(Debug, Clone)]
335pub struct Enumerator {
336    pub name: InternedStr,
337    pub value: Option<Box<Expr>>,
338    pub loc: SourceLocation,
339}
340
341/// パラメータ宣言
342#[derive(Debug, Clone)]
343pub struct ParamDecl {
344    pub specs: DeclSpecs,
345    pub declarator: Option<Declarator>,
346    pub loc: SourceLocation,
347}
348
349/// パラメータリスト
350#[derive(Debug, Clone)]
351pub struct ParamList {
352    pub params: Vec<ParamDecl>,
353    pub is_variadic: bool,
354}
355
356/// 初期化子付き宣言子
357#[derive(Debug, Clone)]
358pub struct InitDeclarator {
359    pub declarator: Declarator,
360    pub init: Option<Initializer>,
361}
362
363/// 宣言子
364#[derive(Debug, Clone)]
365pub struct Declarator {
366    pub name: Option<InternedStr>,
367    pub derived: Vec<DerivedDecl>,
368    pub loc: SourceLocation,
369}
370
371/// 派生宣言子(ポインタ、配列、関数)
372#[derive(Debug, Clone)]
373pub enum DerivedDecl {
374    Pointer(TypeQualifiers),
375    Array(ArrayDecl),
376    Function(ParamList),
377}
378
379/// 配列宣言子
380#[derive(Debug, Clone)]
381pub struct ArrayDecl {
382    pub size: Option<Box<Expr>>,
383    pub qualifiers: TypeQualifiers,
384    pub is_static: bool,
385    pub is_vla: bool,
386}
387
388/// 初期化子
389#[derive(Debug, Clone)]
390pub enum Initializer {
391    Expr(Box<Expr>),
392    List(Vec<InitializerItem>),
393}
394
395/// 初期化子リスト項目
396#[derive(Debug, Clone)]
397pub struct InitializerItem {
398    pub designation: Vec<Designator>,
399    pub init: Initializer,
400}
401
402/// 指示子
403#[derive(Debug, Clone)]
404pub enum Designator {
405    Index(Box<Expr>),
406    Member(InternedStr),
407}
408
409/// 文
410#[derive(Debug, Clone)]
411pub enum Stmt {
412    /// 複合文
413    Compound(CompoundStmt),
414    /// 式文
415    Expr(Option<Box<Expr>>, SourceLocation),
416    /// if文
417    If {
418        cond: Box<Expr>,
419        then_stmt: Box<Stmt>,
420        else_stmt: Option<Box<Stmt>>,
421        loc: SourceLocation,
422    },
423    /// switch文
424    Switch {
425        expr: Box<Expr>,
426        body: Box<Stmt>,
427        loc: SourceLocation,
428    },
429    /// while文
430    While {
431        cond: Box<Expr>,
432        body: Box<Stmt>,
433        loc: SourceLocation,
434    },
435    /// do-while文
436    DoWhile {
437        body: Box<Stmt>,
438        cond: Box<Expr>,
439        loc: SourceLocation,
440    },
441    /// for文
442    For {
443        init: Option<ForInit>,
444        cond: Option<Box<Expr>>,
445        step: Option<Box<Expr>>,
446        body: Box<Stmt>,
447        loc: SourceLocation,
448    },
449    /// goto文
450    Goto(InternedStr, SourceLocation),
451    /// continue文
452    Continue(SourceLocation),
453    /// break文
454    Break(SourceLocation),
455    /// return文
456    Return(Option<Box<Expr>>, SourceLocation),
457    /// ラベル文
458    Label {
459        name: InternedStr,
460        stmt: Box<Stmt>,
461        loc: SourceLocation,
462    },
463    /// case文
464    Case {
465        expr: Box<Expr>,
466        stmt: Box<Stmt>,
467        loc: SourceLocation,
468    },
469    /// default文
470    Default {
471        stmt: Box<Stmt>,
472        loc: SourceLocation,
473    },
474    /// asm文
475    Asm {
476        loc: SourceLocation,
477    },
478}
479
480/// for文の初期化部
481#[derive(Debug, Clone)]
482pub enum ForInit {
483    Expr(Box<Expr>),
484    Decl(Declaration),
485}
486
487/// 複合文
488#[derive(Debug, Clone)]
489pub struct CompoundStmt {
490    pub items: Vec<BlockItem>,
491    pub info: NodeInfo,
492}
493
494impl CompoundStmt {
495    /// 後方互換性のための loc アクセサ
496    pub fn loc(&self) -> &SourceLocation {
497        &self.info.loc
498    }
499}
500
501/// ブロック内項目
502#[derive(Debug, Clone)]
503pub enum BlockItem {
504    Decl(Declaration),
505    Stmt(Stmt),
506}
507
508/// ビルトイン呼び出しの引数(型名 or 式)
509///
510/// `offsetof(type, member)` のように、引数に型名を取りうるビルトイン関数で使用。
511#[derive(Debug, Clone)]
512pub enum BuiltinArg {
513    Expr(Box<Expr>),
514    TypeName(Box<TypeName>),
515}
516
517/// 式の種類
518#[derive(Debug, Clone)]
519pub enum ExprKind {
520    // 一次式
521    Ident(InternedStr),
522    IntLit(i64),
523    UIntLit(u64),
524    FloatLit(f64),
525    CharLit(u8),
526    StringLit(Vec<u8>),
527
528    // 後置式
529    Index {
530        expr: Box<Expr>,
531        index: Box<Expr>,
532    },
533    Call {
534        func: Box<Expr>,
535        args: Vec<Expr>,
536    },
537    Member {
538        expr: Box<Expr>,
539        member: InternedStr,
540    },
541    PtrMember {
542        expr: Box<Expr>,
543        member: InternedStr,
544    },
545    PostInc(Box<Expr>),
546    PostDec(Box<Expr>),
547    CompoundLit {
548        type_name: Box<TypeName>,
549        init: Vec<InitializerItem>,
550    },
551
552    // 単項式
553    PreInc(Box<Expr>),
554    PreDec(Box<Expr>),
555    AddrOf(Box<Expr>),
556    Deref(Box<Expr>),
557    UnaryPlus(Box<Expr>),
558    UnaryMinus(Box<Expr>),
559    BitNot(Box<Expr>),
560    LogNot(Box<Expr>),
561    Sizeof(Box<Expr>),
562    SizeofType(Box<TypeName>),
563    Alignof(Box<TypeName>),
564    Cast {
565        type_name: Box<TypeName>,
566        expr: Box<Expr>,
567    },
568
569    // 二項式
570    Binary {
571        op: BinOp,
572        lhs: Box<Expr>,
573        rhs: Box<Expr>,
574    },
575
576    // 条件式
577    Conditional {
578        cond: Box<Expr>,
579        then_expr: Box<Expr>,
580        else_expr: Box<Expr>,
581    },
582
583    // 代入式
584    Assign {
585        op: AssignOp,
586        lhs: Box<Expr>,
587        rhs: Box<Expr>,
588    },
589
590    // コンマ式
591    Comma {
592        lhs: Box<Expr>,
593        rhs: Box<Expr>,
594    },
595
596    // GCC拡張: ステートメント式 ({ ... })
597    StmtExpr(CompoundStmt),
598
599    /// アサーション式(マクロが空に展開されても保持)
600    Assert {
601        kind: AssertKind,
602        condition: Box<Expr>,
603    },
604
605    /// マクロ呼び出し(元の呼び出し情報と展開結果を両方保持)
606    ///
607    /// 全てのマクロを常に展開しながら、元のマクロ呼び出し情報を AST に保持する。
608    /// - `expanded`: 型推論・意味解析用の展開結果
609    /// - `name` と `args`: コード生成時にマクロ呼び出しを再構築
610    MacroCall {
611        /// マクロ名
612        name: InternedStr,
613        /// 元の引数(パース済み式)
614        args: Vec<Expr>,
615        /// 展開後の式(型推論・意味解析用)
616        expanded: Box<Expr>,
617        /// マクロ呼び出し位置
618        call_loc: SourceLocation,
619    },
620
621    /// ビルトイン関数呼び出し(引数に型名を含みうる)
622    ///
623    /// `offsetof(type, member)`, `__builtin_types_compatible_p(type1, type2)` 等、
624    /// 引数に型名を取りうるビルトイン関数をパースするための汎用ノード。
625    BuiltinCall {
626        name: InternedStr,
627        args: Vec<BuiltinArg>,
628    },
629}
630
631/// 式ノード
632#[derive(Debug, Clone)]
633pub struct Expr {
634    /// 式の一意識別子
635    pub id: ExprId,
636    /// 式の種類
637    pub kind: ExprKind,
638    /// ソース位置
639    pub loc: SourceLocation,
640}
641
642impl Expr {
643    /// 新しい式ノードを作成
644    pub fn new(kind: ExprKind, loc: SourceLocation) -> Self {
645        Self {
646            id: ExprId::next(),
647            kind,
648            loc,
649        }
650    }
651
652    /// 式の位置情報を取得(後方互換性)
653    pub fn loc(&self) -> &SourceLocation {
654        &self.loc
655    }
656}
657
658/// 型名(キャストやsizeofで使用)
659#[derive(Debug, Clone)]
660pub struct TypeName {
661    pub specs: DeclSpecs,
662    pub declarator: Option<AbstractDeclarator>,
663}
664
665/// 抽象宣言子(名前なし)
666#[derive(Debug, Clone)]
667pub struct AbstractDeclarator {
668    pub derived: Vec<DerivedDecl>,
669}
670
671/// 二項演算子
672#[derive(Debug, Clone, Copy, PartialEq, Eq)]
673pub enum BinOp {
674    // 乗除
675    Mul,
676    Div,
677    Mod,
678    // 加減
679    Add,
680    Sub,
681    // シフト
682    Shl,
683    Shr,
684    // 比較
685    Lt,
686    Gt,
687    Le,
688    Ge,
689    Eq,
690    Ne,
691    // ビット演算
692    BitAnd,
693    BitXor,
694    BitOr,
695    // 論理演算
696    LogAnd,
697    LogOr,
698}
699
700/// 代入演算子
701#[derive(Debug, Clone, Copy, PartialEq, Eq)]
702pub enum AssignOp {
703    Assign,
704    MulAssign,
705    DivAssign,
706    ModAssign,
707    AddAssign,
708    SubAssign,
709    ShlAssign,
710    ShrAssign,
711    AndAssign,
712    XorAssign,
713    OrAssign,
714}
715
716/// アサーションマクロの種類
717#[derive(Debug, Clone, Copy, PartialEq, Eq)]
718pub enum AssertKind {
719    /// assert(condition)
720    Assert,
721    /// assert_(condition) - 末尾カンマ付き
722    AssertUnderscore,
723}
724#[cfg(test)]
725mod tests {
726    use super::*;
727    use crate::intern::StringInterner;
728
729    #[test]
730    fn test_type_qualifiers_is_empty() {
731        let empty = TypeQualifiers::default();
732        assert!(empty.is_empty());
733
734        let with_const = TypeQualifiers {
735            is_const: true,
736            ..Default::default()
737        };
738        assert!(!with_const.is_empty());
739    }
740
741    // MacroInvocation tests
742
743    #[test]
744    fn test_macro_invocation_new() {
745        let mut interner = StringInterner::new();
746        let name = interner.intern("FOO");
747        let loc = SourceLocation::default();
748
749        let inv = MacroInvocation::new(name, loc.clone());
750
751        assert_eq!(inv.name, name);
752        assert_eq!(inv.call_loc, loc);
753        assert!(inv.args.is_none());
754    }
755
756    #[test]
757    fn test_macro_invocation_with_args() {
758        let mut interner = StringInterner::new();
759        let name = interner.intern("ADD");
760        let loc = SourceLocation::default();
761        let args = vec!["a".to_string(), "b".to_string()];
762
763        let inv = MacroInvocation::with_args(name, loc.clone(), args.clone());
764
765        assert_eq!(inv.name, name);
766        assert_eq!(inv.call_loc, loc);
767        assert_eq!(inv.args, Some(args));
768    }
769
770    // MacroExpansionInfo tests
771
772    #[test]
773    fn test_macro_expansion_info_new() {
774        let info = MacroExpansionInfo::new();
775        assert!(info.is_empty());
776        assert_eq!(info.len(), 0);
777        assert!(info.innermost().is_none());
778        assert!(info.outermost().is_none());
779    }
780
781    #[test]
782    fn test_macro_expansion_info_push() {
783        let mut interner = StringInterner::new();
784        let mut info = MacroExpansionInfo::new();
785
786        let inv1 = MacroInvocation::new(interner.intern("FOO"), SourceLocation::default());
787        let inv2 = MacroInvocation::new(interner.intern("BAR"), SourceLocation::default());
788
789        info.push(inv1.clone());
790        assert_eq!(info.len(), 1);
791        assert!(!info.is_empty());
792
793        info.push(inv2.clone());
794        assert_eq!(info.len(), 2);
795
796        // outermost は最初に追加したもの
797        assert_eq!(info.outermost().unwrap().name, inv1.name);
798        // innermost は最後に追加したもの
799        assert_eq!(info.innermost().unwrap().name, inv2.name);
800    }
801
802    #[test]
803    fn test_macro_expansion_info_chain() {
804        let mut interner = StringInterner::new();
805        let mut info = MacroExpansionInfo::new();
806
807        // A → B → C のチェーン
808        info.push(MacroInvocation::new(interner.intern("A"), SourceLocation::default()));
809        info.push(MacroInvocation::new(interner.intern("B"), SourceLocation::default()));
810        info.push(MacroInvocation::new(interner.intern("C"), SourceLocation::default()));
811
812        assert_eq!(info.chain.len(), 3);
813        assert_eq!(interner.get(info.chain[0].name), "A");
814        assert_eq!(interner.get(info.chain[1].name), "B");
815        assert_eq!(interner.get(info.chain[2].name), "C");
816    }
817
818    // NodeInfo tests
819
820    #[test]
821    fn test_node_info_new() {
822        let loc = SourceLocation::new(crate::source::FileId::default(), 10, 5);
823        let info = NodeInfo::new(loc.clone());
824
825        assert_eq!(info.loc, loc);
826        assert!(!info.is_from_macro());
827        assert!(info.macro_info().is_none());
828    }
829
830    #[test]
831    fn test_node_info_with_empty_macro_info() {
832        let loc = SourceLocation::default();
833        let macro_info = MacroExpansionInfo::new();
834
835        let info = NodeInfo::with_macro_info(loc.clone(), macro_info);
836
837        // 空のマクロ情報は None として保存される
838        assert!(!info.is_from_macro());
839        assert!(info.macro_info().is_none());
840    }
841
842    #[test]
843    fn test_node_info_with_macro_info() {
844        let mut interner = StringInterner::new();
845        let loc = SourceLocation::default();
846
847        let mut macro_info = MacroExpansionInfo::new();
848        macro_info.push(MacroInvocation::new(interner.intern("FOO"), SourceLocation::default()));
849
850        let info = NodeInfo::with_macro_info(loc.clone(), macro_info);
851
852        assert!(info.is_from_macro());
853        assert!(info.macro_info().is_some());
854        assert_eq!(info.macro_info().unwrap().len(), 1);
855    }
856
857    #[test]
858    fn test_node_info_default() {
859        let info = NodeInfo::default();
860
861        assert_eq!(info.loc, SourceLocation::default());
862        assert!(!info.is_from_macro());
863    }
864}