Skip to main content

cure_engine/rules/
mod.rs

1//! 引擎内置通用规则:只依赖 `Lang` 抽象,任何语言 crate 均可复用。
2//!
3//! 每条规则文档化其语义前提;所有提案都必须严格降低成本(runner 校验)。
4
5
6
7use crate::analysis::{prefix_effects_readable, subtree_contains};
8use crate::effect::Effect;
9use crate::kind::{BinOp, LitRef, NodeKind, UnOp};
10use crate::pattern::{matches, Pat};
11use crate::rule::{Edit, RewriteCtx, Rule};
12use crate::lang::{Lang, ReassocOutcome};
13use crate::walk::Walk;
14
15// ---------------------------------------------------------------------------
16// 括号消除:Paren(x) → x(纯分组节点,删除永远安全)
17// ---------------------------------------------------------------------------
18
19pub struct ParenRemoval;
20
21impl<L: Lang> Rule<L> for ParenRemoval {
22    fn name(&self) -> &'static str {
23        "paren_removal"
24    }
25    fn kinds(&self) -> &'static [NodeKind] {
26        &[NodeKind::Paren]
27    }
28    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
29        let RewriteCtx { lang, walk: _ } = ctx;
30        if lang.kind(id) != NodeKind::Paren {
31            return None;
32        }
33        let inner = *lang.children(id).first()?;
34        Some(Edit::Replace {
35            target: id,
36            with: inner,
37        })
38    }
39}
40
41// ---------------------------------------------------------------------------
42// 常量条件:if (true) {A} [else B] → A;if (false) {A} else B → 删除
43// ---------------------------------------------------------------------------
44
45/// 语句自身终结其所在**语句列表**的后续(return/throw/yield 终结方法/块,
46/// break/continue 终结所在块——JLS 14.21 语义)。
47/// javac 对 `if (true) 终结语句` 后跟语句有「条件编译豁免」——后续按可达
48/// 处理;剥掉 if 壳后豁免消失,同列表后续变硬不可达(javac 拒绝)。
49fn self_is_terminal<L: Lang>(lang: &L, n: L::Id) -> bool {
50    matches!(
51        lang.kind(n),
52        NodeKind::Return | NodeKind::Throw | NodeKind::Break | NodeKind::Continue | NodeKind::Yield
53    )
54}
55
56/// 子树是否含 switch 表达式产出(yield)。折叠丢弃含 yield 的分支会
57/// 缩小产出集 → switch 表达式静态类型改变(var 推断随之破坏)。
58fn contains_yield<L: Lang>(lang: &L, n: L::Id) -> bool {
59    subtree_contains(lang, n, |x| lang.kind(x) == NodeKind::Yield)
60}
61
62pub struct ConstCondition;
63
64impl<L: Lang> Rule<L> for ConstCondition {
65    fn name(&self) -> &'static str {
66        "const_condition"
67    }
68    fn kinds(&self) -> &'static [NodeKind] {
69        &[NodeKind::If]
70    }
71    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
72        let RewriteCtx { lang, walk } = ctx;
73        if lang.kind(id) != NodeKind::If {
74            return None;
75        }
76        let ch = lang.children(id);
77        let cond = *ch.first()?;
78        match lang.literal(cond) {
79            Some(LitRef::Bool(true)) => {
80                // then 分支必然执行:拼进父块(避免嵌套块);非块父级则整体替换。
81                // then 必然终结(return/break 等)→ 后续兄弟不可达,须一并
82                // 删除——否则产出 `return 1; return 2;` 不可编译
83                //(InputArrayTrailingComma 抓获;unreachable_after_terminal
84                // 是 --dead-code 门控,默认模式依赖本规则自洽)
85                let then = ch.get(1).copied()?;
86                // R15 P0-1(o4 形态)抓获:被丢弃的 else 含 yield → switch
87                // 表达式产出集缩小 → 静态类型变化(var 推断破坏)→ 拒绝
88                if let Some(&els) = ch.get(2) {
89                    if contains_yield(&*lang, els) {
90                        return None;
91                    }
92                }
93                let insert: Vec<L::Id> = if lang.kind(then) == NodeKind::Block {
94                    lang.children(then).to_vec()
95                } else {
96                    vec![then]
97                };
98                let terminates = insert.iter().any(|&s| self_is_terminal(lang, s));
99                if let (Some(parent), Some(index)) = (walk.parent(id), walk.index(id)) {
100                    if lang.kind(parent) == NodeKind::Block {
101                        let siblings = lang.children(parent).to_vec();
102                        let remove = if terminates && index + 1 < siblings.len() {
103                            siblings.len() - index
104                        } else {
105                            1
106                        };
107                        // R15 P0-1(o3 同类)抓获:删除的尾随兄弟含 yield →
108                        // 产出集缩小 → 静态类型变化 → 拒绝
109                        if remove > 1
110                            && siblings[index + 1..]
111                                .iter()
112                                .any(|&s| contains_yield(&*lang, s))
113                        {
114                            return None;
115                        }
116                        return Some(Edit::Splice {
117                            node: parent,
118                            index,
119                            remove,
120                            insert,
121                        });
122                    }
123                    // R15 P0-3(UnreachableVar)抓获:case 组(标签后的
124                    // 语句序列)中整体替换时,then 终结且 if 后还有尾随
125                    // 语句 → 折叠使尾随不可达(JLS 14.21 条件编译豁免
126                    // 消失)。case 组中声明的作用域覆盖整个 switch 块
127                    //(删 `int i=1` 会断 `default: i=2` 引用)——无法安全
128                    // 删除,唯一安全动作是拒绝折叠。其余非块父级(if/while
129                    // 等控制体的唯一语句孩子、else 分支、do-while 条件)
130                    // 不存在尾随语句——照常替换。
131                    if lang.kind(parent) == NodeKind::Case && terminates {
132                        let siblings = lang.children(parent).to_vec();
133                        if index + 1 < siblings.len() {
134                            return None;
135                        }
136                    }
137                }
138                Some(Edit::Replace {
139                    target: id,
140                    with: then,
141                })
142            }
143            Some(LitRef::Bool(false)) => {
144                // else 分支必然执行:保留之;无 else(或空 else)才可整删
145                // R15 P0-1(o3 形态)抓获:then 分支整体被丢弃(换 else 或
146                // 删除)——含 yield 则 switch 表达式产出集缩小 → 静态类型
147                // 变化(var 推断破坏)→ 拒绝
148                let then = *ch.get(1)?;
149                if contains_yield(&*lang, then) {
150                    return None;
151                }
152                let els = ch.get(2).copied();
153                if let (Some(parent), Some(index)) = (walk.parent(id), walk.index(id)) {
154                    if lang.kind(parent) == NodeKind::Block {
155                        let insert: Vec<L::Id> = match els {
156                            Some(e) => {
157                                if lang.kind(e) == NodeKind::Block {
158                                    lang.children(e).to_vec()
159                                } else {
160                                    vec![e]
161                                }
162                            }
163                            None => Vec::new(),
164                        };
165                        return Some(if insert.is_empty() {
166                            Edit::Delete { node: id }
167                        } else {
168                            Edit::Splice {
169                                node: parent,
170                                index,
171                                remove: 1,
172                                insert,
173                            }
174                        });
175                    }
176                }
177                match els {
178                    Some(e) => Some(Edit::Replace {
179                        target: id,
180                        with: e,
181                    }),
182                    None => Some(Edit::Delete { node: id }),
183                }
184            }
185            _ => None,
186        }
187    }
188}
189
190// ---------------------------------------------------------------------------
191// 布尔返回:if (c) return true else return false → return c(反极性 → return !c)
192// 前提:c 为原始 boolean。
193// ---------------------------------------------------------------------------
194
195// 裸分支:if (c) return true; else return false;
196static P_IF_RET_TF: Pat = Pat::Kind(
197    NodeKind::If,
198    &[Pat::Bind("cond"), Pat::Kind(NodeKind::Return, &[Pat::LitBool(true)]), Pat::Kind(NodeKind::Return, &[Pat::LitBool(false)])],
199);
200static P_IF_RET_FT: Pat = Pat::Kind(
201    NodeKind::If,
202    &[Pat::Bind("cond"), Pat::Kind(NodeKind::Return, &[Pat::LitBool(false)]), Pat::Kind(NodeKind::Return, &[Pat::LitBool(true)])],
203);
204// 块包裹分支(反编译器/规范形态):if (c) { return true; } else { return false; }
205static P_IF_BRET_TF: Pat = Pat::Kind(
206    NodeKind::If,
207    &[
208        Pat::Bind("cond"),
209        Pat::Kind(NodeKind::Block, &[Pat::Kind(NodeKind::Return, &[Pat::LitBool(true)])]),
210        Pat::Kind(NodeKind::Block, &[Pat::Kind(NodeKind::Return, &[Pat::LitBool(false)])]),
211    ],
212);
213static P_IF_BRET_FT: Pat = Pat::Kind(
214    NodeKind::If,
215    &[
216        Pat::Bind("cond"),
217        Pat::Kind(NodeKind::Block, &[Pat::Kind(NodeKind::Return, &[Pat::LitBool(false)])]),
218        Pat::Kind(NodeKind::Block, &[Pat::Kind(NodeKind::Return, &[Pat::LitBool(true)])]),
219    ],
220);
221
222pub struct BooleanReturn;
223
224impl<L: Lang> Rule<L> for BooleanReturn {
225    fn name(&self) -> &'static str {
226        "boolean_return"
227    }
228    fn kinds(&self) -> &'static [NodeKind] {
229        &[NodeKind::If]
230    }
231    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
232        let RewriteCtx { lang, walk: _ } = ctx;
233        if lang.kind(id) != NodeKind::If {
234            return None;
235        }
236        // 四种形态:裸/块分支 × 正/反极性。块分支整体被裸 return 替换。
237        let negated = |cond: L::Id, lang: &mut L| {
238            let nc = lang.build_unary(UnOp::Not, cond);
239            lang.build_return(Some(nc))
240        };
241        for (pat, invert) in [
242            (&P_IF_RET_TF, false),
243            (&P_IF_BRET_TF, false),
244            (&P_IF_RET_FT, true),
245            (&P_IF_BRET_FT, true),
246        ] {
247            if let Some(b) = matches(&*lang, id, pat) {
248                let cond = lookup(&b, "cond")?;
249                if !lang.is_bool(cond) {
250                    return None;
251                }
252                let ret = if invert {
253                    negated(cond, lang)
254                } else {
255                    lang.build_return(Some(cond))
256                };
257                return Some(Edit::Replace {
258                    target: id,
259                    with: ret,
260                });
261            }
262        }
263        None
264    }
265}
266
267fn lookup<Id: Copy>(binds: &[(&'static str, Id)], name: &str) -> Option<Id> {
268    binds.iter().find(|(n, _)| *n == name).map(|(_, id)| *id)
269}
270
271// ---------------------------------------------------------------------------
272// 空分支:if (c) {} else {B} → if (!c) {B};if (c) {A} else {} → if (c) {A};
273//         if (c) {} → 删除(仅当 c 无副作用)。
274// ---------------------------------------------------------------------------
275
276pub struct IfElseEmpty;
277
278impl<L: Lang> Rule<L> for IfElseEmpty {
279    fn name(&self) -> &'static str {
280        "if_else_empty"
281    }
282    fn kinds(&self) -> &'static [NodeKind] {
283        &[NodeKind::If]
284    }
285    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
286        let RewriteCtx { lang, walk } = ctx;
287        if lang.kind(id) != NodeKind::If {
288            return None;
289        }
290        let ch = lang.children(id);
291        let cond = *ch.first()?;
292        let is_empty_block = |n: L::Id| -> bool {
293            lang.kind(n) == NodeKind::Block && lang.children(n).is_empty()
294        };
295        match ch.len() {
296            3 => {
297                let (then, els) = (ch[1], ch[2]);
298                if is_empty_block(then) {
299                    if is_empty_block(els) {
300                        // 两支全空:塌缩成 if(c){},交给 len==2 分支处理
301                        return Some(Edit::Splice {
302                            node: id,
303                            index: 0,
304                            remove: 3,
305                            insert: vec![cond, then],
306                        });
307                    }
308                    // then 空、else 有内容:取反条件交换分支(条件两侧都恰好求值一次,永远安全)
309                    let nc = lang.build_unary(UnOp::Not, cond);
310                    return Some(Edit::Splice {
311                        node: id,
312                        index: 0,
313                        remove: 3,
314                        insert: vec![nc, els],
315                    });
316                }
317                if is_empty_block(els) {
318                    return Some(Edit::Splice {
319                        node: id,
320                        index: 0,
321                        remove: 3,
322                        insert: vec![cond, then],
323                    });
324                }
325                None
326            }
327            2 => {
328                let then = ch[1];
329                // 【位置守卫】Delete 只在语句位置(父为 Block)合法:
330                // if 处于分支位置(if(c){ if(c2){} }——else-if 链化后的
331                // 常见形态)时,抽走分支会给父 If 留下"只有条件没有体"的
332                // 残骸(1-child If,打印机越界 panic——真实大语料抓获)。
333                // 分支位置的空体 if 由父 If 的规则吸收(塌缩后自身再走
334                // len==2/len==3 变换)。
335                let parent_is_block = walk
336                    .parent(id)
337                    .map(|p| lang.kind(p) == NodeKind::Block)
338                    .unwrap_or(false);
339                if is_empty_block(then)
340                    && lang.effect(cond) <= Effect::MayRead
341                    && parent_is_block
342                {
343                    // 删除整个 if 会丢掉 cond 的求值,仅当 cond 无副作用时安全
344                    return Some(Edit::Delete { node: id });
345                }
346                None
347            }
348            _ => None,
349        }
350    }
351}
352
353// ---------------------------------------------------------------------------
354// 布尔比较:x == true → x;x == false → !x;x != true → !x;x != false → x(两个操作数序)
355// 前提:x 为原始 boolean(装箱比较是引用比较,is_bool 必须排除)。
356// ---------------------------------------------------------------------------
357
358pub struct BoolCompare;
359
360impl<L: Lang> Rule<L> for BoolCompare {
361    fn name(&self) -> &'static str {
362        "bool_compare"
363    }
364    fn kinds(&self) -> &'static [NodeKind] {
365        &[NodeKind::Binary]
366    }
367    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
368        let RewriteCtx { lang, walk } = ctx;
369        if lang.kind(id) != NodeKind::Binary {
370            return None;
371        }
372        let op = lang.bin_op(id)?;
373        if !matches!(op, BinOp::Eq | BinOp::Ne) {
374            return None;
375        }
376        let ch = lang.children(id);
377        let (l, r) = (*ch.first()?, *ch.get(1)?);
378        let lit_bool = |n: L::Id| -> Option<bool> {
379            match lang.literal(n) {
380                Some(LitRef::Bool(b)) => Some(b),
381                _ => None,
382            }
383        };
384        // 统一成 (x, lit)
385        let (x, lit) = match (lit_bool(l), lit_bool(r)) {
386            (None, Some(b)) => (l, b),
387            (Some(b), None) => (r, b),
388            _ => return None,
389        };
390        if !lang.is_bool(x) {
391            // 条件位上下文松弛:if/while 的条件表达式必为 boolean
392            //(IteratorWildcard 抓获:`x == false` 的 x 是方法调用——
393            // 返回类型无类型信息即被拒)。仅当本节点恰是 If/While 的
394            // 条件孩子时放行
395            let in_cond = walk.parent(id).is_some_and(|p| {
396                matches!(lang.kind(p), NodeKind::If | NodeKind::While) && lang.children(p).first() == Some(&id)
397            });
398            if !in_cond {
399                return None;
400            }
401        }
402        // (op, lit) → 替换结果
403        let neg = match (op, lit) {
404            (BinOp::Eq, true) | (BinOp::Ne, false) => false,
405            (BinOp::Eq, false) | (BinOp::Ne, true) => true,
406            _ => return None,
407        };
408        let with = if neg {
409            lang.build_unary(UnOp::Not, x)
410        } else {
411            x
412        };
413        Some(Edit::Replace {
414            target: id,
415            with,
416        })
417    }
418}
419
420// ---------------------------------------------------------------------------
421// 双重否定:!!x → x
422// 安全性:`!x` 要能通过类型检查,x 必为 boolean,无需类型查询。
423// ---------------------------------------------------------------------------
424
425pub struct DoubleNot;
426
427impl<L: Lang> Rule<L> for DoubleNot {
428    fn name(&self) -> &'static str {
429        "double_not"
430    }
431    fn kinds(&self) -> &'static [NodeKind] {
432        &[NodeKind::Unary]
433    }
434    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
435        let RewriteCtx { lang, walk: _ } = ctx;
436        if lang.kind(id) != NodeKind::Unary || lang.un_op(id) != Some(UnOp::Not) {
437            return None;
438        }
439        let inner = *lang.children(id).first()?;
440        if lang.kind(inner) != NodeKind::Unary || lang.un_op(inner) != Some(UnOp::Not) {
441            return None;
442        }
443        let x = *lang.children(inner).first()?;
444        Some(Edit::Replace {
445            target: id,
446            with: x,
447        })
448    }
449}
450
451// ---------------------------------------------------------------------------
452// 常量折叠:!true → false / !false → true
453// (局部传播把常量内联进 !x 后,由此规则收敛到自然形态)
454// ---------------------------------------------------------------------------
455
456pub struct BoolNotFold;
457
458impl<L: Lang> Rule<L> for BoolNotFold {
459    fn name(&self) -> &'static str {
460        "bool_not_fold"
461    }
462    fn kinds(&self) -> &'static [NodeKind] {
463        &[NodeKind::Unary]
464    }
465    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
466        let RewriteCtx { lang, walk: _ } = ctx;
467        if lang.kind(id) != NodeKind::Unary || lang.un_op(id) != Some(UnOp::Not) {
468            return None;
469        }
470        let operand = *lang.children(id).first()?;
471        match lang.literal(operand) {
472            Some(LitRef::Bool(b)) => {
473                let folded = lang.build_bool(!b);
474                Some(Edit::Replace {
475                    target: id,
476                    with: folded,
477                })
478            }
479            _ => None,
480        }
481    }
482}
483
484// ---------------------------------------------------------------------------
485// 自赋值:x = x → 删除(仅限语言层局部变量)
486// ---------------------------------------------------------------------------
487
488pub struct SelfAssign;
489
490impl<L: Lang> Rule<L> for SelfAssign {
491    fn name(&self) -> &'static str {
492        "self_assign"
493    }
494    fn kinds(&self) -> &'static [NodeKind] {
495        &[NodeKind::Assign]
496    }
497    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
498        let RewriteCtx { lang, walk } = ctx;
499        if lang.kind(id) != NodeKind::Assign {
500            return None;
501        }
502        if lang.assign_op(id).is_some() {
503            return None; // x += x 有读语义差异,不动
504        }
505        let ch = lang.children(id);
506        let (t, v) = (*ch.first()?, *ch.get(1)?);
507        if lang.kind(t) != NodeKind::VarRef || lang.kind(v) != NodeKind::VarRef {
508            return None;
509        }
510        if lang.var_name(t) != lang.var_name(v) || !lang.is_local_var(t) {
511            return None;
512        }
513        // 删除目标必须是**语句**:`x = x;` 的 AST 形态是 ExprStmt[Assign]
514        // ——删 Assign 留下空 ExprStmt 壳,后续规则按 children[0] 遍历
515        // 即 panic(ddc weixin gp0.d1 复现:clinit 里 R8 寄存器噪声
516        // `file = file;` 触发)。嵌套赋值位(`y = (x = x)` 的值孩子)删
517        // 中树节点直接留洞——拒绝。Block 直挂 Assign 的语言形态照旧删
518        // Assign 本身(Block 孩子删除安全)。
519        let (parent, _) = walk.parents.get(&id)?;
520        match lang.kind(*parent) {
521            NodeKind::ExprStmt => Some(Edit::Delete { node: *parent }),
522            NodeKind::Block => Some(Edit::Delete { node: id }),
523            _ => None,
524        }
525    }
526}
527
528// ---------------------------------------------------------------------------
529// 算术恒等式(仅精确整数,浮点有 -0.0/NaN 陷阱):
530// x+0 → x, 0+x → x, x-0 → x, x*1 → x, 1*x → x, x/1 → x
531// ---------------------------------------------------------------------------
532
533
534// ---------------------------------------------------------------------------
535// 死声明删除:`T x;`(零使用、零求值)或 `T x = V;`(V 纯/MayRead 且
536// 零使用)。声明之后整个区域对 x 零事件(读/写/遮蔽/不透明全无)。
537// 反编译器把寄存器噪声折叠后常残留零用途声明(如 PMD 噪声文件消解
538// 后的 `int a;`)。匿名类捕获由 opaque 守卫拒绝(对抗波 4 教训)。
539// ---------------------------------------------------------------------------
540
541pub struct DeadDecl;
542
543impl<L: Lang> Rule<L> for DeadDecl {
544    fn name(&self) -> &'static str {
545        "dead_decl"
546    }
547    fn kinds(&self) -> &'static [NodeKind] {
548        &[NodeKind::VarDecl]
549    }
550    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
551        let RewriteCtx { lang, walk } = ctx;
552        if lang.kind(id) != NodeKind::VarDecl {
553            return None;
554        }
555        let ch = lang.children(id).to_vec();
556        // 有 init:V 的求值会被一并删除——仅纯/只读可删(MayThrow 不行:
557        // `int x = 1/0;` 删掉会失去异常)
558        if let Some(&v) = ch.first() {
559            if lang.effect(v) > Effect::MayRead {
560                return None;
561            }
562        }
563        let parent = walk.parent(id)?;
564        if lang.kind(parent) != NodeKind::Block {
565            return None;
566        }
567        let idx = walk.index(id)?;
568        let stmts = lang.children(parent).to_vec();
569        // **句法扫描**(任何同名 VarRef 引用 → 保留):事件模型对复合
570        // 赋值目标内的读有盲区(`arr[j] += 5` 的 j——scan_region 的
571        // Assign 分支只递归 RHS),零事件 ≠ 零引用(differential Adv5
572        // 抓获:删掉 j 后 arr[j] 悬空)。写目标本身也是 VarRef,同样被
573        // 句法扫描覆盖。
574        let name_str = lang.var_name(id)?.to_string();
575        let referenced = stmts[idx + 1..].iter().any(|&s| {
576            subtree_contains(&*lang, s, |n| {
577                lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name_str.as_str())
578            })
579        });
580        if referenced {
581            return None;
582        }
583        // 遮蔽 / 不透明(匿名类捕获的原文引用无 AST 节点)仍走事件扫描
584        let name_key = lang.var_key(id)?;
585        let mut w = Watch::<L>::new(name_key, &[]);
586        for &s in &stmts[idx + 1..] {
587            scan_region(&*lang, s, &mut w);
588        }
589        if w.opaque || w.shadowed {
590            return None;
591        }
592        Some(Edit::Delete { node: id })
593    }
594}
595
596// ---------------------------------------------------------------------------
597// 重赋值折回声明(寄存器累加器形态):
598//   T x = e; …(对 x 零事件)…; x = x op K;  →  T x = e op K;
599//   (复合形态 `x op= K` 与展开形态 `x = x op K` 均可)
600//
601// e 的求值位置**不动**(仍在声明处);被删除的只是后面那条纯 delta
602// 语句;声明与折回点之间对 x 零事件 ⇒ 中间值从未被观察 ⇒ 恒安全。
603// 语义:x 的终值 (e op K) 由同一算符作用于同一操作数计算——精确
604// (整数环绕/浮点舍入均逐位一致)。
605// 拒绝:Div/Rem 且 K==0(折回后异常从后面的语句提前到声明处——
606// 中间语句的副作用顺序改变);K 非字面量;op 为短路/比较。
607// 之后 local_propagation 可继续把 e op K 内联到唯一使用处。
608// ---------------------------------------------------------------------------
609
610pub struct AssignBackFold;
611
612impl<L: Lang> Rule<L> for AssignBackFold {
613    fn name(&self) -> &'static str {
614        "assign_back_fold"
615    }
616    fn kinds(&self) -> &'static [NodeKind] {
617        &[NodeKind::VarDecl]
618    }
619    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
620        let RewriteCtx { lang, walk } = ctx;
621        if lang.kind(id) != NodeKind::VarDecl {
622            return None;
623        }
624        let ch = lang.children(id).to_vec();
625        let (&init, has_init) = (ch.first()?, !ch.is_empty());
626        if !has_init {
627            return None; // 无 init 用 decl_assign_merge / dead_decl 处理
628        }
629        let name_key = lang.var_key(id)?;
630        // 窄类型(byte/short/char 等)复合赋值含隐式收窄——折回声明
631        // 产出超域非法常量或丢静态类型(differential Adv2 抓获:
632        // `char ch = 'a'; ch += 2` 折后 println 打 99 而非 'c')
633        if !lang.is_wide_decl(id) {
634            return None;
635        }
636        let parent = walk.parent(id)?;
637        if lang.kind(parent) != NodeKind::Block {
638            return None;
639        }
640        let idx = walk.index(id)?;
641        let stmts = lang.children(parent).to_vec();
642
643        // 扫描声明之后的语句:对 x 的首个引用必须恰是「重赋值」。
644        // 句法扫描兜底事件模型盲区(复合赋值目标内的读——`arr[j]+=5`
645        // 的 j 对事件索引不可见);首个引用非重赋值形态 → 中间值被
646        // 观察,拒绝。
647        let name_str = lang.var_name(id)?.to_string();
648        for &s in &stmts[idx + 1..] {
649            let mut w = Watch::<L>::new(name_key, &[]);
650            scan_region(&*lang, s, &mut w);
651            let referenced = subtree_contains(&*lang, s, |n| {
652                lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name_str.as_str())
653            });
654            let touched = referenced || w.opaque || w.shadowed;
655            if !touched {
656                continue; // 与 x 无关的语句,跳过
657            }
658            // 首个触碰 x 的语句必须是重赋值 `x = x op K`
659            let assign = match lang.kind(s) {
660                NodeKind::Assign => s,
661                NodeKind::ExprStmt => {
662                    let c = lang.children(s);
663                    if c.len() == 1 && lang.kind(c[0]) == NodeKind::Assign {
664                        c[0]
665                    } else {
666                        return None;
667                    }
668                }
669                _ => return None, // 读/遮蔽/不透明先出现 → 中间值被观察
670            };
671            let ach = lang.children(assign).to_vec();
672            if ach.len() != 2 {
673                return None;
674            }
675            let (target, rhs) = (ach[0], ach[1]);
676            if lang.kind(target) != NodeKind::VarRef || lang.var_key(target) != Some(name_key) {
677                return None;
678            }
679            // (op, K):复合形态(RHS 即字面量操作数)/ 展开形态
680            // (RHS = Binary{x op K})
681            let (op, k) = match lang.assign_op(assign) {
682                Some(op) => (op, lang.literal(rhs).and_then(|x| x.as_int())?),
683                None => {
684                    if lang.kind(rhs) != NodeKind::Binary {
685                        return None;
686                    }
687                    let op = lang.bin_op(rhs)?;
688                    let rc = lang.children(rhs).to_vec();
689                    if rc.len() != 2 || lang.kind(rc[0]) != NodeKind::VarRef {
690                        return None;
691                    }
692                    // 左操作数必须是 x 自身(名字键等值);右操作数字面量
693                    if lang.var_key(rc[0]) != Some(name_key) {
694                        return None;
695                    }
696                    (op, lang.literal(rc[1]).and_then(|x| x.as_int())?)
697                }
698            };
699            if op.is_short_circuit() || op.is_comparison() {
700                return None;
701            }
702            // Div/Rem 且 K==0:折回后异常提前 → 中间语句副作用顺序改变
703            if matches!(op, BinOp::Div | BinOp::Rem) && k == 0 {
704                return None;
705            }
706            // long 域声明的 K 提升(H1 抓获:`long g=2147483647;
707            // g=g+1` 折成 int 字面量对 → i32 环绕 -2147483648,静默
708            // 错值)。init 若是 int 字面量也一并提升——保证 const_fold
709            // 走 i64 域
710            let lit = if lang.is_long_decl(id) {
711                lang.build_int(k, true)
712            } else {
713                lang.build_int(k, false)
714            };
715            let init = if lang.is_long_decl(id) {
716                match lang.literal(init) {
717                    Some(crate::kind::LitRef::Int(v)) => lang.build_int(v, true),
718                    _ => init,
719                }
720            } else {
721                init
722            };
723            let merged = lang.build_bin(op, init, lit);
724            // 声明原位换 init(Splice 孩子),语句删除
725            return Some(Edit::Multi(vec![
726                Edit::Delete { node: s },
727                Edit::Splice { node: id, index: 0, remove: ch.len(), insert: vec![merged] },
728            ]));
729        }
730        None
731    }
732}
733
734pub struct ArithIdentity;
735
736impl<L: Lang> Rule<L> for ArithIdentity {
737    fn name(&self) -> &'static str {
738        "arith_identity"
739    }
740    fn kinds(&self) -> &'static [NodeKind] {
741        &[NodeKind::Binary]
742    }
743    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
744        let RewriteCtx { lang, walk: _ } = ctx;
745        if lang.kind(id) != NodeKind::Binary {
746            return None;
747        }
748        let op = lang.bin_op(id)?;
749        let ch = lang.children(id);
750        let (l, r) = (*ch.first()?, *ch.get(1)?);
751        let int_lit = |n: L::Id, v: i64| -> bool {
752            matches!(lang.literal(n), Some(l) if l.as_int() == Some(v))
753        };
754        let x = match op {
755            BinOp::Add if int_lit(r, 0) => l,
756            BinOp::Add if int_lit(l, 0) => r,
757            BinOp::Sub if int_lit(r, 0) => l,
758            BinOp::Mul if int_lit(r, 1) => l,
759            BinOp::Mul if int_lit(l, 1) => r,
760            BinOp::Div if int_lit(r, 1) => l,
761            _ => return None,
762        };
763        if !lang.is_exact_int(x) {
764            return None;
765        }
766        Some(Edit::Replace {
767            target: id,
768            with: x,
769        })
770    }
771}
772
773// ---------------------------------------------------------------------------
774// 局部变量传播:
775//   T x = V; …; [唯一一次读 x,且区间内无对相关变量的写、无遮蔽]
776//   → 用 V 替换该次读,删除声明。
777//
778// 安全条件:
779//   - effect(V) ≤ MayRead(纯值/局部读):可自由移动,只要求区间内的
780//     显式局部写不与 V 读到的变量相交;
781//   - effect(V) > MayRead(可能抛/写/未知):仅当声明与唯一使用**相邻**、
782//     使用处于直线语句(return/expr-stmt/assign/throw)、路径无条件求值、
783//     且 use 之前求值的兄弟子树效果 ≤ MayRead 时才内联
784//     (保持 V 先于语句内其他效果求值)。
785// ---------------------------------------------------------------------------
786
787
788/// 语句区间内名字的**句法** VarRef 出现次数(逐节点计数;含赋值目标、
789/// 数组下标基——事件模型对这些位置的读不可见)。传播类规则的引用
790/// 计数兜底。注意与「语句级存在性」区分:同一语句里出现两次要计 2。
791fn count_name_refs<L: Lang>(lang: &L, stmts: &[L::Id], name: &str) -> usize {
792    let mut n: usize = 0;
793    for &s in stmts {
794        count_var_refs(lang, s, name, &mut n);
795    }
796    n
797}
798
799/// null 字面量不可安全内联的使用位:沿 Paren 链向上(Paren 不改变静
800/// 态类型),首遇 Call/New(实参或 callee 位)或 Member/Index/InstanceOf
801/// 头位即拒绝——裸 null 在这些位置丢失声明类型带来的重载消歧依据
802///(`sb.append(null)` 对 append(CharSequence)/append(char[]) 二义),
803/// 或干脆非法(`null.m()`)。Cast 及其余节点重建类型语境 → 安全。
804/// 传播类规则(local/assign)共用的位置门。
805fn null_unsafe_position<L: Lang>(lang: &L, walk: &Walk<L>, use_id: L::Id) -> bool {
806    let mut cur = use_id;
807    while let Some(&(p, _)) = walk.parents.get(&cur) {
808        match lang.kind(p) {
809            NodeKind::Paren => cur = p,
810            NodeKind::Call
811            | NodeKind::New
812            | NodeKind::Member
813            | NodeKind::Index
814            | NodeKind::InstanceOf => return true,
815            _ => return false,
816        }
817    }
818    false
819}
820
821/// 有声明类型的值(VarRef)不可内联进**类型判定位**:cast 操作数与
822/// instanceof 被测式的可转换性依赖被替换变量的静态类型——`Object o =
823/// k3Var; String s = (String) o;` 合法,内联成 `(String) k3Var` 后引用
824/// 类型不相关 → 不可编译(ddc weixin dt/k 复现:R8 宽化赋值的 Object
825/// 中转变量被传播进 narrowing cast)。沿 Paren 链向上,首遇 Cast /
826/// InstanceOf 即命中;其余位置类型语境与变量无关 → 放行。字面量自带
827/// 类型不受此限(null 走 null_unsafe_position)。
828fn typed_position_unsafe<L: Lang>(lang: &L, walk: &Walk<L>, use_id: L::Id) -> bool {
829    let mut cur = use_id;
830    while let Some(&(p, _)) = walk.parents.get(&cur) {
831        match lang.kind(p) {
832            NodeKind::Paren => cur = p,
833            NodeKind::Cast | NodeKind::InstanceOf => return true,
834            _ => return false,
835        }
836    }
837    false
838}
839
840fn count_var_refs<L: Lang>(lang: &L, node: L::Id, name: &str, n: &mut usize) {
841    if lang.kind(node) == NodeKind::VarRef && lang.var_name(node) == Some(name) {
842        *n += 1;
843    }
844    for &c in lang.children(node) {
845        count_var_refs(lang, c, name, n);
846    }
847}
848
849pub struct LocalPropagation;
850
851impl<L: Lang> Rule<L> for LocalPropagation {
852    fn name(&self) -> &'static str {
853        "local_propagation"
854    }
855    fn kinds(&self) -> &'static [NodeKind] {
856        &[NodeKind::VarDecl]
857    }
858    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
859        let RewriteCtx { lang, walk } = ctx;
860        if lang.kind(id) != NodeKind::VarDecl {
861            return None;
862        }
863        let name = lang.var_name(id)?.to_string();
864        let ch = lang.children(id);
865        if ch.len() != 1 {
866            return None; // 必须有且仅有 init
867        }
868        let value = ch[0];
869        // 裸数组字面量只在声明/赋值 RHS 位置合法(Java/多数语言同此);
870        // 传播到任意表达式位置会产出非法源码,且多站点传播会破坏数组对象
871        // 同一性 → 拒绝(显式 new T[]{…} 形态可安全传播)
872        if lang.kind(value) == NodeKind::ArrayLit {
873            return None;
874        }
875        // lambda / 方法引用值:内联进 receiver 位产出非法 Java
876        //((() -> {}).run() / String::length.apply()——对抗波 2 抓获)。
877        // 参数位合法但罕见——统一保守拒绝。
878        if matches!(lang.kind(value), NodeKind::Lambda | NodeKind::MethodRef) {
879            return None;
880        }
881        // 自引用 init(int x = x + 1 之类)直接放弃
882        if subtree_contains(&*lang, value, |n| {
883            lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name.as_str())
884        }) {
885            return None;
886        }
887        let parent = walk.parent(id)?;
888        if lang.kind(parent) != NodeKind::Block {
889            return None;
890        }
891        let index = walk.index(id)?;
892        let stmts: Vec<L::Id> = lang.children(parent).to_vec();
893        if index + 1 > stmts.len() {
894            return None;
895        }
896
897        // 字符类型声明:内联值必须是 Char 字面量(其他 int 型值——字面量
898        // 或表达式——会让 println/拼接观察到 int 而非 char:
899        // `char c = 98; println(c)` 打 'b',内联后打 98)。int 字面量
900        // init 就地转换为 Char 字面量再传播(Java char 域 u16;转换
901        // 随声明删除获得正成本——纯归一化规则过不了严格降本门)。
902        let mut value = value;
903        if lang.is_char_decl(id) {
904            match lang.literal(value) {
905                Some(LitRef::Char(_)) => {}
906                Some(LitRef::Int(v)) => {
907                    // Java char = UTF-16 单元:域 [0, 0xFFFF](代理区也拒,
908                    // 打印不合法)
909                    let c = u32::try_from(v)
910                        .ok()
911                        .filter(|&u| (0..=0xFFFF).contains(&u) && !(0xD800..=0xDFFF).contains(&u))
912                        .and_then(char::from_u32)?;
913                    value = lang.build_char(c);
914                }
915                _ => return None,
916            }
917        }
918        // long 域声明 + int 字面量 init:按 i32 域传播会让后续算术在
919        // i32 环绕(`long n = 5; n + 2147483647` 曾折成 -2147483644,
920        // 正确值 2147483652——边界攻击 t06d 抓获)。就地转 Long 字面量
921        //(5L)传播,const_fold 走 i64 域
922        if lang.is_long_decl(id) {
923            if let Some(LitRef::Int(v)) = lang.literal(value) {
924                value = lang.build_int(v, true);
925            }
926        }
927        // byte/short 窄域声明:Int 字面量内联到**调用实参位**是非法收窄
928        //(JLS 常量收窄仅限赋值上下文——t04h 抓获:eat(127, 1023) 进
929        // byte/short 形参不可编译)。使用位置不可判 → 保守拒绝传播
930        //(char 域已有 Int→Char 转换——Char 字面量到 char 形参合法)
931        if !lang.is_wide_decl(id) && !lang.is_char_decl(id) {
932            return None;
933        }
934
935        // 扫描 decl 之后的区域(用途/遮蔽全区间;写冲突窗口见下)。
936        // 句法引用计数兜底事件盲区:赋值目标内的读(t[k]=… 的 t)
937        // 对事件索引不可见——bd.java 差分抓获:load 被替换而 store
938        // 目标残留,输出引用已删除的变量。
939        let name_str = lang.var_name(id)?.to_string();
940        // **λ 捕获守卫**(jOOQ Tools.hasAmbiguousNames 抓获:`Set names =
941        // new HashSet<>(); return anyMatch(fields, f -> !names.add(...))`
942        // 曾被内联成 `f -> !new HashSet<>().add(...)`——每次谓词新建
943        // Set,add 恒 true,重名检测恒 false)→ 拒绝传播
944        {
945            let mut captured = false;
946            for &st in &stmts[index + 1..] {
947                // λ 体内引用 x → 捕获(延迟/多次求值——内联 init 改变
948                // 求值次数与状态共享)
949                if subtree_contains(&*lang, st, |n| {
950                    if lang.kind(n) == NodeKind::Lambda {
951                        return subtree_contains(&*lang, n, |m| {
952                            lang.kind(m) == NodeKind::VarRef
953                                && lang.var_name(m) == Some(name_str.as_str())
954                        });
955                    }
956                    false
957                }) {
958                    captured = true;
959                    break;
960                }
961            }
962            if captured {
963                return None;
964            }
965        }
966        let syntactic_refs = count_name_refs(&*lang, &stmts[index + 1..], &name_str);
967        if syntactic_refs != 1 {
968            return None;
969        }
970        let name_key = lang.var_key(id)?;
971        let mut wa = Watch::<L>::new(name_key, &[]);
972        for &s in &stmts[index + 1..] {
973            scan_region(&*lang, s, &mut wa);
974        }
975        if wa.opaque || wa.shadowed || wa.uses.len() != 1 {
976            return None;
977        }
978        let use_id = wa.uses[0];
979
980        // 纯自赋值(x = x)形态拒绝传播:让 self_assign 先删。传播会把
981        // RHS 换成声明值制造悬挂写 `i = 1`——store_kill 删声明后
982        // dead_store 因锚点缺失无法清理(golden self_assign_removed
983        // 抓获:期望 keep(); 实得 i = 1; keep();)
984        if let Some(&(p, _)) = walk.parents.get(&use_id) {
985            if lang.kind(p) == NodeKind::Assign && lang.assign_op(p).is_none() {
986                let pch = lang.children(p);
987                if pch.len() == 2
988                    && lang.kind(pch[0]) == NodeKind::VarRef
989                    && lang.var_key(pch[0]) == Some(name_key)
990                    && pch[1] == use_id
991                {
992                    return None;
993                }
994            }
995        }
996        // raw 泛型接收位守卫(Lang 钩子):声明的静态类型与 init 的静态
997        // 类型在成员解析上不等价(Java raw `List l = m(); l.add("x")`
998        // 内联后 CAP#1 硬错——mockito 抓获)。使用位的父/头信息由
999        // walk 提供(Lang 侧无父指针)
1000        {
1001            let (up, head) = match walk.parents.get(&use_id) {
1002                Some(&(p, _)) => {
1003                    (Some(p), lang.children(p).first() == Some(&use_id))
1004                }
1005                None => (None, false),
1006            };
1007            if lang.receiver_propagation_unsound(id, value, up, head) {
1008                return None;
1009            }
1010        }
1011        // null 字面量**与基本类型字面量**不得内联进需要引用类型的表达式
1012        // 位:调用接收者(`null.setArgName(...)` / `65.getClass()`——后者
1013        // R13 P0-2 抓获:`Object o = +c; o.getClass()` 常量传播产出
1014        // `65.getClass()` 非法 Java);for-each 可迭代位;数组访问基座
1015        //(`null[0]`);字段/数组基座同理。字符串字面量接收者合法
1016        //(`"a".length()`)不在拒绝域
1017        if matches!(
1018            lang.literal(value),
1019            Some(
1020                LitRef::Null
1021                    | LitRef::Int(_)
1022                    | LitRef::Long(_)
1023                    | LitRef::Float(_)
1024                    | LitRef::Double(_)
1025                    | LitRef::Char(_)
1026                    | LitRef::Bool(_)
1027            )
1028        ) {
1029            let mut cur = use_id;
1030            while let Some(&(p, _)) = walk.parents.get(&cur) {
1031                let at_head = lang.children(p).first() == Some(&cur);
1032                match lang.kind(p) {
1033                    // null.m() / null[i](Member 基座与 Index 基座)
1034                    NodeKind::Member | NodeKind::Index if at_head => return None,
1035                    // 静态调用 callee 位(防御)
1036                    NodeKind::Call if at_head => return None,
1037                    // instanceof 被测式(R14 族 C 抓获:`Object o = 3.5f;
1038                    // o instanceof Double` 曾内联成 `3.5f instanceof Double`
1039                    // ——基元模式预览语法不可编译)
1040                    NodeKind::InstanceOf if at_head => return None,
1041                    // for-each 可迭代位(ForEach 的第 1 个孩子 = iterable)
1042                    NodeKind::ForEach => {
1043                        let ch = lang.children(p);
1044                        if ch.first() == Some(&cur) {
1045                            return None;
1046                        }
1047                    }
1048                    // synchronized (null…) 锁位(唯一孩子)
1049                    NodeKind::Synchronized => {
1050                        let ch = lang.children(p);
1051                        if ch.len() == 1 && ch[0] == cur {
1052                            return None;
1053                        }
1054                    }
1055                    _ => {}
1056                }
1057                cur = p;
1058            }
1059        }
1060        // null 字面量实参位:`String s = null; sb.append(s)` 合法——s 的
1061        // 声明类型是重载消歧依据;内联成 `sb.append(null)` 后
1062        // append(CharSequence) 与 append(char[]) 二义,不可编译
1063        //(ddc 输出 PurchasesOrchestrator 复现:R8 null 复位赋值 + 单次
1064        // 使用恰好落在重载族调用上)。沿 Paren 链向上(Paren 不改变静
1065        // 态类型),首遇 Call/New 实参位即拒绝;Cast 及其余节点重建类
1066        // 型语境(`(String) s` 重新钉住重载)→ 放行
1067        if matches!(lang.literal(value), Some(LitRef::Null))
1068            && null_unsafe_position(&*lang, walk, use_id)
1069        {
1070            return None;
1071        }
1072        // VarRef 值不得内联进 cast/instanceof 类型判定位(声明类型即合法
1073        // 性依据——同 null 实参位的族)
1074        if lang.kind(value) == NodeKind::VarRef
1075            && typed_position_unsafe(&*lang, walk, use_id)
1076        {
1077            return None;
1078        }
1079        // value 读到的名字键(写冲突兴趣集;reads 含 name 自身——一票否决)
1080        let mut watch_keys: Vec<L::NameKey> = Vec::new();
1081        collect_read_keys(&*lang, value, &mut watch_keys);
1082        watch_keys.push(name_key);
1083        // 写冲突窗口 = [decl 后, 使用语句]:纯值移动到使用点,
1084        // 使用点之后的写不影响(值已被消费)。首个含 use 的语句即使用语句
1085        //(uses[0] 是遍历序首个读,与 subtree_contains 等价)
1086        let mut wb = Watch::<L>::new(name_key, &watch_keys);
1087        let mut use_stmt_idx = None;
1088        for (off, &s) in stmts[index + 1..].iter().enumerate() {
1089            let uses_before = wb.uses.len();
1090            scan_region(&*lang, s, &mut wb);
1091            if wb.uses.len() > uses_before {
1092                use_stmt_idx = Some(index + 1 + off);
1093                break; // 使用语句之后的写不参与冲突判定
1094            }
1095        }
1096        // 字段读移动守卫:值中含**非局部** VarRef(可变字段——跨调用/跨
1097        // 线程可变):把读从声明点移动到使用点会改变读时机(d.java 抓获:
1098        // `boolean var2 = b; for (a var1 : a()) { var1.i(); if (var2)… }` 折
1099        // 成 if (b)——入口快照变成每次调用后现读,b 有跨文件写点)。
1100        // 窗口内语句须全 Pure(无调用/无写/无读)。
1101        // Call 的 callee VarRef 是方法名(不同命名空间)——不算字段读
1102        if subtree_contains(&*lang, value, |n| {
1103            if lang.kind(n) != NodeKind::VarRef || lang.is_local_var(n) {
1104                return false;
1105            }
1106            // 仅**本单元声明的字段**(局部/参数/未解析名——如手工 AST
1107            // 无作用域——不算)
1108            if !lang.var_name(n).is_some_and(|nm| lang.is_field_name(nm)) {
1109                return false;
1110            }
1111            let is_callee = match walk.parent(n) {
1112                Some(p) => {
1113                    matches!(lang.kind(p), NodeKind::Call) && lang.children(p).first() == Some(&n)
1114                }
1115                None => false,
1116            };
1117            !is_callee
1118        }) {
1119            if let Some(ui) = use_stmt_idx {
1120                for &s in &stmts[index + 1..=ui] {
1121                    if lang.effect(s) != Effect::Pure {
1122                        return None;
1123                    }
1124                }
1125            }
1126        }
1127        // 声明删除前提:use 之后不得再出现对该名字的任何引用(读/写/遮蔽)。
1128        // 值的传播只关心窗口内写,但**删声明**要求名字彻底无残留引用——
1129        // 使用点之后的死写(如 v = "y")同样引用声明,残留会让输出失去声明。
1130        if let Some(ui) = use_stmt_idx {
1131            // 句法版:任何残留引用(含事件不可见的目标位)都拒绝删声明
1132            if count_name_refs(&*lang, &stmts[ui + 1..], &name_str) != 0 {
1133                return None;
1134            }
1135            let mut wc = Watch::<L>::new(name_key, &[name_key]);
1136            for &s in &stmts[ui + 1..] {
1137                scan_region(&*lang, s, &mut wc);
1138                if wc.opaque || !wc.uses.is_empty() || wc.wrote(name_key) || wc.shadowed {
1139                    return None;
1140                }
1141            }
1142        }
1143        let ve = lang.effect(value);
1144
1145        if ve <= Effect::MayRead {
1146            // 自由移动:区间内的显式局部写不得触碰 V 读到的变量
1147            // (对声明变量自身的写也包含在 writes 里,一票否决)
1148            if let Some(target_key) =
1149                use_stmt_target_write_key(&*lang, &stmts[index + 1..], use_id)
1150            {
1151                wb.clear_wrote(target_key);
1152            }
1153            if wb.opaque || wb.any_write() {
1154                return None;
1155            }
1156            return Some(Edit::Multi(vec![
1157                Edit::Replace {
1158                    target: use_id,
1159                    with: value,
1160                },
1161                Edit::Delete { node: id },
1162            ]));
1163        }
1164
1165        // 有副作用的 V:只允许相邻 + 直线 + 前缀可读
1166        if index + 1 >= stmts.len() {
1167            return None;
1168        }
1169        let stmt = stmts[index + 1];
1170        if !subtree_contains(&*lang, stmt, |n| n == use_id) {
1171            return None;
1172        }
1173        match lang.kind(stmt) {
1174            // VarDecl 同样合法:init 就是语句的全部求值,V 内联进 init 的
1175            // 求值时机与原声明位置一致(相邻保证无插入效果)
1176            NodeKind::Return
1177            | NodeKind::ExprStmt
1178            | NodeKind::Assign
1179            | NodeKind::Throw
1180            | NodeKind::VarDecl => {}
1181            _ => return None,
1182        }
1183        if !straight_path(&*lang, stmt, use_id) {
1184            return None;
1185        }
1186        if !prefix_effects_readable(&*lang, stmt, use_id) {
1187            return None;
1188        }
1189        Some(Edit::Multi(vec![
1190            Edit::Replace {
1191                target: use_id,
1192                with: value,
1193            },
1194            Edit::Delete { node: id },
1195        ]))
1196    }
1197}
1198
1199/// 区域扫描观察:主名字的读 + 小兴趣集的写命中 + 同名遮蔽。
1200///
1201/// 规则预先声明感兴趣的**写名字**(通常 ≤4:主名字 + value 读到的变量),
1202/// 收集期直接判中——零哈希、零集合重建。对比旧版:每次检查重建
1203/// `HashSet<&str>`(分配/重哈希/释放)曾占 release 运行时间 ~50%。
1204pub(crate) struct Watch<L: Lang> {
1205    /// 区域含不透明(Raw)内容:读/写集不可证明——所有守卫保守拒绝
1206    opaque: bool,
1207    /// 主名字键:读收集 + 遮蔽判定(整数等值比较)
1208    name: L::NameKey,
1209    /// 写冲突兴趣名字键(典型 2~4 个)
1210    watch: Vec<L::NameKey>,
1211    /// 与 watch 一一对应:窗口内是否出现过该名字的写
1212    writes_hit: Vec<bool>,
1213    shadowed: bool,
1214    /// 主名字的读(遍历序)
1215    uses: Vec<L::Id>,
1216}
1217
1218impl<L: Lang> Watch<L> {
1219    pub(crate) fn new(name: L::NameKey, watch: &[L::NameKey]) -> Self {
1220        Watch {
1221            opaque: false,
1222            name,
1223            watch: watch.to_vec(),
1224            writes_hit: vec![false; watch.len()],
1225            shadowed: false,
1226            uses: Vec::new(),
1227        }
1228    }
1229    /// 名字键 `k` 在窗口内是否被写(聚合判断)
1230    pub(crate) fn wrote(&self, k: L::NameKey) -> bool {
1231        self.watch
1232            .iter()
1233            .zip(&self.writes_hit)
1234            .any(|(w, h)| *h && *w == k)
1235    }
1236    /// 任一兴趣名字被写
1237    pub(crate) fn any_write(&self) -> bool {
1238        self.writes_hit.iter().any(|h| *h)
1239    }
1240    /// 清除对 `k` 的写命中(use 语句自身对目标的写不参与冲突判定)
1241    pub(crate) fn clear_wrote(&mut self, k: L::NameKey) {
1242        for (w, h) in self.watch.iter().zip(self.writes_hit.iter_mut()) {
1243            if *w == k {
1244                *h = false;
1245            }
1246        }
1247    }
1248}
1249
1250/// 扫描一个语句子树:主名字的**读**、兴趣名字的**写命中**、同名声明遮蔽。
1251fn scan_region<L: Lang>(lang: &L, node: L::Id, w: &mut Watch<L>) {
1252    lang.debug_verify_events(node);
1253    if let Some(events) = lang.region_events(node) {
1254        // 主名字区间:Use 收集 + Shadow 命中 + Write 命中(name 可能在 watch 里)
1255        let lo = events.partition_point(|e| e.key < w.name);
1256        let hi = events.partition_point(|e| e.key <= w.name);
1257        for e in &events[lo..hi] {
1258            match e.kind {
1259                crate::kind::EventKind::Use => w.uses.push(e.node),
1260                crate::kind::EventKind::Shadow => w.shadowed = true,
1261                crate::kind::EventKind::Write => {
1262                    for (wn, hit) in w.watch.iter().zip(w.writes_hit.iter_mut()) {
1263                        if *wn == w.name {
1264                            *hit = true;
1265                        }
1266                    }
1267                }
1268                // 防御:索引层保证含 Raw 的语句不建索引(键排序分区看不见
1269                // Opaque 键),此处理论上不可达
1270                crate::kind::EventKind::Opaque => w.opaque = true,
1271            }
1272        }
1273        // 其余 watch 键区间:只找 Write
1274        for (i, wk) in w.watch.iter().enumerate() {
1275            if *wk == w.name {
1276                continue; // 已随主名字区间处理
1277            }
1278            let lo = events.partition_point(|e| e.key < *wk);
1279            let hi = events.partition_point(|e| e.key <= *wk);
1280            for e in &events[lo..hi] {
1281                if e.kind == crate::kind::EventKind::Write {
1282                    w.writes_hit[i] = true;
1283                    break; // 区间内任一 Write 即命中
1284                }
1285            }
1286        }
1287        return;
1288    }
1289    // 递归路径也查不透明(索引被失效后落到此处的防御)
1290    if lang.is_opaque(node) {
1291        w.opaque = true;
1292        return;
1293    }
1294    // 无索引语言:原递归遍历(事件序一致;键比较同上)
1295    match lang.kind(node) {
1296        NodeKind::Assign => {
1297            let ch = lang.children(node);
1298            if let Some(&t) = ch.first() {
1299                if lang.kind(t) == NodeKind::VarRef {
1300                    if let Some(k) = lang.var_key(t) {
1301                        for (wn, hit) in w.watch.iter().zip(w.writes_hit.iter_mut()) {
1302                            if *wn == k {
1303                                *hit = true;
1304                            }
1305                        }
1306                    }
1307                }
1308            }
1309            if let Some(&v) = ch.get(1) {
1310                scan_region(lang, v, w);
1311            }
1312        }
1313        NodeKind::Unary if lang.un_op(node).is_some_and(|o| o.is_incdec()) => {
1314            let ch = lang.children(node);
1315            if let Some(&t) = ch.first() {
1316                if lang.kind(t) == NodeKind::VarRef {
1317                    if let Some(k) = lang.var_key(t) {
1318                        for (wn, hit) in w.watch.iter().zip(w.writes_hit.iter_mut()) {
1319                            if *wn == k {
1320                                *hit = true;
1321                            }
1322                        }
1323                    }
1324                }
1325            }
1326        }
1327        NodeKind::VarDecl => {
1328            if let Some(k) = lang.var_key(node) {
1329                if k == w.name {
1330                    w.shadowed = true;
1331                }
1332                for (wn, hit) in w.watch.iter().zip(w.writes_hit.iter_mut()) {
1333                    if *wn == k {
1334                        *hit = true;
1335                    }
1336                }
1337            }
1338            for &c in lang.children(node) {
1339                scan_region(lang, c, w);
1340            }
1341        }
1342        // ForEach 循环变量 / Catch 绑定:在子作用域声明了同名变量 → 视为遮蔽;
1343        // ForEach 每轮给循环变量赋值 → 也算显式写。
1344        NodeKind::ForEach | NodeKind::Catch => {
1345            if let Some(k) = lang.var_key(node) {
1346                if k == w.name {
1347                    w.shadowed = true;
1348                }
1349                if lang.kind(node) == NodeKind::ForEach {
1350                    for (wn, hit) in w.watch.iter().zip(w.writes_hit.iter_mut()) {
1351                        if *wn == k {
1352                            *hit = true;
1353                        }
1354                    }
1355                }
1356            }
1357            for &c in lang.children(node) {
1358                scan_region(lang, c, w);
1359            }
1360        }
1361        NodeKind::VarRef => {
1362            if lang.var_key(node) == Some(w.name) {
1363                w.uses.push(node);
1364            }
1365        }
1366        NodeKind::Raw => {
1367            // 不可解析原文:读/写集未知
1368            w.opaque = true;
1369        }
1370        _ => {
1371            for &c in lang.children(node) {
1372                scan_region(lang, c, w);
1373            }
1374        }
1375    }
1376}
1377
1378/// root → target 的路径上不得有条件求值结构(Ternary / If / 短路右支)。
1379fn straight_path<L: Lang>(lang: &L, root: L::Id, target: L::Id) -> bool {
1380    fn go<L: Lang>(lang: &L, node: L::Id, target: L::Id) -> bool {
1381        if node == target {
1382            return true;
1383        }
1384        match lang.kind(node) {
1385            NodeKind::Ternary | NodeKind::If => return false,
1386            NodeKind::Binary if lang.bin_op(node).is_some_and(|o| o.is_short_circuit()) => {
1387                return false
1388            }
1389            _ => {}
1390        }
1391        for &c in lang.children(node) {
1392            if subtree_contains(lang, c, |n| n == target) {
1393                return go(lang, c, target);
1394            }
1395        }
1396        false
1397    }
1398    go(lang, root, target)
1399}
1400
1401
1402// ---------------------------------------------------------------------------
1403// 短路折叠:
1404//   false && x → false / true || x → true(x 原本就不求值,恒安全)
1405//   true && x → x / false || x → x / x && true → x / x || false → x(x 保留,恒安全)
1406//   x && false → false / x || true → true(x 的求值被丢弃,需 effect ≤ MayRead)
1407// ---------------------------------------------------------------------------
1408
1409pub struct BoolShortCircuit;
1410
1411impl<L: Lang> Rule<L> for BoolShortCircuit {
1412    fn name(&self) -> &'static str {
1413        "bool_short_circuit"
1414    }
1415    fn kinds(&self) -> &'static [NodeKind] {
1416        &[NodeKind::Binary]
1417    }
1418    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1419        let RewriteCtx { lang, walk: _ } = ctx;
1420        if lang.kind(id) != NodeKind::Binary {
1421            return None;
1422        }
1423        let op = lang.bin_op(id)?;
1424        if !op.is_short_circuit() {
1425            return None;
1426        }
1427        let ch = lang.children(id);
1428        let (l, r) = (*ch.first()?, *ch.get(1)?);
1429        let is_lit = |n: L::Id, v: bool| matches!(lang.literal(n), Some(LitRef::Bool(b)) if b == v);
1430        // 左侧字面量:短路后 x 可能根本不求值 → 直接取字面量结果
1431        let with = match (op, is_lit(l, true), is_lit(l, false)) {
1432            (BinOp::And, _, true) => l,  // false && x → false(x 不求值)
1433            (BinOp::Or, true, _) => l,   // true || x → true(x 不求值)
1434            (BinOp::And, true, _) => r,  // true && x → x
1435            (BinOp::Or, _, true) => r,   // false || x → x
1436            _ => {
1437                // 右侧字面量:x && true → x / x || false → x(x 保留求值,恒安全);
1438                // x && false → false / x || true → true(x 的求值被丢弃,需可丢弃)
1439                match (op, is_lit(r, true), is_lit(r, false)) {
1440                    (BinOp::And, true, _) => l,
1441                    (BinOp::Or, _, true) => l,
1442                    (BinOp::And, _, true) | (BinOp::Or, true, _)
1443                        if lang.effect(l) <= Effect::MayRead => {
1444                            r
1445                        }
1446                    _ => return None,
1447                }
1448            }
1449        };
1450        Some(Edit::Replace {
1451            target: id,
1452            with,
1453        })
1454    }
1455}
1456
1457// ---------------------------------------------------------------------------
1458// 比较取反:!(a == b) → a != b(恒安全,含 NaN/引用);
1459// !(a < b) → a >= b 等次序比较仅精确整数(浮点 NaN 下不成立)。
1460// ---------------------------------------------------------------------------
1461
1462pub struct NotCompare;
1463
1464impl<L: Lang> Rule<L> for NotCompare {
1465    fn name(&self) -> &'static str {
1466        "not_compare"
1467    }
1468    fn kinds(&self) -> &'static [NodeKind] {
1469        &[NodeKind::Unary]
1470    }
1471    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1472        let RewriteCtx { lang, walk: _ } = ctx;
1473        if lang.kind(id) != NodeKind::Unary || lang.un_op(id) != Some(UnOp::Not) {
1474            return None;
1475        }
1476        let inner = *lang.children(id).first()?;
1477        if lang.kind(inner) != NodeKind::Binary {
1478            return None;
1479        }
1480        let op = lang.bin_op(inner)?;
1481        let neg = match op {
1482            BinOp::Eq => BinOp::Ne,
1483            BinOp::Ne => BinOp::Eq,
1484            BinOp::Lt => BinOp::Ge,
1485            BinOp::Le => BinOp::Gt,
1486            BinOp::Gt => BinOp::Le,
1487            BinOp::Ge => BinOp::Lt,
1488            _ => return None,
1489        };
1490        if op.is_short_circuit() {
1491            return None;
1492        }
1493        // 次序比较的取反仅对精确整数成立(NaN: !(a<b)=true 但 a>=b=false)
1494        if matches!(op, BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) {
1495            let ch = lang.children(inner);
1496            if !lang.is_exact_int(*ch.first()?) || !lang.is_exact_int(*ch.get(1)?) {
1497                return None;
1498            }
1499        }
1500        let ch = lang.children(inner).to_vec();
1501        let rebuilt = lang.build_bin(neg, ch[0], ch[1]);
1502        Some(Edit::Replace {
1503            target: id,
1504            with: rebuilt,
1505        })
1506    }
1507}
1508
1509// ---------------------------------------------------------------------------
1510// 三元折叠:true ? a : b → a;false ? a : b → b(另一支原本不求值,恒安全);
1511//           c ? a : a → a(c 的求值被丢弃,需 effect ≤ MayRead)
1512// ---------------------------------------------------------------------------
1513
1514/// 折臂敏感位:从 `id` 向上穿过 Paren/Ternary(类型透明链),最终落在
1515/// **推断声明**(Java 10 `var`)的 init 上 → true。var 的静态类型由整个
1516/// init 表达式推断(三元 = lub(两臂))——折臂改类型。其余容器(实参/
1517/// 二元操作数/Cast/λ 体)的静态类型由外层结构决定,内层折臂不影响推断。
1518fn in_inferred_var_init<L: Lang>(lang: &L, walk: &Walk<L>, mut id: L::Id) -> bool {
1519    while let Some(&(p, _)) = walk.parents.get(&id) {
1520        match lang.kind(p) {
1521            NodeKind::Paren | NodeKind::Ternary => id = p,
1522            NodeKind::VarDecl => return lang.is_inferred_decl(p),
1523            _ => return false,
1524        }
1525    }
1526    false
1527}
1528
1529pub struct TernaryFold;
1530
1531impl<L: Lang> Rule<L> for TernaryFold {
1532    fn name(&self) -> &'static str {
1533        "ternary_fold"
1534    }
1535    fn kinds(&self) -> &'static [NodeKind] {
1536        &[NodeKind::Ternary]
1537    }
1538    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1539        let RewriteCtx { lang, walk } = ctx;
1540        if lang.kind(id) != NodeKind::Ternary {
1541            return None;
1542        }
1543        let ch = lang.children(id);
1544        let (c, a, b) = (*ch.first()?, *ch.get(1)?, *ch.get(2)?);
1545        match lang.literal(c) {
1546            // R15 P0-1(ClassNotFoundExceptionDueToPrunedCodeTest o1/o2)
1547            // 抓获:`var o1 = false ? new Object(){} : null` 曾折成
1548            // `var o1 = null`——var 推断从匿名类类型变 null 类型,
1549            // `o1 == o1` 不可编译。推断声明 init 位(类型透明链上)
1550            // 拒绝折臂。
1551            Some(LitRef::Bool(true)) => {
1552                if !in_inferred_var_init(&*lang, walk, id) {
1553                    return Some(Edit::Replace { target: id, with: a });
1554                }
1555            }
1556            Some(LitRef::Bool(false))
1557                if !in_inferred_var_init(&*lang, walk, id) => {
1558                    return Some(Edit::Replace { target: id, with: b });
1559                }
1560            _ => {}
1561        }
1562        // c ? a : a:两臂结构全同 → 折叠不改变静态类型(lub(a,a)=a),
1563        // var init 位同样安全
1564        if crate::analysis::structurally_equal(&*lang, a, b) && lang.effect(c) <= Effect::MayRead {
1565            return Some(Edit::Replace { target: id, with: a });
1566        }
1567        None
1568    }
1569}
1570
1571// ---------------------------------------------------------------------------
1572// 三元布尔:c ? true : false → c;c ? false : true → !c(c 为原始 boolean)
1573// ---------------------------------------------------------------------------
1574
1575pub struct TernaryBool;
1576
1577impl<L: Lang> Rule<L> for TernaryBool {
1578    fn name(&self) -> &'static str {
1579        "ternary_bool"
1580    }
1581    fn kinds(&self) -> &'static [NodeKind] {
1582        &[NodeKind::Ternary]
1583    }
1584    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1585        let RewriteCtx { lang, walk: _ } = ctx;
1586        if lang.kind(id) != NodeKind::Ternary {
1587            return None;
1588        }
1589        let ch = lang.children(id);
1590        let (c, a, b) = (*ch.first()?, *ch.get(1)?, *ch.get(2)?);
1591        let lb = |n: L::Id| matches!(lang.literal(n), Some(LitRef::Bool(v)) if v);
1592        let is_false = |n: L::Id| matches!(lang.literal(n), Some(LitRef::Bool(v)) if !v);
1593        if !lang.is_bool(c) {
1594            return None;
1595        }
1596        let with = if lb(a) && is_false(b) {
1597            c
1598        } else if is_false(a) && lb(b) {
1599            lang.build_unary(UnOp::Not, c)
1600        } else {
1601            return None;
1602        };
1603        Some(Edit::Replace {
1604            target: id,
1605            with,
1606        })
1607    }
1608}
1609
1610// ---------------------------------------------------------------------------
1611// 整数常量折叠 + 字符串拼接:形态匹配在引擎(双字面量 + 非短路/比较
1612// 算符),数值/拼接**语义**全权在 Lang::fold_lit_bin(Java:JLS i32/i64
1613// 环绕 + 移位掩码 + 除零不折 + "a"+1 拼接;其他语言各自定义)。
1614// ---------------------------------------------------------------------------
1615
1616pub struct ConstFoldBin;
1617
1618impl<L: Lang> Rule<L> for ConstFoldBin {
1619    fn name(&self) -> &'static str {
1620        "const_fold_bin"
1621    }
1622    fn kinds(&self) -> &'static [NodeKind] {
1623        &[NodeKind::Binary]
1624    }
1625    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1626        let RewriteCtx { lang, walk: _ } = ctx;
1627        if lang.kind(id) != NodeKind::Binary {
1628            return None;
1629        }
1630        let op = lang.bin_op(id)?;
1631        if op.is_short_circuit() || op.is_comparison() {
1632            return None;
1633        }
1634        let ch = lang.children(id);
1635        let (l, r) = (*ch.first()?, *ch.get(1)?);
1636        // 双字面量才考虑折叠(具体哪些组合可折由语言语义决定)
1637        lang.literal(l)?;
1638        lang.literal(r)?;
1639        let with = lang.fold_lit_bin(op, l, r)?;
1640        Some(Edit::Replace {
1641            target: id,
1642            with,
1643        })
1644    }
1645}
1646
1647// ---------------------------------------------------------------------------
1648// 零元素 / 平凡算术:
1649//   0 * x → 0、x * 0 → 0(x 求值被丢弃:需 effect ≤ MayRead 且精确整数——
1650//     浮点 0.0*NaN=NaN)
1651//   x - x → 0(同名局部整型变量)
1652//   x << 0 / x >> 0 / x >>> 0 → x(位移 0 恒等,x 保留,恒安全)
1653// ---------------------------------------------------------------------------
1654
1655pub struct ArithZero;
1656
1657impl<L: Lang> Rule<L> for ArithZero {
1658    fn name(&self) -> &'static str {
1659        "arith_zero"
1660    }
1661    fn kinds(&self) -> &'static [NodeKind] {
1662        &[NodeKind::Binary]
1663    }
1664    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1665        let RewriteCtx { lang, walk: _ } = ctx;
1666        if lang.kind(id) != NodeKind::Binary {
1667            return None;
1668        }
1669        let op = lang.bin_op(id)?;
1670        let ch = lang.children(id);
1671        let (l, r) = (*ch.first()?, *ch.get(1)?);
1672        let int_lit = |n: L::Id, v: i64| lang.literal(n).and_then(|x| x.as_int()) == Some(v);
1673
1674        // 移位 0:x << 0 → x(恒等)
1675        if matches!(op, BinOp::Shl | BinOp::Shr | BinOp::UShr) && int_lit(r, 0) {
1676            return Some(Edit::Replace {
1677                target: id,
1678                with: l,
1679            });
1680        }
1681        // 0 * x → 0 / x * 0 → 0
1682        if op == BinOp::Mul {
1683            let (zero, other) = if int_lit(l, 0) {
1684                (l, r)
1685            } else if int_lit(r, 0) {
1686                (r, l)
1687            } else {
1688                return None;
1689            };
1690            if !lang.is_exact_int(other) || lang.effect(other) > Effect::MayRead {
1691                return None;
1692            }
1693            return Some(Edit::Replace {
1694                target: id,
1695                with: zero,
1696            });
1697        }
1698        // x - x → 0(同名局部变量,整型)
1699        if op == BinOp::Sub
1700            && lang.kind(l) == NodeKind::VarRef
1701            && lang.kind(r) == NodeKind::VarRef
1702            && lang.var_name(l) == lang.var_name(r)
1703            && lang.is_local_var(l)
1704            && lang.is_exact_int(l)
1705        {
1706            let with = lang.build_int(0, false);
1707            return Some(Edit::Replace {
1708                target: id,
1709                with,
1710            });
1711        }
1712        None
1713    }
1714}
1715
1716// ---------------------------------------------------------------------------
1717// 死赋值:x = a; x = b; → x = b;(a 的求值被丢弃:局部变量 x + effect(a) ≤ MayRead)
1718// 含声明形:int x = a; x = b; → int x = b;
1719// ---------------------------------------------------------------------------
1720
1721
1722// ---------------------------------------------------------------------------
1723// 逆运算对抵消(寄存器噪声):`x op= K;` 紧跟 `x op⁻¹= K;`(同局部变量、
1724// 同字面量常量、相邻语句、精确整型)→ 两条全删。
1725//   `x += K; x -= K` → 删(模 2^w 加法群恒等)
1726//   `x ^= K; x ^= K` → 删(XOR 自逆)
1727//   `x -= K; x += K` → 删(对称)
1728// 展开形态 `x = x + K; x = x - K`(RHS = Binary(x op K))与混合形态
1729// (`x += K; x = x - K`)同样处理——反编译器常输出展开形态。
1730// 相邻 ⇒ 两句之间无任何求值 ⇒ 删除恒安全(x 终值不变;x 的旧值
1731// 不被其他求值观察到)。
1732// 守卫:x 为局部变量(is_local_var——字段写有可见副作用);K 为
1733// 无副作用字面量;x 精确整型(浮点 (x+K)-K 在溢出/Inf 上 ≠ x)。
1734// 真实样本:PMD 语料 PMDTaskTestExample.java(a+=1; a-=1 交替 50 次
1735// 完全不动——寄存器噪声经典形态,109 行全为噪声)。
1736// ---------------------------------------------------------------------------
1737
1738pub struct InverseAssignPair;
1739
1740impl<L: Lang> Rule<L> for InverseAssignPair {
1741    fn name(&self) -> &'static str {
1742        "inverse_assign_pair"
1743    }
1744    fn kinds(&self) -> &'static [NodeKind] {
1745        &[NodeKind::Block]
1746    }
1747    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1748        let RewriteCtx { lang, .. } = ctx;
1749        let ch = lang.children(id).to_vec();
1750        if ch.len() < 2 {
1751            return None;
1752        }
1753        for w in 0..ch.len() - 1 {
1754            let (s1, s2) = (ch[w], ch[w + 1]);
1755            // 窗口左端不是赋值语句 → 滑到下一窗口(不能整check放弃)
1756            let Some(a1) = norm_assign(lang, s1) else { continue };
1757            let Some(a2) = norm_assign(lang, s2) else { continue };
1758            // 同一局部变量(名字键等值)
1759            if a1.key != a2.key || !a1.local || !a2.local {
1760                continue;
1761            }
1762            // 精确整型(模 2^w 群恒等性成立;浮点舍入破坏交换律)
1763            if !a1.exact_int || !a2.exact_int {
1764                continue;
1765            }
1766            // 同一常量 + 互逆算符
1767            if a1.k != a2.k {
1768                continue;
1769            }
1770            let inverse = match (a1.op, a2.op) {
1771                (BinOp::Add, BinOp::Sub) | (BinOp::Sub, BinOp::Add) => true,
1772                (BinOp::BitXor, BinOp::BitXor) => true,
1773                _ => false,
1774            };
1775            if !inverse {
1776                continue;
1777            }
1778            // 删除两条语句:先删靠后的(索引不失效),再删靠前的
1779            return Some(Edit::Multi(vec![
1780                Edit::Delete { node: s2 },
1781                Edit::Delete { node: s1 },
1782            ]));
1783        }
1784        None
1785    }
1786}
1787
1788/// 归一化一条赋值语句 → `(变量键, 算符, 常量)`。
1789/// 接受复合形态(`x op= K`,RHS 即字面量)与展开形态(`x = x op K`,
1790/// RHS = Binary{op, VarRef(x), K})。
1791struct NormAssign<K> {
1792    key: K,
1793    op: BinOp,
1794    k: i64,
1795    local: bool,
1796    /// 精确整型(浮点 (x+K)-K 在舍入/Inf 上 ≠ x,必须拒绝)
1797    exact_int: bool,
1798}
1799
1800fn norm_assign<L: Lang>(lang: &L, stmt: L::Id) -> Option<NormAssign<L::NameKey>> {
1801    // 语句形态:ExprStmt{Assign} 或裸 Assign
1802    let a = match lang.kind(stmt) {
1803        NodeKind::ExprStmt => {
1804            let c = lang.children(stmt);
1805            if c.len() == 1 && lang.kind(c[0]) == NodeKind::Assign {
1806                c[0]
1807            } else {
1808                return None;
1809            }
1810        }
1811        NodeKind::Assign => stmt,
1812        _ => return None,
1813    };
1814    let ch = lang.children(a).to_vec();
1815    if ch.len() != 2 {
1816        return None;
1817    }
1818    let (target, rhs) = (ch[0], ch[1]);
1819    if lang.kind(target) != NodeKind::VarRef {
1820        return None;
1821    }
1822    let key = lang.var_key(target)?;
1823    let local = lang.is_local_var(target);
1824    let exact_int = lang.is_exact_int(target);
1825    // RHS 的求值效果:字面量 Pure;Binary(VarRef, lit) 是 Pure/MayRead——
1826    // 展开形态对 x 旧值的读正是我们要抵消的一部分(两句间的观察点
1827    // 为空),但 Binary 内若非纯形态拒绝
1828    match lang.assign_op(a) {
1829        // 复合形态:`x op= K`——RHS 就是操作数
1830        Some(op) => {
1831            let k = lang.literal(rhs).and_then(|x| x.as_int())?;
1832            Some(NormAssign { key, op, k, local, exact_int })
1833        }
1834        // 展开形态:`x = x op K`——RHS = Binary{op, VarRef(x), K}
1835        None => {
1836            if lang.kind(rhs) != NodeKind::Binary {
1837                return None;
1838            }
1839            let op = lang.bin_op(rhs)?;
1840            let rc = lang.children(rhs).to_vec();
1841            if rc.len() != 2 {
1842                return None;
1843            }
1844            // 左操作数必须是 x 自身(名字键等值)
1845            if lang.kind(rc[0]) != NodeKind::VarRef || lang.var_key(rc[0]) != Some(key) {
1846                return None;
1847            }
1848            let k = lang.literal(rc[1]).and_then(|x| x.as_int())?;
1849            Some(NormAssign { key, op, k, local, exact_int })
1850        }
1851    }
1852}
1853
1854pub struct DeadStore;
1855
1856impl<L: Lang> Rule<L> for DeadStore {
1857    fn name(&self) -> &'static str {
1858        "dead_store"
1859    }
1860    fn kinds(&self) -> &'static [NodeKind] {
1861        &[NodeKind::VarDecl, NodeKind::Assign, NodeKind::ExprStmt]
1862    }
1863    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
1864        let RewriteCtx { lang, walk } = ctx;
1865        // 归一化第一条语句:VarDecl / Assign / ExprStmt{Assign}
1866        let (decl_form, first_assign) = match lang.kind(id) {
1867            NodeKind::VarDecl => {
1868                if lang.children(id).is_empty() {
1869                    return None; // 无 init 的声明不适用
1870                }
1871                (true, None)
1872            }
1873            NodeKind::Assign => (false, Some(id)),
1874            NodeKind::ExprStmt => {
1875                let ch = lang.children(id);
1876                if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
1877                    (false, Some(ch[0]))
1878                } else {
1879                    return None;
1880                }
1881            }
1882            _ => return None,
1883        };
1884        let first_value = if decl_form {
1885            *lang.children(id).first()?
1886        } else {
1887            let a = first_assign?;
1888            if lang.assign_op(a).is_some() {
1889                return None; // 复合赋值有读语义
1890            }
1891            *lang.children(a).get(1)?
1892        };
1893
1894        // 父 Block + 相邻下一条语句
1895        let parent = walk.parent(id)?;
1896        if lang.kind(parent) != NodeKind::Block {
1897            return None;
1898        }
1899        let idx = walk.index(id)?;
1900        let stmts = lang.children(parent).to_vec();
1901        let next_stmt = *stmts.get(idx + 1)?;
1902
1903        // 归一化第二条语句:Assign / ExprStmt{Assign}(简单赋值);
1904        // 不是赋值 → 落入「零用途死存储」形态(见下)
1905        let second = match lang.kind(next_stmt) {
1906            NodeKind::Assign => Some(next_stmt),
1907            NodeKind::ExprStmt => {
1908                let ch = lang.children(next_stmt);
1909                if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
1910                    Some(ch[0])
1911                } else {
1912                    None
1913                }
1914            }
1915            _ => None,
1916        };
1917        let Some(second) = second else {
1918            // 零用途死存储:后继对该变量**无读且无写**(含遮蔽重声明),
1919            // 存入的值永不流出 → 整条删除。值效果 ≤ MayRead 才可丢弃。
1920            // (批量化后可达的形态:传播先消费了击杀写,init 残留为死值;
1921            //   旧逐编辑时序下由相邻对形态逐步吸收,未暴露此缺口。)
1922            // **作用域前提**:名字必须声明于本块(块级作用域,出块不可见)。
1923            // 外层声明的名字可能在本块之后被外层代码读取(if/while 分支里
1924            // 对外层变量的赋值就是典型)→ 扫描只覆盖本块尾部,必须拒绝。
1925            // (property.rs seed=29 的随机程序抓获此漏洞。)
1926            let (name_node, target_local) = if decl_form {
1927                (id, true)
1928            } else {
1929                let t = *lang.children(first_assign?).first()?;
1930                if lang.kind(t) != NodeKind::VarRef {
1931                    return None;
1932                }
1933                (t, lang.is_local_var(t))
1934            };
1935            // 赋值形态:目标必须是本局部(声明形态天然是局部)
1936            if !target_local {
1937                return None;
1938            }
1939            let name = lang.var_name(name_node)?.to_string();
1940            let declared_in_this_block = if decl_form {
1941                true // 检查对象就是本块的声明
1942            } else if parent == walk.root {
1943                // 方法体根块:尾部扫描覆盖到方法末尾——参数/局部变量的
1944                // 零后续事件即可判定为死(方法外不可见)
1945                true
1946            } else {
1947                // 嵌套块:名字必须声明于本块(外层声明的名字可能被
1948                // 本块之后的外层代码读取)
1949                stmts[..idx].iter().any(|&s| {
1950                    lang.kind(s) == NodeKind::VarDecl && lang.var_name(s) == Some(name.as_str())
1951                })
1952            };
1953            if !declared_in_this_block {
1954                return None;
1955            }
1956            let name_key0 = lang.var_key(name_node)?;
1957            let mut w0 = Watch::<L>::new(name_key0, &[name_key0]);
1958            for &s in &stmts[idx + 1..] {
1959                scan_region(&*lang, s, &mut w0);
1960            }
1961            // 只判**本名字**的读/写(watch 集即本名字);Raw 区域不可证明
1962            if w0.opaque || !w0.uses.is_empty() || w0.wrote(name_key0) || w0.shadowed {
1963                return None;
1964            }
1965            // 句法补扫:事件模型对赋值**目标子树**的读失明(arr[j]='q'
1966            // 的 j 不产生 Use 事件——传播类规则同源问题第三次现身)。
1967            // 零用途判死前句法计数目标位置的下标读
1968            for &s in &stmts[idx + 1..] {
1969                if subtree_contains(&*lang, s, |n| {
1970                    lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name.as_str())
1971                }) {
1972                    return None;
1973                }
1974            }
1975            if lang.effect(first_value) > Effect::MayRead {
1976                return None;
1977            }
1978            return Some(Edit::Delete { node: id });
1979        };
1980        if lang.assign_op(second).is_some() {
1981            return None;
1982        }
1983        let nch = lang.children(second);
1984        let (target, value) = (*nch.first()?, *nch.get(1)?);
1985        if lang.kind(target) != NodeKind::VarRef {
1986            return None;
1987        }
1988
1989        // 变量一致性 + 局部性
1990        let name = if decl_form {
1991            if lang.var_name(id) != lang.var_name(target) {
1992                return None;
1993            }
1994            lang.var_name(id).map(|s| s.to_string())
1995        } else {
1996            let a = first_assign?;
1997            let t = *lang.children(a).first()?;
1998            if lang.kind(t) != NodeKind::VarRef {
1999                return None;
2000            }
2001            if lang.var_name(t) != lang.var_name(target) || !lang.is_local_var(t) {
2002                return None;
2003            }
2004            lang.var_name(t).map(|s| s.to_string())
2005        }?;
2006        // b 中不得引用 x(x = b 依赖旧值时不可删第一条)
2007        if subtree_contains(&*lang, value, |n| {
2008            lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name.as_str())
2009        }) {
2010            return None;
2011        }
2012        // a 的求值被丢弃:effect ≤ MayRead
2013        if lang.effect(first_value) > Effect::MayRead {
2014            return None;
2015        }
2016
2017        if decl_form {
2018            // int x = a; x = b; → init 换成 b,删除第二条语句
2019            Some(Edit::Multi(vec![
2020                Edit::Replace {
2021                    target: first_value,
2022                    with: value,
2023                },
2024                Edit::Delete {
2025                    node: next_stmt,
2026                },
2027            ]))
2028        } else {
2029            // x = a; x = b; → 删除第一条语句(id 本身:Assign 或 ExprStmt)
2030            Some(Edit::Delete { node: id })
2031        }
2032    }
2033}
2034
2035// ---------------------------------------------------------------------------
2036// 不可达语句删除(块内 return/throw/break/continue 之后的语句)。
2037// 语义安全(永不执行),但属于 DCE 范畴——**默认不启用**,经 all_rules() 选配。
2038// ---------------------------------------------------------------------------
2039
2040/// 块展平:Block 的直接孩子是 Block 且**内层无任何声明**(VarDecl/
2041/// ForEach/Catch 绑定引入作用域)→ 内层语句上提。典型形态:try 剥壳、
2042/// CFF 还原后的裸嵌套块。无声明 ⇒ 无遮蔽 ⇒ 语义等价。
2043pub struct BlockFlatten;
2044
2045impl<L: Lang> Rule<L> for BlockFlatten {
2046    fn name(&self) -> &'static str {
2047        "block_flatten"
2048    }
2049    fn kinds(&self) -> &'static [NodeKind] {
2050        &[NodeKind::Block]
2051    }
2052    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2053        let RewriteCtx { lang, walk } = ctx;
2054        let parent = walk.parent(id)?;
2055        if lang.kind(parent) != NodeKind::Block {
2056            return None;
2057        }
2058        // 内层不得有任何声明(作用域引入)
2059        let inner = lang.children(id).to_vec();
2060        let declares = |n: L::Id| -> bool {
2061            matches!(
2062                lang.kind(n),
2063                NodeKind::VarDecl | NodeKind::ForEach | NodeKind::Catch
2064            )
2065        };
2066        if inner.iter().any(|&s| declares(s)) {
2067            return None;
2068        }
2069        // 模式绑定流作用域(R15 三角化根因 1——BindingsTest1 抓获):
2070        // instanceof 绑定(藏在 while/for/if 条件子树里,不在直接孩子的
2071        // declares 三类中)的作用域按 JLS 6.3 可越出语句到 enclosing
2072        // block——上提曾使两个匿名块内的 String s 绑定落进同一方法域
2073        //(javac「变量 s 重复定义」)
2074        if lang.has_pattern_bindings(id) {
2075            return None;
2076        }
2077        let idx = walk.index(id)?;
2078        Some(Edit::Splice {
2079            node: parent,
2080            index: idx,
2081            remove: 1,
2082            insert: inner,
2083        })
2084    }
2085}
2086
2087/// 数值双重取负:-(-x) → x(补码回绕下恒等:-(-MIN) ≡ MIN ≡ x);
2088/// -(-lit) → |lit|(解析器不折负字面量的外层负)。
2089pub struct DoubleNegFold;
2090
2091impl<L: Lang> Rule<L> for DoubleNegFold {
2092    fn name(&self) -> &'static str {
2093        "double_neg_fold"
2094    }
2095    fn kinds(&self) -> &'static [NodeKind] {
2096        &[NodeKind::Unary]
2097    }
2098    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2099        let RewriteCtx { lang, .. } = ctx;
2100        if lang.un_op(id) != Some(UnOp::Neg) {
2101            return None;
2102        }
2103        let inner = *lang.children(id).first()?;
2104        if lang.un_op(inner) == Some(UnOp::Neg) {
2105            let x = *lang.children(inner).first()?;
2106            return Some(Edit::Replace {
2107                target: id,
2108                with: x,
2109            });
2110        }
2111        // -(-lit):负数值字面量取外层负 → 正字面量(宽度溢出时语言侧
2112        // 拒绝——Java i32 的 `-(-2147483648)` 无法表示)
2113        if let Some((v, wide)) = lang.literal(inner).and_then(|l| match l {
2114            LitRef::Int(v) => Some((v, false)),
2115            LitRef::Long(v) => Some((v, true)),
2116            _ => None,
2117        }) {
2118            if v < 0 {
2119                let n = lang.fold_lit_neg(v, wide)?;
2120                let with = lang.build_int(n, wide);
2121                return Some(Edit::Replace {
2122                    target: id,
2123                    with,
2124                });
2125            }
2126        }
2127        None
2128    }
2129}
2130
2131pub struct UnreachableAfterTerminal;
2132
2133impl<L: Lang> Rule<L> for UnreachableAfterTerminal {
2134    fn name(&self) -> &'static str {
2135        "unreachable_after_terminal"
2136    }
2137    fn kinds(&self) -> &'static [NodeKind] {
2138        &[NodeKind::Block]
2139    }
2140    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2141        let RewriteCtx { lang, walk: _ } = ctx;
2142        if lang.kind(id) != NodeKind::Block {
2143            return None;
2144        }
2145        let children = lang.children(id).to_vec();
2146        let terminal = |n: L::Id| -> bool {
2147            matches!(
2148                lang.kind(n),
2149                NodeKind::Return | NodeKind::Throw | NodeKind::Break | NodeKind::Continue
2150            )
2151        };
2152        let mut cut: Option<(usize, usize)> = None;
2153        for (i, &s) in children.iter().enumerate() {
2154            if terminal(s) && i + 1 < children.len() {
2155                cut = Some((i + 1, children.len() - i - 1));
2156                break;
2157            }
2158        }
2159        let (index, remove) = cut?;
2160        Some(Edit::Splice {
2161            node: id,
2162            index,
2163            remove,
2164            insert: Vec::new(),
2165        })
2166    }
2167}
2168
2169
2170// ---------------------------------------------------------------------------
2171// 比较常量折叠(反混淆核心):1 < 2 → true、2 == 3 → false。
2172// 仅整数(含 long)与布尔字面量;浮点(NaN 语义)与字符串(引用比较)不折。
2173// 连锁:boolean b = 2 > 1; if (b) {...} → 不透明谓词被完全击穿。
2174// ---------------------------------------------------------------------------
2175
2176pub struct CmpConstFold;
2177
2178impl<L: Lang> Rule<L> for CmpConstFold {
2179    fn name(&self) -> &'static str {
2180        "cmp_const_fold"
2181    }
2182    fn kinds(&self) -> &'static [NodeKind] {
2183        &[NodeKind::Binary]
2184    }
2185    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2186        let RewriteCtx { lang, walk: _ } = ctx;
2187        if lang.kind(id) != NodeKind::Binary {
2188            return None;
2189        }
2190        let op = lang.bin_op(id)?;
2191        if !op.is_comparison() {
2192            return None;
2193        }
2194        let ch = lang.children(id);
2195        let (l, r) = (*ch.first()?, *ch.get(1)?);
2196        // 双字面量才考虑折叠;可比较种类与比较语义由语言决定
2197        // (Java:整数/字符/布尔 Eq/Ne;字符串是引用比较 → 不折)
2198        lang.literal(l)?;
2199        lang.literal(r)?;
2200        let v = lang.fold_lit_cmp(op, l, r)?;
2201        let with = lang.build_bool(v);
2202        Some(Edit::Replace {
2203            target: id,
2204            with,
2205        })
2206    }
2207}
2208
2209// ---------------------------------------------------------------------------
2210// 位运算恒等式(混淆器高频产物):
2211//   x ^ 0 → x、0 ^ x → x、x | 0 → x、0 | x → x、x & -1 → x、-1 & x → x(x 保留,恒安全)
2212//   x | -1 → -1、x & 0 → 0、0 & x → 0(x 求值被丢弃 → effect ≤ MayRead)
2213//   x ^ x → 0(同名局部整型变量)
2214// ---------------------------------------------------------------------------
2215
2216pub struct BitIdentity;
2217
2218impl<L: Lang> Rule<L> for BitIdentity {
2219    fn name(&self) -> &'static str {
2220        "bit_identity"
2221    }
2222    fn kinds(&self) -> &'static [NodeKind] {
2223        &[NodeKind::Binary]
2224    }
2225    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2226        let RewriteCtx { lang, walk: _ } = ctx;
2227        if lang.kind(id) != NodeKind::Binary {
2228            return None;
2229        }
2230        let op = lang.bin_op(id)?;
2231        if !matches!(op, BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor) {
2232            return None;
2233        }
2234        let ch = lang.children(id);
2235        let (l, r) = (*ch.first()?, *ch.get(1)?);
2236        let int_lit = |n: L::Id| lang.literal(n).and_then(|x| x.as_int());
2237
2238        // x ^ x → 0(同名局部变量)
2239        if op == BinOp::BitXor
2240            && lang.kind(l) == NodeKind::VarRef
2241            && lang.kind(r) == NodeKind::VarRef
2242            && lang.var_name(l) == lang.var_name(r)
2243            && lang.is_local_var(l)
2244            && lang.is_exact_int(l)
2245        {
2246            let with = lang.build_int(0, false);
2247            return Some(Edit::Replace {
2248                target: id,
2249                with,
2250            });
2251        }
2252
2253        // 字面量在任一侧(互换尝试)
2254        for (x, k) in [(l, r), (r, l)] {
2255            let Some(kv) = int_lit(k) else {
2256                continue;
2257            };
2258            if !lang.is_exact_int(x) {
2259                continue;
2260            }
2261            let identity = match (op, kv) {
2262                (BinOp::BitXor, 0) => Some(x),          // x ^ 0 → x
2263                (BinOp::BitOr, 0) => Some(x),           // x | 0 → x
2264                (BinOp::BitAnd, -1) => Some(x),         // x & -1 → x
2265                (BinOp::BitAnd, 0) | (BinOp::BitOr, -1) => {
2266                    // x & 0 → 0 / x | -1 → -1:丢弃 x 求值,需可丢弃
2267                    if lang.effect(x) > Effect::MayRead {
2268                        None
2269                    } else {
2270                        Some(k)
2271                    }
2272                }
2273                _ => None,
2274            };
2275            if let Some(with) = identity {
2276                return Some(Edit::Replace {
2277                    target: id,
2278                    with,
2279                });
2280            }
2281        }
2282        None
2283    }
2284}
2285
2286// ---------------------------------------------------------------------------
2287// 算术/异或重结合(混淆器经典):(x + K1) - K2 → x ± K、(x ^ K1) ^ K2 → x ^ K。
2288// 整数回绕算术下恒安全;K == 0 时直接得 x((x + 5) - 5 → x、(x ^ 84) ^ 84 → x)。
2289// ---------------------------------------------------------------------------
2290
2291pub struct ArithReassoc;
2292
2293impl<L: Lang> Rule<L> for ArithReassoc {
2294    fn name(&self) -> &'static str {
2295        "arith_reassoc"
2296    }
2297    fn kinds(&self) -> &'static [NodeKind] {
2298        &[NodeKind::Binary]
2299    }
2300    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2301        let RewriteCtx { lang, walk: _ } = ctx;
2302        if lang.kind(id) != NodeKind::Binary {
2303            return None;
2304        }
2305        let op2 = lang.bin_op(id)?;
2306        if !matches!(op2, BinOp::Add | BinOp::Sub | BinOp::BitXor) {
2307            return None;
2308        }
2309        let och = lang.children(id).to_vec();
2310        let inner = och[0];
2311        if lang.kind(inner) != NodeKind::Binary {
2312            return None;
2313        }
2314        let op1 = lang.bin_op(inner)?;
2315        let ich = lang.children(inner).to_vec();
2316        let x = ich[0];
2317
2318        // 字符串拼接重结合:(x + "K1") + "K2" → x + "K1K2"
2319        // (拼接满足结合律且各操作数恰按序求值一次;x 任意类型)。
2320        // **整链折叠**:左倾链 (((x+"a")+"a")+"a")… 一刀折成 x+"aaa…"——
2321        // 逐层折每 pass 一层是 O(n²)(openjdk DeepStringConcat 32001 项
2322        // 78s/32k passes 抓获;整链后 1 编辑收敛)
2323        if op1 == BinOp::Add && op2 == BinOp::Add {
2324            if let (Some(LitRef::Str(k1)), Some(LitRef::Str(k2))) =
2325                (lang.literal(ich[1]), lang.literal(och[1]))
2326            {
2327                // 收集左倾链(外→内),要求每层 (child + "str") 同构
2328                let mut chain: Vec<L::Id> = vec![id];
2329                let mut cur = id;
2330                loop {
2331                    let cch = lang.children(cur).to_vec();
2332                    let next = cch[0];
2333                    let deeper = lang.kind(next) == NodeKind::Binary
2334                        && lang.bin_op(next) == Some(BinOp::Add)
2335                        && matches!(lang.literal(lang.children(next).to_vec()[1]),
2336                            Some(LitRef::Str(_)));
2337                    if deeper {
2338                        chain.push(next);
2339                        cur = next;
2340                    } else {
2341                        break;
2342                    }
2343                }
2344                // base = 最内层的左操作数;parts 内→外 = 源顺序
2345                let innermost = *chain.last().unwrap();
2346                let ich2 = lang.children(innermost).to_vec();
2347                let base = ich2[0];
2348                let mut joined = String::new();
2349                for &n in chain.iter().rev() {
2350                    if let Some(LitRef::Str(k)) =
2351                        lang.literal(lang.children(n).to_vec()[1])
2352                    {
2353                        joined.push_str(k);
2354                    }
2355                }
2356                let _ = (k1, k2); // 已并入 joined
2357                let lit = lang.build_str(&joined);
2358                let with = lang.build_bin(BinOp::Add, base, lit);
2359                return Some(Edit::Replace {
2360                    target: id,
2361                    with,
2362                });
2363            }
2364        }
2365
2366        // 整数重结合:(x ± K1) ± K2 → x ± K、(x ^ K1) ^ K2 → x ^ K
2367        // 常量合并与宽度回绕语义在 Lang::reassoc_delta(Java:i32/i64
2368        // JLS 环绕——i32 合并溢出不回绕会产出非法字面量)
2369        let k1 = lang.literal(ich[1]).and_then(|x| x.as_int())?;
2370        let k2 = lang.literal(och[1]).and_then(|x| x.as_int())?;
2371        if !lang.is_exact_int(x) {
2372            return None;
2373        }
2374        let is_long = matches!(lang.literal(ich[1]), Some(LitRef::Long(_)))
2375            || matches!(lang.literal(och[1]), Some(LitRef::Long(_)));
2376        let with = match lang.reassoc_delta(op1, k1, op2, k2, is_long)? {
2377            ReassocOutcome::Neutral => x,
2378            ReassocOutcome::Lit(lit, op) => lang.build_bin(op, x, lit),
2379        };
2380        Some(Edit::Replace {
2381            target: id,
2382            with,
2383        })
2384    }
2385}
2386
2387// ---------------------------------------------------------------------------
2388// if→三元归并(反编译器/混淆器经典形态):
2389//   if (c) return a; else return b;    →  return c ? a : b;
2390//   if (c) return a; return b;(收尾) →  return c ? a : b;
2391// 恒安全:c 单次求值、a/b 条件求值在两种形态下一致(三元是惰性的)。
2392// 布尔特例由 ternary_bool 继续收敛成 return c / return !c。
2393// ---------------------------------------------------------------------------
2394
2395pub struct IfToTernary;
2396
2397impl<L: Lang> Rule<L> for IfToTernary {
2398    fn name(&self) -> &'static str {
2399        "if_to_ternary"
2400    }
2401    fn kinds(&self) -> &'static [NodeKind] {
2402        &[NodeKind::If]
2403    }
2404    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2405        let RewriteCtx { lang, walk } = ctx;
2406        if lang.kind(id) != NodeKind::If {
2407            return None;
2408        }
2409        let ch = lang.children(id).to_vec();
2410        let c = ch[0];
2411
2412        // 提取"单 return 语句"分支:Block{Return} 或裸 Return
2413        let single_ret = |n: L::Id| -> Option<Option<L::Id>> {
2414            match lang.kind(n) {
2415                NodeKind::Return => Some(lang.children(n).first().copied()),
2416                NodeKind::Block if lang.children(n).len() == 1 => {
2417                    let inner = lang.children(n)[0];
2418                    if lang.kind(inner) == NodeKind::Return {
2419                        Some(lang.children(inner).first().copied())
2420                    } else {
2421                        None
2422                    }
2423                }
2424                _ => None,
2425            }
2426        };
2427
2428        if ch.len() == 3 {
2429            // 完整 if-else:两支都是单 return
2430            let a = single_ret(ch[1])?;
2431            let b = single_ret(ch[2])?;
2432            let with = match (a, b) {
2433                (Some(va), Some(vb)) => {
2434                    let t = lang.build_ternary(c, va, vb);
2435                    lang.build_return(Some(t))
2436                }
2437                (None, None) => lang.build_return(None),
2438                _ => return None,
2439            };
2440            return Some(Edit::Replace {
2441                target: id,
2442                with,
2443            });
2444        }
2445
2446        // if-then + 紧随的收尾 return(必须是父块最后一条语句)
2447        if ch.len() != 2 {
2448            return None;
2449        }
2450        let a = single_ret(ch[1])?;
2451        let parent = walk.parent(id)?;
2452        if lang.kind(parent) != NodeKind::Block {
2453            return None;
2454        }
2455        let idx = walk.index(id)?;
2456        let stmts = lang.children(parent).to_vec();
2457        if idx + 2 != stmts.len() {
2458            return None; // return 必须是最后一条
2459        }
2460        let tail = stmts[idx + 1];
2461        if lang.kind(tail) != NodeKind::Return {
2462            return None;
2463        }
2464        let b = lang.children(tail).first().copied();
2465        let with = match (a, b) {
2466            (Some(va), Some(vb)) => {
2467                let t = lang.build_ternary(c, va, vb);
2468                lang.build_return(Some(t))
2469            }
2470            (None, None) => lang.build_return(None),
2471            _ => return None,
2472        };
2473        Some(Edit::Splice {
2474            node: parent,
2475            index: idx,
2476            remove: 2,
2477            insert: vec![with],
2478        })
2479    }
2480}
2481
2482// ---------------------------------------------------------------------------
2483// if→三元赋值归并:
2484//   if (c) { x = a; } else { x = b; }  →  x = c ? a : b;
2485// 恒安全(x 为变量名,两种形态各求值一次;a/b 条件求值一致)。
2486// ---------------------------------------------------------------------------
2487
2488pub struct IfAssignTernary;
2489
2490impl<L: Lang> Rule<L> for IfAssignTernary {
2491    fn name(&self) -> &'static str {
2492        "if_assign_ternary"
2493    }
2494    fn kinds(&self) -> &'static [NodeKind] {
2495        &[NodeKind::If]
2496    }
2497    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2498        let RewriteCtx { lang, walk: _ } = ctx;
2499        if lang.kind(id) != NodeKind::If {
2500            return None;
2501        }
2502        let ch = lang.children(id).to_vec();
2503        if ch.len() != 3 {
2504            return None;
2505        }
2506        let c = ch[0];
2507        // 单赋值分支:Block{Assign} / Block{ExprStmt{Assign}} / 裸(ExprStmt 包裹的)Assign
2508        let single_assign = |n: L::Id| -> Option<(L::Id, L::Id)> {
2509            let unwrap = |i: L::Id| -> L::Id {
2510                if lang.kind(i) == NodeKind::ExprStmt {
2511                    let ch = lang.children(i);
2512                    if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
2513                        return ch[0];
2514                    }
2515                }
2516                i
2517            };
2518            let inner = match lang.kind(n) {
2519                NodeKind::Assign => n,
2520                NodeKind::ExprStmt => unwrap(n),
2521                NodeKind::Block if lang.children(n).len() == 1 => unwrap(lang.children(n)[0]),
2522                _ => return None,
2523            };
2524            if lang.kind(inner) != NodeKind::Assign {
2525                return None;
2526            }
2527            if lang.assign_op(inner).is_some() {
2528                return None;
2529            }
2530            let a = lang.children(inner).to_vec();
2531            if lang.kind(a[0]) != NodeKind::VarRef {
2532                return None;
2533            }
2534            Some((a[0], a[1]))
2535        };
2536        let (t1, va) = single_assign(ch[1])?;
2537        let (t2, vb) = single_assign(ch[2])?;
2538        if lang.var_name(t1) != lang.var_name(t2) || lang.var_name(t1).is_none() {
2539            return None;
2540        }
2541        let t = lang.build_ternary(c, va, vb);
2542        let with = lang.build_assign(t1, t);
2543        Some(Edit::Replace {
2544            target: id,
2545            with,
2546        })
2547    }
2548}
2549
2550
2551// ---------------------------------------------------------------------------
2552// 声明-赋值合并(反编译器把声明与赋值拆开的形态):
2553//   int x; x = 5;  →  int x = 5;
2554// 守卫:相邻同块、简单赋值、value 不引用 x(依赖旧值则非法)。
2555// 之后 local_propagation 可继续把 init 内联到唯一使用处。
2556// ---------------------------------------------------------------------------
2557
2558pub struct DeclAssignMerge;
2559
2560impl<L: Lang> Rule<L> for DeclAssignMerge {
2561    fn name(&self) -> &'static str {
2562        "decl_assign_merge"
2563    }
2564    fn kinds(&self) -> &'static [NodeKind] {
2565        &[NodeKind::VarDecl]
2566    }
2567    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2568        let RewriteCtx { lang, walk } = ctx;
2569        if lang.kind(id) != NodeKind::VarDecl || !lang.children(id).is_empty() {
2570            return None; // 必须是无 init 声明
2571        }
2572        let name = lang.var_name(id)?.to_string();
2573        let parent = walk.parent(id)?;
2574        if lang.kind(parent) != NodeKind::Block {
2575            return None;
2576        }
2577        let idx = walk.index(id)?;
2578        let stmts = lang.children(parent).to_vec();
2579        let next = *stmts.get(idx + 1)?;
2580        // 下一条:Assign(x, v) / ExprStmt{Assign(x, v)}(简单赋值)
2581        let assign = match lang.kind(next) {
2582            NodeKind::Assign => next,
2583            NodeKind::ExprStmt => {
2584                let ch = lang.children(next);
2585                if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
2586                    ch[0]
2587                } else {
2588                    return None;
2589                }
2590            }
2591            _ => return None,
2592        };
2593        if lang.assign_op(assign).is_some() {
2594            return None;
2595        }
2596        let ach = lang.children(assign).to_vec();
2597        let (target, value) = (ach[0], ach[1]);
2598        if lang.kind(target) != NodeKind::VarRef || lang.var_name(target) != Some(name.as_str()) {
2599            return None;
2600        }
2601        // value 不得引用 x(读旧值)
2602        if subtree_contains(&*lang, value, |n| {
2603            lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name.as_str())
2604        }) {
2605            return None;
2606        }
2607        Some(Edit::Multi(vec![
2608            Edit::Splice {
2609                node: id,
2610                index: 0,
2611                remove: 0,
2612                insert: vec![value],
2613            },
2614            Edit::Delete { node: next },
2615        ]))
2616    }
2617}
2618
2619// ---------------------------------------------------------------------------
2620// 赋值传播(寄存器拷贝消除,jadx/jcdc 产物):
2621//   x = v; …唯一一次读 x(区间内无对 x / v 读集的写、无遮蔽)…
2622//   → 用 v 替换该次读,删除赋值。
2623// 安全锚点:x 必须在本块内有前置声明(赋值无作用域,块外读取会破坏语义)。
2624// v 纯/只读 → 自由移动(写冲突检查);v 有副作用 → 相邻 + 直线 + 可读前缀。
2625// ---------------------------------------------------------------------------
2626
2627pub struct AssignPropagation;
2628
2629impl<L: Lang> Rule<L> for AssignPropagation {
2630    fn name(&self) -> &'static str {
2631        "assign_propagation"
2632    }
2633    fn kinds(&self) -> &'static [NodeKind] {
2634        &[NodeKind::Assign, NodeKind::ExprStmt]
2635    }
2636    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2637        let RewriteCtx { lang, walk } = ctx;
2638        // 语句形态:Assign / ExprStmt{Assign}
2639        let (assign, stmt_node) = match lang.kind(id) {
2640            NodeKind::Assign => (id, id),
2641            NodeKind::ExprStmt => {
2642                let ch = lang.children(id);
2643                if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
2644                    (ch[0], id)
2645                } else {
2646                    return None;
2647                }
2648            }
2649            _ => return None,
2650        };
2651        if lang.assign_op(assign).is_some() {
2652            return None;
2653        }
2654        let ach = lang.children(assign).to_vec();
2655        let (target, value) = (ach[0], ach[1]);
2656        if lang.kind(target) != NodeKind::VarRef || !lang.is_local_var(target) {
2657            return None;
2658        }
2659        // 裸数组字面量只在声明/赋值 RHS 位置合法,传播会产出非法源码 → 拒绝
2660        if lang.kind(value) == NodeKind::ArrayLit {
2661            return None;
2662        }
2663        // lambda / 方法引用值同 ArrayLit:receiver 位非法 → 保守拒绝
2664        if matches!(lang.kind(value), NodeKind::Lambda | NodeKind::MethodRef) {
2665            return None;
2666        }
2667        let name = lang.var_name(target)?.to_string();
2668
2669        let parent = walk.parent(stmt_node)?;
2670        if lang.kind(parent) != NodeKind::Block {
2671            return None;
2672        }
2673        let idx = walk.index(stmt_node)?;
2674        let stmts = lang.children(parent).to_vec();
2675
2676        // 锚点:x 在本块 idx 之前有 VarDecl(保证 x 不会逃逸到块外)
2677        let anchored = stmts[..idx].iter().any(|&s| {
2678            lang.kind(s) == NodeKind::VarDecl && lang.var_name(s) == Some(name.as_str())
2679        });
2680        if !anchored {
2681            return None;
2682        }
2683
2684        // value 不引用 x(x = x + 1 之类)
2685        if subtree_contains(&*lang, value, |n| {
2686            lang.kind(n) == NodeKind::VarRef && lang.var_name(n) == Some(name.as_str())
2687        }) {
2688            return None;
2689        }
2690
2691        // 扫描赋值之后的区域(用途/遮蔽全区间;写冲突窗口见下)。
2692        // 句法引用计数兜底(同 local_propagation——bd.java 教训)
2693        let name_key = lang.var_key(target)?;
2694        if count_name_refs(&*lang, &stmts[idx + 1..], &name) != 1 {
2695            return None;
2696        }
2697        let mut wa = Watch::<L>::new(name_key, &[]);
2698        for &s in &stmts[idx + 1..] {
2699            scan_region(&*lang, s, &mut wa);
2700        }
2701        if wa.opaque || wa.shadowed || wa.uses.len() != 1 {
2702            return None;
2703        }
2704        let use_id = wa.uses[0];
2705        // null 字面量:接收者位(AST 形态 Call→Member→[recv],VarRef 的
2706        // 父是 Member)或静态调用 callee(防御)之外,**实参位**同样拒绝
2707        // ——`str2 = null; append(str2)` 合法(str2 声明类型钉住重载),
2708        // 内联成 `append(null)` 后 append(CharSequence)/append(char[])
2709        // 二义(ddc 输出 PurchasesOrchestrator 复现)。null_unsafe_position
2710        // 沿 Paren 链判位;Cast 包裹((String) s)重建类型 → 放行
2711        if matches!(lang.literal(value), Some(LitRef::Null))
2712            && null_unsafe_position(&*lang, walk, use_id)
2713        {
2714            return None;
2715        }
2716        // VarRef 值不得内联进 cast/instanceof 类型判定位(声明类型即合法
2717        // 性依据——同 null 实参位的族)
2718        if lang.kind(value) == NodeKind::VarRef
2719            && typed_position_unsafe(&*lang, walk, use_id)
2720        {
2721            return None;
2722        }
2723        // 写冲突兴趣集:value 读到的名字键 + x 自身(自身被写 → 覆盖,拒绝)
2724        let mut watch_keys: Vec<L::NameKey> = Vec::new();
2725        collect_read_keys(&*lang, value, &mut watch_keys);
2726        watch_keys.push(name_key);
2727        let mut wb = Watch::<L>::new(name_key, &watch_keys);
2728        for &s in &stmts[idx + 1..] {
2729            let uses_before = wb.uses.len();
2730            scan_region(&*lang, s, &mut wb);
2731            if uses_before < wb.uses.len() {
2732                break; // 使用语句之后的写不参与冲突判定
2733            }
2734        }
2735        // x 自身在窗口内被写 → 赋值会被覆盖,拒绝(先于目标写排除)
2736        if wb.wrote(name_key) {
2737            return None;
2738        }
2739        let ve = lang.effect(value);
2740
2741        if ve <= Effect::MayRead {
2742            if let Some(target_key) = use_stmt_target_write_key(&*lang, &stmts[idx + 1..], use_id) {
2743                wb.clear_wrote(target_key);
2744            }
2745            if wb.any_write() {
2746                return None;
2747            }
2748            return Some(Edit::Multi(vec![
2749                Edit::Replace {
2750                    target: use_id,
2751                    with: value,
2752                },
2753                Edit::Delete { node: stmt_node },
2754            ]));
2755        }
2756
2757        // 有副作用:相邻 + 直线 + 可读前缀(与 local_propagation 同判据)
2758        if idx + 1 >= stmts.len() {
2759            return None;
2760        }
2761        let stmt = stmts[idx + 1];
2762        if !subtree_contains(&*lang, stmt, |n| n == use_id) {
2763            return None;
2764        }
2765        match lang.kind(stmt) {
2766            NodeKind::Return
2767            | NodeKind::ExprStmt
2768            | NodeKind::Assign
2769            | NodeKind::Throw
2770            | NodeKind::VarDecl => {}
2771            _ => return None,
2772        }
2773        if !straight_path(&*lang, stmt, use_id) {
2774            return None;
2775        }
2776        if !prefix_effects_readable(&*lang, stmt, use_id) {
2777            return None;
2778        }
2779        Some(Edit::Multi(vec![
2780            Edit::Replace {
2781                target: use_id,
2782                with: value,
2783            },
2784            Edit::Delete { node: stmt_node },
2785        ]))
2786    }
2787}
2788
2789
2790/// 单一使用点若恰为 `target = use` 的 RHS,则该语句对 target 的写发生在
2791/// use 求值**之后**——从写冲突集中排除(否则 `int v = x + s; x = v;` 这类
2792/// 循环尾寄存器回拷永远无法内联)。
2793/// 排除目标必须≠被传播变量自身:`int i = 1; i = i;` 里排除 `i` 会删掉声明
2794/// 留下无绑定的赋值(该场景由 self_assign 处理)。
2795fn use_stmt_target_write_key<L: Lang>(
2796    lang: &L,
2797    stmts_after: &[L::Id],
2798    use_id: L::Id,
2799) -> Option<L::NameKey> {
2800    for &s in stmts_after {
2801        if subtree_contains(lang, s, |n| n == use_id) {
2802            let assign = match lang.kind(s) {
2803                NodeKind::Assign => s,
2804                NodeKind::ExprStmt => {
2805                    let ch = lang.children(s);
2806                    if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
2807                        ch[0]
2808                    } else {
2809                        return None;
2810                    }
2811                }
2812                _ => return None,
2813            };
2814            if lang.assign_op(assign).is_some() {
2815                return None;
2816            }
2817            let ch = lang.children(assign);
2818            if ch.len() == 2 && ch[1] == use_id && lang.kind(ch[0]) == NodeKind::VarRef {
2819                return lang.var_key(ch[0]);
2820            }
2821            return None;
2822        }
2823    }
2824    None
2825}
2826
2827/// 收集 `id` 子树中 VarRef 读到的全部名字键(去重,线性)。
2828/// 替代旧 reads_vars 的 HashSet 版:value 的读名字典型 ≤10,线性查重更快。
2829fn collect_read_keys<L: Lang>(lang: &L, id: L::Id, out: &mut Vec<L::NameKey>) {
2830    let mut stack = vec![id];
2831    while let Some(n) = stack.pop() {
2832        if lang.kind(n) == NodeKind::VarRef {
2833            if let Some(k) = lang.var_key(n) {
2834                if !out.contains(&k) {
2835                    out.push(k);
2836                }
2837            }
2838        }
2839        for &c in lang.children(n) {
2840            stack.push(c);
2841        }
2842    }
2843}
2844
2845
2846// ---------------------------------------------------------------------------
2847// 尾部 continue 删除(反编译器产物):
2848//   while (c) { …; continue; }  →  while (c) { … }
2849// 循环体最后一条无标签 continue 与顺序落入下一轮等价。恒安全。
2850// ---------------------------------------------------------------------------
2851
2852pub struct TrailingContinue;
2853
2854impl<L: Lang> Rule<L> for TrailingContinue {
2855    fn name(&self) -> &'static str {
2856        "trailing_continue"
2857    }
2858    fn kinds(&self) -> &'static [NodeKind] {
2859        &[NodeKind::While, NodeKind::For, NodeKind::DoWhile, NodeKind::ForEach]
2860    }
2861    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2862        let RewriteCtx { lang, walk: _ } = ctx;
2863        // While/For/DoWhile/ForEach 的 body 为 Block 且末语句为无标签 continue
2864        let body = match lang.kind(id) {
2865            NodeKind::While | NodeKind::For | NodeKind::DoWhile | NodeKind::ForEach => {
2866                *lang.children(id).last()?
2867            }
2868            _ => return None,
2869        };
2870        if lang.kind(body) != NodeKind::Block {
2871            return None;
2872        }
2873        let ch = lang.children(body).to_vec();
2874        let last = *ch.last()?;
2875        if lang.kind(last) != NodeKind::Continue || !lang.children(last).is_empty() {
2876            // JavaAST 的 Continue 标签在负载里,children 为空即无标签(引擎层约定)
2877            // 对带标签的语言实现:children[last] 非空即有标签 → 不动
2878            if lang.kind(last) != NodeKind::Continue {
2879                return None;
2880            }
2881        }
2882        Some(Edit::Delete { node: last })
2883    }
2884}
2885
2886// ---------------------------------------------------------------------------
2887// 多用途拷贝传播(寄存器副本消除):
2888//   x = y;(y 为简单 VarRef,x 有本块声明锚点,之后无对 x/y 的写、无遮蔽)
2889//   → 把 x 的**所有**后续读替换为 y,删除赋值。
2890// 守卫 y 不被写:替换后各使用点读的是 y 的当前值,须与原 x 的值一致。
2891// ---------------------------------------------------------------------------
2892
2893pub struct MultiUseCopyPropagation;
2894
2895impl<L: Lang> Rule<L> for MultiUseCopyPropagation {
2896    fn name(&self) -> &'static str {
2897        "multi_use_copy"
2898    }
2899    fn kinds(&self) -> &'static [NodeKind] {
2900        &[NodeKind::Assign, NodeKind::ExprStmt]
2901    }
2902    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
2903        let RewriteCtx { lang, walk } = ctx;
2904        // 语句形态:Assign(x, VarRef y) / ExprStmt{Assign(...)}
2905        let (assign, stmt_node) = match lang.kind(id) {
2906            NodeKind::Assign => (id, id),
2907            NodeKind::ExprStmt => {
2908                let ch = lang.children(id);
2909                if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
2910                    (ch[0], id)
2911                } else {
2912                    return None;
2913                }
2914            }
2915            _ => return None,
2916        };
2917        if lang.assign_op(assign).is_some() {
2918            return None;
2919        }
2920        let ach = lang.children(assign).to_vec();
2921        let (target, value) = (ach[0], ach[1]);
2922        if lang.kind(target) != NodeKind::VarRef || lang.kind(value) != NodeKind::VarRef {
2923            return None;
2924        }
2925        // lambda / 方法引用值:内联进 receiver 位非法(对抗波 2)→ 保守拒绝
2926        if matches!(lang.kind(value), NodeKind::Lambda | NodeKind::MethodRef) {
2927            return None;
2928        }
2929        if !lang.is_local_var(target) {
2930            return None;
2931        }
2932        let name = lang.var_name(target)?.to_string();
2933        let src = lang.var_name(value)?.to_string();
2934        if name == src {
2935            return None;
2936        }
2937
2938        let parent = walk.parent(stmt_node)?;
2939        if lang.kind(parent) != NodeKind::Block {
2940            return None;
2941        }
2942        let idx = walk.index(stmt_node)?;
2943        let stmts = lang.children(parent).to_vec();
2944
2945        // 锚点:x 在本块 idx 之前有 VarDecl
2946        let anchored = stmts[..idx].iter().any(|&s| {
2947            lang.kind(s) == NodeKind::VarDecl && lang.var_name(s) == Some(name.as_str())
2948        });
2949        if !anchored {
2950            return None;
2951        }
2952
2953        // 扫描后续:收集 x 的全部读;对 x 的任何写 / 对 y 的任何写 / 遮蔽 → 拒绝
2954        let name_key = lang.var_key(target)?;
2955        let src_key = lang.var_key(value)?;
2956        let mut w1 = Watch::<L>::new(name_key, &[name_key, src_key]);
2957        for &s in &stmts[idx + 1..] {
2958            scan_region(&*lang, s, &mut w1);
2959        }
2960        if w1.opaque || w1.shadowed || w1.uses.is_empty() {
2961            return None;
2962        }
2963        if w1.wrote(name_key) || w1.wrote(src_key) {
2964            return None;
2965        }
2966        // 句法守卫:x 在赋值后的句法出现总数(含数组写 base——x[i]=v
2967        // 的 x 不产生事件,事件模型盲区)必须等于事件 uses 数。
2968        // 出现 > uses ⇒ 存在事件看不见的引用(bd.java 差分二轮抓获:
2969        // var10004 = var154 的读被替换、var10004[i]= 写目标残留 →
2970        // 读写裂脑 → 类初始化 AIOOBE)
2971        let synth = count_name_refs(&*lang, &stmts[idx + 1..], &name);
2972        if synth != w1.uses.len() {
2973            return None;
2974        }
2975        // y 也不得在【赋值前】与 x 指向不同值(x=y 之前 y 已是其所值,无需检查);
2976        // 但 x=y 之间不能有对 y 的写(相邻语句,天然无中间)——赋值本身就是当前值 ✓
2977
2978        // VarRef 值(y)不得内联进 cast/instanceof 类型判定位:被替换
2979        // 变量(x)的声明类型是这些位置可转换性的依据——`Object x =
2980        // k3Var; s = (String) x;` 合法,替换成 `(String) k3Var` 引用类型
2981        // 不相关即不可编译(ddc weixin dt/k 复现)。任一使用点命中 →
2982        // 整体拒绝(多用途替换不可拆单点)。
2983        if w1.uses
2984            .iter()
2985            .any(|&u| typed_position_unsafe(&*lang, walk, u))
2986        {
2987            return None;
2988        }
2989
2990        let mut edits: Vec<Edit<L>> = w1.uses
2991            .iter()
2992            .map(|&u| Edit::Replace {
2993                target: u,
2994                with: value,
2995            })
2996            .collect();
2997        edits.push(Edit::Delete { node: stmt_node });
2998        Some(Edit::Multi(edits))
2999    }
3000}
3001
3002
3003// ---------------------------------------------------------------------------
3004// 尾部裸 return 删除(DAD/androguard 伪影):
3005//   void 方法/构造器体最后一条无值 return 与自然结束等价,删除。
3006// 仅匹配根块(方法体)末语句,避免动到块中间的提前 return。
3007// ---------------------------------------------------------------------------
3008
3009pub struct TrailingReturn;
3010
3011impl<L: Lang> Rule<L> for TrailingReturn {
3012    fn name(&self) -> &'static str {
3013        "trailing_return"
3014    }
3015    fn kinds(&self) -> &'static [NodeKind] {
3016        &[NodeKind::Return]
3017    }
3018    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
3019        let root = ctx.root();
3020        let parent = ctx.parent(id)?;
3021        let lang = ctx.lang;
3022        if lang.kind(id) != NodeKind::Return || !lang.children(id).is_empty() {
3023            return None;
3024        }
3025        if parent != root || lang.kind(parent) != NodeKind::Block {
3026            return None;
3027        }
3028        if lang.children(parent).last() != Some(&id) {
3029            return None;
3030        }
3031        Some(Edit::Delete { node: id })
3032    }
3033}
3034
3035
3036// ---------------------------------------------------------------------------
3037// 三元-布尔运算归并(反混淆产物):
3038//   c ? a : false → c && a、c ? true : a → c || a(a 为布尔)
3039//   c 单次求值、a 条件求值,两种形态完全一致。
3040// ---------------------------------------------------------------------------
3041
3042pub struct TernaryBoolOp;
3043
3044impl<L: Lang> Rule<L> for TernaryBoolOp {
3045    fn name(&self) -> &'static str {
3046        "ternary_bool_op"
3047    }
3048    fn kinds(&self) -> &'static [NodeKind] {
3049        &[NodeKind::Ternary]
3050    }
3051    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
3052        let RewriteCtx { lang, walk: _ } = ctx;
3053        if lang.kind(id) != NodeKind::Ternary {
3054            return None;
3055        }
3056        let ch = lang.children(id);
3057        let (c, a, b) = (*ch.first()?, *ch.get(1)?, *ch.get(2)?);
3058        let lb = |n: L::Id| matches!(lang.literal(n), Some(LitRef::Bool(v)) if v);
3059        let is_false = |n: L::Id| matches!(lang.literal(n), Some(LitRef::Bool(v)) if !v);
3060        let with = if is_false(b) && lang.is_bool(a) {
3061            lang.build_bin(BinOp::And, c, a)
3062        } else if lb(b) && lang.is_bool(a) {
3063            // c ? a : true ≡ !c || a —— 少见,跳过保持保守
3064            return None;
3065        } else if lb(a) && lang.is_bool(b) {
3066            // c ? true : b ≡ c || b
3067            lang.build_bin(BinOp::Or, c, b)
3068        } else if is_false(a) && lang.is_bool(b) {
3069            // c ? false : b ≡ !c && b —— 少见,跳过保持保守
3070            return None;
3071        } else {
3072            return None;
3073        };
3074        Some(Edit::Replace {
3075            target: id,
3076            with,
3077        })
3078    }
3079}
3080
3081
3082// ---------------------------------------------------------------------------
3083// 远距存储消除(寄存器预声明清理,ddc/jcdc 产物):
3084//   int x = 0; …(无 x 事件)…; x = 1;   →  int x = 1;(字面量提升)
3085//   int x = 0; …(无 x 事件)…; x = v;   →  int x;(init 死亡,剥除)
3086//   x = 0; …(无 x 事件)…; x = v;       →  删除第一条(值 ≤ MayRead)
3087// 守卫:首个 x 事件必须是写;语句内 x 出现若非简单赋值目标即视为读(阻断)。
3088// ---------------------------------------------------------------------------
3089
3090pub struct StoreKill;
3091
3092/// 语句级事件分类:任意路径的读都保活 init;只有**支配写**才击杀。
3093/// (条件分支里的读在部分路径消费旧值——`x = C ? x+1 : x+2` 的分支读
3094/// 就是活引用;条件分支里的写不必然执行 → 不击杀,继续扫。)
3095enum KillEvent<L: Lang> {
3096    /// 任意位置的读 → init 活着
3097    Read,
3098    /// 支配位置的简单赋值(写)
3099    DomWrite(L::Id),
3100    /// 同名重声明(遮蔽)
3101    Shadow,
3102}
3103
3104/// 扫描一个节点在 `name` 上的事件。
3105/// `dominating`:当前子树是否在必经路径上(If/While 的 cond、Ternary 的
3106/// cond、For 的 init/cond、非短路二元两侧 = true;分支体/循环体 = false)。
3107fn scan_kill_event<L: Lang>(
3108    lang: &L,
3109    node: L::Id,
3110    name: &str,
3111    dominating: bool,
3112) -> Option<KillEvent<L>> {
3113    match lang.kind(node) {
3114        NodeKind::VarRef => {
3115            if lang.var_name(node) == Some(name) {
3116                Some(KillEvent::Read)
3117            } else {
3118                None
3119            }
3120        }
3121        NodeKind::VarDecl => {
3122            if lang.var_name(node) == Some(name) {
3123                Some(KillEvent::Shadow)
3124            } else {
3125                // 其他变量声明:init 必经求值
3126                for &c in lang.children(node) {
3127                    if let Some(e) = scan_kill_event(lang, c, name, dominating) {
3128                        return Some(e);
3129                    }
3130                }
3131                None
3132            }
3133        }
3134        NodeKind::Assign => {
3135            let ch = lang.children(node);
3136            // RHS 先求值
3137            if let Some(&val) = ch.get(1) {
3138                if let Some(e) = scan_kill_event(lang, val, name, dominating) {
3139                    if matches!(e, KillEvent::Read | KillEvent::Shadow) {
3140                        return Some(e);
3141                    }
3142                }
3143            }
3144            if lang.assign_op(node).is_none() {
3145                if let Some(&t) = ch.first() {
3146                    if lang.kind(t) == NodeKind::VarRef && lang.var_name(t) == Some(name) {
3147                        if dominating {
3148                            return Some(KillEvent::DomWrite(node));
3149                        }
3150                        return None; // 条件写:不击杀,也不算读
3151                    }
3152                }
3153            }
3154            None
3155        }
3156        NodeKind::If | NodeKind::While | NodeKind::Ternary => {
3157            // cond 必经;分支体/循环体不必然——但其中的【读】仍保活 init,
3158            // 必须扫描(以非支配标记:读传播,写不击杀)
3159            let ch = lang.children(node);
3160            if let Some(&c) = ch.first() {
3161                if let Some(e) = scan_kill_event(lang, c, name, true) {
3162                    return Some(e);
3163                }
3164            }
3165            for &c in &ch[1..] {
3166                if let Some(e) = scan_kill_event(lang, c, name, false) {
3167                    if matches!(e, KillEvent::Read | KillEvent::Shadow) {
3168                        return Some(e);
3169                    }
3170                }
3171            }
3172            None
3173        }
3174        NodeKind::Binary => {
3175            let op = lang.bin_op(node)?;
3176            let ch = lang.children(node);
3177            if op.is_short_circuit() {
3178                // 左支必经;右支条件求值(读→保活;写→不击杀)
3179                if let Some(&l) = ch.first() {
3180                    if let Some(e) = scan_kill_event(lang, l, name, true) {
3181                        return Some(e);
3182                    }
3183                }
3184                if let Some(&r) = ch.get(1) {
3185                    if let Some(e) = scan_kill_event(lang, r, name, false) {
3186                        if matches!(e, KillEvent::Read | KillEvent::Shadow) {
3187                            return Some(e);
3188                        }
3189                    }
3190                }
3191                None
3192            } else {
3193                for &c in ch {
3194                    if let Some(e) = scan_kill_event(lang, c, name, dominating) {
3195                        return Some(e);
3196                    }
3197                }
3198                None
3199            }
3200        }
3201        NodeKind::For | NodeKind::ForEach | NodeKind::Switch | NodeKind::Try => {
3202            // 必经部分(For 的 inits+cond / ForEach 的 iterable / Switch 的
3203            // subject)以支配标记扫;其余(循环体/case 体/try 块)以非支配
3204            // 标记扫——其中的读仍保活
3205            let ch = lang.children(node);
3206            let dom_len = match lang.kind(node) {
3207                NodeKind::For => ch.len().saturating_sub(2),
3208                NodeKind::ForEach | NodeKind::Switch => 1,
3209                _ => 0,
3210            };
3211            for &c in &ch[..dom_len] {
3212                if let Some(e) = scan_kill_event(lang, c, name, true) {
3213                    return Some(e);
3214                }
3215            }
3216            for &c in &ch[dom_len..] {
3217                if let Some(e) = scan_kill_event(lang, c, name, false) {
3218                    if matches!(e, KillEvent::Read | KillEvent::Shadow) {
3219                        return Some(e);
3220                    }
3221                }
3222            }
3223            None
3224        }
3225        _ => {
3226            for &c in lang.children(node) {
3227                if let Some(e) = scan_kill_event(lang, c, name, dominating) {
3228                    return Some(e);
3229                }
3230            }
3231            None
3232        }
3233    }
3234}
3235
3236impl<L: Lang> Rule<L> for StoreKill {
3237    fn name(&self) -> &'static str {
3238        "store_kill"
3239    }
3240    fn kinds(&self) -> &'static [NodeKind] {
3241        &[NodeKind::VarDecl, NodeKind::Assign, NodeKind::ExprStmt]
3242    }
3243    fn check(&self, ctx: RewriteCtx<'_, L>, id: L::Id) -> Option<Edit<L>> {
3244        let RewriteCtx { lang, walk } = ctx;
3245        // 形态:VarDecl(带 init) 或 Assign(裸/ExprStmt 包裹)
3246        let (is_decl, stmt_node, first_value) = match lang.kind(id) {
3247            NodeKind::VarDecl => {
3248                if lang.children(id).is_empty() {
3249                    return None;
3250                }
3251                (true, id, *lang.children(id).first()?)
3252            }
3253            NodeKind::Assign => {
3254                if lang.assign_op(id).is_some() {
3255                    return None;
3256                }
3257                (false, id, *lang.children(id).get(1)?)
3258            }
3259            NodeKind::ExprStmt => {
3260                let ch = lang.children(id);
3261                if ch.len() == 1 && lang.kind(ch[0]) == NodeKind::Assign {
3262                    let a = ch[0];
3263                    if lang.assign_op(a).is_some() {
3264                        return None;
3265                    }
3266                    (false, id, *lang.children(a).get(1)?)
3267                } else {
3268                    return None;
3269                }
3270            }
3271            _ => return None,
3272        };
3273        let name = if is_decl {
3274            lang.var_name(id)?.to_string()
3275        } else {
3276            let a = match lang.kind(id) {
3277                NodeKind::Assign => id,
3278                _ => lang.children(id)[0],
3279            };
3280            let t = *lang.children(a).first()?;
3281            if lang.kind(t) != NodeKind::VarRef || !lang.is_local_var(t) {
3282                return None;
3283            }
3284            lang.var_name(t)?.to_string()
3285        };
3286
3287        let parent = walk.parent(stmt_node)?;
3288        if lang.kind(parent) != NodeKind::Block {
3289            return None;
3290        }
3291        let idx = walk.index(stmt_node)?;
3292        let stmts = lang.children(parent).to_vec();
3293
3294        // 扫描:读(任意路径)→ 保活;支配写 → 击杀;条件写 → 继续
3295        let mut killed_by: Option<(usize, L::Id)> = None;
3296        for (si, &s) in stmts.iter().enumerate().skip(idx + 1) {
3297            match scan_kill_event(&*lang, s, &name, true) {
3298                Some(KillEvent::Read) | Some(KillEvent::Shadow) => return None,
3299                Some(KillEvent::DomWrite(assign)) => {
3300                    killed_by = Some((si, assign));
3301                    break;
3302                }
3303                None => continue,
3304            }
3305        }
3306        let (si, kill_assign) = killed_by?;
3307        // 击杀语句级守卫:击杀赋值必须就是**顶层语句本身**(或其
3308        // ExprStmt 包裹)。嵌套击杀(do-while 体/裸块/for-init 里的写)
3309        // 曾按 stmts[si] 删整条外层语句——连兄弟副作用一起删
3310        //(RealTimeSequencer.pump() 的 133 行 do-while 曾被整删成
3311        // 3 行;ConstantPool.writeTags 双 for+switch 全删——JDK 语料
3312        // ≥9 文件)。同语句内击杀点之后的读也无法用语句级窗口证明
3313        // 不可达 → 保守拒绝嵌套击杀(顶层击杀不受影响)
3314        {
3315            let kill_container = match walk.parents.get(&kill_assign) {
3316                Some(&(p, _)) if lang.kind(p) == NodeKind::ExprStmt => p,
3317                _ => kill_assign,
3318            };
3319            if kill_container != stmts[si] {
3320                return None;
3321            }
3322        }
3323        // 异常窗口守卫:被击杀点到击杀点之间的语句若可能抛(效果 >
3324        // MayRead),异常路径会绕过击杀点直达 finally/catch——后者可能
3325        // 在「中间值」状态读到本变量(finally-flag 恢复模式:
3326        // v=true; setSoTimeout(1); v=false; finally{if(v)…}——差分
3327        // 抓获:v=true 曾被杀,异常路径的恢复逻辑变死代码)
3328        for &s in &stmts[idx + 1..si] {
3329            if lang.effect(s) > Effect::MayRead {
3330                return None;
3331            }
3332        }
3333
3334        if is_decl {
3335            // 击杀赋值的值是字面量 → 提升进声明 init
3336            // (原 init 被替换丢弃——同样必须可丢弃,副作用调用不得删!)
3337            if lang.effect(first_value) > Effect::MayRead {
3338                return None;
3339            }
3340            let value = *lang.children(kill_assign).get(1)?;
3341            if is_literal(lang, value) {
3342                let assign_stmt = stmts[si];
3343                return Some(Edit::Multi(vec![
3344                    Edit::Splice {
3345                        node: id,
3346                        index: 0,
3347                        remove: 1,
3348                        insert: vec![value],
3349                    },
3350                    Edit::Delete { node: assign_stmt },
3351                ]));
3352            }
3353            // 否则:剥除 init(裸声明)——init 必须可丢弃(副作用调用不得删!)。
3354            // 推断类型声明(Java `var`)剥 init 后非法——拒绝
3355            //(obf_fuzz 差分 seed 4 抓获:`var flag;` 编译失败)
3356            if lang.is_inferred_decl(id) {
3357                return None;
3358            }
3359            if lang.effect(first_value) > Effect::MayRead {
3360                return None;
3361            }
3362            return Some(Edit::Splice {
3363                node: id,
3364                index: 0,
3365                remove: 1,
3366                insert: Vec::new(),
3367            });
3368        }
3369        // 赋值形态:首值必须可丢弃
3370        if lang.effect(first_value) > Effect::MayRead {
3371            return None;
3372        }
3373        Some(Edit::Delete { node: stmt_node })
3374    }
3375}
3376
3377/// value 是否为字面量(提升安全:无求值位置问题)。
3378fn is_literal<L: Lang>(lang: &L, n: L::Id) -> bool {
3379    matches!(lang.kind(n), NodeKind::Literal)
3380}
3381
3382// ---------------------------------------------------------------------------
3383// 注册表
3384// ---------------------------------------------------------------------------
3385
3386/// 默认规则(保守集:不做 DCE 类清理)。
3387pub fn default_rules<L: Lang>() -> Vec<Box<dyn Rule<L>>> {
3388    vec![
3389        Box::new(DoubleNegFold),
3390        Box::new(BlockFlatten),
3391        Box::new(ParenRemoval),
3392        Box::new(ConstCondition),
3393        Box::new(BooleanReturn),
3394        Box::new(IfToTernary),
3395        Box::new(IfAssignTernary),
3396        Box::new(IfElseEmpty),
3397        Box::new(BoolCompare),
3398        Box::new(DoubleNot),
3399        Box::new(BoolNotFold),
3400        Box::new(BoolShortCircuit),
3401        Box::new(NotCompare),
3402        Box::new(TernaryFold),
3403        Box::new(TernaryBool),
3404        Box::new(TernaryBoolOp),
3405        Box::new(ConstFoldBin),
3406        Box::new(CmpConstFold),
3407        Box::new(BitIdentity),
3408        Box::new(ArithReassoc),
3409        Box::new(SelfAssign),
3410        Box::new(ArithIdentity),
3411        Box::new(ArithZero),
3412        Box::new(DeclAssignMerge),
3413        Box::new(LocalPropagation),
3414        Box::new(AssignPropagation),
3415        Box::new(MultiUseCopyPropagation),
3416        Box::new(TrailingReturn),
3417        Box::new(InverseAssignPair),
3418        Box::new(DeadDecl),
3419        Box::new(AssignBackFold),
3420        Box::new(DeadStore),
3421        Box::new(StoreKill),
3422    ]
3423}
3424
3425/// 全量规则(含 DCE 类选配项;按设计文档"可选配,默认不启用")。
3426pub fn all_rules<L: Lang>() -> Vec<Box<dyn Rule<L>>> {
3427    let mut rules = default_rules();
3428    rules.push(Box::new(UnreachableAfterTerminal));
3429    rules
3430}