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;
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/// Java AST arena。只追加不回收,[`JavaId`] 永不失效。
232#[derive(Default, Debug)]
233pub struct JavaAst {
234    pub(crate) nodes: Vec<Node>,
235    /// prepare() 重建:JavaId → 聚合效果。
236    /// 槽位 = arena 下标(稠密 u32);None = 未算/失效。Vec 索引替代哈希。
237    effect_cache: Vec<Option<Effect>>,
238    /// prepare() 重建:VarRef 节点 → 声明类型(作用域解析)。
239    /// 槽位 = arena 下标;None = 未解析。Vec 索引替代哈希。
240    var_types: Vec<Option<JType>>,
241    /// 方法参数类型(由 simplify 门面按方法设置,作为根作用域)。
242    param_scope: Vec<(String, JType)>,
243    /// 类级常量字段(static final 且字面量/字面量数组初始化、无写、无同名局部)
244    /// → 初始化节点。由 simplify_unit 填充(跨方法解密的字符串表)。
245    pub const_fields: HashMap<String, JavaId>,
246    /// 可安全做 VarRef → 字面量传播的常量字段名(标量字面量且声明类型
247    /// 与字面量种类精确匹配——过载解析/常量池身份不受影响)。
248    /// 数组常量不进(只走下标折叠,整表引用不复制)。
249    pub const_scalars: HashSet<String>,
250    /// 空私有方法(no-op 调用清理用):名字 → 元数 → 同名同元数全部
251    /// 候选(参数类型表 + 是否 private 空体)。调用点做类型适用性消解
252    ///(唯一适用者且为 private 空体 → no-op)。同名任意方法含 varargs →
253    /// 该名整体放弃(varargs 可吸收任意元数)。由 simplify_unit 填充
254    ///(--dead-code 门控)。
255    pub noop_private_methods: HashMap<String, HashMap<usize, Vec<NoopCandidate>>>,
256    /// 字段声明类型表(名字 → JType;同名二见移除)——调用点实参静态
257    /// 类型解析用(VarRef 解析不到局部时查字段)。collect_unit_consts 填充。
258    pub field_types: HashMap<String, JType>,
259    /// 本单元声明了名为 String/StringBuilder 的类型(遮蔽 java.lang——
260    /// new String("x") 折叠/字符串链折叠在该单元全部拒绝。探针 T4a/b
261    /// 抓获:`class String{…}` 同文件时 new String 折叠产出不可编译或
262    /// 静默错值)。collect_unit_consts 每轮重算。
263    pub unit_shadows_lang: bool,
264    /// 已知为**泛型**的类型简单名(单元内带 ty_params 的类型 + 常见
265    /// JDK 泛型库类)。raw 引用(无类型实参)这些名字时,接收位传播
266    /// 改变成员解析(raw 擦除 vs 泛型形参——CAP#1 编译错)。
267    pub raw_generic_names: std::collections::HashSet<String>,
268    /// final 字段名集合(同名二见移除——保守)。static_exec 截断守卫
269    /// 用:前缀字段写被 rest 再赋值时,仅 final 才放弃(非 final 的
270    /// 材料化写是死写,语义恒等、可编译)。
271    pub final_fields: HashSet<String>,
272    /// 可内联的单 return 方法:名字 → (参数名表, 返回表达式节点)。
273    /// 由 simplify_unit 填充(解密 helper:d(0) → 方法体)。
274    pub inline_methods: HashMap<String, (Vec<String>, JavaId)>,
275    /// String 引用身份比较缓存:(root, 结果)。prepare() 清空(树已变),
276    /// 首次查询时计算——供 new String(lit) 等折叠守卫复用(每轮至多一次全扫)。
277    string_identity: std::cell::Cell<Option<(JavaId, bool)>>,
278    /// **单元级** String 身份比较存在标志(collect_unit_consts 每轮重算)。
279    /// new String(lit) 解包为池化字面量会翻转任何 == 观察点——字段 init
280    /// 解包的观察点在**其他方法**里(InputNoWhitespaceAfterWithEmoji 抓获
281    /// 合成证实:a == "hello" false→true),单根扫描看不见 → 单元级守卫。
282    pub unit_string_identity: bool,
283    /// 名字 intern 表 + 节点名字键(cure-tree `NameTable`;本语言
284    /// `Lang::NameKey = u32` intern id)。单元级持久、只增;prepare
285    /// 增量扩展新节点,既有节点键与其名字恒同。
286    names: NameTable,
287    /// 区域事件索引(cure-tree `EventStore`):B3 惰性重建 + 编辑失效。
288    /// 供引擎 scan_region 快路径——收集器在 cure-tree,只依赖 Lang
289    /// 钩子,遍历序与引擎原递归严格一致。
290    events: EventStore<JavaId, u32>,
291    /// 上次 prepare 的根。B3 早退(events_clean)只对**树全局**缓存
292    /// (事件索引/效果表)合法;var_types 是 **root 相关**的作用域分析
293    /// ——根变化时必须重建,否则 is_local_var 全 false、传播规则停摆
294    /// (deobfuscate 差分抓获:`t = bump(2)` 不再内联)。
295    prepared_root: Option<JavaId>,
296}
297
298// ---------------------------------------------------------------------------
299// 编译单元 / 成员(签名层:签名保真、方法体进 arena)
300// ---------------------------------------------------------------------------
301
302/// 方法/构造器参数。
303#[derive(Clone, PartialEq, Debug)]
304pub struct Param {
305    /// `final` / 注解等原文(可为空串)。
306    pub mods: String,
307    pub ty: JType,
308    /// `int... args`
309    pub varargs: bool,
310    pub name: String,
311}
312
313/// 字段声明中的一个声明符(`int a = 1, b[];` 里的 a、b)。
314#[derive(Clone, PartialEq, Debug)]
315pub struct Declarator {
316    pub name: String,
317    /// C 风格后缀维度 `int a[][]` 中名字后面的 `[]` 数。
318    pub extra_dims: u16,
319    /// 初始化表达式(arena 节点)。
320    pub init: Option<JavaId>,
321}
322
323/// 类成员。
324#[derive(Clone, PartialEq, Debug)]
325pub enum Member {
326    Field { mods: String, ty: JType, declarators: Vec<Declarator> },
327    Method {
328        mods: String,
329        /// 泛型参数原文(含尖括号,可为空串)。
330        ty_params: String,
331        ret: JType,
332        name: String,
333        params: Vec<Param>,
334        throws: Vec<String>,
335        /// 方法体 Block;None 表示 abstract/native/接口声明。可能是 Raw 节点。
336        body: Option<JavaId>,
337    },
338    Constructor {
339        mods: String,
340        ty_params: String,
341        name: String,
342        params: Vec<Param>,
343        throws: Vec<String>,
344        body: Option<JavaId>,
345        /// record 紧凑构造器:`Name { … }`(无参数列表,签名继承自 record 头)
346        compact: bool,
347    },
348    /// 实例/静态初始化块。
349    Initializer { is_static: bool, body: JavaId },
350    /// 嵌套类型。
351    Type(Box<TypeDecl>),
352    /// 不可解析成员(原文保真)。
353    Raw(String),
354}
355
356#[derive(Clone, Copy, PartialEq, Eq, Debug)]
357pub enum TypeKind {
358    Class,
359    Interface,
360    Enum,
361    Record,
362    Annotation,
363}
364
365/// 类型声明。
366#[derive(Clone, PartialEq, Debug)]
367pub struct TypeDecl {
368    pub kind: TypeKind,
369    /// 修饰符 + 注解原文。
370    pub mods: String,
371    pub name: String,
372    /// 泛型参数原文(含尖括号,可为空串);record 的头部参数原文存在 header。
373    pub ty_params: String,
374    /// record 组件头原文(`(int a, String b)`),非 record 为空串。
375    pub header: String,
376    pub extends: Vec<String>,
377    pub implements: Vec<String>,
378    /// sealed 类型的 permits 子句原文列表(打印 `permits A, B`)。
379    pub permits: Vec<String>,
380    /// 枚举常量原文(解析失败时兜底保真)。
381    pub enum_constants: Vec<String>,
382    pub members: Vec<Member>,
383}
384
385/// 编译单元。
386#[derive(Clone, PartialEq, Debug, Default)]
387pub struct CompilationUnit {
388    /// package 名(不含 `package`/`;`)。
389    pub package: Option<String>,
390    /// package 声明前的包级注解原文(package-info.java 的 @NullMarked /
391    /// @Deprecated——149 文件曾静默丢弃,RUNTIME 保留期改变整包契约)。
392    pub package_annotations: String,
393    /// import 项原文(如 `java.util.List` / `static x.y.*`)。
394    pub imports: Vec<String>,
395    pub types: Vec<TypeDecl>,
396    /// 顶层不可解析区域原文(按出现顺序保真)。
397    pub raws: Vec<String>,
398}
399
400/// 解析错误(位置为 1-based 行/列)。
401#[derive(Clone, PartialEq, Eq, Debug)]
402pub struct ParseError {
403    pub line: usize,
404    pub col: usize,
405    pub message: String,
406}
407
408// ---------------------------------------------------------------------------
409// JavaAst 主体
410// ---------------------------------------------------------------------------
411
412impl JavaAst {
413    pub fn new() -> Self {
414        Self::default()
415    }
416
417    /// 以 node 的负载 + 指定 children 构造新节点(深拷贝/替换用)。
418    pub fn clone_node(&mut self, id: JavaId, children: Vec<JavaId>) -> JavaId {
419        let data = self.nodes[id.0 as usize].data.clone();
420        self.push(data, children)
421    }
422
423    fn push(&mut self, data: NodeData, children: Vec<JavaId>) -> JavaId {
424        let id = JavaId(self.nodes.len() as u32);
425        self.nodes.push(Node { data, children: ChildList::from_vec(children) });
426        id
427    }
428
429    pub fn node(&self, id: JavaId) -> &Node {
430        &self.nodes[id.0 as usize]
431    }
432    pub fn data(&self, id: JavaId) -> &NodeData {
433        &self.node(id).data
434    }
435
436    /// 固有方法(与 Lang trait 同名;供不依赖引擎的下游使用,如 printer)。
437    pub fn kind(&self, id: JavaId) -> NodeKind {
438        match &self.nodes[id.0 as usize].data {
439            NodeData::Block | NodeData::Group => NodeKind::Block,
440            NodeData::Empty => NodeKind::Empty,
441            NodeData::Yield => NodeKind::Yield,
442            NodeData::ExprStmt => NodeKind::ExprStmt,
443            NodeData::VarDecl { .. } => NodeKind::VarDecl,
444            NodeData::Assign { .. } => NodeKind::Assign,
445            NodeData::If => NodeKind::If,
446            NodeData::While => NodeKind::While,
447            NodeData::DoWhile => NodeKind::DoWhile,
448            NodeData::For { .. } => NodeKind::For,
449            NodeData::ForEach { .. } => NodeKind::ForEach,
450            NodeData::Return => NodeKind::Return,
451            NodeData::Break { .. } => NodeKind::Break,
452            NodeData::Continue { .. } => NodeKind::Continue,
453            NodeData::Throw => NodeKind::Throw,
454            NodeData::Try => NodeKind::Try,
455            NodeData::Catch { .. } => NodeKind::Catch,
456            NodeData::Synchronized => NodeKind::Synchronized,
457            NodeData::Switch => NodeKind::Switch,
458            NodeData::Case { .. } => NodeKind::Case,
459            NodeData::Label { .. } => NodeKind::Label,
460            NodeData::Assert => NodeKind::Assert,
461            NodeData::Raw { .. } => NodeKind::Raw,
462            NodeData::Binary { .. } => NodeKind::Binary,
463            NodeData::Unary { .. } => NodeKind::Unary,
464            NodeData::Call => NodeKind::Call,
465            NodeData::Member { .. } => NodeKind::Member,
466            NodeData::Index => NodeKind::Index,
467            NodeData::Cast { .. } => NodeKind::Cast,
468            NodeData::Paren => NodeKind::Paren,
469            NodeData::Ternary => NodeKind::Ternary,
470            NodeData::New { .. } => NodeKind::New,
471            NodeData::NewArray { .. } => NodeKind::NewArray,
472            NodeData::ArrayLit => NodeKind::ArrayLit,
473            NodeData::VarRef { .. } => NodeKind::VarRef,
474            NodeData::Literal(_) => NodeKind::Literal,
475            NodeData::This => NodeKind::This,
476            NodeData::Super => NodeKind::This,
477            NodeData::InstanceOf { .. } => NodeKind::InstanceOf,
478            NodeData::Lambda { .. } => NodeKind::Lambda,
479            NodeData::MethodRef { .. } => NodeKind::MethodRef,
480        }
481    }
482    /// arena 节点总数(诊断/深度测量用)。
483    pub fn node_count(&self) -> usize {
484        self.nodes.len()
485    }
486
487    pub fn children(&self, id: JavaId) -> &[JavaId] {
488        self.nodes[id.0 as usize].children.as_slice()
489    }
490
491    // ---- builder:语句 ----
492
493    pub fn block(&mut self, stmts: Vec<JavaId>) -> JavaId {
494        self.push(NodeData::Block, stmts)
495    }
496    pub fn empty(&mut self) -> JavaId {
497        self.push(NodeData::Empty, vec![])
498    }
499    pub fn expr_stmt(&mut self, e: JavaId) -> JavaId {
500        self.push(NodeData::ExprStmt, vec![e])
501    }
502    pub fn var_decl(&mut self, name: &str, ty: JType, init: Option<JavaId>) -> JavaId {
503        self.var_decl_final(name, ty, init, false)
504    }
505    /// final 局部声明(JLS 4.12.4:case 标签常量的必要条件——
506    /// final 局部删除曾致 `case ARRAY_BOUND:` 失去常量性不可编译,
507    /// LargeFile.java 抓获)。
508    pub fn var_decl_final(
509        &mut self,
510        name: &str,
511        ty: JType,
512        init: Option<JavaId>,
513        final_mod: bool,
514    ) -> JavaId {
515        self.push(
516            NodeData::VarDecl {
517                name: name.into(),
518                ty,
519                final_mod,
520            },
521            init.into_iter().collect(),
522        )
523    }
524    pub fn assign(&mut self, target: JavaId, value: JavaId) -> JavaId {
525        self.push(NodeData::Assign { op: None }, vec![target, value])
526    }
527    pub fn assign_op(&mut self, op: BinOp, target: JavaId, value: JavaId) -> JavaId {
528        self.push(NodeData::Assign { op: Some(op) }, vec![target, value])
529    }
530    pub fn if_(&mut self, cond: JavaId, then: JavaId, els: Option<JavaId>) -> JavaId {
531        let mut ch = vec![cond, then];
532        ch.extend(els);
533        self.push(NodeData::If, ch)
534    }
535    pub fn while_(&mut self, cond: JavaId, body: JavaId) -> JavaId {
536        self.push(NodeData::While, vec![cond, body])
537    }
538    pub fn do_while(&mut self, body: JavaId, cond: JavaId) -> JavaId {
539        self.push(NodeData::DoWhile, vec![body, cond])
540    }
541    pub fn for_(
542        &mut self,
543        inits: Vec<JavaId>,
544        cond: Option<JavaId>,
545        steps: Vec<JavaId>,
546        body: JavaId,
547    ) -> JavaId {
548        let ni = inits.len();
549        let ns = steps.len();
550        let mut ch = inits;
551        let has_cond = cond.is_some();
552        ch.extend(cond);
553        ch.extend(steps);
554        ch.push(body);
555        self.push(
556            NodeData::For {
557                inits: ni as u8,
558                has_cond,
559                steps: ns as u8,
560            },
561            ch,
562        )
563    }
564    pub fn for_each(&mut self, name: &str, ty: JType, iterable: JavaId, body: JavaId) -> JavaId {
565        self.push(
566            NodeData::ForEach {
567                name: name.into(),
568                ty,
569            },
570            vec![iterable, body],
571        )
572    }
573    pub fn yield_(&mut self, expr: JavaId) -> JavaId {
574        self.push(NodeData::Yield, vec![expr])
575    }
576    pub fn ret(&mut self, value: Option<JavaId>) -> JavaId {
577        self.push(NodeData::Return, value.into_iter().collect())
578    }
579    pub fn break_(&mut self, label: Option<&str>) -> JavaId {
580        self.push(
581            NodeData::Break {
582                label: label.map(Into::into),
583            },
584            vec![],
585        )
586    }
587    pub fn continue_(&mut self, label: Option<&str>) -> JavaId {
588        self.push(
589            NodeData::Continue {
590                label: label.map(Into::into),
591            },
592            vec![],
593        )
594    }
595    pub fn throw(&mut self, e: JavaId) -> JavaId {
596        self.push(NodeData::Throw, vec![e])
597    }
598    pub fn try_(
599        &mut self,
600        resources: Vec<JavaId>,
601        try_block: JavaId,
602        catches: Vec<JavaId>,
603        finally: Option<JavaId>,
604    ) -> JavaId {
605        let mut ch = resources;
606        ch.push(try_block);
607        ch.extend(catches);
608        ch.extend(finally);
609        self.push(NodeData::Try, ch)
610    }
611    pub fn catch_(&mut self, ty_raw: &str, name: &str, block: JavaId) -> JavaId {
612        self.push(
613            NodeData::Catch {
614                ty_raw: ty_raw.into(),
615                name: name.into(),
616            },
617            vec![block],
618        )
619    }
620    pub fn synchronized(&mut self, lock: JavaId, block: JavaId) -> JavaId {
621        self.push(NodeData::Synchronized, vec![lock, block])
622    }
623    pub fn switch_(&mut self, subject: JavaId, cases: Vec<JavaId>) -> JavaId {
624        let mut ch = vec![subject];
625        ch.extend(cases);
626        self.push(NodeData::Switch, ch)
627    }
628    pub fn case_(
629        &mut self,
630        labels: Vec<JavaId>,
631        is_default: bool,
632        arrow: bool,
633        stmts: Vec<JavaId>,
634    ) -> JavaId {
635        let n = labels.len() as u16;
636        let mut ch = labels;
637        ch.extend(stmts);
638        self.push(
639            NodeData::Case {
640                labels: n,
641                is_default,
642                arrow,
643            },
644            ch,
645        )
646    }
647    pub fn label(&mut self, name: &str, stmt: JavaId) -> JavaId {
648        self.push(NodeData::Label { name: name.into() }, vec![stmt])
649    }
650    pub fn assert_(&mut self, cond: JavaId, msg: Option<JavaId>) -> JavaId {
651        let mut ch = vec![cond];
652        ch.extend(msg);
653        self.push(NodeData::Assert, ch)
654    }
655    pub fn raw(&mut self, text: &str) -> JavaId {
656        self.push(NodeData::Raw { text: text.into() }, vec![])
657    }
658
659    // ---- builder:表达式 ----
660
661    pub fn bin(&mut self, op: BinOp, l: JavaId, r: JavaId) -> JavaId {
662        self.push(NodeData::Binary { op }, vec![l, r])
663    }
664    pub fn un(&mut self, op: UnOp, e: JavaId) -> JavaId {
665        self.push(NodeData::Unary { op }, vec![e])
666    }
667    pub fn call(&mut self, callee: JavaId, args: Vec<JavaId>) -> JavaId {
668        let mut ch = vec![callee];
669        ch.extend(args);
670        self.push(NodeData::Call, ch)
671    }
672    pub fn member(&mut self, obj: JavaId, name: &str) -> JavaId {
673        let sym = self.intern_sym(name);
674        self.push(NodeData::Member { name: sym }, vec![obj])
675    }
676    pub fn index(&mut self, arr: JavaId, idx: JavaId) -> JavaId {
677        self.push(NodeData::Index, vec![arr, idx])
678    }
679    pub fn cast(&mut self, ty: JType, e: JavaId) -> JavaId {
680        self.push(NodeData::Cast { ty }, vec![e])
681    }
682    pub fn paren(&mut self, e: JavaId) -> JavaId {
683        self.push(NodeData::Paren, vec![e])
684    }
685    pub fn ternary(&mut self, c: JavaId, a: JavaId, b: JavaId) -> JavaId {
686        self.push(NodeData::Ternary, vec![c, a, b])
687    }
688    pub fn new_(&mut self, ty: JType, args: Vec<JavaId>) -> JavaId {
689        self.push(NodeData::New { ty, anon_raw: None }, args)
690    }
691    pub fn new_anon(&mut self, ty: JType, args: Vec<JavaId>, body_raw: String) -> JavaId {
692        self.push(
693            NodeData::New {
694                ty,
695                anon_raw: Some(body_raw),
696            },
697            args,
698        )
699    }
700    pub fn new_array(
701        &mut self,
702        ty: JType,
703        dims: u16,
704        sized: u16,
705        sizes: Vec<JavaId>,
706        init: Option<JavaId>,
707    ) -> JavaId {
708        let mut ch = sizes;
709        ch.extend(init);
710        self.push(NodeData::NewArray { ty, dims, sized }, ch)
711    }
712    /// 合成分组(无作用域)。
713    pub fn group(&mut self, stmts: Vec<JavaId>) -> JavaId {
714        self.push(NodeData::Group, stmts)
715    }
716    pub fn array_lit(&mut self, elems: Vec<JavaId>) -> JavaId {
717        self.push(NodeData::ArrayLit, elems)
718    }
719    pub fn var(&mut self, name: &str) -> JavaId {
720        let sym = self.intern_sym(name);
721        self.push(NodeData::VarRef { name: sym }, vec![])
722    }
723    pub fn lit(&mut self, l: Lit) -> JavaId {
724        self.push(NodeData::Literal(l), vec![])
725    }
726    fn build_int_impl(&mut self, v: i64, long: bool) -> JavaId {
727        if long {
728            self.lit(Lit::Long(v))
729        } else {
730            self.lit(Lit::Int(v))
731        }
732    }
733    pub fn this(&mut self) -> JavaId {
734        self.push(NodeData::This, vec![])
735    }
736    pub fn super_(&mut self) -> JavaId {
737        self.push(NodeData::Super, vec![])
738    }
739    pub fn instance_of(&mut self, e: JavaId, ty: JType, bind: Option<&str>) -> JavaId {
740        self.push(
741            NodeData::InstanceOf {
742                ty,
743                bind: bind.map(Into::into),
744            },
745            vec![e],
746        )
747    }
748    pub fn lambda(&mut self, params_raw: &str, body: JavaId) -> JavaId {
749        self.push(
750            NodeData::Lambda {
751                params_raw: params_raw.into(),
752            },
753            vec![body],
754        )
755    }
756    pub fn method_ref(&mut self, receiver: JavaId, name: &str) -> JavaId {
757        let sym = self.intern_sym(name);
758        self.push(NodeData::MethodRef { name: sym }, vec![receiver])
759    }
760
761    // ---- 便捷 ----
762
763    /// `obj.name(args…)` 调用。
764    pub fn method_call(&mut self, obj: JavaId, name: &str, args: Vec<JavaId>) -> JavaId {
765        let m = self.member(obj, name);
766        self.call(m, args)
767    }
768    /// 裸方法调用 `name(args…)`(隐式 this / static)。
769    pub fn plain_call(&mut self, name: &str, args: Vec<JavaId>) -> JavaId {
770        let f = self.var(name);
771        self.call(f, args)
772    }
773
774    /// 作用域解析后的 VarRef 类型(prepare 之后有效)。
775    pub fn var_type(&self, id: JavaId) -> Option<&JType> {
776        self.var_types.get(id.0 as usize).and_then(|t| t.as_ref())
777    }
778
779    /// root 子树内是否存在「两侧都可能为 String」的 ==/!=(引用比较)?
780    /// 折叠守卫用:new String(lit)/常量链等产出池化字面量会改变 == 语义。
781    /// 结果按 (root, prepare 代次) 缓存——prepare 每次改树后清空,
782    /// 首次查询全扫一次,同轮内所有守卫调用复用。
783    /// 多根扫描:任一根存在 String 身份比较。
784    pub fn any_string_identity(&self, roots: &[JavaId]) -> bool {
785        roots.iter().any(|&r| {
786            let hit = Self::scan_string_identity(self, r);
787            if hit {
788                self.string_identity.set(Some((r, true)));
789            }
790            hit
791        })
792    }
793
794    pub fn has_string_identity_compare(&self, root: JavaId) -> bool {
795        if let Some((r, v)) = self.string_identity.get() {
796            if r == root {
797                return v;
798            }
799        }
800        let v = Self::scan_string_identity(self, root);
801        self.string_identity.set(Some((root, v)));
802        v
803    }
804
805    fn scan_string_identity(&self, root: JavaId) -> bool {
806        let mut stack = vec![root];
807        while let Some(id) = stack.pop() {
808            if let NodeData::Binary { op: BinOp::Eq | BinOp::Ne } = self.data(id) {
809                let ch = self.children(id);
810                if ch.len() == 2
811                    && self.expr_maybe_string(ch[0])
812                    && self.expr_maybe_string(ch[1])
813                {
814                    return true;
815                }
816            }
817            for &c in self.children(id) {
818                stack.push(c);
819            }
820        }
821        false
822    }
823
824    /// `==`/`!=` 的这个操作数可能持有 String 引用吗?(保守近似)
825    fn expr_maybe_string(&self, id: JavaId) -> bool {
826        match self.data(id) {
827            NodeData::Literal(Lit::Str(_)) => true,
828            // null/this/数组/instanceof/数值布尔字面量:折叠不可能改变其 == 结果
829            NodeData::Literal(_) | NodeData::This | NodeData::Super
830            | NodeData::NewArray { .. } | NodeData::ArrayLit | NodeData::InstanceOf { .. } => false,
831            NodeData::VarRef { .. } => self.var_type(id).map_or(true, Self::type_maybe_string),
832            NodeData::Cast { ty } => Self::type_maybe_string(ty),
833            NodeData::Paren => self
834                .children(id)
835                .first()
836                .map_or(true, |&c| self.expr_maybe_string(c)),
837            // 拼接:任一操作数 String ⇒ 结果 String;其余二元运算结果必为原始类型
838            NodeData::Binary { op } if *op == BinOp::Add => {
839                self.children(id).iter().any(|&c| self.expr_maybe_string(c))
840            }
841            NodeData::Binary { .. } => false,
842            NodeData::Ternary => self
843                .children(id)
844                .get(1..)
845                .map_or(true, |cs| cs.iter().any(|&c| self.expr_maybe_string(c))),
846            // Call/Member/Index/MethodRef/Raw/Unary/Lambda…:类型未知或引用 → 保守视为可能
847            _ => true,
848        }
849    }
850
851    /// 类型可能持有 String 引用吗?
852    fn type_maybe_string(t: &JType) -> bool {
853        match t {
854            JType::Bool | JType::Byte | JType::Short | JType::Int | JType::Long
855            | JType::Char | JType::Float | JType::Double | JType::Void
856            | JType::Array(_) => false, // 数组引用不是 String 本体(元素访问走 Index 节点)
857            JType::Var => true,         // var / 推断 / 未知
858            JType::Ref(n) => {
859                let base = n.split('<').next().unwrap_or(n).trim();
860                let last = base.rsplit('.').next().unwrap_or(base);
861                matches!(
862                    last,
863                    "String" | "Object" | "CharSequence" | "Comparable" | "Serializable"
864                ) || n.contains('<') // 泛型容器:剥壳后无法判定 → 保守
865                // 单字母大写:类型参数 T/E/R(无界,运行期可为 String)
866                || (last.len() <= 2 && last.chars().next().is_some_and(|c| c.is_uppercase()))
867            }
868        }
869    }
870
871
872    /// 设置当前方法的参数类型表(作为根作用域参与解析)。
873    pub fn set_param_scope(&mut self, params: &[(String, JType)]) {
874        self.param_scope = params.to_vec();
875    }
876
877    /// 名字是否为当前方法参数(虚拟执行的字段写守卫——参数写不得
878    /// 误记为字段写)。
879    pub fn is_param_name(&self, name: &str) -> bool {
880        self.param_scope.iter().any(|(n, _)| n == name)
881    }
882
883    /// 名字键 → 名字反查(虚拟执行的字段写材料化)。
884    pub fn name_of_key(&self, k: u32) -> Option<String> {
885        Some(self.names.name(k).to_string())
886    }
887    pub fn clear_param_scope(&mut self) {
888        self.param_scope.clear();
889    }
890}
891
892// ---------------------------------------------------------------------------
893// Lang 实现
894// ---------------------------------------------------------------------------
895
896/// 类型名的基名(剥泛型实参 + 取最后点分段):`List<String>` → `List`、
897/// `java.util.Map<K,V>` → `Map`。接收位类型绑定守卫用(同名构造视为
898/// 静态类型一致;注解/显式类型实参前缀的罕见形态不匹配 → 保守拒绝)。
899fn type_base_name(n: &str) -> &str {
900    let no_args = match n.find('<') {
901        Some(i) => &n[..i],
902        None => n,
903    };
904    no_args.rsplit('.').next().unwrap_or(no_args)
905}
906
907// ---------------------------------------------------------------------------
908// JLS 整数折叠辅助(从 cure-engine 迁入——数值语义归属语言侧)
909// ---------------------------------------------------------------------------
910
911/// i64 算术(long 语义):除/余除数为 0 不折(ArithmeticException)。
912/// 移位量按 JLS 掩码(long: & 63)。
913fn fold_i64(op: BinOp, a: i64, b: i64) -> Option<i64> {
914    use BinOp::*;
915    Some(match op {
916        Add => a.wrapping_add(b),
917        Sub => a.wrapping_sub(b),
918        Mul => a.wrapping_mul(b),
919        Div => {
920            if b == 0 {
921                return None;
922            }
923            a.wrapping_div(b)
924        }
925        Rem => {
926            if b == 0 {
927                return None;
928            }
929            a.wrapping_rem(b)
930        }
931        Shl => a.wrapping_shl((b as u64 & 63) as u32),
932        Shr => a.wrapping_shr((b as u64 & 63) as u32),
933        UShr => ((a as u64).wrapping_shr((b as u64 & 63) as u32)) as i64,
934        BitAnd => a & b,
935        BitXor => a ^ b,
936        BitOr => a | b,
937        _ => return None,
938    })
939}
940
941/// i32 算术(int 语义):操作数按 i32 回绕;移位量按 JLS 掩码(& 31)。
942fn fold_i32(op: BinOp, a: i64, b: i64) -> Option<i64> {
943    use BinOp::*;
944    let (x, y) = (a as i32, b as i32);
945    Some(match op {
946        Add => x.wrapping_add(y) as i64,
947        Sub => x.wrapping_sub(y) as i64,
948        Mul => x.wrapping_mul(y) as i64,
949        Div => {
950            if y == 0 {
951                return None;
952            }
953            x.wrapping_div(y) as i64
954        }
955        Rem => {
956            if y == 0 {
957                return None;
958            }
959            x.wrapping_rem(y) as i64
960        }
961        Shl => x.wrapping_shl((y as u32) & 31) as i64,
962        Shr => x.wrapping_shr((y as u32) & 31) as i64,
963        UShr => (x as u32).wrapping_shr((y as u32) & 31) as i64,
964        BitAnd => (x & y) as i64,
965        BitXor => (x ^ y) as i64,
966        BitOr => (x | y) as i64,
967        _ => return None,
968    })
969}
970
971/// 数值比较折叠(整数/字符提升为 int 后比较)。
972fn cmp_i64(op: BinOp, x: i64, y: i64) -> Option<bool> {
973    use BinOp::*;
974    Some(match op {
975        Lt => x < y,
976        Le => x <= y,
977        Gt => x > y,
978        Ge => x >= y,
979        Eq => x == y,
980        Ne => x != y,
981        _ => return None,
982    })
983}
984
985impl Lang for JavaAst {
986    type Id = JavaId;
987    type NameKey = u32;
988
989    fn kind(&self, id: JavaId) -> NodeKind {
990        JavaAst::kind(self, id)
991    }
992
993    fn children(&self, id: JavaId) -> &[JavaId] {
994        JavaAst::children(self, id)
995    }
996
997    fn set_child(&mut self, parent: JavaId, index: usize, new: JavaId) {
998        self.nodes[parent.0 as usize].children.set(index, new);
999    }
1000    fn remove_child(&mut self, parent: JavaId, index: usize) {
1001        self.nodes[parent.0 as usize].children.remove(index);
1002    }
1003    fn splice(&mut self, node: JavaId, index: usize, remove: usize, insert: Vec<JavaId>) {
1004        self.nodes[node.0 as usize].children.splice(index, remove, insert);
1005    }
1006
1007    fn build_return(&mut self, value: Option<JavaId>) -> JavaId {
1008        self.ret(value)
1009    }
1010    fn build_block(&mut self, stmts: Vec<JavaId>) -> JavaId {
1011        self.block(stmts)
1012    }
1013    fn build_unary(&mut self, op: UnOp, operand: JavaId) -> JavaId {
1014        self.un(op, operand)
1015    }
1016    fn build_bool(&mut self, v: bool) -> JavaId {
1017        self.lit(Lit::Bool(v))
1018    }
1019    fn build_int(&mut self, v: i64, long: bool) -> JavaId {
1020        self.build_int_impl(v, long)
1021    }
1022    fn build_str(&mut self, s: &str) -> JavaId {
1023        self.lit(Lit::Str(s.to_string()))
1024    }
1025    fn build_char(&mut self, c: char) -> JavaId {
1026        self.lit(Lit::Char(c))
1027    }
1028    fn build_bin(&mut self, op: BinOp, l: JavaId, r: JavaId) -> JavaId {
1029        self.bin(op, l, r)
1030    }
1031    fn build_ternary(&mut self, c: JavaId, a: JavaId, b: JavaId) -> JavaId {
1032        self.ternary(c, a, b)
1033    }
1034    fn build_assign(&mut self, target: JavaId, value: JavaId) -> JavaId {
1035        self.assign(target, value)
1036    }
1037
1038    // ---- 字面量折叠语义(JLS;引擎侧只做形态匹配)----
1039
1040    fn fold_lit_bin(&mut self, op: BinOp, l: JavaId, r: JavaId) -> Option<JavaId> {
1041        let ll = self.literal(l)?;
1042        let rr = self.literal(r)?;
1043        // 字符串拼接(Str 与 Str/Char/Int/Long/Bool 字面量——拼接的隐式
1044        // valueOf 对这些基元是确定性的;浮点除外:Double.toString 算法与
1045        // Rust Display 不保证逐位一致)
1046        if op == BinOp::Add {
1047            let str_of = |x: LitRef<'_>| -> Option<String> {
1048                match x {
1049                    LitRef::Str(s) => Some(s.to_string()),
1050                    LitRef::Char(c) => Some(c.to_string()),
1051                    LitRef::Int(v) => Some(v.to_string()),
1052                    LitRef::Long(v) => Some(v.to_string()),
1053                    LitRef::Bool(b) => Some(b.to_string()),
1054                    _ => None,
1055                }
1056            };
1057            if matches!(ll, LitRef::Str(_)) || matches!(rr, LitRef::Str(_)) {
1058                if let (Some(a), Some(b)) = (str_of(ll), str_of(rr)) {
1059                    return Some(self.build_str(&format!("{a}{b}")));
1060                }
1061            }
1062        }
1063        // 整数折叠(JLS 环绕):1+2→3、2*3→6、1<<3→8、& | ^ 等。
1064        // 除/余除数为 0 不折叠(ArithmeticException 语义)。
1065        let int_of = |x: LitRef<'_>| -> Option<i64> {
1066            match x {
1067                // Java 中 char 参与算术时提升为 int
1068                LitRef::Int(v) | LitRef::Long(v) => Some(v),
1069                LitRef::Char(c) => Some(c as u32 as i64),
1070                _ => None,
1071            }
1072        };
1073        let (a, b) = (int_of(ll)?, int_of(rr)?);
1074        let wide = matches!(ll, LitRef::Long(_)) || matches!(rr, LitRef::Long(_));
1075        let v = if wide { fold_i64(op, a, b) } else { fold_i32(op, a, b) }?;
1076        Some(self.build_int(v, wide))
1077    }
1078
1079    fn fold_lit_cmp(&mut self, op: BinOp, l: JavaId, r: JavaId) -> Option<bool> {
1080        let ll = self.literal(l)?;
1081        let rr = self.literal(r)?;
1082        // 整数/字符按数值比较(char 与 int 比较同样提升为 int)
1083        let int_of = |x: LitRef<'_>| -> Option<i64> {
1084            match x {
1085                LitRef::Int(v) | LitRef::Long(v) => Some(v),
1086                LitRef::Char(c) => Some(c as u32 as i64),
1087                _ => None,
1088            }
1089        };
1090        if let (Some(x), Some(y)) = (int_of(ll), int_of(rr)) {
1091            return cmp_i64(op, x, y);
1092        }
1093        // 布尔相等(装箱引用 == 语义上不可折,但布尔字面量场景下
1094        // true/false 是规范实例,值比较与引用比较一致)
1095        if let (LitRef::Bool(x), LitRef::Bool(y)) = (ll, rr) {
1096            if matches!(op, BinOp::Eq | BinOp::Ne) {
1097                return Some(if op == BinOp::Eq { x == y } else { x != y });
1098            }
1099        }
1100        // 字符串(引用比较)与浮点(NaN)不折
1101        None
1102    }
1103
1104    fn fold_lit_neg(&mut self, v: i64, wide: bool) -> Option<i64> {
1105        // `-(-2147483648)`:i32 域内无 +2147483648,拒绝折叠
1106        let n = -v;
1107        if !wide && n > i32::MAX as i64 {
1108            return None;
1109        }
1110        Some(n)
1111    }
1112
1113    fn reassoc_delta(
1114        &mut self,
1115        op1: BinOp,
1116        k1: i64,
1117        op2: BinOp,
1118        k2: i64,
1119        wide: bool,
1120    ) -> Option<ReassocOutcome<JavaId>> {
1121        use BinOp::*;
1122        let raw: i64 = match (op1, op2) {
1123            (BitXor, BitXor) => k1 ^ k2,
1124            (a, b) if matches!(a, Add | Sub) && matches!(b, Add | Sub) => {
1125                let sign = |o: BinOp| if o == Sub { -1i64 } else { 1i64 };
1126                sign(a) * k1 + sign(b) * k2
1127            }
1128            _ => return None,
1129        };
1130        // JLS 宽度回绕:i32 合并结果溢出必须回绕——不回绕会产出
1131        // 非法字面量(`x + 2147483648` 无法作为 int 编译)
1132        let d = if wide { raw } else { raw as i32 as i64 };
1133        if d == 0 {
1134            return Some(ReassocOutcome::Neutral);
1135        }
1136        if op1 == BitXor && op2 == BitXor {
1137            return Some(ReassocOutcome::Lit(self.build_int(d, wide), BitXor));
1138        }
1139        if d > 0 {
1140            Some(ReassocOutcome::Lit(self.build_int(d, wide), Add))
1141        } else {
1142            // 负 delta 用 `x - |d|`;|d| 回绕后仍为负(仅 ±2^31 边界)
1143            // 或宽整数 -2^63 取反溢出时,退回 `x + d`(负字面量)——
1144            // 二者模 2^宽度 同余,语法均合法
1145            let nd = if wide { d.checked_neg().unwrap_or(d) } else { (d as i32).wrapping_neg() as i64 };
1146            if nd > 0 {
1147                Some(ReassocOutcome::Lit(self.build_int(nd, wide), Sub))
1148            } else {
1149                Some(ReassocOutcome::Lit(self.build_int(d, wide), Add))
1150            }
1151        }
1152    }
1153
1154    fn copy_subtree(&mut self, id: JavaId) -> JavaId {
1155        let old_children: Vec<JavaId> = self.nodes[id.0 as usize].children.as_slice().to_vec();
1156        let mut children = Vec::with_capacity(old_children.len());
1157        for c in old_children {
1158            children.push(self.copy_subtree(c));
1159        }
1160        let data = self.nodes[id.0 as usize].data.clone();
1161        self.push(data, children)
1162    }
1163
1164    fn effect(&self, id: JavaId) -> Effect {
1165        if let Some(e) = self.effect_cache.get(id.0 as usize).and_then(|x| *x) {
1166            return e;
1167        }
1168        // 缓存未命中(结构不变量被破坏时)退化为按需递归
1169        let mut e = self.own_effect(id);
1170        for &c in self.nodes[id.0 as usize].children.as_slice() {
1171            e = e.worst(self.effect(c));
1172        }
1173        e
1174    }
1175
1176    fn invalidate_effect(&mut self, id: JavaId) {
1177        if let Some(slot) = self.effect_cache.get_mut(id.0 as usize) {
1178            *slot = None;
1179        }
1180        // 事件索引同步失效:本节点子树若被改,其预计算事件已陈旧
1181        // (B3 脏标记 + 清空该槽——见 cure-tree EventStore)
1182        self.events.invalidate(id.0 as usize);
1183    }
1184
1185    fn debug_verify_events(&self, stmt: JavaId) {
1186        if !verify_events_on() {
1187            return;
1188        }
1189        if let Some(indexed) = self.region_events(stmt) {
1190            let fresh = cure_tree::collect_region_events(self, stmt);
1191            // 比较(键+种类+节点)三元组序列
1192            let key = |e: &cure_engine::kind::RegionEvent<JavaId, u32>| {
1193                (e.key, matches!(e.kind, cure_engine::kind::EventKind::Use), e.node.0)
1194            };
1195            let a: Vec<_> = indexed.iter().map(key).collect();
1196            let b: Vec<_> = fresh.iter().map(key).collect();
1197            if a != b {
1198                eprintln!(
1199                    "[EVENTS-STALE] stmt #{} kind={:?}: indexed {} events, fresh {} events",
1200                    stmt.0, self.kind(stmt), a.len(), b.len()
1201                );
1202            }
1203        }
1204    }
1205
1206    fn region_events(
1207        &self,
1208        id: JavaId,
1209    ) -> Option<&[cure_engine::kind::RegionEvent<JavaId, u32>]> {
1210        // 空序列 = 未索引(非语句节点或已失效)→ None 走原递归
1211        let v = self.events.slot(id.0 as usize);
1212        if v.is_empty() {
1213            None
1214        } else {
1215            Some(v)
1216        }
1217    }
1218
1219    fn var_key(&self, id: JavaId) -> Option<u32> {
1220        self.names.var_key(id.0 as usize)
1221    }
1222
1223    fn node_index(&self, id: JavaId) -> usize {
1224        id.0 as usize
1225    }
1226    fn id_of_index(&self, idx: usize) -> JavaId {
1227        JavaId(idx as u32)
1228    }
1229
1230    fn is_opaque(&self, id: JavaId) -> bool {
1231        match self.data(id) {
1232            // 不可解析原文
1233            NodeData::Raw { .. } => true,
1234            // 匿名类体是原文(捕获的外部局部变量不可见)——
1235            // 对抗波 4:仅被匿名类捕获的变量曾被零用途规则误删
1236            NodeData::New { anon_raw: Some(_), .. } => true,
1237            _ => false,
1238        }
1239    }
1240
1241    fn own_effect(&self, id: JavaId) -> Effect {
1242        match self.data(id) {
1243            NodeData::Literal(_)
1244            | NodeData::This
1245            | NodeData::Super
1246            | NodeData::Paren
1247            | NodeData::Block
1248            | NodeData::Group
1249            | NodeData::Empty
1250            | NodeData::VarDecl { .. }
1251            | NodeData::Break { .. }
1252            | NodeData::Continue { .. }
1253            | NodeData::Try
1254            | NodeData::Catch { .. }
1255            | NodeData::Switch
1256            | NodeData::Case { .. }
1257            | NodeData::Label { .. }
1258            | NodeData::ExprStmt
1259            | NodeData::Ternary
1260            | NodeData::ArrayLit
1261            | NodeData::Lambda { .. }
1262            | NodeData::MethodRef { .. }
1263            | NodeData::InstanceOf { .. } => Effect::Pure,
1264            NodeData::VarRef { .. } => Effect::MayRead,
1265            NodeData::Member { .. } => Effect::MayThrow,
1266            NodeData::Index => Effect::MayThrow,
1267            NodeData::New { .. } | NodeData::NewArray { .. } => Effect::MayThrow,
1268            NodeData::Call => Effect::Unknown,
1269            NodeData::Assign { .. } => Effect::MayWrite,
1270            NodeData::Unary { op } => {
1271                if op.is_incdec() {
1272                    Effect::MayWrite
1273                } else {
1274                    Effect::Pure
1275                }
1276            }
1277            NodeData::Binary { op } => {
1278                if op.may_div_zero() {
1279                    Effect::MayThrow
1280                } else {
1281                    Effect::Pure
1282                }
1283            }
1284            NodeData::Cast { ty } => {
1285                if ty.is_ref() {
1286                    // 引用转型可能抛 ClassCastException
1287                    Effect::MayThrow
1288                } else {
1289                    Effect::Pure
1290                }
1291            }
1292            NodeData::For { .. } | NodeData::ForEach { .. } | NodeData::If => Effect::MayRead,
1293            NodeData::While | NodeData::DoWhile => Effect::MayRead,
1294            NodeData::Return | NodeData::Yield => Effect::MayThrow,
1295            NodeData::Throw => Effect::MayThrow,
1296            NodeData::Assert => Effect::MayThrow,
1297            NodeData::Synchronized => Effect::MayWrite,
1298            NodeData::Raw { .. } => Effect::Unknown,
1299        }
1300    }
1301
1302    fn is_bool(&self, id: JavaId) -> bool {
1303        match self.data(id) {
1304            NodeData::Literal(l) => matches!(l, Lit::Bool(_)),
1305            NodeData::Unary { op } => *op == UnOp::Not,
1306            NodeData::Binary { op } => {
1307                op.is_comparison() || matches!(op, BinOp::And | BinOp::Or)
1308            }
1309            NodeData::Ternary => {
1310                let ch = self.children(id);
1311                self.is_bool(ch[1]) && self.is_bool(ch[2])
1312            }
1313            NodeData::Paren => self.is_bool(self.children(id)[0]),
1314            NodeData::InstanceOf { .. } => true,
1315            NodeData::VarRef { .. } => self
1316                .var_types
1317                .get(id.0 as usize)
1318                .and_then(|t| t.as_ref())
1319                .is_some_and(|t| t.is_bool()),
1320            _ => false,
1321        }
1322    }
1323
1324    fn is_exact_int(&self, id: JavaId) -> bool {
1325        match self.data(id) {
1326            NodeData::Literal(l) => matches!(
1327                l,
1328                Lit::Int(_) | Lit::Long(_) | Lit::Char(_) | Lit::NumRaw { val: NumVal::Int(_) | NumVal::Long(_), .. }
1329            ),
1330            NodeData::VarRef { .. } => {
1331                self.var_types.get(id.0 as usize).and_then(|t| t.as_ref()).is_some_and(|t| t.is_integral())
1332            }
1333            NodeData::Binary { op } => {
1334                let ch = self.children(id);
1335                (op.is_arith() || op.is_comparison())
1336                    && self.is_exact_int(ch[0])
1337                    && self.is_exact_int(ch[1])
1338            }
1339            NodeData::Cast { ty } => ty.is_integral(),
1340            NodeData::Paren => self.is_exact_int(self.children(id)[0]),
1341            NodeData::Ternary => {
1342                let ch = self.children(id);
1343                self.is_exact_int(ch[1]) && self.is_exact_int(ch[2])
1344            }
1345            _ => false,
1346        }
1347    }
1348
1349    fn is_local_var(&self, id: JavaId) -> bool {
1350        // VarRef 必须解析到局部变量/参数(var_types 作用域解析)才可
1351        // 被传播/删除规则触碰——字段引用(this.x / 静态字段裸名)有
1352        // 跨方法可见性。未解析(Raw 区域/坏代码)同样返回 false(保守)。
1353        // 差分审查抓获:dead_store 曾据此把 `first = cl;`(静态字段写)
1354        // 当局部死存储消除,双向链表表头更新静默丢失。
1355        matches!(self.data(id), NodeData::VarRef { .. }) && self.var_type(id).is_some()
1356    }
1357
1358    fn is_inferred_decl(&self, decl: JavaId) -> bool {
1359        matches!(self.data(decl), NodeData::VarDecl { ty: JType::Var, .. })
1360    }
1361
1362    fn is_char_decl(&self, decl: JavaId) -> bool {
1363        matches!(self.data(decl), NodeData::VarDecl { ty: JType::Char, .. })
1364    }
1365
1366    fn has_pattern_bindings(&self, root: JavaId) -> bool {
1367        let mut stack = vec![root];
1368        while let Some(n) = stack.pop() {
1369            if let NodeData::InstanceOf { bind: Some(_), .. } = self.data(n) {
1370                return true;
1371            }
1372            for &c in self.children(n) {
1373                stack.push(c);
1374            }
1375        }
1376        false
1377    }
1378
1379    fn is_long_decl(&self, decl: JavaId) -> bool {
1380        matches!(self.data(decl), NodeData::VarDecl { ty: JType::Long, .. })
1381    }
1382    fn is_wide_decl(&self, decl: JavaId) -> bool {
1383        // 窄类型(byte/short/char)复合赋值含隐式收窄:delta 折回声明
1384        // 会产出超域非法常量或丢静态类型(char 99 → println 打数字)
1385        !matches!(
1386            self.data(decl),
1387            NodeData::VarDecl { ty: JType::Byte | JType::Short | JType::Char, .. }
1388        )
1389    }
1390
1391    fn receiver_propagation_unsound(
1392        &self,
1393        decl: JavaId,
1394        value: JavaId,
1395        use_parent: Option<JavaId>,
1396        use_at_head: bool,
1397    ) -> bool {
1398        // 使用位必须是成员访问接收者(Member 的 child 0)——实参位
1399        // raw↔泛型双向兼容(unchecked),不敏感
1400        let is_receiver = matches!(use_parent, Some(p) if {
1401            matches!(self.data(p), NodeData::Member { .. }) && use_at_head
1402        });
1403        if is_receiver {
1404            // 装箱丢失(R13 P0-2):引用声明 + 基本类型值——接收位无装箱转换
1405            if self.receiver_boxing_unsound(decl, value) {
1406                return true;
1407            }
1408            // New 值接收位类型绑定守卫(R15 终审 P0-4/P0-5 抓获):
1409            // (a) diamond(`new ArrayList<>()`)——类型推断依赖赋值目标,
1410            //     脱离赋值位内联进接收位退化为无目标推断
1411            //     (MethodRefToInner 抓获:`List<String> l = new ArrayList<>();
1412            //     l.stream().forEach(TestString::new)` → Stream<Object>,
1413            //     构造器引用 Object 无法转 String);
1414            // (b) 构造类型基名 ≠ 声明类型基名——接收者静态类型改变,方法
1415            //     绑定与 throws 子句随之改变(CloneableProblem 抓获:
1416            //     `A a0 = new CloneableProblem(0); a0.clone()` 内联后
1417            //     A.clone() 的 CloneNotSupportedException 不再可抛,catch 失据)。
1418            if self.receiver_new_type_unsound(decl, value) {
1419                return true;
1420            }
1421            // 声明类型为 **已知泛型的 raw 引用**(无类型实参——擦除成员解析):
1422            // var 推断/显式带实参/非泛型/未知外部类型不触发(保守——未知名
1423            // 保持传播,与修复前行为一致)
1424            let raw_ref = match self.data(decl) {
1425                NodeData::VarDecl { ty: JType::Ref(n), .. } => {
1426                    !n.contains('<')
1427                        && n.rsplit('.').next().is_some_and(|base| {
1428                            self.raw_generic_names.contains(base)
1429                        })
1430                }
1431                _ => false,
1432            };
1433            if !raw_ref {
1434                return false;
1435            }
1436            // init 静态类型可能**带泛型**:调用(返回类型未知)或带实参 new
1437            match self.data(value) {
1438                NodeData::Call => true,
1439                NodeData::New { ty, .. } => {
1440                    matches!(ty, JType::Ref(n) if n.contains('<'))
1441                }
1442                _ => false,
1443            }
1444        } else {
1445            // 数组访问基座(Index 的 child 0):new 数组值的元素类型绑定
1446            // 守卫(R15 终审 P0-2 续,T8357653b 抓获)——声明元素带泛型
1447            // 实参(`B<?>[] b2 = new B[1]`)时内联进 `b2[0]` 基座使元素
1448            // 从 B<?> 变 raw B,成员解析走擦除(rett() 返回 Object →
1449            // `String s2 = …` 赋值失败)。元素名须**全串**一致(含实参),
1450            // 维度须与声明嵌套一致;var 推断声明恒安全
1451            if matches!(use_parent, Some(p) if {
1452                matches!(self.data(p), NodeData::Index) && use_at_head
1453            }) {
1454                return self.index_base_newarray_unsound(decl, value);
1455            }
1456            false
1457        }
1458    }
1459
1460    fn bin_op(&self, id: JavaId) -> Option<BinOp> {
1461        match self.data(id) {
1462            NodeData::Binary { op } => Some(*op),
1463            _ => None,
1464        }
1465    }
1466    fn un_op(&self, id: JavaId) -> Option<UnOp> {
1467        match self.data(id) {
1468            NodeData::Unary { op } => Some(*op),
1469            _ => None,
1470        }
1471    }
1472    fn literal(&self, id: JavaId) -> Option<LitRef<'_>> {
1473        match self.data(id) {
1474            NodeData::Literal(l) => Some(match l {
1475                Lit::Bool(b) => LitRef::Bool(*b),
1476                Lit::Int(v) => LitRef::Int(*v),
1477                Lit::Long(v) => LitRef::Long(*v),
1478                Lit::Float(v) => LitRef::Float(*v),
1479                Lit::Double(v) => LitRef::Double(*v),
1480                Lit::Char(c) => LitRef::Char(*c),
1481                Lit::Str(s) => LitRef::Str(s),
1482                // TextBlock 的**值**需完整 JLS §3.10.6 处理(附加缩进
1483                // 剥离 + 行尾空白剔除 + \s 转义——InputJava14EscapedS
1484                // 抓获:按原始内文求值把 assert 折成 false)。存的是原文
1485                //(往返保真),值语义未实现 → 保守不当作字面量(折叠拒
1486                // 绝;打印路径不经过 literal())
1487                Lit::TextBlock(_) => return None,
1488                Lit::NumRaw { val, .. } => match val {
1489                    NumVal::Int(v) => LitRef::Int(*v),
1490                    NumVal::Long(v) => LitRef::Long(*v),
1491                    NumVal::Float(v) => LitRef::Float(*v),
1492                    NumVal::Double(v) => LitRef::Double(*v),
1493                },
1494                Lit::Null => LitRef::Null,
1495            }),
1496            _ => None,
1497        }
1498    }
1499    fn var_name(&self, id: JavaId) -> Option<&str> {
1500        match self.data(id) {
1501            NodeData::VarRef { name } => Some(self.sn(*name)),
1502            NodeData::VarDecl { name, .. } => Some(name),
1503            NodeData::ForEach { name, .. } | NodeData::Catch { name, .. } => Some(name),
1504            _ => None,
1505        }
1506    }
1507    fn member_name(&self, id: JavaId) -> Option<&str> {
1508        match self.data(id) {
1509            NodeData::Member { name } => Some(self.sn(*name)),
1510            NodeData::MethodRef { name } => Some(self.sn(*name)),
1511            _ => None,
1512        }
1513    }
1514    fn is_field_name(&self, name: &str) -> bool {
1515        self.field_types.contains_key(name)
1516    }
1517    fn payload_equal(&self, a: JavaId, b: JavaId) -> bool {
1518        // 字面量:值级比较(NumRaw 的 0x1F 与 Int 的 31 值等可折——
1519        // data 全等会退化成原文等)
1520        if let (NodeData::Literal(x), NodeData::Literal(y)) = (self.data(a), self.data(b)) {
1521            return lit_value_eq(x, y);
1522        }
1523        self.data(a) == self.data(b)
1524    }
1525    fn assign_op(&self, id: JavaId) -> Option<BinOp> {
1526        match self.data(id) {
1527            NodeData::Assign { op } => *op,
1528            _ => None,
1529        }
1530    }
1531
1532    /// 重建缓存:
1533    /// 1) 效果表——arena 按升序扫描(child index < parent index 不变量);
1534    /// 2) 变量类型表——从 root 做作用域栈遍历。
1535    fn prepare(&mut self, root: JavaId) {
1536
1537        if cnt_prepare_on() {
1538            PREPARE_CALLS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
1539            PREPARE_NODES.fetch_add(self.nodes.len(), std::sync::atomic::Ordering::Relaxed);
1540        }
1541        // 名字键增量扩展(cure-tree NameTable):新节点 intern(既有节点
1542        // 键不变——名字与位置无关)。名字先收集(&self 借用安全形态),
1543        // 再批量扩展(&mut self.names)。
1544        let n_nodes = self.nodes.len();
1545        let key_slots = self.names.key_slots();
1546        if key_slots < n_nodes {
1547            let names: Vec<Option<String>> = (key_slots..n_nodes)
1548                .map(|i| self.var_name(JavaId(i as u32)).map(|n| n.to_string()))
1549                .collect();
1550            self.names.extend_owned(key_slots, &names);
1551        }
1552        // 守卫缓存失效:树已变
1553        self.string_identity.set(None);
1554        // 区域事件索引【惰性重建】(B3,cure-tree EventStore):只重建
1555        // **空条目**——被 invalidate_effect 失效的语句、或新语句。未失效
1556        // 条目的事件是子树局部的(与位置无关)。关键不变量:**一切**改树
1557        // 路径都必须失效受影响语句的条目:
1558        //   - 立即 Replace:目标祖先链 + with 子树中既有节点的**旧容器**
1559        //     祖先链(搬移——pass.rs 立即路径两处都做)
1560        //   - 队列编辑应用:同上(pass.rs deferred 应用后统一失效)
1561        // 违反不变量的后果:陈旧事件驱动错误决策(B2 教训:cff_diamond
1562        // 差分当场抓获)。性能背景:Types.java 上 prepare 每 pass 全量重建
1563        // = 726 倍冗余(37 万文件语料 prepare 占 57% 线程时间)。
1564        self.events.resize(n_nodes);
1565        if self.events.is_clean() {
1566            if self.prepared_root == Some(root) {
1567                return;
1568            }
1569            // 树全局缓存(事件/效果表)仍有效;根变了 → 只重建
1570            // root 相关的作用域分析段
1571            self.rebuild_var_types(root);
1572            self.prepared_root = Some(root);
1573            return;
1574        }
1575        self.prepared_root = Some(root);
1576        self.events.mark_clean();
1577        for sr in cure_tree::stmt_roots(self, root) {
1578            let idx = sr.0 as usize;
1579            if self.events.slot(idx).is_empty() {
1580                let events = cure_tree::collect_region_events(self, sr);
1581                self.events.put(idx, events);
1582            }
1583        }
1584        // ---- 效果表(cure-tree rebuild_effects:不动点 sweep——
1585        // children-先于-parent 索引序 + 注入节点违例多轮收敛)----
1586        let effects = cure_tree::rebuild_effects(self, n_nodes);
1587        self.effect_cache = effects;
1588        self.rebuild_var_types(root);
1589    }
1590}
1591
1592impl JavaAst {
1593    /// root 相关的作用域分析(从 prepare 提取——根变化时单独重建)。
1594    pub(crate) fn rebuild_var_types(&mut self, root: JavaId) {
1595        // ---- 变量类型(作用域栈)----
1596        self.var_types.clear();
1597        self.var_types.resize(self.nodes.len(), None);
1598        #[derive(Clone)]
1599        enum Frame {
1600            Enter(JavaId),
1601            Exit,
1602            PopScope,
1603            Bind(String, JType),
1604        }
1605        let mut base: HashMap<String, JType> = HashMap::new();
1606        for (n, t) in &self.param_scope {
1607            base.insert(n.clone(), t.clone());
1608        }
1609        let mut scopes: Vec<HashMap<String, JType>> = vec![base];
1610        let mut stack = vec![Frame::Enter(root)];
1611        while let Some(f) = stack.pop() {
1612            match f {
1613                Frame::Enter(id) => {
1614                    let node = &self.nodes[id.0 as usize];
1615                    enum Action {
1616                        None,
1617                        Scope,
1618                        Bind(String, JType),
1619                    }
1620                    let action = match &node.data {
1621                        NodeData::Block | NodeData::For { .. } | NodeData::Try => Action::Scope,
1622                        NodeData::VarDecl { name, ty, .. } => {
1623                            scopes.last_mut().unwrap().insert(name.clone(), ty.clone());
1624                            Action::None
1625                        }
1626                        NodeData::VarRef { name } => {
1627                            if let Some(t) = scopes
1628                                .iter()
1629                                .rev()
1630                                .find_map(|s| s.get(self.sn(*name)))
1631                                .cloned()
1632                            {
1633                                self.var_types[id.0 as usize] = Some(t);
1634                            }
1635                            Action::None
1636                        }
1637                        NodeData::Catch { name, .. } => {
1638                            Action::Bind(name.clone(), JType::Var)
1639                        }
1640                        NodeData::ForEach { name, ty } => {
1641                            Action::Bind(name.clone(), ty.clone())
1642                        }
1643                        _ => Action::None,
1644                    };
1645                    // 期望弹出顺序:[Bind?] children… [PopScope?] Exit
1646                    // ⇒ 压栈顺序取反:Exit、[PopScope]、children(逆序)、[Bind]
1647                    stack.push(Frame::Exit);
1648                    if matches!(action, Action::Scope | Action::Bind(_, _)) {
1649                        scopes.push(HashMap::new());
1650                        stack.push(Frame::PopScope);
1651                    }
1652                    for &c in node.children.as_slice().iter().rev() {
1653                        stack.push(Frame::Enter(c));
1654                    }
1655                    if let Action::Bind(n, t) = action {
1656                        stack.push(Frame::Bind(n, t));
1657                    }
1658                }
1659                Frame::Bind(name, ty) => {
1660                    scopes.last_mut().unwrap().insert(name, ty);
1661                }
1662                Frame::PopScope => {
1663                    scopes.pop();
1664                }
1665                Frame::Exit => {}
1666            }
1667        }
1668    }
1669}
1670
1671// ---------------------------------------------------------------------------
1672// 区域事件索引(使用索引):规则区域扫描的预计算。
1673// 遍历序必须与引擎 scan_region 原递归严格一致:
1674//   Assign      → [Write(目标)] + value 子树(目标本身不再当 Use 扫)
1675//   自增自减    → [Write(目标)],不扫子
1676//   VarDecl     → [Write, Shadow] + 全部孩子
1677//   ForEach     → [Write, Shadow] + 全部孩子;Catch → [Shadow] + 孩子
1678//   VarRef      → [Use]
1679//   其余        → 依序拼接孩子
1680// ---------------------------------------------------------------------------
1681
1682impl JavaAst {
1683    /// 局部传播到成员访问接收位的**装箱丢失**检查:声明为引用类型 +
1684    /// 值是基本类型形态(原始字面量/基本类型变量/算术一元二元——
1685    /// R13 P0-2 抓获:`Object o = +c; o.getClass()` 曾内联成
1686    /// `(+c).getClass()` / 常量传播折成 `65.getClass()`——int 接收者
1687    /// 不可解引用;装箱转换只发生在赋值/传参位,接收位无转换)。
1688    /// 字符串字面量/引用变量合法(`"a".length()`)。
1689    /// 接收位 `new` 值的类型可靠性(R15 终审 P0-4/P0-5):diamond 无目标
1690    /// 推断不可靠;构造类型基名 ≠ 声明类型基名(接口/父类型声明的实现类
1691    /// 构造)→ 接收者静态类型改变 → 方法绑定/throws 子句可能改变 →
1692    /// 不可靠。同名构造(`Foo f = new Foo(); f.m()`)与 var 推断声明
1693    ///(推断类型即 init 类型)保持传播。
1694    fn receiver_new_type_unsound(&self, decl: JavaId, value: JavaId) -> bool {
1695        let NodeData::New { ty, .. } = self.data(value) else {
1696            return false;
1697        };
1698        let decl_ty = match self.data(decl) {
1699            NodeData::VarDecl { ty, .. } => ty,
1700            _ => return false,
1701        };
1702        // var:推断类型 == init 静态类型——New 与之恒等(含 diamond:
1703        // `var l = new ArrayList<>()` 本就按无目标推断)
1704        if matches!(decl_ty, JType::Var) {
1705            return false;
1706        }
1707        let name = match ty {
1708            JType::Ref(n) => n.as_str(),
1709            // 非引用构造类型(不可能出现在合法 new;防御拒绝)
1710            _ => return true,
1711        };
1712        // diamond:推断依赖赋值目标——接收位无目标
1713        if name.ends_with("<>") {
1714            return true;
1715        }
1716        match decl_ty {
1717            JType::Ref(d) => type_base_name(d) != type_base_name(name),
1718            // 声明为数组/基元却以类构造为 init——恒不可靠(防御)
1719            _ => true,
1720        }
1721    }
1722
1723    /// 数组访问基座(`b2[0]` 的 b2 位)`new` 数组值的元素类型可靠性
1724    /// (R15 终审 P0-2 续,T8357653b 抓获):声明元素类型与 new 的元素
1725    /// 类型须**全串一致**(含泛型实参——`B<?>[] b2 = new B[1]` 内联使
1726    /// b2[0] 从 B<?> 变 raw B → 成员解析擦除化),维度数须与声明嵌套
1727    /// 一致。var 推断声明(推断类型即 init 类型)恒安全。
1728    fn index_base_newarray_unsound(&self, decl: JavaId, value: JavaId) -> bool {
1729        let NodeData::NewArray { ty, dims, .. } = self.data(value) else {
1730            return false;
1731        };
1732        let decl_ty = match self.data(decl) {
1733            NodeData::VarDecl { ty, .. } => ty,
1734            _ => return false,
1735        };
1736        if matches!(decl_ty, JType::Var) {
1737            return false;
1738        }
1739        // 声明的数组嵌套层数 + 最内元素类型(Ref 全串含泛型实参)
1740        let mut elem: &JType = decl_ty;
1741        let mut nest = 0u16;
1742        while let JType::Array(inner) = elem {
1743            elem = inner.as_ref();
1744            nest += 1;
1745        }
1746        nest != *dims || *elem != *ty
1747    }
1748
1749    fn receiver_boxing_unsound(&self, decl: JavaId, value: JavaId) -> bool {
1750        let declared_ref = match self.data(decl) {
1751            NodeData::VarDecl { ty, .. } => ty.is_ref(),
1752            _ => false,
1753        };
1754        if !declared_ref {
1755            return false;
1756        }
1757        match self.data(value) {
1758            NodeData::Literal(
1759                Lit::Int(_) | Lit::Long(_) | Lit::Float(_) | Lit::Double(_) | Lit::Bool(_)
1760                | Lit::Char(_),
1761            ) => true,
1762            // 基本类型变量(var_type 解析参数/局部声明类型)
1763            NodeData::VarRef { .. } => matches!(
1764                self.var_type(value),
1765                Some(
1766                    JType::Int
1767                        | JType::Long
1768                        | JType::Byte
1769                        | JType::Short
1770                        | JType::Char
1771                        | JType::Float
1772                        | JType::Double
1773                        | JType::Bool
1774                )
1775            ),
1776            // 算术/逻辑一元二元:结果必为基本类型
1777            NodeData::Unary { .. } | NodeData::Binary { .. } => true,
1778            // 三元:结果可为基本类型(R14 族 B 抓获:`Object o = true ?
1779            // 'a' : 'b'; o.hashCode()` 曾内联成 'a'.hashCode() 不可解引用)
1780            // ——含引用臂的保守拒绝(过度面小)
1781            NodeData::Ternary => true,
1782            // 基本类型 cast:(int) 'a' 结果 int——引用 cast 保守同拒
1783            NodeData::Cast { .. } => true,
1784            // instanceof:结果恒 boolean
1785            NodeData::InstanceOf { .. } => true,
1786            // 装箱类型声明 + 调用/成员/下标值(返回类型未知——s.charAt(0)
1787            // 等基本返回调用内联进接收位丢装箱——R14 终审 P0-2 抓获:
1788            // `Character c = s.charAt(0); return c.toString()` 曾产出
1789            // `s.charAt(0).toString()` 无法取消引用 char)。装箱名精确
1790            // 匹配,非装箱引用类型(Foo f = m(); f.x())不受限
1791            NodeData::Call | NodeData::Member { .. } | NodeData::Index => {
1792                match self.data(decl) {
1793                    NodeData::VarDecl { ty: JType::Ref(n), .. } => {
1794                        let boxed = [
1795                            "Character", "Integer", "Long", "Boolean", "Double",
1796                            "Float", "Byte", "Short", "Number", "AtomicInteger",
1797                            "AtomicLong",
1798                        ];
1799                        n.rsplit('.').next().is_some_and(|b| boxed.contains(&b))
1800                    }
1801                    _ => false,
1802                }
1803            }
1804            _ => false,
1805        }
1806    }
1807
1808    /// 名字 → 实化键(持久表,只增;同名字恒同键)。
1809    /// intern 名字 → Sym(复用 name_intern 表 + sym_names 向量)。
1810    pub fn intern_sym(&mut self, name: &str) -> Sym {
1811        Sym(self.names.intern(name))
1812    }
1813
1814    /// Sym → 名字原文。
1815    pub fn sn(&self, sym: Sym) -> &str {
1816        self.names.name(sym.0)
1817    }
1818
1819
1820
1821
1822}
1823
1824
1825// ---------------------------------------------------------------------------
1826// 结构化指标:编译单元级聚合(供 --stats 等评估简化效果——节点数 /
1827// 判定点 / 嵌套深度不受格式化影响,只被语义简化改变)
1828// ---------------------------------------------------------------------------
1829
1830/// 编译单元全部可执行体(方法/构造器/初始化块,含嵌套类型)的
1831/// 结构指标总和。
1832pub fn unit_metrics(ast: &JavaAst, unit: &CompilationUnit) -> TreeMetrics {
1833    let mut total = TreeMetrics::default();
1834    for ty in &unit.types {
1835        metrics_of_type(ast, ty, &mut total);
1836    }
1837    total
1838}
1839
1840fn metrics_of_type(ast: &JavaAst, ty: &TypeDecl, total: &mut TreeMetrics) {
1841    for m in &ty.members {
1842        match m {
1843            Member::Method { body: Some(b), .. } | Member::Constructor { body: Some(b), .. } => {
1844                total.add(subtree_metrics(ast, *b));
1845            }
1846            Member::Initializer { body, .. } => {
1847                total.add(subtree_metrics(ast, *body));
1848            }
1849            Member::Type(t) => metrics_of_type(ast, t, total),
1850            _ => {}
1851        }
1852    }
1853}
1854
1855static ENV_CACHED: std::sync::OnceLock<(bool, bool)> = std::sync::OnceLock::new();
1856fn env_flags() -> (bool, bool) {
1857    *ENV_CACHED.get_or_init(|| {
1858        (
1859            std::env::var("CURE_CNT_PREPARE").is_ok(),
1860            std::env::var("CURE_VERIFY_EVENTS").is_ok(),
1861        )
1862    })
1863}
1864fn cnt_prepare_on() -> bool { env_flags().0 }
1865fn verify_events_on() -> bool { env_flags().1 }
1866
1867pub static PREPARE_CALLS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
1868pub static PREPARE_NODES: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
1869
1870pub static COLLECT_CALLS: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
1871
1872// ---------------------------------------------------------------------------
1873// 测试
1874// ---------------------------------------------------------------------------
1875
1876#[cfg(test)]
1877mod tests {
1878    use super::*;
1879
1880    #[test]
1881    fn builder_smoke() {
1882        let mut a = JavaAst::new();
1883        let one = a.lit(Lit::Int(1));
1884        let x = a.var_decl("x", JType::Int, Some(one));
1885        let xv = a.var("x");
1886        let r = a.ret(Some(xv));
1887        let body = a.block(vec![x, r]);
1888        assert_eq!(a.kind(body), NodeKind::Block);
1889        assert_eq!(a.children(body).len(), 2);
1890    }
1891
1892    #[test]
1893    fn effect_aggregation() {
1894        let mut a = JavaAst::new();
1895        let f = a.plain_call("foo", vec![]);
1896        let r = a.ret(Some(f));
1897        let body = a.block(vec![r]);
1898        a.prepare(body);
1899        assert_eq!(a.effect(f), Effect::Unknown);
1900        assert_eq!(a.effect(r), Effect::Unknown);
1901        assert_eq!(a.effect(body), Effect::Unknown);
1902
1903        let mut b = JavaAst::new();
1904        let two = b.lit(Lit::Int(2));
1905        let three = b.lit(Lit::Int(3));
1906        let add = b.bin(BinOp::Add, two, three);
1907        let r2 = b.ret(Some(add));
1908        let body2 = b.block(vec![r2]);
1909        b.prepare(body2);
1910        assert_eq!(b.effect(add), Effect::Pure);
1911        // return 语句本身按控制流计为 MayThrow,Block 聚合随之
1912        assert_eq!(b.effect(r2), Effect::MayThrow);
1913        assert_eq!(b.effect(body2), Effect::MayThrow);
1914    }
1915
1916    #[test]
1917    fn var_type_resolution_and_shadowing() {
1918        let mut a = JavaAst::new();
1919        // { boolean b = true; { int b2 = 1; b2; } b; }
1920        let one = a.lit(Lit::Int(1));
1921        let b2_decl = a.var_decl("b2", JType::Int, Some(one));
1922        let inner_b2 = a.var("b2");
1923        let inner_stmt = a.expr_stmt(inner_b2);
1924        let inner = a.block(vec![b2_decl, inner_stmt]);
1925        let tv = a.lit(Lit::Bool(true));
1926        let decl_b = a.var_decl("b", JType::Bool, Some(tv));
1927        let outer_b = a.var("b");
1928        let outer_stmt = a.expr_stmt(outer_b);
1929        let body = a.block(vec![decl_b, inner, outer_stmt]);
1930        a.prepare(body);
1931        assert!(a.is_bool(outer_b));
1932        // b2 的使用在 inner 块内,类型可解析
1933        assert!(a.var_type(inner_b2).is_some());
1934    }
1935
1936    #[test]
1937    fn raw_and_foreach_semantics() {
1938        let mut a = JavaAst::new();
1939        // { int x = 1; RAW; for (String s : list) { s.len(); } }
1940        let one = a.lit(Lit::Int(1));
1941        let dx = a.var_decl("x", JType::Int, Some(one));
1942        let r = a.raw("broken ~!@ code");
1943        let sv = a.var("s");
1944        let call = a.method_call(sv, "len", vec![]);
1945        let es = a.expr_stmt(call);
1946        let body = a.block(vec![es]);
1947        let lst = a.var("list");
1948        let fe = a.for_each("s", JType::Ref("String".into()), lst, body);
1949        let all = a.block(vec![dx, r, fe]);
1950        a.prepare(all);
1951        assert_eq!(a.kind(r), NodeKind::Raw);
1952        assert_eq!(a.effect(r), Effect::Unknown);
1953        assert!(a.var_type(sv).is_some()); // 循环变量类型可解析
1954    }
1955
1956    #[test]
1957    fn num_raw_literal() {
1958        let mut a = JavaAst::new();
1959        let l = a.lit(Lit::NumRaw {
1960            text: "0x1F".into(),
1961            val: NumVal::Int(31),
1962        });
1963        a.prepare(l);
1964        assert!(a.is_exact_int(l));
1965        assert!(matches!(a.literal(l), Some(LitRef::Int(31))));
1966    }
1967}