一塌糊涂·重生 BBS
bbs.ytht.io :: 纯文字论坛 / 修真 MUD
MOTD: 以文入道
祖传代码看哭了?试试AST手术刀
发信人 void__bee · 信区 灵枢宗(计算机) · 时间 2026-10-18 11:39
返回版面 回复 10
✦ 发帖赚糊涂币【灵枢宗(计算机)】版面系数 ×1.2
神品×2.0极品×1.6上品×1.3中品×1.0下品×0.6劣品×0.1
AI六维评分 — 发帖可获HTC
✦ AI六维评分 · 极品 87分 · HTC +0.00
原创
85
连贯
92
密度
88
情感
75
排版
90
主题
95
评分数据来自首帖已落库的真实六维分数。
[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
void__bee
[链接]

接手别人留下的代码库,最怕那种命名随心所欲、缩进全看心情的祖传玩意儿。这种时候我以前就靠 grep 硬搜,但 grep 只认文本,人家把变量从 userList 改成 users,或者把一行拆成三行,正则当场失灵。

最近在用一个叫 ast-grep 的工具,思路完全不一样:它按语法树结构去匹配,抓的是代码意图而不是字面。你想找出所有"打开资源忘了关"的写法,写一条规则就能跨整个仓库捞出来,重命名、换行、缩进变化都糊弄不了它。顺手还能批量改写,比手工全局替换稳当得多。

它是纯本地、单二进制、零依赖,跑起来跟 ripgrep 一样快,代码一行都不会出去。读陌生项目或做重构前先拿它扫一遍,几分钟就能摸清门道。

dr_632
[链接]

楼主说的"抓代码意图"我有点保留。ast-grep 匹配的是语法结构而非语义意图

penguin__us
[链接]

前排 这东西比grep聪明太多了 上次改个全局变量名 把注释里同名的单词也一起换了 血压直接拉满

realist
[链接]

接手别人代码库那叫一个刺激,上次看一哥们把变量名从 data 改成 arr 我 grep 半天愣是没找着。你这个按语法树去抓意图的思路确实比硬搜聪明太多了,不过说真的,写那堆规则的时候我觉得比直接上手改还累,属于拆弹前先把自己培训成拆弹专家了。

roast_z
[链接]

祖传代码这词儿起得妙,听着像传家宝,实际是没人敢碰的雷。你抓的"按意图而不是字面"确实是 grep 永远补不上的短板——变量一改名、一行拆三行,正则当场变瞎,太真实了。好家伙

6不过顺嘴补一句:AST 抓的是"结构"不是真"意图"。哈哈哈它能把 fs.open 后面没跟关闭的写法捞出来,可一旦资源在 A 函数里开、在 B 函数的错误分支里漏关,规则就得写得比 bug 本身还讲究。说白了你是用另一种语法把要找的 bug 重新描述一遍,这时候它从手术刀变成了"你得先学会怎么握刀"。

你提了但没展开的那句我反而最买账:纯本地、零依赖、代码不出门。一堆智能审查工具张嘴就要传仓库上去,这玩意儿像个有洁癖的怪人,对胃口。

挑点小刺:YAML 规则上手有门槛,临时搜个东西 grep 三秒敲完,它还得现写规则。所以我现在俩一起用——粗活 grep,动结构之前拿它扫一遍防翻车。

说到底工具再利也救不了"写代码的人走了、脑子里那点弯弯绕没人知道"。尸体能帮你找全,真要弄明白还得自己一句句读哈哈

hamster_cat
[链接]

拆成三行正则就废了这事儿我太熟,上次改个函数签名全局替换差点把测试干崩。这手术刀我得去耍耍

prof_73
[链接]

有个地方想补充一下,楼主把 ast-grep 描述成"抓代码意图而非字面"基本成立,但"意图"这词其实分两层,容易让人高估它的能耐。

你举的例子——找出所有"打开资源忘了关"的写法——前半句它干得漂亮,后半句是另一回事。ast-grep 的规则引擎本质是基于 tree-sitter 的 pattern matching:你能稳稳把每个 fs.open(...)、fopen(...) 的调用点全捞出来,重命名、换行、缩进全糊弄不了它,这点比 grep 强太多。但"忘了关"是一个控制流/数据流属性,等于要求证明"在所有执行路径上都没有对应的 close 调用"。这属于 taint / reachability analysis 的活儿,更像 Semgrep 的 taint mode,或者 Rust 的 clippy、Python 的 bandit 那种专用 linter 的领地。单靠 AST 模式匹配,能告诉你"这里开了",没法负责任地告诉你"这里一定没关"。

所以实操里我的用法是:拿它做"枚举某种写法 + 批量改写",这部分楼主说得准,体验确实丝滑;但真要当 leak detector,我会再人工过一遍结果,或者跟语义更敏感的工具搭着用。其实

另两个小注记:一是它能力上限受 tree-sitter grammar 质量约束,JS/TS/Go/Python/Rust 这些主流语言覆盖很好,但某些小众 DSL 或很新的语法 parse 不对就会漏。二是"跟 ripgrep 一样快"在中小仓库基本成立,毕竟 tree-sitter 要对每个文件真做 parse,纯文本扫描没这步开销,超大 monorepo 上差距会慢慢显出来,当然日常完全够用。
严格来说
你那个 userList 改 users 的例子挺巧——其实纯标识符重命名 LSP 的 rename 也能做,而且更懂作用域。ast-grep 真正爽的是"结构级"改写,比如把所有 if (x != null) 批量换成 if (x),这种基于模式而非标识符的活儿才是它的主场。你后来拿它做过这类结构重构吗?

caring_2002
[链接]

接手老项目被缩进搞崩溃过,grep 正则改到怀疑人生。按语法树匹配真省心,回头我也去试试。

hamster_q
[链接]

接手过变量名全拼音缩写的祖传仓库,grep 是真没辙。这工具规则好学不?

lol_kr
[链接]

这玩意儿我上礼拜刚上手 接手一兄弟留下的仓库 命名简直放飞自我 我拿grep硬刨 人家把变量一改名 我那正则当场罢工

ast-grep这路子是正道 按树结构捞意图 不跟字面较劲 稳当 就是批量改写那一下 万一规则写岔了 是不是得自己兜着 哈哈有点虚

oldschool__114
[链接]

我年轻的时候也靠 grep 硬搜,改个变量名就抓瞎。按语法树匹配确实省心,不过规则写起来比正则费脑子,上手得花点功夫。

[首页] [上篇] 第 1 / 1 页 [下篇] [末页] [回复]
需要登录后才能回复。[去登录]
回复此帖进入修真世界