bigywater.tech
Rust · 161

Clippy 静态检查

Clippy 能抓住什么、有多挑剔、哪些问题会直接让构建失败、能自动修复多少?这篇不转述文档,直接对一份故意写坏的代码跑 cargo clippy,把诊断、等级、开关与自动修复全部亲眼看一遍。

11 条
默认配置下 clippy 对示例库的诊断数
2 个
默认就是 deny(error)的 lint:eq_op、absurd_extreme_comparisons
7 行
cargo clippy --fix 自动修改的行数

诊断长什么样

实测 · 本机执行输出
  退出码 101;共 11 条诊断(clippy 的 lint 9 个)
  触发的 lint: ['absurd_extreme_comparisons', 'bool_comparison', 'clone_on_copy', 'eq_op', 'len_zero', 'manual_map', 'needless_range_loop', 'needless_return', 'ptr_arg']
  前几条完整诊断:
    warning: unneeded `return` statement
     --> src/lib.rs:5:5
      |
    5 |     return s;                                               // needless_return
      |     ^^^^^^^^
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#needless_return
      = note: `#[warn(clippy::needless_return)]` on by default
    help: remove `return`
      |
    5 -     return s;                                               // needless_return
    5 +     s// needless_return
      |
    warning: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
     --> src/lib.rs:2:21
      |
    2 | pub fn sum_first(v: &Vec<i32>) -> i32 {                    // ptr_arg:参数应该是 &[i32]
      |                     ^^^^^^^^^
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#ptr_arg
      = note: `#[warn(clippy::ptr_arg)]` on by default
    help: change this to
      |
    2 - pub fn sum_first(v: &Vec<i32>) -> i32 {                    // ptr_arg:参数应该是 &[i32]
    2 + pub fn sum_first(v: &[i32]) -> i32 {                    // ptr_arg:参数应该是 &[i32]
      |
    warning: the loop variable `i` is only used to index `v`
     --> src/lib.rs:4:14
      |
    4 |     for i in 0..v.len() { s += v[i]; }                      // needless_range_loop
      |              ^^^^^^^^^^
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#needless_range_loop
      = note: `#[warn(clippy::needless_range_loop)]` on by default
    help: consider using an iterator
      |
    4 -     for i in 0..v.len() { s += v[i]; }                      // needless_range_loop
    4 +     for <item> in &v { s += v[i]; }                      // needless_range_loop
      |

代码格式化见rustfmt 格式化;持续集成里怎么用见Rust 项目持续集成。clippy 0.1.98。

deny 级别的 lint

实测 · 本机执行输出
  error 2 条:['error: equal expressions as operands to `==`', 'error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false'];deny 级别的 lint:['eq_op', 'absurd_extreme_comparisons'];cargo clippy 退出码 101
  warning 行 9 条

lint 的等级

实测 · 本机执行输出
  默认                           诊断 11 条;lint 数 9;退出码 101
  -W clippy::pedantic          诊断 22 条;lint 数 11;退出码 101
  -A clippy::all(全部允许)         诊断 1 条;lint 数 0;退出码 0
  pedantic 额外触发的 lint: ['bool_to_int_with_if', 'must_use_candidate']

局部关闭与 -D warnings

实测 · 本机执行输出
  加了 #[allow] 后退出码 0;剩下的 lint:['bool_comparison', 'clone_on_copy', 'manual_map', 'needless_range_loop', 'needless_return', 'ptr_arg']
  再加 -D warnings:退出码 101(警告变成错误,CI 会失败)

自动修复

实测 · 本机执行输出
  --fix 退出码 0;修改了 7 行:
    -    return s;                                               // needless_return
    +    s// needless_return
    -pub fn is_empty_len(v: &[u8]) -> bool { v.len() == 0 }      // len_zero
    -pub fn flag(b: bool) -> i32 { if b == true { 1 } else { 0 } }  // bool_comparison + bool_to_int_with_if
    -pub fn double(o: Option<i32>) -> Option<i32> { match o { Some(x) => Some(x * 2), None => None } }   // manual_map
    -pub fn copy_clone(x: i32) -> i32 { x.clone() }              // clone_on_copy
    +pub fn is_empty_len(v: &[u8]) -> bool { v.is_empty() }      // len_zero
    +pub fn flag(b: bool) -> i32 { if b { 1 } else { 0 } }  // bool_comparison + bool_to_int_with_if
    +pub fn double(o: Option<i32>) -> Option<i32> { o.map(|x| x * 2) }   // manual_map
    +pub fn copy_clone(x: i32) -> i32 { x }              // clone_on_copy
    -pub fn same(x: i32) -> bool { true }                      // eq_op:两边相同(deny 级别)
    -pub fn absurd(x: u32) -> bool { false }                     // absurd_extreme_comparisons:无符号数永远不小于 0(deny 级别)
    +pub fn same(_x: i32) -> bool { true }                      // eq_op:两边相同(deny 级别)
    +pub fn absurd(_x: u32) -> bool { false }                     // absurd_extreme_comparisons:无符号数永远不小于 0(deny 级别)
  修复后再跑 clippy:剩下的 lint ['needless_range_loop', 'ptr_arg']

分步演示

Clippy
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。clippy 0.1.98(随 rustc 1.98.1)
    • 没有验证:clippy.toml 的配置(msrv、阈值)、[lints.clippy] 在 Cargo.toml 里的写法、nursery 与 restriction 组、clippy 与 rust-analyzer 的集成、--fix 在有未提交改动时的保护、其它版本的 lint 差别
    京ICP备2026067502号-1京公网安备11010502063487号