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