Skip to main content

cure_engine/
analysis.rs

1//! 通用轻量分析:局部变量读/写集合(只依赖 `Lang` 规范词汇表)。
2
3
4use crate::kind::NodeKind;
5use crate::lang::Lang;
6
7/// `node` 子树中**显式写**的局部变量名集合。
8/// 注意:`Call`/`Member` 等不可知的写不计入——但那些节点的 effect 会是
9/// Unknown/MayThrow,调用方须先按 effect 分类,再对“只读局部”路径用本函数。
10pub fn local_writes<'a, L: Lang>(lang: &'a L, id: L::Id, out: &mut crate::walk::StrSet<'a>) {
11    match lang.kind(id) {
12        NodeKind::Assign => {
13            let children = lang.children(id);
14            if let Some(&t) = children.first() {
15                if lang.kind(t) == NodeKind::VarRef {
16                    if let Some(n) = lang.var_name(t) {
17                        out.insert(n);
18                    }
19                }
20            }
21            if let Some(&v) = children.get(1) {
22                local_writes(lang, v, out);
23            }
24        }
25        NodeKind::Unary => {
26            if let Some(op) = lang.un_op(id) {
27                if op.is_incdec() {
28                    let children = lang.children(id);
29                    if let Some(&t) = children.first() {
30                        if lang.kind(t) == NodeKind::VarRef {
31                            if let Some(n) = lang.var_name(t) {
32                                out.insert(n);
33                            }
34                        }
35                    }
36                }
37            }
38            for &c in lang.children(id) {
39                local_writes(lang, c, out);
40            }
41        }
42        NodeKind::VarDecl => {
43            if let Some(n) = lang.var_name(id) {
44                out.insert(n);
45            }
46            for &c in lang.children(id) {
47                local_writes(lang, c, out);
48            }
49        }
50        _ => {
51            for &c in lang.children(id) {
52                local_writes(lang, c, out);
53            }
54        }
55    }
56}
57
58/// `node` 子树中所有被**读**的变量名(VarRef)。
59pub fn reads_vars<'a, L: Lang>(lang: &'a L, id: L::Id, out: &mut crate::walk::StrSet<'a>) {
60    if lang.kind(id) == NodeKind::VarRef {
61        if let Some(n) = lang.var_name(id) {
62            out.insert(n);
63        }
64    }
65    for &c in lang.children(id) {
66        reads_vars(lang, c, out);
67    }
68}
69
70/// 子树中是否存在满足谓词的节点(迭代,防爆栈)。
71pub fn subtree_contains<L: Lang>(lang: &L, id: L::Id, pred: impl Fn(L::Id) -> bool) -> bool {
72    let mut stack = vec![id];
73    while let Some(n) = stack.pop() {
74        if pred(n) {
75            return true;
76        }
77        for &c in lang.children(n) {
78            stack.push(c);
79        }
80    }
81    false
82}
83
84/// 求值顺序上位于 `target` 之前的兄弟子树,效果是否全部 ≤ `MayRead`。
85/// (局部变量读与“非写”效果之间可重排;任何 MayThrow 及以上都阻断。)
86///
87/// `target` 必须在 `root` 子树内。短路的右操作数按“会求值”保守处理。
88pub fn prefix_effects_readable<L: Lang>(lang: &L, root: L::Id, target: L::Id) -> bool {
89    fn go<L: Lang>(lang: &L, node: L::Id, target: L::Id) -> bool {
90        if node == target {
91            return true;
92        }
93        for &c in lang.children(node) {
94            if crate::analysis::subtree_contains(lang, c, |n| n == target) {
95                // target 在 c 内:c 之前的兄弟都必须 ≤ MayRead
96                // (循环里已经在 return 前检查过前面的兄弟)
97                return go(lang, c, target);
98            } else {
99                if lang.effect(c) > crate::effect::Effect::MayRead {
100                    return false;
101                }
102            }
103        }
104        true
105    }
106    go(lang, root, target)
107}
108
109/// 两棵子树是否**语法结构相同**(kind/运算符/字面量/变量名/children 逐位一致)。
110/// 用于 `c ? a : a` 这类同支折叠的判定。纯语法比较,不含语义等价判断。
111pub fn structurally_equal<L: Lang>(lang: &L, a: L::Id, b: L::Id) -> bool {
112    if lang.kind(a) != lang.kind(b) {
113        return false;
114    }
115    if lang.bin_op(a) != lang.bin_op(b) || lang.un_op(a) != lang.un_op(b) {
116        return false;
117    }
118    if lang.var_name(a) != lang.var_name(b) {
119        return false;
120    }
121    // 成员名(x.f 的 f / X::m 的 m):var_name 不覆盖 Member——
122    // syms.objectType 与 syms.botType 曾被误判相等 → ternary_fold
123    // `c ? a : a` 分支删除活分支(Types.java Rewriter.high 抓获)
124    if lang.member_name(a) != lang.member_name(b) {
125        return false;
126    }
127    // 节点负载(New.ty/anon_raw、Cast.ty、InstanceOf.ty/bind、
128    // Lambda.params_raw 等):children 相同但类型不同曾判相等——
129    // `cond ? new FairSync() : new NonfairSync()` 90 处误折
130    //(JDK 语料,5 例运行时行为改变证实)
131    if !lang.payload_equal(a, b) {
132        return false;
133    }
134    match (lang.literal(a), lang.literal(b)) {
135        (Some(x), Some(y)) if x == y => {}
136        (None, None) => {}
137        _ => return false,
138    }
139    let (ca, cb) = (lang.children(a), lang.children(b));
140    if ca.len() != cb.len() {
141        return false;
142    }
143    ca.iter().zip(cb.iter()).all(|(&x, &y)| structurally_equal(lang, x, y))
144}
145
146// ---------------------------------------------------------------------------
147// 结构化简化指标:节点数 / 判定点(McCabe 决策点)/ 最大嵌套深度。
148//
149// 与行数不同,这三项**不受格式化影响**——只被语义简化改变。用于
150// 区分「真简化」与「纯格式归一」,以及在大语料上定位未简化的文件
151// (指标零变化 = 无规则命中)。
152// ---------------------------------------------------------------------------
153
154/// 一个根(通常是方法体)的结构指标。
155#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
156pub struct TreeMetrics {
157    /// 子树节点总数(从根可达的 arena 节点;不含编辑残留的游离节点)。
158    pub nodes: u64,
159    /// 判定点数:if / while / do / for / foreach / case / catch / 三元 /
160    /// `&&` / `||`(McCabe 复杂度的决策点部分)。
161    pub decisions: u64,
162    /// 最大嵌套深度(语句容器嵌套层数;反编译嵌套块与扁平化状态机
163    /// 的直接体现)。
164    pub max_depth: u32,
165}
166
167impl TreeMetrics {
168    pub fn add(&mut self, other: TreeMetrics) {
169        self.nodes += other.nodes;
170        self.decisions += other.decisions;
171        self.max_depth = self.max_depth.max(other.max_depth);
172    }
173}
174
175/// 是否为语句容器(进入其孩子算一层嵌套)。
176fn is_container(k: NodeKind) -> bool {
177    matches!(
178        k,
179        NodeKind::Block
180            | NodeKind::If
181            | NodeKind::While
182            | NodeKind::DoWhile
183            | NodeKind::For
184            | NodeKind::ForEach
185            | NodeKind::Try
186            | NodeKind::Catch
187            | NodeKind::Switch
188            | NodeKind::Synchronized
189    )
190}
191
192/// 是否为判定点(kind 级)。
193fn is_decision_kind(k: NodeKind) -> bool {
194    matches!(
195        k,
196        NodeKind::If
197            | NodeKind::While
198            | NodeKind::DoWhile
199            | NodeKind::For
200            | NodeKind::ForEach
201            | NodeKind::Case
202            | NodeKind::Catch
203            | NodeKind::Ternary
204    )
205}
206
207/// 从 `root`(方法体等)累计结构指标。
208pub fn subtree_metrics<L: Lang>(lang: &L, root: L::Id) -> TreeMetrics {
209    let mut m = TreeMetrics::default();
210    walk_metrics(lang, root, 0, &mut m);
211    m
212}
213
214fn walk_metrics<L: Lang>(lang: &L, id: L::Id, depth: u32, m: &mut TreeMetrics) {
215    m.nodes += 1;
216    let k = lang.kind(id);
217    if is_decision_kind(k) {
218        m.decisions += 1;
219    }
220    // 短路 && / || 是独立判定点(路径分叉)
221    if k == NodeKind::Binary && lang.bin_op(id).is_some_and(|o| o.is_short_circuit()) {
222        m.decisions += 1;
223    }
224    let child_depth = if is_container(k) { depth + 1 } else { depth };
225    if child_depth > m.max_depth {
226        m.max_depth = child_depth;
227    }
228    for &c in lang.children(id) {
229        walk_metrics(lang, c, child_depth, m);
230    }
231}