12个版本
0.1.11 | 2023年2月2日 |
---|---|
0.1.10 | 2023年2月2日 |
0.1.9 | 2023年1月22日 |
0.1.6 | 2022年11月24日 |
在开发工具类别中排名396
每月下载量36次
95KB
2K SLoC
rust-diagnostics
这是一个工具,可以将代码片段的诊断作为注释插入到Rust代码中,并检查警告/错误在git提交历史中是如何被修复的。
Rust编译器在控制台显示许多诊断信息,使用文件名和行号来指示它们的精确位置。没有IDE,程序员需要来回切换命令控制台和编辑器。
此工具将诊断消息直接插入,这可能能够启用基于转换器的机器学习方法来分析Rust诊断语义。
通过额外的参数,此工具还可以检查在修订版r1中发现的警告是如何由修订版r2手动修复的。
目前我们已将此工具与clippy
和git2-rs
集成。
安装
cargo install rust-diagnostics
用法
以下是命令的完整语法。
rust-diagnostics [--patch <commit_id> [--confirm] [--pair] [--function] [--single] [--location] [--mixed] ]
运行示例
为了说明其用法,我们使用一个小示例,我们可以称之为一个abc
项目。
rm -rf abc
cargo init --bin abc
cat > abc/src/main.rs <<EOF
fn main() {
let s = std::fs::read_to_string("Cargo.toml").unwrap();
println!("{s}");
}
EOF
将警告信息插入Rust代码
rust-diagnostics
的默认函数(即,没有任何参数)将警告信息插入Rust代码。例如,
cd abc
rust-diagnostics
该命令调用clippy
来报告所有警告
Checking abc v0.1.0 (...)
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
There are 1 warnings in 1 files.
结果,还创建了一个新的文件夹diagnostics
,其中包含一个文件src/main.rs
fn main() {
let s = /*#[Warning(clippy::unwrap_used)*/std::fs::read_to_string("Cargo.toml").unwrap()/*
#[Warning(clippy::unwrap_used)
note: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
if this value is an `Err`, it will panic
requested on the command line with `-W clippy::unwrap-used`*/;
println!("The configuration file is: {s}");
}
如我们所见,相关的警告已经被两个注释标记,在违规代码之前和之后。之前的注释表示警告类型,这里是clippy::unwrap_used
。之后的注释也指示了由cargo clippy
报告的一些附加注释,提供了警告类型的详细信息和解决该问题的提示。在这个例子中,unwrap_used
没有自动修复。
分析变更历史中手动修复的警告
上述工具的扩展功能很有用,它可以检查更改历史中有多少警告被修复,是自动通过 cargo clippy --fix
实现的,还是通过手动补丁修复的。如果手动修复是重复的,那么它对学习语言很有帮助,无论是手动还是通过机器学习。
为此,我们通过在 git 仓库中做些修改来重新启动示例。
rm -rf abc
cargo init --vcs git --bin abc
cd abc
cat > src/main.rs <<EOF
fn main() {
let s = std::fs::read_to_string("Cargo.toml").unwrap();
println!("{s}");
}
EOF
git commit -am "r1"
cat > src/main.rs <<EOF
fn main() {
if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
println!("{s}");
}
}
EOF
git commit -am "r2"
这里使用 --vcs git
选项是为了让示例项目包含一些更改历史,以便说明与 git 仓库分析相关的功能。
如果你检查代码并想知道修订版 r2 是否修复了修订版 r1 的警告,你可以使用 git log -p
来首先识别修订的提交 ID。
commit 839164fa28d71a9c00009c9e25bc84dce6caa286 .......... (r2)
Author: ...
Date: ...
update
diff --git a/src/main.rs b/src/main.rs
index 36d2d89..6175ab1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
fn main() {
- let s = std::fs::read_to_string("Cargo.toml").unwrap();
- println!("{s}");
+ if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
+ println!("{s}");
+ }
}
commit 6fafc98041f47155bc51c5ddc55b8e8b0b7548bf .......... (r1)
Author: ...
Date: ...
init
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..36d2d89
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,5 @@
+
+fn main() {
+ let s = std::fs::read_to_string("Cargo.toml").unwrap();
+ println!("{s}");
+}
然后运行以下两个命令,我们可以检查 r1 的警告是否被 r2 修复。
git checkout $r1
rust-diagnostics --patch $r2 --confirm
输出 diagnostics.log
包含 $r1 的警告数量以及 $r1..$r2 之间影响修复列表中警告的块。
例如,输出将与 git diff
格式的输出相同
There are 1 warnings in 1 files.
##[Warning(clippy::unwrap_used)
@@ -3,2 +3,3 @@ fn main() {
- let s = std::fs::read_to_string("Cargo.toml").unwrap();
- println!("{s}");
+ if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
+ println!("{s}");
+ }
注意,这里我们移除了所有上下文行,就像 -U0
选项的 git-diff
命令一样,这样就可以得到更精确的补丁功能上下文。
使用 --pair
选项生成一对
使用 --pair
选项将补丁转换为变化前后的代码对
git checkout $r1
rust-diagnostics --patch $r2 --confirm --pair
例如,diagnostics.log
将包含
There are 1 warnings in 1 files.
##[Warning(clippy::unwrap_used)
@@ -3,2 +3,3 @@ fn main() {
let s = std::fs::read_to_string("Cargo.toml").unwrap();
println!("{s}");
=== 19a3477889393ea2cdd0edcb5e6ab30c ===
if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
println!("{s}");
}
注意。为了避免与现有代码冲突,我们在对偶的分隔符中使用哈希键 19a3477889393ea2cdd0edcb5e6ab30c
,它是由以下命令创建的
echo rust-diagnostics | md5sum
使用 --function
选项生成函数上下文
对偶可能过于简略,我们使用 --function
选项来打印补丁周围的函数作为其上下文
git checkout $r1
rust-diagnostics --patch $r2 --confirm --pair --function
例如,它将打印以下内容
There are 1 warnings in 1 files.
##[Warning(clippy::unwrap_used)
@@ -3,2 +3,3 @@ fn main() {
fn main() {
let s = std::fs::read_to_string("Cargo.toml").unwrap();
println!("{s}");
}
=== 19a3477889393ea2cdd0edcb5e6ab30c ===
@@ -3,2 +3,3 @@ fn main() {
fn main() {
if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
println!("{s}");
}
}
使用 --location
选项生成标记上下文
此选项可以将根据 clippy
生成的警告位置及其修复提示插入到原始上下文中。
git checkout $r1
rust-diagnostics --patch $r2 --confirm --pair --function --location
例如,它将打印以下内容
There are 1 warnings in 1 files.
##[Warning(clippy::unwrap_used)
fn main() {
let s = /*#[Warning(clippy::unwrap_used)*/std::fs::read_to_string("Cargo.toml").unwrap()/*
#[Warning(clippy::unwrap_used)
note: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
if this value is an `Err`, it will panic
requested on the command line with `-W clippy::unwrap-used`*/;
println!("{s}");
}
=== 19a3477889393ea2cdd0edcb5e6ab30c ===
fn main() {
if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
println!("{s}");
}
}
使用 --mixed
选项生成混合上下文和补丁
此选项可以将上下文与实际补丁配对。
git checkout $r1
rust-diagnostics --patch $r2 --confirm --pair --function --location --mixed
例如,它将打印以下内容
There are 1 warnings in 1 files.
##[Warning(clippy::unwrap_used)
fn main() {
let s = /*#[Warning(clippy::unwrap_used)*/std::fs::read_to_string("Cargo.toml").unwrap()/*
#[Warning(clippy::unwrap_used)
note: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
if this value is an `Err`, it will panic
requested on the command line with `-W clippy::unwrap-used`*/;
println!("{s}");
}
=== 19a3477889393ea2cdd0edcb5e6ab30c ===
- let s = std::fs::read_to_string("Cargo.toml").unwrap();
- println!("{s}");
+ if let Ok(s) = std::fs::read_to_string("Cargo.toml") {
+ println!("{s}");
+ }
注意,我们不保留标题,因为如果我们已经知道警告的位置,行号就不再重要了,而插入的标记提示已经移动了原始行号。
计算警告数量
另一种计算警告数量的方法是使用 "cargo lintcheck"。
致谢
- David Wood 提出了我们可以使用
--message-format=json
选项从 Rust 编译器获取诊断信息,这大大节省了修改 Rust 编译器的努力。现在我们的解决方案在一定程度上独立于 Rust 编译器的实现; - Mara Bos 提供了一些关于如何使用
if-let
语句解决unwrap()
警告的提示; - Amanieu d'Antras 对实践中某些 clippy 规则的必要性进行了解释,他还提高了底层 BTreeMap 的性能。
- Josh Triplett 实现了底层的
git2-rs
,它用 Rust 包装了libgit2
库。 - 李春苗博士实现了重构规则
unwrapped_used.txl
,以自动修复相应的警告。 - Nghi Bui 博士 提出了一种创建混合对的想法。
依赖项
~207MB
~5.5M SLoC