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