Skip to main content

cure_java_ast/
lib.rs

1//! # cure-java-ast
2//!
3//! Java AST(arena + NodeId)+ 编译单元/成员结构 + builder + [`cure_engine::Lang`] 实现。
4//!
5//! 覆盖反编译器产出的常见 Java:完整语句集(含 try/catch、switch、for-each、
6//! lambda 等)、完整表达式集、类/接口/枚举成员。签名里的泛型/注解以**原文**字符串
7//! 保留(保真打印),方法体内才是可简化的 arena 节点。
8//!
9//! 零外部依赖(仅依赖 cure-engine),可单独作为"Java AST + 语义查询"基础库引用。
10//!
11//! arena 不变量:children 永远先于父节点入 arena(index 递增)。
12
13use std::collections::{HashMap, HashSet};
14
15use cure_engine::analysis::{subtree_metrics, TreeMetrics};
16use cure_engine::lang::{ReassocOutcome, StmtKill};
17use cure_engine::Lang;
18pub use cure_tree::ChildList;
19use cure_tree::{EventStore, NameTable};
20
21// 本 crate 自用 + 供下游 crate(如 cure-java-print/parser)免依赖引擎直接使用
22pub use cure_engine::kind::{BinOp, LitRef, NodeKind, UnOp};
23pub use cure_engine::Effect;
24
25// ---------------------------------------------------------------------------
26// 基础类型
27// ---------------------------------------------------------------------------
28
29/// arena 句柄。
30#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
31pub struct JavaId(pub u32);
32impl Default for JavaId {
33    fn default() -> Self {
34        JavaId(u32::MAX)
35    }
36}
37
38/// Java 类型(第一阶段的最小集合;`Ref` 存类型名字符串,泛型参数并入字符串)。
39#[derive(Clone, PartialEq, Eq, Debug)]
40pub enum JType {
41    Bool,
42    Byte,
43    Short,
44    Int,
45    Long,
46    Char,
47    Float,
48    Double,
49    Void,
50    /// 引用类型,存点分名或简单名(可含泛型参数原文,如 `Map<String, ?>`)。
51    Ref(String),
52    Array(Box<JType>),
53    /// var / 推断类型 / 未知。
54    Var,
55}
56
57impl JType {
58    pub fn is_ref(&self) -> bool {
59        matches!(self, JType::Ref(_) | JType::Array(_))
60    }
61    pub fn is_integral(&self) -> bool {
62        matches!(
63            self,
64            JType::Byte | JType::Short | JType::Int | JType::Long | JType::Char
65        )
66    }
67    pub fn is_bool(&self) -> bool {
68        matches!(self, JType::Bool)
69    }
70}
71
72/// 数值字面量的解析值(用于语义查询;原文见 [`Lit::NumRaw`])。
73#[derive(Clone, Copy, PartialEq, Debug)]
74pub enum NumVal {
75    Int(i64),
76    Long(i64),
77    Float(f64),
78    Double(f64),
79}
80
81/// 字面量。
82#[derive(Clone, PartialEq, Debug)]
83pub enum Lit {
84    Bool(bool),
85    Int(i64),
86    Long(i64),
87    Float(f64),
88    Double(f64),
89    Char(char),
90    Str(String),
91    /// 文本块(`"""..."""`),存去引号后的原文。
92    TextBlock(String),
93    /// 带原文的数值字面量:保留 0x1F / 1.5e2f / 1_000_000L 等原文形式。
94    NumRaw { text: String, val: NumVal },
95    Null,
96}
97
98/// 节点负载:children 统一放在 [`Node::children`],这里只放非节点数据。
99#[derive(Clone, PartialEq, Debug)]
100pub enum NodeData {
101    // ---- 语句 ----
102    Block,
103    /// 合成分组(无花括号、**无作用域**):多声明符等"一句多语句"的承载。
104    /// 语句列表处在解析期就地展开;若存活到打印,按同缩进无括号输出。
105    /// kind() 映射为 Block(引擎规则透明),但语义上不引入词法作用域。
106    Group,
107    Empty,
108    /// `yield expr;`(switch 表达式产出)。孩子 [expr]。
109    Yield,
110
111    ExprStmt,
112    VarDecl { name: String, ty: JType, final_mod: bool },
113    Assign { op: Option<BinOp> },
114    If,
115    While,
116    DoWhile,
117    For { inits: u8, has_cond: bool, steps: u8 },
118    ForEach { name: String, ty: JType },
119    Return,
120    Break { label: Option<String> },
121    Continue { label: Option<String> },
122    Throw,
123    /// children: `[resource…, try_block, catch…, (finally)?]`
124    Try,
125    /// `catch (ty_raw name)`,children: `[block]`
126    Catch { ty_raw: String, name: String },
127    /// children: `[lock, block]`
128    Synchronized,
129    /// children: `[subject, case…]`
130    Switch,
131    /// children: `[label…, stmts…]`(前 `labels` 个是 case 标签表达式)
132    Case { labels: u16, is_default: bool, arrow: bool },
133    /// children: `[stmt]`
134    Label { name: String },
135    /// children: `[cond, (msg)?]`
136    Assert,
137    /// 不可解析的原文区域:原样保留,简化规则不触碰。
138    Raw { text: String },
139
140    // ---- 表达式 ----
141    Binary { op: BinOp },
142    Unary { op: UnOp },
143    /// children: `[callee, arg…]`
144    Call,
145    /// children: `[object]`;`name` 为成员名。
146    Member { name: Sym },
147    /// children: `[array, index]`
148    Index,
149    Cast { ty: JType },
150    Paren,
151    Ternary,
152    /// `new T(args…)`;匿名类体以原文附加。
153    New { ty: JType, anon_raw: Option<String> },
154    /// `new T[sz…][]… [init]`;ty 为元素类型,dims=总维数,sized=带尺寸维数;
155    /// children: `[size…, (ArrayLit)?]`
156    NewArray { ty: JType, dims: u16, sized: u16 },
157    ArrayLit,
158    VarRef { name: Sym },
159    Literal(Lit),
160    This,
161    /// `super`(super.foo() / super(args) 的 callee)
162    Super,
163    /// children: `[expr]`;`x instanceof T bind`
164    InstanceOf { ty: JType, bind: Option<String> },
165    /// children: `[body]`(body 为 Block 或表达式)
166    Lambda { params_raw: String },
167    /// children: `[receiver]`;`recv::name`(name 含 `new`)
168    MethodRef { name: Sym },
169}
170
171#[derive(Clone, PartialEq, Debug)]
172pub struct Node {
173    pub data: NodeData,
174    pub children: ChildList<JavaId>,
175}
176
177/// 符号(intern 名字 id)。VarRef/Member/MethodRef 的名字字段——
178/// 87% 重复率(实测 jdk-sources:4754 个名字节点仅 669 个唯一),
179/// String→Sym 后:构造去重、比较 u32、clone 零分配(copy_subtree/
180/// clone_node 全线受益)。
181#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
182pub struct Sym(pub u32);
183
184/// Lit 值级相等(payload_equal 用;TextBlock 无值语义 → false)。
185fn lit_value_eq(x: &Lit, y: &Lit) -> bool {
186    fn r(l: &Lit) -> Option<cure_engine::kind::LitRef<'_>> {
187        Some(match l {
188            Lit::Bool(b) => LitRef::Bool(*b),
189            Lit::Int(v) => LitRef::Int(*v),
190            Lit::Long(v) => LitRef::Long(*v),
191            Lit::Float(v) => LitRef::Float(*v),
192            Lit::Double(v) => LitRef::Double(*v),
193            Lit::Char(c) => LitRef::Char(*c),
194            Lit::Str(s) => LitRef::Str(s.as_str()),
195            Lit::NumRaw { val, .. } => match val {
196                NumVal::Int(v) => LitRef::Int(*v),
197                NumVal::Long(v) => LitRef::Long(*v),
198                NumVal::Float(v) => LitRef::Float(*v),
199                NumVal::Double(v) => LitRef::Double(*v),
200            },
201            Lit::Null => LitRef::Null,
202            Lit::TextBlock(_) => return None,
203        })
204    }
205    // ±0.0 位模式区分(IEEE == 视相等但 1/x 符号不同——ES
206    // StripeStatsHarvesterTests 抓获:b ? 0.0 : -0.0 曾折成 0.0)
207    match (r(x), r(y)) {
208        (Some(rx), Some(ry)) => {
209            if let (LitRef::Double(a), LitRef::Double(b)) = (rx, ry) {
210                return a == b && a.is_sign_negative() == b.is_sign_negative();
211            }
212            if let (LitRef::Float(a), LitRef::Float(b)) = (rx, ry) {
213                return a == b && a.is_sign_negative() == b.is_sign_negative();
214            }
215            rx == ry
216        }
217        _ => false,
218    }
219}
220
221/// 同名同元数方法候选(no-op 调用消解用)。
222#[derive(Clone, Debug)]
223pub struct NoopCandidate {
224    /// 形参类型表。
225    pub params: Vec<JType>,
226    /// private + 空体(no-op)。
227    pub noop: bool,
228}
229
230
231// ---------------------------------------------------------------------------
232// 外部事实(front-end facts)——cure-engine Lang 事实查询面的 Java 载体。
233//
234// 持有 IR/类型/数据流信息的调用方(反编译前端)对源码可见变量与被调
235// 成员的权威陈述。语言无关的词汇语义见 cure_engine::lang 的 trait 文档;
236// 本结构只是键的承载(局部名 → 变量事实;成员名 → 调用副作用上限)。
237// 生命周期 = 编译单元:换单元必须 clear_facts()(simplify_unit 门面
238// 已自动管理)。零依赖 Rust 结构(序列化形态留给后续 feature 门控)。
239// ---------------------------------------------------------------------------
240
241/// 单个局部变量的事实集(全部缺省 false = 未知/不成立)。
242#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
243pub struct VarFacts {
244    /// 源码外无隐藏写,可见写恰为一次(单一定义)。
245    pub single_def: bool,
246    /// 读点恰为一次(前端权威计数)。
247    pub single_use: bool,
248    /// 静态类型为原始 boolean(寄存器复用 demux 的真值)。
249    pub bool_valued: bool,
250}
251
252/// 编译单元级事实集:局部名(前端发射的名字与源码文本一致——名字是
253/// 文本往返的稳定键)→ 变量事实;被调成员名 → 副作用上限。
254#[derive(Debug, Clone, Default)]
255pub struct JavaFacts {
256    pub vars: HashMap<String, VarFacts>,
257    pub call_effects: HashMap<String, std::collections::HashSet<cure_engine::Effect>>,
258}
259
260impl JavaFacts {
261    pub fn var(&self, name: &str) -> VarFacts {
262        self.vars.get(name).copied().unwrap_or_default()
263    }
264}
265
266/// Per-statement syntactic name facts used by propagation rules: VarRef
267/// multiplicity plus whether a lambda in the subtree captures the name.
268/// Built once per statement alongside the region-event index and
269/// invalidated by the same `invalidate_effect` ancestor walk.
270#[derive(Clone, Copy, Debug)]
271struct StmtFact {
272    key: u32,
273    refs: u32,
274    lambda_cap: bool,
275    /// VarDecl/ForEach/Catch declares this name (region-event Shadow).
276    shadow: bool,
277}
278
279/// Per-statement kill event (`collect_stmt_kill_events`). `kind`:
280/// 1 = Read, 2 = Shadow, 3 = DomWrite.
281#[derive(Clone, Copy, Debug)]
282struct StmtKillFact {
283    key: u32,
284    kind: u8,
285    assign: JavaId,
286}
287
288
289#[derive(Clone, Copy, Debug)]
290struct StmtOpq {
291    opaque: bool,
292}
293
294#[derive(Default, Debug)]
295pub struct JavaAst {
296    pub(crate) nodes: Vec<Node>,
297    /// 外部事实(前端注入;编译单元生命周期)。None = 纯源码保守模式。
298    pub facts: Option<JavaFacts>,
299    /// prepare() 重建:JavaId → 聚合效果。
300    /// 槽位 = arena 下标(稠密 u32);None = 未算/失效。Vec 索引替代哈希。
301    effect_cache: Vec<Option<Effect>>,
302    /// prepare() 重建:VarRef 节点 → 声明类型(作用域解析)。
303    /// 槽位 = arena 下标;None = 未解析。Vec 索引替代哈希。
304    var_types: Vec<Option<JType>>,
305    /// 方法参数类型(由 simplify 门面按方法设置,作为根作用域)。
306    param_scope: Vec<(String, JType)>,
307    /// 类级常量字段(static final 且字面量/字面量数组初始化、无写、无同名局部)
308    /// → 初始化节点。由 simplify_unit 填充(跨方法解密的字符串表)。
309    pub const_fields: HashMap<String, JavaId>,
310    /// 可安全做 VarRef → 字面量传播的常量字段名(标量字面量且声明类型
311    /// 与字面量种类精确匹配——过载解析/常量池身份不受影响)。
312    /// 数组常量不进(只走下标折叠,整表引用不复制)。
313    pub const_scalars: HashSet<String>,
314    /// 空私有方法(no-op 调用清理用):名字 → 元数 → 同名同元数全部
315    /// 候选(参数类型表 + 是否 private 空体)。调用点做类型适用性消解
316    ///(唯一适用者且为 private 空体 → no-op)。同名任意方法含 varargs →
317    /// 该名整体放弃(varargs 可吸收任意元数)。由 simplify_unit 填充
318    ///(--dead-code 门控)。
319    pub noop_private_methods: HashMap<String, HashMap<usize, Vec<NoopCandidate>>>,
320    /// 字段声明类型表(名字 → JType;同名二见移除)——调用点实参静态
321    /// 类型解析用(VarRef 解析不到局部时查字段)。collect_unit_consts 填充。
322    pub field_types: HashMap<String, JType>,
323    /// 本单元声明了名为 String/StringBuilder 的类型(遮蔽 java.lang——
324    /// new String("x") 折叠/字符串链折叠在该单元全部拒绝。探针 T4a/b
325    /// 抓获:`class String{…}` 同文件时 new String 折叠产出不可编译或
326    /// 静默错值)。collect_unit_consts 每轮重算。
327    pub unit_shadows_lang: bool,
328    /// 已知为**泛型**的类型简单名(单元内带 ty_params 的类型 + 常见
329    /// JDK 泛型库类)。raw 引用(无类型实参)这些名字时,接收位传播
330    /// 改变成员解析(raw 擦除 vs 泛型形参——CAP#1 编译错)。
331    pub raw_generic_names: std::collections::HashSet<String>,
332    /// final 字段名集合(同名二见移除——保守)。static_exec 截断守卫
333    /// 用:前缀字段写被 rest 再赋值时,仅 final 才放弃(非 final 的
334    /// 材料化写是死写,语义恒等、可编译)。
335    pub final_fields: HashSet<String>,
336    /// 当前正在简化的方法返回类型(simplify_member 设置)——窄类型
337    /// return 的常量收窄守卫用(if→三元合并前检查)。None = 非方法体。
338    pub current_return_ty: Option<JType>,
339    /// 可内联的单 return 方法:名字 → (参数名表, 返回表达式节点, 声明
340    /// 该方法的类的简单名)。owner 供 const_method_inline 的归属守卫:
341    /// 限定调用的接收者类名必须与之一致——名字匹配不判归属会把 JDK 的
342    /// Integer.valueOf 当本类同名方法内联。由 simplify_unit 填充(解密
343    /// helper:d(0) → 方法体)。
344    pub inline_methods: HashMap<String, (Vec<String>, JavaId, String)>,
345    /// String 引用身份比较缓存:(root, 结果)。prepare() 清空(树已变),
346    /// 首次查询时计算——供 new String(lit) 等折叠守卫复用(每轮至多一次全扫)。
347    string_identity: std::cell::Cell<Option<(JavaId, bool)>>,
348    /// **单元级** String 身份比较存在标志(collect_unit_consts 每轮重算)。
349    /// new String(lit) 解包为池化字面量会翻转任何 == 观察点——字段 init
350    /// 解包的观察点在**其他方法**里(InputNoWhitespaceAfterWithEmoji 抓获
351    /// 合成证实:a == "hello" false→true),单根扫描看不见 → 单元级守卫。
352    pub unit_string_identity: bool,
353    /// 名字 intern 表 + 节点名字键(cure-tree `NameTable`;本语言
354    /// `Lang::NameKey = u32` intern id)。单元级持久、只增;prepare
355    /// 增量扩展新节点,既有节点键与其名字恒同。
356    names: NameTable,
357    /// 区域事件索引(cure-tree `EventStore`):B3 惰性重建 + 编辑失效。
358    /// 供引擎 scan_region 快路径——收集器在 cure-tree,只依赖 Lang
359    /// 钩子,遍历序与引擎原递归严格一致。
360    events: EventStore<JavaId, u32>,
361    /// 语句级名字事实(稠密槽 = 语句根 arena 下标;None = 未建/失效)。
362    stmt_facts: Vec<Option<Box<[StmtFact]>>>,
363    /// 语句级 kill 事件(同一槽位与失效机制)。
364    stmt_kills: Vec<Option<Box<[StmtKillFact]>>>,
365    /// 语句是否含不透明区域(与其余索引同一失效机制)。
366    stmt_opq: Vec<Option<StmtOpq>>,
367    /// 上次 prepare 的根。B3 早退(events_clean)只对**树全局**缓存
368    /// (事件索引/效果表)合法;var_types 是 **root 相关**的作用域分析
369    /// ——根变化时必须重建,否则 is_local_var 全 false、传播规则停摆
370    /// (deobfuscate 差分抓获:`t = bump(2)` 不再内联)。
371    prepared_root: Option<JavaId>,
372}
373
374// ---------------------------------------------------------------------------
375// 编译单元 / 成员(签名层:签名保真、方法体进 arena)
376// ---------------------------------------------------------------------------
377
378/// 方法/构造器参数。
379#[derive(Clone, PartialEq, Debug)]
380pub struct Param {
381    /// `final` / 注解等原文(可为空串)。
382    pub mods: String,
383    pub ty: JType,
384    /// `int... args`
385    pub varargs: bool,
386    pub name: String,
387}
388
389/// 字段声明中的一个声明符(`int a = 1, b[];` 里的 a、b)。
390#[derive(Clone, PartialEq, Debug)]
391pub struct Declarator {
392    pub name: String,
393    /// C 风格后缀维度 `int a[][]` 中名字后面的 `[]` 数。
394    pub extra_dims: u16,
395    /// 初始化表达式(arena 节点)。
396    pub init: Option<JavaId>,
397}
398
399/// 类成员。
400#[derive(Clone, PartialEq, Debug)]
401pub enum Member {
402    Field { mods: String, ty: JType, declarators: Vec<Declarator> },
403    Method {
404        mods: String,
405        /// 泛型参数原文(含尖括号,可为空串)。
406        ty_params: String,
407        ret: JType,
408        name: String,
409        params: Vec<Param>,
410        throws: Vec<String>,
411        /// 方法体 Block;None 表示 abstract/native/接口声明。可能是 Raw 节点。
412        body: Option<JavaId>,
413    },
414    Constructor {
415        mods: String,
416        ty_params: String,
417        name: String,
418        params: Vec<Param>,
419        throws: Vec<String>,
420        body: Option<JavaId>,
421        /// record 紧凑构造器:`Name { … }`(无参数列表,签名继承自 record 头)
422        compact: bool,
423    },
424    /// 实例/静态初始化块。
425    Initializer { is_static: bool, body: JavaId },
426    /// 嵌套类型。
427    Type(Box<TypeDecl>),
428    /// 不可解析成员(原文保真)。
429    Raw(String),
430}
431
432#[derive(Clone, Copy, PartialEq, Eq, Debug)]
433pub enum TypeKind {
434    Class,
435    Interface,
436    Enum,
437    Record,
438    Annotation,
439}
440
441/// 类型声明。
442#[derive(Clone, PartialEq, Debug)]
443pub struct TypeDecl {
444    pub kind: TypeKind,
445    /// 修饰符 + 注解原文。
446    pub mods: String,
447    pub name: String,
448    /// 泛型参数原文(含尖括号,可为空串);record 的头部参数原文存在 header。
449    pub ty_params: String,
450    /// record 组件头原文(`(int a, String b)`),非 record 为空串。
451    pub header: String,
452    pub extends: Vec<String>,
453    pub implements: Vec<String>,
454    /// sealed 类型的 permits 子句原文列表(打印 `permits A, B`)。
455    pub permits: Vec<String>,
456    /// 枚举常量原文(解析失败时兜底保真)。
457    pub enum_constants: Vec<String>,
458    pub members: Vec<Member>,
459}
460
461/// 编译单元。
462#[derive(Clone, PartialEq, Debug, Default)]
463pub struct CompilationUnit {
464    /// package 名(不含 `package`/`;`)。
465    pub package: Option<String>,
466    /// package 声明前的包级注解原文(package-info.java 的 @NullMarked /
467    /// @Deprecated——149 文件曾静默丢弃,RUNTIME 保留期改变整包契约)。
468    pub package_annotations: String,
469    /// 文件头注释块(首条声明之前):license header、`//noinspection` 等。
470    /// 打印器原样放在 package/import 之前。
471    pub header_comments: String,
472    /// import 项原文(如 `java.util.List` / `static x.y.*`)。
473    pub imports: Vec<String>,
474    pub types: Vec<TypeDecl>,
475    /// 顶层不可解析区域原文(按出现顺序保真)。
476    pub raws: Vec<String>,
477}
478
479/// 解析错误(位置为 1-based 行/列)。
480#[derive(Clone, PartialEq, Eq, Debug)]
481pub struct ParseError {
482    pub line: usize,
483    pub col: usize,
484    pub message: String,
485}
486
487// ---------------------------------------------------------------------------
488// JavaAst 主体
489// ---------------------------------------------------------------------------
490
491impl JavaAst {
492    pub fn new() -> Self {
493        Self::default()
494    }
495
496    /// 以 node 的负载 + 指定 children 构造新节点(深拷贝/替换用)。
497    pub fn clone_node(&mut self, id: JavaId, children: Vec<JavaId>) -> JavaId {
498        let data = self.nodes[id.0 as usize].data.clone();
499        self.push(data, children)
500    }
501
502    fn push(&mut self, data: NodeData, children: Vec<JavaId>) -> JavaId {
503        let id = JavaId(self.nodes.len() as u32);
504        self.nodes.push(Node { data, children: ChildList::from_vec(children) });
505        id
506    }
507
508    pub fn node(&self, id: JavaId) -> &Node {
509        &self.nodes[id.0 as usize]
510    }
511    pub fn data(&self, id: JavaId) -> &NodeData {
512        &self.node(id).data
513    }
514
515    /// 固有方法(与 Lang trait 同名;供不依赖引擎的下游使用,如 printer)。
516    pub fn kind(&self, id: JavaId) -> NodeKind {
517        match &self.nodes[id.0 as usize].data {
518            NodeData::Block | NodeData::Group => NodeKind::Block,
519            NodeData::Empty => NodeKind::Empty,
520            NodeData::Yield => NodeKind::Yield,
521            NodeData::ExprStmt => NodeKind::ExprStmt,
522            NodeData::VarDecl { .. } => NodeKind::VarDecl,
523            NodeData::Assign { .. } => NodeKind::Assign,
524            NodeData::If => NodeKind::If,
525            NodeData::While => NodeKind::While,
526            NodeData::DoWhile => NodeKind::DoWhile,
527            NodeData::For { .. } => NodeKind::For,
528            NodeData::ForEach { .. } => NodeKind::ForEach,
529            NodeData::Return => NodeKind::Return,
530            NodeData::Break { .. } => NodeKind::Break,
531            NodeData::Continue { .. } => NodeKind::Continue,
532            NodeData::Throw => NodeKind::Throw,
533            NodeData::Try => NodeKind::Try,
534            NodeData::Catch { .. } => NodeKind::Catch,
535            NodeData::Synchronized => NodeKind::Synchronized,
536            NodeData::Switch => NodeKind::Switch,
537            NodeData::Case { .. } => NodeKind::Case,
538            NodeData::Label { .. } => NodeKind::Label,
539            NodeData::Assert => NodeKind::Assert,
540            NodeData::Raw { .. } => NodeKind::Raw,
541            NodeData::Binary { .. } => NodeKind::Binary,
542            NodeData::Unary { .. } => NodeKind::Unary,
543            NodeData::Call => NodeKind::Call,
544            NodeData::Member { .. } => NodeKind::Member,
545            NodeData::Index => NodeKind::Index,
546            NodeData::Cast { .. } => NodeKind::Cast,
547            NodeData::Paren => NodeKind::Paren,
548            NodeData::Ternary => NodeKind::Ternary,
549            NodeData::New { .. } => NodeKind::New,
550            NodeData::NewArray { .. } => NodeKind::NewArray,
551            NodeData::ArrayLit => NodeKind::ArrayLit,
552            NodeData::VarRef { .. } => NodeKind::VarRef,
553            NodeData::Literal(_) => NodeKind::Literal,
554            NodeData::This => NodeKind::This,
555            NodeData::Super => NodeKind::This,
556            NodeData::InstanceOf { .. } => NodeKind::InstanceOf,
557            NodeData::Lambda { .. } => NodeKind::Lambda,
558            NodeData::MethodRef { .. } => NodeKind::MethodRef,
559        }
560    }
561    /// arena 节点总数(诊断/深度测量用)。
562    pub fn node_count(&self) -> usize {
563        self.nodes.len()
564    }
565
566    pub fn children(&self, id: JavaId) -> &[JavaId] {
567        self.nodes[id.0 as usize].children.as_slice()
568    }
569
570    // ---- builder:语句 ----
571
572    pub fn block(&mut self, stmts: Vec<JavaId>) -> JavaId {
573        self.push(NodeData::Block, stmts)
574    }
575    pub fn empty(&mut self) -> JavaId {
576        self.push(NodeData::Empty, vec![])
577    }
578    pub fn expr_stmt(&mut self, e: JavaId) -> JavaId {
579        self.push(NodeData::ExprStmt, vec![e])
580    }
581    pub fn var_decl(&mut self, name: &str, ty: JType, init: Option<JavaId>) -> JavaId {
582        self.var_decl_final(name, ty, init, false)
583    }
584    /// final 局部声明(JLS 4.12.4:case 标签常量的必要条件——
585    /// final 局部删除曾致 `case ARRAY_BOUND:` 失去常量性不可编译,
586    /// LargeFile.java 抓获)。
587    pub fn var_decl_final(
588        &mut self,
589        name: &str,
590        ty: JType,
591        init: Option<JavaId>,
592        final_mod: bool,
593    ) -> JavaId {
594        self.push(
595            NodeData::VarDecl {
596                name: name.into(),
597                ty,
598                final_mod,
599            },
600            init.into_iter().collect(),
601        )
602    }
603    pub fn assign(&mut self, target: JavaId, value: JavaId) -> JavaId {
604        self.push(NodeData::Assign { op: None }, vec![target, value])
605    }
606    pub fn assign_op(&mut self, op: BinOp, target: JavaId, value: JavaId) -> JavaId {
607        self.push(NodeData::Assign { op: Some(op) }, vec![target, value])
608    }
609    pub fn if_(&mut self, cond: JavaId, then: JavaId, els: Option<JavaId>) -> JavaId {
610        let mut ch = vec![cond, then];
611        ch.extend(els);
612        self.push(NodeData::If, ch)
613    }
614    pub fn while_(&mut self, cond: JavaId, body: JavaId) -> JavaId {
615        self.push(NodeData::While, vec![cond, body])
616    }
617    pub fn do_while(&mut self, body: JavaId, cond: JavaId) -> JavaId {
618        self.push(NodeData::DoWhile, vec![body, cond])
619    }
620    pub fn for_(
621        &mut self,
622        inits: Vec<JavaId>,
623        cond: Option<JavaId>,
624        steps: Vec<JavaId>,
625        body: JavaId,
626    ) -> JavaId {
627        let ni = inits.len();
628        let ns = steps.len();
629        let mut ch = inits;
630        let has_cond = cond.is_some();
631        ch.extend(cond);
632        ch.extend(steps);
633        ch.push(body);
634        self.push(
635            NodeData::For {
636                inits: ni as u8,
637                has_cond,
638                steps: ns as u8,
639            },
640            ch,
641        )
642    }
643    pub fn for_each(&mut self, name: &str, ty: JType, iterable: JavaId, body: JavaId) -> JavaId {
644        self.push(
645            NodeData::ForEach {
646                name: name.into(),
647                ty,
648            },
649            vec![iterable, body],
650        )
651    }
652    pub fn yield_(&mut self, expr: JavaId) -> JavaId {
653        self.push(NodeData::Yield, vec![expr])
654    }
655    pub fn ret(&mut self, value: Option<JavaId>) -> JavaId {
656        self.push(NodeData::Return, value.into_iter().collect())
657    }
658    pub fn break_(&mut self, label: Option<&str>) -> JavaId {
659        self.push(
660            NodeData::Break {
661                label: label.map(Into::into),
662            },
663            vec![],
664        )
665    }
666    pub fn continue_(&mut self, label: Option<&str>) -> JavaId {
667        self.push(
668            NodeData::Continue {
669                label: label.map(Into::into),
670            },
671            vec![],
672        )
673    }
674    pub fn throw(&mut self, e: JavaId) -> JavaId {
675        self.push(NodeData::Throw, vec![e])
676    }
677    pub fn try_(
678        &mut self,
679        resources: Vec<JavaId>,
680        try_block: JavaId,
681        catches: Vec<JavaId>,
682        finally: Option<JavaId>,
683    ) -> JavaId {
684        let mut ch = resources;
685        ch.push(try_block);
686        ch.extend(catches);
687        ch.extend(finally);
688        self.push(NodeData::Try, ch)
689    }
690    pub fn catch_(&mut self, ty_raw: &str, name: &str, block: JavaId) -> JavaId {
691        self.push(
692            NodeData::Catch {
693                ty_raw: ty_raw.into(),
694                name: name.into(),
695            },
696            vec![block],
697        )
698    }
699    pub fn synchronized(&mut self, lock: JavaId, block: JavaId) -> JavaId {
700        self.push(NodeData::Synchronized, vec![lock, block])
701    }
702    pub fn switch_(&mut self, subject: JavaId, cases: Vec<JavaId>) -> JavaId {
703        let mut ch = vec![subject];
704        ch.extend(cases);
705        self.push(NodeData::Switch, ch)
706    }
707    pub fn case_(
708        &mut self,
709        labels: Vec<JavaId>,
710        is_default: bool,
711        arrow: bool,
712        stmts: Vec<JavaId>,
713    ) -> JavaId {
714        let n = labels.len() as u16;
715        let mut ch = labels;
716        ch.extend(stmts);
717        self.push(
718            NodeData::Case {
719                labels: n,
720                is_default,
721                arrow,
722            },
723            ch,
724        )
725    }
726    pub fn label(&mut self, name: &str, stmt: JavaId) -> JavaId {
727        self.push(NodeData::Label { name: name.into() }, vec![stmt])
728    }
729    pub fn assert_(&mut self, cond: JavaId, msg: Option<JavaId>) -> JavaId {
730        let mut ch = vec![cond];
731        ch.extend(msg);
732        self.push(NodeData::Assert, ch)
733    }
734    pub fn raw(&mut self, text: &str) -> JavaId {
735        self.push(NodeData::Raw { text: text.into() }, vec![])
736    }
737
738    // ---- builder:表达式 ----
739
740    pub fn bin(&mut self, op: BinOp, l: JavaId, r: JavaId) -> JavaId {
741        self.push(NodeData::Binary { op }, vec![l, r])
742    }
743    pub fn un(&mut self, op: UnOp, e: JavaId) -> JavaId {
744        self.push(NodeData::Unary { op }, vec![e])
745    }
746    pub fn call(&mut self, callee: JavaId, args: Vec<JavaId>) -> JavaId {
747        let mut ch = vec![callee];
748        ch.extend(args);
749        self.push(NodeData::Call, ch)
750    }
751    pub fn member(&mut self, obj: JavaId, name: &str) -> JavaId {
752        let sym = self.intern_sym(name);
753        self.push(NodeData::Member { name: sym }, vec![obj])
754    }
755    pub fn index(&mut self, arr: JavaId, idx: JavaId) -> JavaId {
756        self.push(NodeData::Index, vec![arr, idx])
757    }
758    pub fn cast(&mut self, ty: JType, e: JavaId) -> JavaId {
759        self.push(NodeData::Cast { ty }, vec![e])
760    }
761    pub fn paren(&mut self, e: JavaId) -> JavaId {
762        self.push(NodeData::Paren, vec![e])
763    }
764    pub fn ternary(&mut self, c: JavaId, a: JavaId, b: JavaId) -> JavaId {
765        self.push(NodeData::Ternary, vec![c, a, b])
766    }
767    pub fn new_(&mut self, ty: JType, args: Vec<JavaId>) -> JavaId {
768        self.push(NodeData::New { ty, anon_raw: None }, args)
769    }
770    pub fn new_anon(&mut self, ty: JType, args: Vec<JavaId>, body_raw: String) -> JavaId {
771        self.push(
772            NodeData::New {
773                ty,
774                anon_raw: Some(body_raw),
775            },
776            args,
777        )
778    }
779    pub fn new_array(
780        &mut self,
781        ty: JType,
782        dims: u16,
783        sized: u16,
784        sizes: Vec<JavaId>,
785        init: Option<JavaId>,
786    ) -> JavaId {
787        let mut ch = sizes;
788        ch.extend(init);
789        self.push(NodeData::NewArray { ty, dims, sized }, ch)
790    }
791    /// 合成分组(无作用域)。
792    pub fn group(&mut self, stmts: Vec<JavaId>) -> JavaId {
793        self.push(NodeData::Group, stmts)
794    }
795    pub fn array_lit(&mut self, elems: Vec<JavaId>) -> JavaId {
796        self.push(NodeData::ArrayLit, elems)
797    }
798    pub fn var(&mut self, name: &str) -> JavaId {
799        let sym = self.intern_sym(name);
800        self.push(NodeData::VarRef { name: sym }, vec![])
801    }
802    pub fn lit(&mut self, l: Lit) -> JavaId {
803        self.push(NodeData::Literal(l), vec![])
804    }
805    fn build_int_impl(&mut self, v: i64, long: bool) -> JavaId {
806        if long {
807            self.lit(Lit::Long(v))
808        } else {
809            self.lit(Lit::Int(v))
810        }
811    }
812    pub fn this(&mut self) -> JavaId {
813        self.push(NodeData::This, vec![])
814    }
815    pub fn super_(&mut self) -> JavaId {
816        self.push(NodeData::Super, vec![])
817    }
818    pub fn instance_of(&mut self, e: JavaId, ty: JType, bind: Option<&str>) -> JavaId {
819        self.push(
820            NodeData::InstanceOf {
821                ty,
822                bind: bind.map(Into::into),
823            },
824            vec![e],
825        )
826    }
827    pub fn lambda(&mut self, params_raw: &str, body: JavaId) -> JavaId {
828        self.push(
829            NodeData::Lambda {
830                params_raw: params_raw.into(),
831            },
832            vec![body],
833        )
834    }
835    pub fn method_ref(&mut self, receiver: JavaId, name: &str) -> JavaId {
836        let sym = self.intern_sym(name);
837        self.push(NodeData::MethodRef { name: sym }, vec![receiver])
838    }
839
840    // ---- 便捷 ----
841
842    /// `obj.name(args…)` 调用。
843    pub fn method_call(&mut self, obj: JavaId, name: &str, args: Vec<JavaId>) -> JavaId {
844        let m = self.member(obj, name);
845        self.call(m, args)
846    }
847    /// 裸方法调用 `name(args…)`(隐式 this / static)。
848    pub fn plain_call(&mut self, name: &str, args: Vec<JavaId>) -> JavaId {
849        let f = self.var(name);
850        self.call(f, args)
851    }
852
853    /// 作用域解析后的 VarRef 类型(prepare 之后有效)。
854    pub fn var_type(&self, id: JavaId) -> Option<&JType> {
855        self.var_types.get(id.0 as usize).and_then(|t| t.as_ref())
856    }
857
858    /// root 子树内是否存在「两侧都可能为 String」的 ==/!=(引用比较)?
859    /// 折叠守卫用:new String(lit)/常量链等产出池化字面量会改变 == 语义。
860    /// 结果按 (root, prepare 代次) 缓存——prepare 每次改树后清空,
861    /// 首次查询全扫一次,同轮内所有守卫调用复用。
862    /// 多根扫描:任一根存在 String 身份比较。
863    pub fn any_string_identity(&self, roots: &[JavaId]) -> bool {
864        roots.iter().any(|&r| {
865            let hit = Self::scan_string_identity(self, r);
866            if hit {
867                self.string_identity.set(Some((r, true)));
868            }
869            hit
870        })
871    }
872
873    pub fn has_string_identity_compare(&self, root: JavaId) -> bool {
874        if let Some((r, v)) = self.string_identity.get() {
875            if r == root {
876                return v;
877            }
878        }
879        let v = Self::scan_string_identity(self, root);
880        self.string_identity.set(Some((root, v)));
881        v
882    }
883
884    fn scan_string_identity(&self, root: JavaId) -> bool {
885        let mut stack = vec![root];
886        while let Some(id) = stack.pop() {
887            if let NodeData::Binary { op: BinOp::Eq | BinOp::Ne } = self.data(id) {
888                let ch = self.children(id);
889                if ch.len() == 2
890                    && self.expr_maybe_string(ch[0])
891                    && self.expr_maybe_string(ch[1])
892                {
893                    return true;
894                }
895            }
896            for &c in self.children(id) {
897                stack.push(c);
898            }
899        }
900        false
901    }
902
903    /// `==`/`!=` 的这个操作数可能持有 String 引用吗?(保守近似)
904    fn expr_maybe_string(&self, id: JavaId) -> bool {
905        match self.data(id) {
906            NodeData::Literal(Lit::Str(_)) => true,
907            // null/this/数组/instanceof/数值布尔字面量:折叠不可能改变其 == 结果
908            NodeData::Literal(_) | NodeData::This | NodeData::Super
909            | NodeData::NewArray { .. } | NodeData::ArrayLit | NodeData::InstanceOf { .. } => false,
910            NodeData::VarRef { .. } => self.var_type(id).map_or(true, Self::type_maybe_string),
911            NodeData::Cast { ty } => Self::type_maybe_string(ty),
912            NodeData::Paren => self
913                .children(id)
914                .first()
915                .map_or(true, |&c| self.expr_maybe_string(c)),
916            // 拼接:任一操作数 String ⇒ 结果 String;其余二元运算结果必为原始类型
917            NodeData::Binary { op } if *op == BinOp::Add => {
918                self.children(id).iter().any(|&c| self.expr_maybe_string(c))
919            }
920            NodeData::Binary { .. } => false,
921            NodeData::Ternary => self
922                .children(id)
923                .get(1..)
924                .map_or(true, |cs| cs.iter().any(|&c| self.expr_maybe_string(c))),
925            // Call/Member/Index/MethodRef/Raw/Unary/Lambda…:类型未知或引用 → 保守视为可能
926            _ => true,
927        }
928    }
929
930    /// 类型可能持有 String 引用吗?
931    fn type_maybe_string(t: &JType) -> bool {
932        match t {
933            JType::Bool | JType::Byte | JType::Short | JType::Int | JType::Long
934            | JType::Char | JType::Float | JType::Double | JType::Void
935            | JType::Array(_) => false, // 数组引用不是 String 本体(元素访问走 Index 节点)
936            JType::Var => true,         // var / 推断 / 未知
937            JType::Ref(n) => {
938                let base = n.split('<').next().unwrap_or(n).trim();
939                let last = base.rsplit('.').next().unwrap_or(base);
940                matches!(
941                    last,
942                    "String" | "Object" | "CharSequence" | "Comparable" | "Serializable"
943                ) || n.contains('<') // 泛型容器:剥壳后无法判定 → 保守
944                // 单字母大写:类型参数 T/E/R(无界,运行期可为 String)
945                || (last.len() <= 2 && last.chars().next().is_some_and(|c| c.is_uppercase()))
946            }
947        }
948    }
949
950
951    /// 设置当前方法的参数类型表(作为根作用域参与解析)。
952    pub fn set_param_scope(&mut self, params: &[(String, JType)]) {
953        self.param_scope = params.to_vec();
954    }
955
956    /// 名字是否为当前方法参数(虚拟执行的字段写守卫——参数写不得
957    /// 误记为字段写)。
958    pub fn is_param_name(&self, name: &str) -> bool {
959        self.param_scope.iter().any(|(n, _)| n == name)
960    }
961
962    /// 名字键 → 名字反查(虚拟执行的字段写材料化)。
963    /// 注入外部事实(前端 IR 权威陈述)。编译单元生命周期——换单元
964    /// 前必须 clear_facts(simplify_unit / simplify_unit_with_facts
965    /// 门面自动管理)。重复注入覆盖。
966    pub fn set_facts(&mut self, facts: JavaFacts) {
967        self.facts = Some(facts);
968    }
969    /// 清空外部事实(回到纯源码保守模式)。
970    pub fn clear_facts(&mut self) {
971        self.facts = None;
972    }
973
974    pub fn name_of_key(&self, k: u32) -> Option<String> {
975        Some(self.names.name(k).to_string())
976    }
977    pub fn clear_param_scope(&mut self) {
978        self.param_scope.clear();
979    }
980}
981
982// ---------------------------------------------------------------------------
983// Lang 实现
984// ---------------------------------------------------------------------------
985
986/// 类型名的基名(剥泛型实参 + 取最后点分段):`List<String>` → `List`、
987/// `java.util.Map<K,V>` → `Map`。接收位类型绑定守卫用(同名构造视为
988/// 静态类型一致;注解/显式类型实参前缀的罕见形态不匹配 → 保守拒绝)。
989fn type_base_name(n: &str) -> &str {
990    let no_args = match n.find('<') {
991        Some(i) => &n[..i],
992        None => n,
993    };
994    no_args.rsplit('.').next().unwrap_or(no_args)
995}
996
997// ---------------------------------------------------------------------------
998// JLS 整数折叠辅助(从 cure-engine 迁入——数值语义归属语言侧)
999// ---------------------------------------------------------------------------
1000
1001/// i64 算术(long 语义):除/余除数为 0 不折(ArithmeticException)。
1002/// 移位量按 JLS 掩码(long: & 63)。
1003fn fold_i64(op: BinOp, a: i64, b: i64) -> Option<i64> {
1004    use BinOp::*;
1005    Some(match op {
1006        Add => a.wrapping_add(b),
1007        Sub => a.wrapping_sub(b),
1008        Mul => a.wrapping_mul(b),
1009        Div => {
1010            if b == 0 {
1011                return None;
1012            }
1013            a.wrapping_div(b)
1014        }
1015        Rem => {
1016            if b == 0 {
1017                return None;
1018            }
1019            a.wrapping_rem(b)
1020        }
1021        Shl => a.wrapping_shl((b as u64 & 63) as u32),
1022        Shr => a.wrapping_shr((b as u64 & 63) as u32),
1023        UShr => ((a as u64).wrapping_shr((b as u64 & 63) as u32)) as i64,
1024        BitAnd => a & b,
1025        BitXor => a ^ b,
1026        BitOr => a | b,
1027        _ => return None,
1028    })
1029}
1030
1031/// i32 算术(int 语义):操作数按 i32 回绕;移位量按 JLS 掩码(& 31)。
1032fn fold_i32(op: BinOp, a: i64, b: i64) -> Option<i64> {
1033    use BinOp::*;
1034    let (x, y) = (a as i32, b as i32);
1035    Some(match op {
1036        Add => x.wrapping_add(y) as i64,
1037        Sub => x.wrapping_sub(y) as i64,
1038        Mul => x.wrapping_mul(y) as i64,
1039        Div => {
1040            if y == 0 {
1041                return None;
1042            }
1043            x.wrapping_div(y) as i64
1044        }
1045        Rem => {
1046            if y == 0 {
1047                return None;
1048            }
1049            x.wrapping_rem(y) as i64
1050        }
1051        Shl => x.wrapping_shl((y as u32) & 31) as i64,
1052        Shr => x.wrapping_shr((y as u32) & 31) as i64,
1053        UShr => (x as u32).wrapping_shr((y as u32) & 31) as i64,
1054        BitAnd => (x & y) as i64,
1055        BitXor => (x ^ y) as i64,
1056        BitOr => (x | y) as i64,
1057        _ => return None,
1058    })
1059}
1060
1061/// 数值比较折叠(整数/字符提升为 int 后比较)。
1062fn cmp_i64(op: BinOp, x: i64, y: i64) -> Option<bool> {
1063    use BinOp::*;
1064    Some(match op {
1065        Lt => x < y,
1066        Le => x <= y,
1067        Gt => x > y,
1068        Ge => x >= y,
1069        Eq => x == y,
1070        Ne => x != y,
1071        _ => return None,
1072    })
1073}
1074
1075/// 表达式静态类型是否已是窄基本类型(short/byte/char)。
1076fn narrow_typed_expr(ast: &JavaAst, id: JavaId) -> bool {
1077    match ast.data(id) {
1078        NodeData::VarRef { .. } => matches!(
1079            ast.var_type(id),
1080            Some(JType::Short | JType::Byte | JType::Char)
1081        ),
1082        NodeData::Cast { ty } => matches!(ty, JType::Short | JType::Byte | JType::Char),
1083        NodeData::Literal(Lit::Char(_)) => true,
1084        _ => false,
1085    }
1086}
1087
1088impl Lang for JavaAst {
1089    type Id = JavaId;
1090    type NameKey = u32;
1091
1092    fn kind(&self, id: JavaId) -> NodeKind {
1093        JavaAst::kind(self, id)
1094    }
1095
1096    fn children(&self, id: JavaId) -> &[JavaId] {
1097        JavaAst::children(self, id)
1098    }
1099
1100    fn set_child(&mut self, parent: JavaId, index: usize, new: JavaId) {
1101        self.nodes[parent.0 as usize].children.set(index, new);
1102    }
1103    fn remove_child(&mut self, parent: JavaId, index: usize) {
1104        self.nodes[parent.0 as usize].children.remove(index);
1105    }
1106    fn splice(&mut self, node: JavaId, index: usize, remove: usize, insert: Vec<JavaId>) {
1107        self.nodes[node.0 as usize].children.splice(index, remove, insert);
1108    }
1109
1110    fn build_return(&mut self, value: Option<JavaId>) -> JavaId {
1111        self.ret(value)
1112    }
1113    fn build_block(&mut self, stmts: Vec<JavaId>) -> JavaId {
1114        self.block(stmts)
1115    }
1116    fn build_unary(&mut self, op: UnOp, operand: JavaId) -> JavaId {
1117        self.un(op, operand)
1118    }
1119    fn build_bool(&mut self, v: bool) -> JavaId {
1120        self.lit(Lit::Bool(v))
1121    }
1122    fn build_int(&mut self, v: i64, long: bool) -> JavaId {
1123        self.build_int_impl(v, long)
1124    }
1125    fn build_str(&mut self, s: &str) -> JavaId {
1126        self.lit(Lit::Str(s.to_string()))
1127    }
1128    fn build_char(&mut self, c: char) -> JavaId {
1129        self.lit(Lit::Char(c))
1130    }
1131    fn build_bin(&mut self, op: BinOp, l: JavaId, r: JavaId) -> JavaId {
1132        self.bin(op, l, r)
1133    }
1134    fn build_ternary(&mut self, c: JavaId, a: JavaId, b: JavaId) -> JavaId {
1135        self.ternary(c, a, b)
1136    }
1137    fn build_assign(&mut self, target: JavaId, value: JavaId) -> JavaId {
1138        self.assign(target, value)
1139    }
1140
1141    // ---- 字面量折叠语义(JLS;引擎侧只做形态匹配)----
1142
1143    fn fold_lit_bin(&mut self, op: BinOp, l: JavaId, r: JavaId) -> Option<JavaId> {
1144        let ll = self.literal(l)?;
1145        let rr = self.literal(r)?;
1146        // 字符串拼接(Str 与 Str/Char/Int/Long/Bool 字面量——拼接的隐式
1147        // valueOf 对这些基元是确定性的;浮点除外:Double.toString 算法与
1148        // Rust Display 不保证逐位一致)
1149        if op == BinOp::Add {
1150            let str_of = |x: LitRef<'_>| -> Option<String> {
1151                match x {
1152                    LitRef::Str(s) => Some(s.to_string()),
1153                    LitRef::Char(c) => Some(c.to_string()),
1154                    LitRef::Int(v) => Some(v.to_string()),
1155                    LitRef::Long(v) => Some(v.to_string()),
1156                    LitRef::Bool(b) => Some(b.to_string()),
1157                    _ => None,
1158                }
1159            };
1160            if matches!(ll, LitRef::Str(_)) || matches!(rr, LitRef::Str(_)) {
1161                if let (Some(a), Some(b)) = (str_of(ll), str_of(rr)) {
1162                    return Some(self.build_str(&format!("{a}{b}")));
1163                }
1164            }
1165        }
1166        // 整数折叠(JLS 环绕):1+2→3、2*3→6、1<<3→8、& | ^ 等。
1167        // 除/余除数为 0 不折叠(ArithmeticException 语义)。
1168        let int_of = |x: LitRef<'_>| -> Option<i64> {
1169            match x {
1170                // Java 中 char 参与算术时提升为 int
1171                LitRef::Int(v) | LitRef::Long(v) => Some(v),
1172                LitRef::Char(c) => Some(c as u32 as i64),
1173                _ => None,
1174            }
1175        };
1176        let (a, b) = (int_of(ll)?, int_of(rr)?);
1177        let wide = matches!(ll, LitRef::Long(_)) || matches!(rr, LitRef::Long(_));
1178        let v = if wide { fold_i64(op, a, b) } else { fold_i32(op, a, b) }?;
1179        Some(self.build_int(v, wide))
1180    }
1181
1182    fn fold_lit_cmp(&mut self, op: BinOp, l: JavaId, r: JavaId) -> Option<bool> {
1183        let ll = self.literal(l)?;
1184        let rr = self.literal(r)?;
1185        // 整数/字符按数值比较(char 与 int 比较同样提升为 int)
1186        let int_of = |x: LitRef<'_>| -> Option<i64> {
1187            match x {
1188                LitRef::Int(v) | LitRef::Long(v) => Some(v),
1189                LitRef::Char(c) => Some(c as u32 as i64),
1190                _ => None,
1191            }
1192        };
1193        if let (Some(x), Some(y)) = (int_of(ll), int_of(rr)) {
1194            return cmp_i64(op, x, y);
1195        }
1196        // 布尔相等(装箱引用 == 语义上不可折,但布尔字面量场景下
1197        // true/false 是规范实例,值比较与引用比较一致)
1198        if let (LitRef::Bool(x), LitRef::Bool(y)) = (ll, rr) {
1199            if matches!(op, BinOp::Eq | BinOp::Ne) {
1200                return Some(if op == BinOp::Eq { x == y } else { x != y });
1201            }
1202        }
1203        // 字符串(引用比较)与浮点(NaN)不折
1204        None
1205    }
1206
1207    fn fold_lit_neg(&mut self, v: i64, wide: bool) -> Option<i64> {
1208        // `-(-2147483648)`:i32 域内无 +2147483648,拒绝折叠
1209        let n = -v;
1210        if !wide && n > i32::MAX as i64 {
1211            return None;
1212        }
1213        Some(n)
1214    }
1215
1216    fn reassoc_delta(
1217        &mut self,
1218        op1: BinOp,
1219        k1: i64,
1220        op2: BinOp,
1221        k2: i64,
1222        wide: bool,
1223    ) -> Option<ReassocOutcome<JavaId>> {
1224        use BinOp::*;
1225        let raw: i64 = match (op1, op2) {
1226            (BitXor, BitXor) => k1 ^ k2,
1227            (a, b) if matches!(a, Add | Sub) && matches!(b, Add | Sub) => {
1228                let sign = |o: BinOp| if o == Sub { -1i64 } else { 1i64 };
1229                // 宽整数域回绕:JLS long 加法模 2^64;debug 下的 i64
1230                // 溢出会 panic(`(x + 9223372036854775806L) + 2L`)
1231                sign(a)
1232                    .wrapping_mul(k1)
1233                    .wrapping_add(sign(b).wrapping_mul(k2))
1234            }
1235            _ => return None,
1236        };
1237        // JLS 宽度回绕:i32 合并结果溢出必须回绕——不回绕会产出
1238        // 非法字面量(`x + 2147483648` 无法作为 int 编译)
1239        let d = if wide { raw } else { raw as i32 as i64 };
1240        if d == 0 {
1241            return Some(ReassocOutcome::Neutral);
1242        }
1243        if op1 == BitXor && op2 == BitXor {
1244            return Some(ReassocOutcome::Lit(self.build_int(d, wide), BitXor));
1245        }
1246        if d > 0 {
1247            Some(ReassocOutcome::Lit(self.build_int(d, wide), Add))
1248        } else {
1249            // 负 delta 用 `x - |d|`;|d| 回绕后仍为负(仅 ±2^31 边界)
1250            // 或宽整数 -2^63 取反溢出时,退回 `x + d`(负字面量)——
1251            // 二者模 2^宽度 同余,语法均合法
1252            let nd = if wide { d.checked_neg().unwrap_or(d) } else { (d as i32).wrapping_neg() as i64 };
1253            if nd > 0 {
1254                Some(ReassocOutcome::Lit(self.build_int(nd, wide), Sub))
1255            } else {
1256                Some(ReassocOutcome::Lit(self.build_int(d, wide), Add))
1257            }
1258        }
1259    }
1260
1261    fn copy_subtree(&mut self, id: JavaId) -> JavaId {
1262        let old_children: Vec<JavaId> = self.nodes[id.0 as usize].children.as_slice().to_vec();
1263        let mut children = Vec::with_capacity(old_children.len());
1264        for c in old_children {
1265            children.push(self.copy_subtree(c));
1266        }
1267        let data = self.nodes[id.0 as usize].data.clone();
1268        self.push(data, children)
1269    }
1270
1271    fn effect(&self, id: JavaId) -> Effect {
1272        if let Some(e) = self.effect_cache.get(id.0 as usize).and_then(|x| *x) {
1273            return e;
1274        }
1275        // 缓存未命中(结构不变量被破坏时)退化为按需递归
1276        let mut e = self.own_effect(id);
1277        for &c in self.nodes[id.0 as usize].children.as_slice() {
1278            e = e.worst(self.effect(c));
1279        }
1280        e
1281    }
1282
1283    fn invalidate_effect(&mut self, id: JavaId) {
1284        if let Some(slot) = self.effect_cache.get_mut(id.0 as usize) {
1285            *slot = None;
1286        }
1287        // 事件索引同步失效:本节点子树若被改,其预计算事件已陈旧
1288        // (B3 脏标记 + 清空该槽——见 cure-tree EventStore)
1289        self.events.invalidate(id.0 as usize);
1290        if let Some(slot) = self.stmt_facts.get_mut(id.0 as usize) {
1291            *slot = None;
1292        }
1293        if let Some(slot) = self.stmt_kills.get_mut(id.0 as usize) {
1294            *slot = None;
1295        }
1296        if let Some(slot) = self.stmt_opq.get_mut(id.0 as usize) {
1297            *slot = None;
1298        }
1299    }
1300
1301    fn debug_verify_events(&self, stmt: JavaId) {
1302        if !verify_events_on() {
1303            return;
1304        }
1305        if let Some(indexed) = self.region_events(stmt) {
1306            let Some(fresh) = cure_tree::collect_region_events(self, stmt) else {
1307                return;
1308            };
1309            // 比较(键+种类+节点)三元组序列
1310            let key = |e: &cure_engine::kind::RegionEvent<JavaId, u32>| {
1311                (e.key, matches!(e.kind, cure_engine::kind::EventKind::Use), e.node.0)
1312            };
1313            let a: Vec<_> = indexed.iter().map(key).collect();
1314            let b: Vec<_> = fresh.iter().map(key).collect();
1315            if a != b {
1316                eprintln!(
1317                    "[EVENTS-STALE] stmt #{} kind={:?}: indexed {} events, fresh {} events",
1318                    stmt.0, self.kind(stmt), a.len(), b.len()
1319                );
1320            }
1321        }
1322    }
1323
1324    fn region_events(
1325        &self,
1326        id: JavaId,
1327    ) -> Option<&[cure_engine::kind::RegionEvent<JavaId, u32>]> {
1328        // 空序列 = 未索引(非语句节点或已失效)→ None 走原递归
1329        self.events.slot(id.0 as usize)
1330    }
1331
1332    fn var_key(&self, id: JavaId) -> Option<u32> {
1333        self.names.var_key(id.0 as usize)
1334    }
1335
1336    fn stmt_var_ref_count(&self, stmt: JavaId, key: u32) -> Option<u32> {
1337        let slot = self.stmt_facts.get(stmt.0 as usize)?.as_deref()?;
1338        Some(
1339            slot.binary_search_by_key(&key, |f| f.key)
1340                .ok()
1341                .map_or(0, |i| slot[i].refs),
1342        )
1343    }
1344
1345    fn stmt_lambda_captures(&self, stmt: JavaId, key: u32) -> Option<bool> {
1346        let slot = self.stmt_facts.get(stmt.0 as usize)?.as_deref()?;
1347        Some(
1348            slot.binary_search_by_key(&key, |f| f.key)
1349                .ok()
1350                .is_some_and(|i| slot[i].lambda_cap),
1351        )
1352    }
1353
1354    fn stmt_kill_event(&self, stmt: JavaId, key: u32) -> Option<StmtKill<JavaId>> {
1355        let slot = self.stmt_kills.get(stmt.0 as usize)?.as_deref()?;
1356        Some(match slot.binary_search_by_key(&key, |f| f.key) {
1357            Ok(i) => match slot[i].kind {
1358                1 => StmtKill::Read,
1359                2 => StmtKill::Shadow,
1360                _ => StmtKill::DomWrite(slot[i].assign),
1361            },
1362            Err(_) => StmtKill::None,
1363        })
1364    }
1365
1366    fn stmt_mentions(&self, stmt: JavaId, key: u32) -> Option<bool> {
1367        let slot = self.stmt_facts.get(stmt.0 as usize)?.as_deref()?;
1368        Some(
1369            slot.binary_search_by_key(&key, |f| f.key)
1370                .ok()
1371                .is_some_and(|i| slot[i].refs > 0 || slot[i].shadow),
1372        )
1373    }
1374
1375    fn stmt_opaque(&self, stmt: JavaId) -> Option<bool> {
1376        self.stmt_opq.get(stmt.0 as usize)?.map(|f| f.opaque)
1377    }
1378
1379    // ---- 外部事实(cure-engine Lang 词汇的 Java 实现:查 facts 槽)----
1380
1381    fn fact_single_def(&self, key: u32) -> bool {
1382        match (&self.facts, self.names.name(key)) {
1383            (Some(f), n) => f.var(n).single_def,
1384            _ => false,
1385        }
1386    }
1387    fn fact_single_use(&self, key: u32) -> bool {
1388        match (&self.facts, self.names.name(key)) {
1389            (Some(f), n) => f.var(n).single_use,
1390            _ => false,
1391        }
1392    }
1393    fn fact_bool_valued(&self, key: u32) -> bool {
1394        match (&self.facts, self.names.name(key)) {
1395            (Some(f), n) => f.var(n).bool_valued,
1396            _ => false,
1397        }
1398    }
1399    fn fact_call_effect(&self, name: &str) -> Option<cure_engine::Effect> {
1400        self.facts
1401            .as_ref()
1402            .and_then(|f| {
1403                f.call_effects.get(name).map(|set| {
1404                    set.iter().copied().fold(Effect::Pure, Effect::worst)
1405                })
1406            })
1407    }
1408
1409    fn node_index(&self, id: JavaId) -> usize {
1410        id.0 as usize
1411    }
1412    fn id_of_index(&self, idx: usize) -> JavaId {
1413        JavaId(idx as u32)
1414    }
1415
1416    fn is_opaque(&self, id: JavaId) -> bool {
1417        match self.data(id) {
1418            // 不可解析原文
1419            NodeData::Raw { .. } => true,
1420            // 匿名类体是原文(捕获的外部局部变量不可见)——
1421            // 对抗波 4:仅被匿名类捕获的变量曾被零用途规则误删
1422            NodeData::New { anon_raw: Some(_), .. } => true,
1423            _ => false,
1424        }
1425    }
1426
1427    fn own_effect(&self, id: JavaId) -> Effect {
1428        match self.data(id) {
1429            NodeData::Literal(_)
1430            | NodeData::This
1431            | NodeData::Super
1432            | NodeData::Paren
1433            | NodeData::Block
1434            | NodeData::Group
1435            | NodeData::Empty
1436            | NodeData::VarDecl { .. }
1437            | NodeData::Break { .. }
1438            | NodeData::Continue { .. }
1439            | NodeData::Try
1440            | NodeData::Catch { .. }
1441            | NodeData::Switch
1442            | NodeData::Case { .. }
1443            | NodeData::Label { .. }
1444            | NodeData::ExprStmt
1445            | NodeData::Ternary
1446            | NodeData::ArrayLit
1447            | NodeData::Lambda { .. }
1448            | NodeData::MethodRef { .. }
1449            | NodeData::InstanceOf { .. } => Effect::Pure,
1450            NodeData::VarRef { .. } => Effect::MayRead,
1451            NodeData::Member { .. } => Effect::MayThrow,
1452            NodeData::Index => Effect::MayThrow,
1453            NodeData::New { .. } | NodeData::NewArray { .. } => Effect::MayThrow,
1454            NodeData::Call => Effect::Unknown,
1455            NodeData::Assign { .. } => Effect::MayWrite,
1456            NodeData::Unary { op } => {
1457                if op.is_incdec() {
1458                    Effect::MayWrite
1459                } else {
1460                    Effect::Pure
1461                }
1462            }
1463            NodeData::Binary { op } => {
1464                if op.may_div_zero() {
1465                    Effect::MayThrow
1466                } else {
1467                    Effect::Pure
1468                }
1469            }
1470            NodeData::Cast { ty } => {
1471                if ty.is_ref() {
1472                    // 引用转型可能抛 ClassCastException
1473                    Effect::MayThrow
1474                } else {
1475                    Effect::Pure
1476                }
1477            }
1478            NodeData::For { .. } | NodeData::ForEach { .. } | NodeData::If => Effect::MayRead,
1479            NodeData::While | NodeData::DoWhile => Effect::MayRead,
1480            NodeData::Return | NodeData::Yield => Effect::MayThrow,
1481            NodeData::Throw => Effect::MayThrow,
1482            NodeData::Assert => Effect::MayThrow,
1483            NodeData::Synchronized => Effect::MayWrite,
1484            NodeData::Raw { .. } => Effect::Unknown,
1485        }
1486    }
1487
1488    fn is_bool(&self, id: JavaId) -> bool {
1489        match self.data(id) {
1490            NodeData::Literal(l) => matches!(l, Lit::Bool(_)),
1491            NodeData::Unary { op } => *op == UnOp::Not,
1492            NodeData::Binary { op } => {
1493                op.is_comparison() || matches!(op, BinOp::And | BinOp::Or)
1494            }
1495            NodeData::Ternary => {
1496                let ch = self.children(id);
1497                self.is_bool(ch[1]) && self.is_bool(ch[2])
1498            }
1499            NodeData::Paren => self.is_bool(self.children(id)[0]),
1500            NodeData::InstanceOf { .. } => true,
1501            NodeData::VarRef { .. } => self
1502                .var_types
1503                .get(id.0 as usize)
1504                .and_then(|t| t.as_ref())
1505                .is_some_and(|t| t.is_bool()),
1506            _ => false,
1507        }
1508    }
1509
1510    fn is_exact_int(&self, id: JavaId) -> bool {
1511        match self.data(id) {
1512            NodeData::Literal(l) => matches!(
1513                l,
1514                Lit::Int(_) | Lit::Long(_) | Lit::Char(_) | Lit::NumRaw { val: NumVal::Int(_) | NumVal::Long(_), .. }
1515            ),
1516            NodeData::VarRef { .. } => {
1517                self.var_types.get(id.0 as usize).and_then(|t| t.as_ref()).is_some_and(|t| t.is_integral())
1518            }
1519            NodeData::Binary { op } => {
1520                let ch = self.children(id);
1521                (op.is_arith() || op.is_comparison())
1522                    && self.is_exact_int(ch[0])
1523                    && self.is_exact_int(ch[1])
1524            }
1525            NodeData::Cast { ty } => ty.is_integral(),
1526            NodeData::Paren => self.is_exact_int(self.children(id)[0]),
1527            NodeData::Ternary => {
1528                let ch = self.children(id);
1529                self.is_exact_int(ch[1]) && self.is_exact_int(ch[2])
1530            }
1531            _ => false,
1532        }
1533    }
1534
1535    fn is_local_var(&self, id: JavaId) -> bool {
1536        // VarRef 必须解析到局部变量/参数(var_types 作用域解析)才可
1537        // 被传播/删除规则触碰——字段引用(this.x / 静态字段裸名)有
1538        // 跨方法可见性。未解析(Raw 区域/坏代码)同样返回 false(保守)。
1539        // 差分审查抓获:dead_store 曾据此把 `first = cl;`(静态字段写)
1540        // 当局部死存储消除,双向链表表头更新静默丢失。
1541        matches!(self.data(id), NodeData::VarRef { .. }) && self.var_type(id).is_some()
1542    }
1543
1544    fn is_inferred_decl(&self, decl: JavaId) -> bool {
1545        matches!(self.data(decl), NodeData::VarDecl { ty: JType::Var, .. })
1546    }
1547
1548    fn is_char_decl(&self, decl: JavaId) -> bool {
1549        matches!(self.data(decl), NodeData::VarDecl { ty: JType::Char, .. })
1550    }
1551
1552    fn has_pattern_bindings(&self, root: JavaId) -> bool {
1553        let mut stack = vec![root];
1554        while let Some(n) = stack.pop() {
1555            if let NodeData::InstanceOf { bind: Some(_), .. } = self.data(n) {
1556                return true;
1557            }
1558            for &c in self.children(n) {
1559                stack.push(c);
1560            }
1561        }
1562        false
1563    }
1564
1565    fn is_long_decl(&self, decl: JavaId) -> bool {
1566        matches!(self.data(decl), NodeData::VarDecl { ty: JType::Long, .. })
1567    }
1568    fn is_wide_decl(&self, decl: JavaId) -> bool {
1569        // 窄类型(byte/short/char)复合赋值含隐式收窄:delta 折回声明
1570        // 会产出超域非法常量或丢静态类型(char 99 → println 打数字)
1571        !matches!(
1572            self.data(decl),
1573            NodeData::VarDecl { ty: JType::Byte | JType::Short | JType::Char, .. }
1574        )
1575    }
1576
1577    fn ternary_merge_ok(&self, target: Option<JavaId>, branches: &[JavaId]) -> bool {
1578        // diamond 构造依赖赋值/返回目标推断;放进三元分支后推断退化
1579        //(`return c ? new ArrayList<>(0) : (List<X>) list;` → 推断成
1580        // ArrayList<Object>,JDK RecordedStackTrace 复现)。
1581        if branches.iter().any(|&b| {
1582            matches!(
1583                self.data(b),
1584                NodeData::New {
1585                    ty: JType::Ref(n),
1586                    ..
1587                } if n.ends_with("<>")
1588            )
1589        }) {
1590            return false;
1591        }
1592        let dest = match target {
1593            Some(t) => self.var_type(t).cloned(),
1594            None => self.current_return_ty.clone(),
1595        };
1596        let narrow = matches!(dest, Some(JType::Short | JType::Byte | JType::Char));
1597        if !narrow {
1598            return true;
1599        }
1600        // 窄类型返回/赋值:原 if 的两支各是常量表达式(int 常量可收窄),
1601        // 合并成非常量三元后收窄失效。仅当两支都已是窄类型形态时放行。
1602        branches.iter().all(|&b| narrow_typed_expr(self, b))
1603    }
1604
1605    fn ternary_arg_unsound(&self, decl: JavaId, _value: JavaId) -> bool {
1606        // 声明类型带类型实参/通配符:实参位的目标类型参与泛型方法推断,
1607        // 多态条件表达式脱离该锚点会推断失败(JDK management 复现)。
1608        matches!(
1609            self.data(decl),
1610            NodeData::VarDecl {
1611                ty: JType::Ref(n),
1612                ..
1613            } if n.contains('<')
1614        )
1615    }
1616
1617    fn propagation_cast_unsound(&self, decl: JavaId, value: JavaId) -> bool {
1618        if self.receiver_boxing_unsound(decl, value) {
1619            return true;
1620        }
1621        // 声明类型是参数化/数组引用且值不是字面量:值的静态类型不可由
1622        // 形状判定,内联进 cast 可能把合法 cast 变成 inconvertible
1623        //(`List<?> list = Arrays.asList(a); (List<X>) list` 合法,
1624        // 换成 List<Object> 后非法——JDK RecordedStackTrace 复现)。
1625        let declared = match self.data(decl) {
1626            NodeData::VarDecl { ty, .. } => ty,
1627            _ => return false,
1628        };
1629        let generic_or_array = match declared {
1630            JType::Ref(n) => n.contains('<'),
1631            JType::Array(_) => true,
1632            _ => false,
1633        };
1634        generic_or_array && !matches!(self.data(value), NodeData::Literal(_))
1635    }
1636
1637    fn receiver_propagation_unsound(
1638        &self,
1639        decl: JavaId,
1640        value: JavaId,
1641        use_parent: Option<JavaId>,
1642        use_at_head: bool,
1643    ) -> bool {
1644        // 使用位必须是成员访问接收者(Member 的 child 0)——实参位
1645        // raw↔泛型双向兼容(unchecked),不敏感
1646        let is_receiver = matches!(use_parent, Some(p) if {
1647            matches!(self.data(p), NodeData::Member { .. }) && use_at_head
1648        });
1649        if is_receiver {
1650            // 装箱丢失(R13 P0-2):引用声明 + 基本类型值——接收位无装箱转换
1651            if self.receiver_boxing_unsound(decl, value) {
1652                return true;
1653            }
1654            // New 值接收位类型绑定守卫(R15 终审 P0-4/P0-5 抓获):
1655            // (a) diamond(`new ArrayList<>()`)——类型推断依赖赋值目标,
1656            //     脱离赋值位内联进接收位退化为无目标推断
1657            //     (MethodRefToInner 抓获:`List<String> l = new ArrayList<>();
1658            //     l.stream().forEach(TestString::new)` → Stream<Object>,
1659            //     构造器引用 Object 无法转 String);
1660            // (b) 构造类型基名 ≠ 声明类型基名——接收者静态类型改变,方法
1661            //     绑定与 throws 子句随之改变(CloneableProblem 抓获:
1662            //     `A a0 = new CloneableProblem(0); a0.clone()` 内联后
1663            //     A.clone() 的 CloneNotSupportedException 不再可抛,catch 失据)。
1664            if self.receiver_new_type_unsound(decl, value) {
1665                return true;
1666            }
1667            // 声明类型带**显式类型实参**且值是方法调用:内联进接收位会
1668            // 丢掉赋值目标对调用链泛型推断的锚定(JDK MethodHandles:
1669            // `Stream<Class<?>> cstream = fini.stream()…map(…);`
1670            // `cstream.findFirst().orElse(void.class)` 内联后 orElse
1671            // 的 Class<Void> 与推断出的 CAP#1 不兼容)。保守拒绝。
1672            if matches!(
1673                self.data(decl),
1674                NodeData::VarDecl {
1675                    ty: JType::Ref(n),
1676                    ..
1677                } if n.contains('<')
1678            ) && matches!(self.data(value), NodeData::Call)
1679            {
1680                return true;
1681            }
1682            // 声明类型为 **已知泛型的 raw 引用**(无类型实参——擦除成员解析):
1683            // var 推断/显式带实参/非泛型/未知外部类型不触发(保守——未知名
1684            // 保持传播,与修复前行为一致)
1685            let raw_ref = match self.data(decl) {
1686                NodeData::VarDecl { ty: JType::Ref(n), .. } => {
1687                    !n.contains('<')
1688                        && n.rsplit('.').next().is_some_and(|base| {
1689                            self.raw_generic_names.contains(base)
1690                        })
1691                }
1692                _ => false,
1693            };
1694            if !raw_ref {
1695                return false;
1696            }
1697            // init 静态类型可能**带泛型**:调用(返回类型未知)或带实参 new
1698            match self.data(value) {
1699                NodeData::Call => true,
1700                NodeData::New { ty, .. } => {
1701                    matches!(ty, JType::Ref(n) if n.contains('<'))
1702                }
1703                _ => false,
1704            }
1705        } else {
1706            // 数组访问基座(Index 的 child 0):new 数组值的元素类型绑定
1707            // 守卫(R15 终审 P0-2 续,T8357653b 抓获)——声明元素带泛型
1708            // 实参(`B<?>[] b2 = new B[1]`)时内联进 `b2[0]` 基座使元素
1709            // 从 B<?> 变 raw B,成员解析走擦除(rett() 返回 Object →
1710            // `String s2 = …` 赋值失败)。元素名须**全串**一致(含实参),
1711            // 维度须与声明嵌套一致;var 推断声明恒安全
1712            if matches!(use_parent, Some(p) if {
1713                matches!(self.data(p), NodeData::Index) && use_at_head
1714            }) {
1715                return self.index_base_newarray_unsound(decl, value);
1716            }
1717            false
1718        }
1719    }
1720
1721    fn bin_op(&self, id: JavaId) -> Option<BinOp> {
1722        match self.data(id) {
1723            NodeData::Binary { op } => Some(*op),
1724            _ => None,
1725        }
1726    }
1727    fn un_op(&self, id: JavaId) -> Option<UnOp> {
1728        match self.data(id) {
1729            NodeData::Unary { op } => Some(*op),
1730            _ => None,
1731        }
1732    }
1733    fn literal(&self, id: JavaId) -> Option<LitRef<'_>> {
1734        match self.data(id) {
1735            NodeData::Literal(l) => Some(match l {
1736                Lit::Bool(b) => LitRef::Bool(*b),
1737                Lit::Int(v) => LitRef::Int(*v),
1738                Lit::Long(v) => LitRef::Long(*v),
1739                Lit::Float(v) => LitRef::Float(*v),
1740                Lit::Double(v) => LitRef::Double(*v),
1741                Lit::Char(c) => LitRef::Char(*c),
1742                Lit::Str(s) => LitRef::Str(s),
1743                // TextBlock 的**值**需完整 JLS §3.10.6 处理(附加缩进
1744                // 剥离 + 行尾空白剔除 + \s 转义——InputJava14EscapedS
1745                // 抓获:按原始内文求值把 assert 折成 false)。存的是原文
1746                //(往返保真),值语义未实现 → 保守不当作字面量(折叠拒
1747                // 绝;打印路径不经过 literal())
1748                Lit::TextBlock(_) => return None,
1749                Lit::NumRaw { val, .. } => match val {
1750                    NumVal::Int(v) => LitRef::Int(*v),
1751                    NumVal::Long(v) => LitRef::Long(*v),
1752                    NumVal::Float(v) => LitRef::Float(*v),
1753                    NumVal::Double(v) => LitRef::Double(*v),
1754                },
1755                Lit::Null => LitRef::Null,
1756            }),
1757            _ => None,
1758        }
1759    }
1760    fn var_name(&self, id: JavaId) -> Option<&str> {
1761        match self.data(id) {
1762            NodeData::VarRef { name } => Some(self.sn(*name)),
1763            NodeData::VarDecl { name, .. } => Some(name),
1764            NodeData::ForEach { name, .. } | NodeData::Catch { name, .. } => Some(name),
1765            _ => None,
1766        }
1767    }
1768    fn member_name(&self, id: JavaId) -> Option<&str> {
1769        match self.data(id) {
1770            NodeData::Member { name } => Some(self.sn(*name)),
1771            NodeData::MethodRef { name } => Some(self.sn(*name)),
1772            _ => None,
1773        }
1774    }
1775    fn double_not_sound(&self, _operand: JavaId) -> bool {
1776        // Java:`!` 操作数必须 boolean(JLS 15.15.6)——可编译的 !!x
1777        // 其 x 恒 boolean,恒等式无条件成立(hard_obfuscation 的
1778        // !!it.hasNext() 迭代器形态依赖此折叠)
1779        true
1780    }
1781
1782    fn var_cast_position_ok(&self, value: JavaId, typed: JavaId) -> bool {
1783        // 值须为 VarRef(其余形态自带类型,不走本裁决)
1784        if !matches!(self.data(value), NodeData::VarRef { .. }) {
1785            return true;
1786        }
1787        // 声明类型未解析(自由名——反编译残缺作用域常态)→ 未知类型
1788        // 可 cast 到任何引用类型,恒可编译(golden redundant_typed_cast:
1789        // `String s = value; return (String) s;` → `(String) value` 保留)
1790        let Some(d) = self.var_type(value).cloned() else {
1791            return true;
1792        };
1793        let t = match self.data(typed) {
1794            NodeData::Cast { ty } => ty.clone(),
1795            NodeData::InstanceOf { ty, .. } => ty.clone(),
1796            _ => return true,
1797        };
1798        if d == t {
1799            return true;
1800        }
1801        // Object 任一侧 → cast/instanceof 恒合法;其余已解析的不同名
1802        // 类型(基元混搭/两个具体引用)→ interface/子类关系不可判,
1803        // 保守拒绝(ddc weixin dt/k 的原始守卫语义保持)
1804        let obj = |ty: &JType| {
1805            matches!(ty, JType::Ref(r) if r == "java.lang.Object" || r == "Object")
1806        };
1807        obj(&d) || obj(&t)
1808    }
1809    fn is_field_name(&self, name: &str) -> bool {
1810        self.field_types.contains_key(name)
1811    }
1812    fn payload_equal(&self, a: JavaId, b: JavaId) -> bool {
1813        // 字面量:值级比较(NumRaw 的 0x1F 与 Int 的 31 值等可折——
1814        // data 全等会退化成原文等)
1815        if let (NodeData::Literal(x), NodeData::Literal(y)) = (self.data(a), self.data(b)) {
1816            return lit_value_eq(x, y);
1817        }
1818        self.data(a) == self.data(b)
1819    }
1820    fn assign_op(&self, id: JavaId) -> Option<BinOp> {
1821        match self.data(id) {
1822            NodeData::Assign { op } => *op,
1823            _ => None,
1824        }
1825    }
1826
1827    /// 重建缓存:
1828    /// 1) 效果表——arena 按升序扫描(child index < parent index 不变量);
1829    /// 2) 变量类型表——从 root 做作用域栈遍历。
1830    fn prepare(&mut self, root: JavaId) {
1831
1832        if cnt_prepare_on() {
1833            PREPARE_CALLS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1834            PREPARE_NODES.fetch_add(self.nodes.len(), std::sync::atomic::Ordering::Relaxed);
1835        }
1836        // 名字键增量扩展(cure-tree NameTable):新节点 intern(既有节点
1837        // 键不变——名字与位置无关)。名字先收集(&self 借用安全形态),
1838        // 再批量扩展(&mut self.names)。
1839        let n_nodes = self.nodes.len();
1840        let key_slots = self.names.key_slots();
1841        if key_slots < n_nodes {
1842            let names: Vec<Option<String>> = (key_slots..n_nodes)
1843                .map(|i| self.var_name(JavaId(i as u32)).map(|n| n.to_string()))
1844                .collect();
1845            self.names.extend_owned(key_slots, &names);
1846        }
1847        // 守卫缓存失效:树已变
1848        self.string_identity.set(None);
1849        // 区域事件索引【惰性重建】(B3,cure-tree EventStore):只重建
1850        // **空条目**——被 invalidate_effect 失效的语句、或新语句。未失效
1851        // 条目的事件是子树局部的(与位置无关)。关键不变量:**一切**改树
1852        // 路径都必须失效受影响语句的条目:
1853        //   - 立即 Replace:目标祖先链 + with 子树中既有节点的**旧容器**
1854        //     祖先链(搬移——pass.rs 立即路径两处都做)
1855        //   - 队列编辑应用:同上(pass.rs deferred 应用后统一失效)
1856        // 违反不变量的后果:陈旧事件驱动错误决策(B2 教训:cff_diamond
1857        // 差分当场抓获)。性能背景:Types.java 上 prepare 每 pass 全量重建
1858        // = 726 倍冗余(37 万文件语料 prepare 占 57% 线程时间)。
1859        self.events.resize(n_nodes);
1860        self.stmt_facts.resize_with(n_nodes, || None);
1861        self.stmt_kills.resize_with(n_nodes, || None);
1862        self.stmt_opq.resize_with(n_nodes, || None);
1863        if self.events.is_clean() {
1864            if self.prepared_root == Some(root) {
1865                return;
1866            }
1867            // 树全局缓存(事件/效果表)仍有效;根变了 → 只重建
1868            // root 相关的作用域分析段
1869            self.rebuild_var_types(root);
1870            self.prepared_root = Some(root);
1871            return;
1872        }
1873        self.prepared_root = Some(root);
1874        self.events.mark_clean();
1875        for sr in cure_tree::stmt_roots(self, root) {
1876            let idx = sr.0 as usize;
1877            if self.events.slot(idx).is_none() {
1878                if let Some(events) = cure_tree::collect_region_events(self, sr) {
1879                    self.events.put(idx, events);
1880                }
1881            }
1882            if self.stmt_facts.get(idx).map_or(true, |f| f.is_none()) {
1883                let facts = self.collect_stmt_facts(sr);
1884                self.stmt_facts[idx] = Some(facts);
1885            }
1886            if self.stmt_kills.get(idx).map_or(true, |f| f.is_none()) {
1887                let kills = self.collect_stmt_kill_facts(sr);
1888                self.stmt_kills[idx] = Some(kills);
1889            }
1890            if self.stmt_opq.get(idx).map_or(true, |f| f.is_none()) {
1891                if let Some(opq) = self.stmt_opaque_fact(sr) {
1892                    self.stmt_opq[idx] = Some(opq);
1893                }
1894            }
1895        }
1896        // ---- 效果表(cure-tree rebuild_effects:不动点 sweep——
1897        // children-先于-parent 索引序 + 注入节点违例多轮收敛)----
1898        let effects = cure_tree::rebuild_effects(self, n_nodes);
1899        self.effect_cache = effects;
1900        self.rebuild_var_types(root);
1901    }
1902}
1903
1904impl JavaAst {
1905    /// One traversal of a statement subtree: every VarRef increments its
1906    /// name key; a VarRef under any Lambda also marks the name as
1907    /// lambda-captured. Sorted by key for binary-search queries.
1908    fn collect_stmt_facts(&self, root: JavaId) -> Box<[StmtFact]> {
1909        let mut counts: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
1910        let mut caps: std::collections::HashSet<u32> = std::collections::HashSet::new();
1911        let mut shadows: std::collections::HashSet<u32> = std::collections::HashSet::new();
1912        let mut stack: Vec<(JavaId, bool)> = vec![(root, false)];
1913        while let Some((id, in_lambda)) = stack.pop() {
1914            let node = &self.nodes[id.0 as usize];
1915            let is_lambda = matches!(node.data, NodeData::Lambda { .. });
1916            let is_named_decl = matches!(
1917                node.data,
1918                NodeData::VarDecl { .. } | NodeData::ForEach { .. } | NodeData::Catch { .. }
1919            );
1920            if matches!(node.data, NodeData::VarRef { .. }) {
1921                if let Some(key) = self.names.var_key(id.0 as usize) {
1922                    *counts.entry(key).or_insert(0) += 1;
1923                    if in_lambda {
1924                        caps.insert(key);
1925                    }
1926                }
1927            } else if is_named_decl {
1928                if let Some(key) = self.names.var_key(id.0 as usize) {
1929                    shadows.insert(key);
1930                }
1931            }
1932            let child_in_lambda = in_lambda || is_lambda;
1933            for &c in node.children.as_slice() {
1934                stack.push((c, child_in_lambda));
1935            }
1936        }
1937        let mut keys: std::collections::HashSet<u32> = counts.keys().copied().collect();
1938        keys.extend(shadows.iter().copied());
1939        let mut facts: Vec<StmtFact> = keys
1940            .into_iter()
1941            .map(|key| StmtFact {
1942                key,
1943                refs: counts.get(&key).copied().unwrap_or(0),
1944                lambda_cap: caps.contains(&key),
1945                shadow: shadows.contains(&key),
1946            })
1947            .collect();
1948        facts.sort_unstable_by_key(|f| f.key);
1949        facts.into_boxed_slice()
1950    }
1951
1952    /// Whether the statement subtree contains an opaque node.
1953    fn stmt_opaque_fact(&self, root: JavaId) -> Option<StmtOpq> {
1954        let mut stack = vec![root];
1955        while let Some(id) = stack.pop() {
1956            if self.is_opaque(id) {
1957                return Some(StmtOpq { opaque: true });
1958            }
1959            for &c in self.nodes[id.0 as usize].children.as_slice() {
1960                stack.push(c);
1961            }
1962        }
1963        Some(StmtOpq { opaque: false })
1964    }
1965
1966    /// One DFS for all names in the statement (first event wins), sorted
1967    /// by key for binary-search queries.
1968    fn collect_stmt_kill_facts(&self, root: JavaId) -> Box<[StmtKillFact]> {
1969        let mut facts: Vec<StmtKillFact> = cure_engine::rules::collect_stmt_kill_events(self, root)
1970            .into_iter()
1971            .map(|(key, event)| match event {
1972                StmtKill::None => unreachable!("collector only records real events"),
1973                StmtKill::Read => StmtKillFact {
1974                    key,
1975                    kind: 1,
1976                    assign: JavaId(0),
1977                },
1978                StmtKill::Shadow => StmtKillFact {
1979                    key,
1980                    kind: 2,
1981                    assign: JavaId(0),
1982                },
1983                StmtKill::DomWrite(assign) => StmtKillFact {
1984                    key,
1985                    kind: 3,
1986                    assign,
1987                },
1988            })
1989            .collect();
1990        facts.sort_unstable_by_key(|f| f.key);
1991        facts.into_boxed_slice()
1992    }
1993
1994    /// root 相关的作用域分析(从 prepare 提取——根变化时单独重建)。
1995    pub(crate) fn rebuild_var_types(&mut self, root: JavaId) {
1996        // ---- 变量类型(作用域栈)----
1997        self.var_types.clear();
1998        self.var_types.resize(self.nodes.len(), None);
1999        #[derive(Clone)]
2000        enum Frame {
2001            Enter(JavaId),
2002            Exit,
2003            PopScope,
2004            Bind(String, JType),
2005        }
2006        let mut base: HashMap<String, JType> = HashMap::new();
2007        for (n, t) in &self.param_scope {
2008            base.insert(n.clone(), t.clone());
2009        }
2010        let mut scopes: Vec<HashMap<String, JType>> = vec![base];
2011        let mut stack = vec![Frame::Enter(root)];
2012        while let Some(f) = stack.pop() {
2013            match f {
2014                Frame::Enter(id) => {
2015                    let node = &self.nodes[id.0 as usize];
2016                    enum Action {
2017                        None,
2018                        Scope,
2019                        Bind(String, JType),
2020                    }
2021                    let action = match &node.data {
2022                        NodeData::Block | NodeData::For { .. } | NodeData::Try => Action::Scope,
2023                        NodeData::VarDecl { name, ty, .. } => {
2024                            scopes.last_mut().unwrap().insert(name.clone(), ty.clone());
2025                            Action::None
2026                        }
2027                        NodeData::VarRef { name } => {
2028                            if let Some(t) = scopes
2029                                .iter()
2030                                .rev()
2031                                .find_map(|s| s.get(self.sn(*name)))
2032                                .cloned()
2033                            {
2034                                self.var_types[id.0 as usize] = Some(t);
2035                            }
2036                            Action::None
2037                        }
2038                        NodeData::Catch { name, .. } => {
2039                            Action::Bind(name.clone(), JType::Var)
2040                        }
2041                        NodeData::ForEach { name, ty } => {
2042                            Action::Bind(name.clone(), ty.clone())
2043                        }
2044                        _ => Action::None,
2045                    };
2046                    // 期望弹出顺序:[Bind?] children… [PopScope?] Exit
2047                    // ⇒ 压栈顺序取反:Exit、[PopScope]、children(逆序)、[Bind]
2048                    stack.push(Frame::Exit);
2049                    if matches!(action, Action::Scope | Action::Bind(_, _)) {
2050                        scopes.push(HashMap::new());
2051                        stack.push(Frame::PopScope);
2052                    }
2053                    for &c in node.children.as_slice().iter().rev() {
2054                        stack.push(Frame::Enter(c));
2055                    }
2056                    if let Action::Bind(n, t) = action {
2057                        stack.push(Frame::Bind(n, t));
2058                    }
2059                }
2060                Frame::Bind(name, ty) => {
2061                    scopes.last_mut().unwrap().insert(name, ty);
2062                }
2063                Frame::PopScope => {
2064                    scopes.pop();
2065                }
2066                Frame::Exit => {}
2067            }
2068        }
2069    }
2070}
2071
2072// ---------------------------------------------------------------------------
2073// 区域事件索引(使用索引):规则区域扫描的预计算。
2074// 遍历序必须与引擎 scan_region 原递归严格一致:
2075//   Assign      → [Write(目标)] + value 子树(目标本身不再当 Use 扫)
2076//   自增自减    → [Write(目标)],不扫子
2077//   VarDecl     → [Write, Shadow] + 全部孩子
2078//   ForEach     → [Write, Shadow] + 全部孩子;Catch → [Shadow] + 孩子
2079//   VarRef      → [Use]
2080//   其余        → 依序拼接孩子
2081// ---------------------------------------------------------------------------
2082
2083impl JavaAst {
2084    /// 局部传播到成员访问接收位的**装箱丢失**检查:声明为引用类型 +
2085    /// 值是基本类型形态(原始字面量/基本类型变量/算术一元二元——
2086    /// R13 P0-2 抓获:`Object o = +c; o.getClass()` 曾内联成
2087    /// `(+c).getClass()` / 常量传播折成 `65.getClass()`——int 接收者
2088    /// 不可解引用;装箱转换只发生在赋值/传参位,接收位无转换)。
2089    /// 字符串字面量/引用变量合法(`"a".length()`)。
2090    /// 接收位 `new` 值的类型可靠性(R15 终审 P0-4/P0-5):diamond 无目标
2091    /// 推断不可靠;构造类型基名 ≠ 声明类型基名(接口/父类型声明的实现类
2092    /// 构造)→ 接收者静态类型改变 → 方法绑定/throws 子句可能改变 →
2093    /// 不可靠。同名构造(`Foo f = new Foo(); f.m()`)与 var 推断声明
2094    ///(推断类型即 init 类型)保持传播。
2095    fn receiver_new_type_unsound(&self, decl: JavaId, value: JavaId) -> bool {
2096        let NodeData::New { ty, .. } = self.data(value) else {
2097            return false;
2098        };
2099        let decl_ty = match self.data(decl) {
2100            NodeData::VarDecl { ty, .. } => ty,
2101            _ => return false,
2102        };
2103        // var:推断类型 == init 静态类型——New 与之恒等(含 diamond:
2104        // `var l = new ArrayList<>()` 本就按无目标推断)
2105        if matches!(decl_ty, JType::Var) {
2106            return false;
2107        }
2108        let name = match ty {
2109            JType::Ref(n) => n.as_str(),
2110            // 非引用构造类型(不可能出现在合法 new;防御拒绝)
2111            _ => return true,
2112        };
2113        // diamond:推断依赖赋值目标——接收位无目标
2114        if name.ends_with("<>") {
2115            return true;
2116        }
2117        match decl_ty {
2118            JType::Ref(d) => type_base_name(d) != type_base_name(name),
2119            // 声明为数组/基元却以类构造为 init——恒不可靠(防御)
2120            _ => true,
2121        }
2122    }
2123
2124    /// 数组访问基座(`b2[0]` 的 b2 位)`new` 数组值的元素类型可靠性
2125    /// (R15 终审 P0-2 续,T8357653b 抓获):声明元素类型与 new 的元素
2126    /// 类型须**全串一致**(含泛型实参——`B<?>[] b2 = new B[1]` 内联使
2127    /// b2[0] 从 B<?> 变 raw B → 成员解析擦除化),维度数须与声明嵌套
2128    /// 一致。var 推断声明(推断类型即 init 类型)恒安全。
2129    fn index_base_newarray_unsound(&self, decl: JavaId, value: JavaId) -> bool {
2130        let NodeData::NewArray { ty, dims, .. } = self.data(value) else {
2131            return false;
2132        };
2133        let decl_ty = match self.data(decl) {
2134            NodeData::VarDecl { ty, .. } => ty,
2135            _ => return false,
2136        };
2137        if matches!(decl_ty, JType::Var) {
2138            return false;
2139        }
2140        // 声明的数组嵌套层数 + 最内元素类型(Ref 全串含泛型实参)
2141        let mut elem: &JType = decl_ty;
2142        let mut nest = 0u16;
2143        while let JType::Array(inner) = elem {
2144            elem = inner.as_ref();
2145            nest += 1;
2146        }
2147        nest != *dims || *elem != *ty
2148    }
2149
2150    fn receiver_boxing_unsound(&self, decl: JavaId, value: JavaId) -> bool {
2151        let declared_ref = match self.data(decl) {
2152            NodeData::VarDecl { ty, .. } => ty.is_ref(),
2153            _ => false,
2154        };
2155        if !declared_ref {
2156            return false;
2157        }
2158        match self.data(value) {
2159            NodeData::Literal(
2160                Lit::Int(_) | Lit::Long(_) | Lit::Float(_) | Lit::Double(_) | Lit::Bool(_)
2161                | Lit::Char(_),
2162            ) => true,
2163            // 基本类型变量(var_type 解析参数/局部声明类型)
2164            NodeData::VarRef { .. } => matches!(
2165                self.var_type(value),
2166                Some(
2167                    JType::Int
2168                        | JType::Long
2169                        | JType::Byte
2170                        | JType::Short
2171                        | JType::Char
2172                        | JType::Float
2173                        | JType::Double
2174                        | JType::Bool
2175                )
2176            ),
2177            // 算术/逻辑一元二元:结果必为基本类型
2178            NodeData::Unary { .. } | NodeData::Binary { .. } => true,
2179            // 三元:结果可为基本类型(R14 族 B 抓获:`Object o = true ?
2180            // 'a' : 'b'; o.hashCode()` 曾内联成 'a'.hashCode() 不可解引用)
2181            // ——含引用臂的保守拒绝(过度面小)
2182            NodeData::Ternary => true,
2183            // 基本类型 cast:(int) 'a' 结果 int——引用 cast 保守同拒
2184            NodeData::Cast { .. } => true,
2185            // instanceof:结果恒 boolean
2186            NodeData::InstanceOf { .. } => true,
2187            // 装箱类型声明 + 调用/成员/下标值(返回类型未知——s.charAt(0)
2188            // 等基本返回调用内联进接收位丢装箱——R14 终审 P0-2 抓获:
2189            // `Character c = s.charAt(0); return c.toString()` 曾产出
2190            // `s.charAt(0).toString()` 无法取消引用 char)。装箱名精确
2191            // 匹配,非装箱引用类型(Foo f = m(); f.x())不受限
2192            NodeData::Call | NodeData::Member { .. } | NodeData::Index => {
2193                match self.data(decl) {
2194                    NodeData::VarDecl { ty: JType::Ref(n), .. } => {
2195                        let boxed = [
2196                            "Character", "Integer", "Long", "Boolean", "Double",
2197                            "Float", "Byte", "Short", "Number", "AtomicInteger",
2198                            "AtomicLong",
2199                        ];
2200                        n.rsplit('.').next().is_some_and(|b| boxed.contains(&b))
2201                    }
2202                    _ => false,
2203                }
2204            }
2205            _ => false,
2206        }
2207    }
2208
2209    /// 名字 → 实化键(持久表,只增;同名字恒同键)。
2210    /// intern 名字 → Sym(复用 name_intern 表 + sym_names 向量)。
2211    pub fn intern_sym(&mut self, name: &str) -> Sym {
2212        Sym(self.names.intern(name))
2213    }
2214
2215    /// Sym → 名字原文。
2216    pub fn sn(&self, sym: Sym) -> &str {
2217        self.names.name(sym.0)
2218    }
2219
2220
2221
2222
2223}
2224
2225
2226// ---------------------------------------------------------------------------
2227// 结构化指标:编译单元级聚合(供 --stats 等评估简化效果——节点数 /
2228// 判定点 / 嵌套深度不受格式化影响,只被语义简化改变)
2229// ---------------------------------------------------------------------------
2230
2231/// 编译单元全部可执行体(方法/构造器/初始化块,含嵌套类型)的
2232/// 结构指标总和。
2233pub fn unit_metrics(ast: &JavaAst, unit: &CompilationUnit) -> TreeMetrics {
2234    let mut total = TreeMetrics::default();
2235    for ty in &unit.types {
2236        metrics_of_type(ast, ty, &mut total);
2237    }
2238    total
2239}
2240
2241fn metrics_of_type(ast: &JavaAst, ty: &TypeDecl, total: &mut TreeMetrics) {
2242    for m in &ty.members {
2243        match m {
2244            Member::Method { body: Some(b), .. } | Member::Constructor { body: Some(b), .. } => {
2245                total.add(subtree_metrics(ast, *b));
2246            }
2247            Member::Initializer { body, .. } => {
2248                total.add(subtree_metrics(ast, *body));
2249            }
2250            Member::Type(t) => metrics_of_type(ast, t, total),
2251            _ => {}
2252        }
2253    }
2254}
2255
2256static ENV_CACHED: std::sync::OnceLock<(bool, bool)> = std::sync::OnceLock::new();
2257fn env_flags() -> (bool, bool) {
2258    *ENV_CACHED.get_or_init(|| {
2259        (
2260            std::env::var("CURE_CNT_PREPARE").is_ok(),
2261            std::env::var("CURE_VERIFY_EVENTS").is_ok(),
2262        )
2263    })
2264}
2265fn cnt_prepare_on() -> bool { env_flags().0 }
2266fn verify_events_on() -> bool { env_flags().1 }
2267
2268pub static PREPARE_CALLS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
2269pub static PREPARE_NODES: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
2270
2271pub static COLLECT_CALLS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
2272
2273// ---------------------------------------------------------------------------
2274// 测试
2275// ---------------------------------------------------------------------------
2276
2277#[cfg(test)]
2278mod tests {
2279    use super::*;
2280
2281    #[test]
2282    fn builder_smoke() {
2283        let mut a = JavaAst::new();
2284        let one = a.lit(Lit::Int(1));
2285        let x = a.var_decl("x", JType::Int, Some(one));
2286        let xv = a.var("x");
2287        let r = a.ret(Some(xv));
2288        let body = a.block(vec![x, r]);
2289        assert_eq!(a.kind(body), NodeKind::Block);
2290        assert_eq!(a.children(body).len(), 2);
2291    }
2292
2293    #[test]
2294    fn effect_aggregation() {
2295        let mut a = JavaAst::new();
2296        let f = a.plain_call("foo", vec![]);
2297        let r = a.ret(Some(f));
2298        let body = a.block(vec![r]);
2299        a.prepare(body);
2300        assert_eq!(a.effect(f), Effect::Unknown);
2301        assert_eq!(a.effect(r), Effect::Unknown);
2302        assert_eq!(a.effect(body), Effect::Unknown);
2303
2304        let mut b = JavaAst::new();
2305        let two = b.lit(Lit::Int(2));
2306        let three = b.lit(Lit::Int(3));
2307        let add = b.bin(BinOp::Add, two, three);
2308        let r2 = b.ret(Some(add));
2309        let body2 = b.block(vec![r2]);
2310        b.prepare(body2);
2311        assert_eq!(b.effect(add), Effect::Pure);
2312        // return 语句本身按控制流计为 MayThrow,Block 聚合随之
2313        assert_eq!(b.effect(r2), Effect::MayThrow);
2314        assert_eq!(b.effect(body2), Effect::MayThrow);
2315    }
2316
2317    #[test]
2318    fn var_type_resolution_and_shadowing() {
2319        let mut a = JavaAst::new();
2320        // { boolean b = true; { int b2 = 1; b2; } b; }
2321        let one = a.lit(Lit::Int(1));
2322        let b2_decl = a.var_decl("b2", JType::Int, Some(one));
2323        let inner_b2 = a.var("b2");
2324        let inner_stmt = a.expr_stmt(inner_b2);
2325        let inner = a.block(vec![b2_decl, inner_stmt]);
2326        let tv = a.lit(Lit::Bool(true));
2327        let decl_b = a.var_decl("b", JType::Bool, Some(tv));
2328        let outer_b = a.var("b");
2329        let outer_stmt = a.expr_stmt(outer_b);
2330        let body = a.block(vec![decl_b, inner, outer_stmt]);
2331        a.prepare(body);
2332        assert!(a.is_bool(outer_b));
2333        // b2 的使用在 inner 块内,类型可解析
2334        assert!(a.var_type(inner_b2).is_some());
2335    }
2336
2337    #[test]
2338    fn raw_and_foreach_semantics() {
2339        let mut a = JavaAst::new();
2340        // { int x = 1; RAW; for (String s : list) { s.len(); } }
2341        let one = a.lit(Lit::Int(1));
2342        let dx = a.var_decl("x", JType::Int, Some(one));
2343        let r = a.raw("broken ~!@ code");
2344        let sv = a.var("s");
2345        let call = a.method_call(sv, "len", vec![]);
2346        let es = a.expr_stmt(call);
2347        let body = a.block(vec![es]);
2348        let lst = a.var("list");
2349        let fe = a.for_each("s", JType::Ref("String".into()), lst, body);
2350        let all = a.block(vec![dx, r, fe]);
2351        a.prepare(all);
2352        assert_eq!(a.kind(r), NodeKind::Raw);
2353        assert_eq!(a.effect(r), Effect::Unknown);
2354        assert!(a.var_type(sv).is_some()); // 循环变量类型可解析
2355    }
2356
2357    #[test]
2358    fn num_raw_literal() {
2359        let mut a = JavaAst::new();
2360        let l = a.lit(Lit::NumRaw {
2361            text: "0x1F".into(),
2362            val: NumVal::Int(31),
2363        });
2364        a.prepare(l);
2365        assert!(a.is_exact_int(l));
2366        assert!(matches!(a.literal(l), Some(LitRef::Int(31))));
2367    }
2368}