2 个版本
使用旧的 Rust 2015
0.1.12 | 2018 年 4 月 20 日 |
---|---|
0.1.0 | 2017 年 10 月 31 日 |
#1347 in Rust 模式
28 每月下载量
用于 rerast
7KB
88 行
Rerast
Rerast 是一个基于规则进行 Rust 代码搜索/替换的工具。一个规则由一个搜索模式、一个替换和一个可能出现在搜索模式和替换中的占位符组成。匹配是在语法上进行的,而不是在文本上,因此格式不重要。占位符是强类型的,并且必须与规则中找到的类型匹配,才能应用规则。
Rerast 已弃用。我们建议使用 rust-analyzer 中提供的 结构化搜索替换 功能。该功能在 vscode 或命令行(以及可能的 vim)中可用。如果您缺少 Rerast 支持(或未支持)的任何特定功能,请在 此问题 上发表评论。
如果您仍然想使用 Rerast,我们建议使用 Rerast 版本 0.1.88 与 Rust 版本 nightly-2020-02-27。有一些 Rerast 的新版本,但新版本中存在一些损坏的功能。
安装
rustup toolchain add nightly-2020-02-27
rustup component add --toolchain nightly-2020-02-27 rustc-dev
cargo +nightly-2020-02-27 install --version 0.1.88 rerast
用法
基本操作可以从命令行完全执行
cargo +nightly-2020-02-27 rerast --placeholders 'a: i32' --search 'a + 1' --replace_with 'a - 1' --diff
或者您可以将您的规则放在一个 Rust 文件中
fn rule1(a: i32) {
replace!(a + 1 => a - 1);
}
然后使用
cargo +nightly-2020-02-27 rerast --rules_file=my_rules.rs
如果您想一次应用多个规则,则必须将您的规则放在文件中。
如果您确实想更新您的文件,可以按照以下方式进行
cargo +nightly-2020-02-27 rerast --placeholders 'a: i32' --search 'a + 1' --replace_with 'a - 1' --force --backup
您可以使用 --file
参数控制 rerast 将规则注入到哪些编译根中,例如
cargo +nightly-2020-02-27 rerast --rules_file=my_rules.rs --targets tests --file tests/testsuite/main.rs --diff
这里有一个更复杂的例子
use std::rc::Rc;
fn rule1<T>(r: Rc<T>) {
replace!(r.clone() => Rc::clone(&r))
}
这里我们将对 Rc 的 clone() 方法的调用替换为更明确的克隆 Rc 的方式 - 通过 Rc::clone。
"r" 是一个占位符,它将匹配指定类型的任何表达式。函数 "rule1" 的名称目前没有用于任何事情。在将来,可能可以通过指定名称来选择性地启用/禁用规则,因此在这里放一个稍微描述性的名称可能是一个好主意。同样,放在函数前面的注释可能在将来显示给用户,当规则匹配时。这还没有实现。
函数可以包含多个 replace! 宏的调用,早期规则优先。如果您想进行多个使用相同占位符的替换,或者想要先处理某些特殊模式,然后再进行更一般的匹配,这很有用。
除了 replace! 之外,还有其他几个替换宏可以使用
- replace_pattern! - 这用于替换模式。例如 &Some(a)。这种模式可能出现在匹配臂或 if let 中。不可反驳的模式(那些保证始终匹配的模式)也可以在 let 语句和函数参数中进行匹配。
- replace_type! - 这用于替换类型。目前它有点受限,因为它不支持占位符。另外,如果您类型只是一个特质,应考虑使用 replace_trait_ref!,因为特质引用可以出现在类型不能出现的环境中 - 特别是泛型边界和 where 子句。
- replace_trait_ref! - 这用于替换对命名特质的引用
替换语句目前已被禁用,等待找到一个好的用例。
匹配宏调用
只要宏调用展开为可匹配的代码,就可以匹配宏调用。然而,请注意,宏调用不会与等效代码匹配,也不会与不同但相同的宏的调用匹配。这是故意的。在验证匹配时,我们检查是否遵循了相同的展开序列。另外,如果宏在每次调用时都展开为不同的内容,它将永远不会匹配。println! 就是一个这样的宏,因为它生成一个在展开代码中引用的常量,每次调用都引用不同的常量。
运算顺序
假设您正在将 foo(a, b) 替换为 a && !b。根据占位符最终匹配的内容和整个表达式的上下文,可能需要额外的括号。例如,如果匹配的代码是 !foo(x == 1, y == 2),如果我们没有添加任何括号,我们最终会得到 !x == 1 && !y == 2,这显然是不正确的。Rerast 会检测到这种情况,并在必要时添加括号以保留替换中的顺序或优先级。这将给出 !(x == 1 && !(y == 2))。
代码格式化
目前不会对代码进行格式化。未匹配的代码将不受影响。替换代码通过复制规则中的替换代码并将任何匹配的模式拼接进来来生成。在未来,我们可能会调整多行替换的缩进。运行 rustfmt 可能是个好主意,因为一些缩进和行长度可能不是最佳的。
递归和重叠匹配
第一个匹配的规则获胜。当某些代码被匹配时,不会对那个代码应用后续的规则。然而,匹配到占位符的代码将被搜索以匹配所有规则。
从源代码更改自动确定规则
如果您即将在源代码的多个地方进行更改,并且您正在使用 git,您可以将更改(或暂存)提交,然后进行一次编辑,然后运行
cargo +nightly-2020-02-27 rerast --replay_git --diff
这将定位项目中的更改表达式(应该只有一个),然后尝试确定会产生这种更改的规则。它将打印规则,然后将其应用到您的项目上。如果您对更改满意,可以再次运行并使用 --force 应用它们,或者您可以将打印出的规则复制到 .rs 文件中并使用 --rules_file 应用。
- 产生的规则将尽可能多地使用占位符。即,在旧代码和新代码中都找到的子表达式将被占位符替换。
- 目前这仅适用于更改的表达式,不适用于语句、类型、模式等。
- 您的代码必须在有和没有更改的情况下都能编译。
限制
- 使用语句尚未更新,因此根据您的规则,在应用规则后可能需要更新。这最终应该得到修复,只是在发布前没有时间,而且有点棘手。
- 您的代码必须能够编译才能使其工作。
- 替换代码也必须能够编译。这意味着rerast在用非废弃版本替换废弃API使用方面比处理破坏性更改做得更好。通常,最好的解决方案是临时创建一个新的API。
- rustdoc中的代码尚未处理和匹配。
- 使用cfg属性禁用的条件代码没有匹配。建议在运行时尽可能启用所有功能,以便尽可能多地检查代码。
- replace_type!还不支持占位符。
- 可能存在许多错误和缺失的功能。请随时提交错误/功能请求。
已知问题
- 如果您在项目中具有集成测试(“tests”目录),则可能没有匹配项。不确定为什么。这始于2020年4月10日的nightly版本。您可能可以通过向cargo rerast传递
--targets ''
来解决这个问题。遗憾的是,这样您将无法在非集成测试(即cfg(test))中获得匹配项。或者,您可以考虑安装较老的rust和相应的rerast版本。 - 在替换中使用
?
目前有问题。我认为这发生在2020年2月。与spans相关的东西发生了变化。
更多示例
请参阅Rerast食谱以获取更多示例。
组
有疑问吗?
请随时在github上提交问题。
作者
请参阅Cargo.toml
贡献
行为准则
本项目遵循Rust行为准则。如果您觉得有人未遵守本项目相关的行为准则,请联系David Lattimore。我的电子邮件地址在Cargo.toml中。
免责声明
这不是一个官方的Google产品。Google之所以发布它,只是因为(原始)作者恰好在那里工作。