定义新的 Lint
定义新 Lint 的第一步是在 Clippy 代码库中定义和注册 Lint。我们可以使用 Clippy 开发工具来处理这一步,因为设置 Lint 涉及到一些样板代码。
Lint 类型
Lint 类型是指你的 Lint 所关注的项目和表达式的类别。
在编写本文档更新时,除了 clippy_lints/src/
下的众多独立 Lint 外,还有 12 种 类型 的 Lint
cargo
类型转换
函数
循环
匹配
方法
其他早期
运算符
强制类型转换
类型
单元类型
utils / internal
(Clippy 内部 Lint)
这些类型将具有一些共同行为的 Lint 分组在一起。例如,functions
将处理 Rust 中函数某些方面的 Lint 分组在一起,例如定义、签名和属性。
有关更多信息,请随时将任何类别下的 Lint 文件与 所有 Clippy Lint 进行比较,或咨询维护人员之一。
Lint 名称
一个好的 Lint 名称很重要,请务必查看 Lint 命名指南。不用担心,如果 Lint 名称不合适,Clippy 团队成员会在 PR 过程中提醒您。
我们将把检测名为 "foo" 的函数的示例 Lint 命名为 foo_functions
。查看 Lint 命名指南,了解为什么这个名称有意义。
添加和注册 Lint
现在选择了名称,我们将 foo_functions
注册为代码库中的 Lint。有两种方法可以注册 Lint。
独立
如果您认为此新 Lint 是独立的 Lint(不属于任何特定的 类型,如 functions
或 loops
),则可以在您的 Clippy 项目中运行以下命令
$ cargo dev new_lint --name=lint_name --pass=late --category=pedantic
这里有两点需要注意
--pass
: 我们在此命令中设置--pass=late
以进行后期 Lint 传递。另一种选择是early
Lint 传递。我们将在 Lint 传递章节中讨论此区别。--category
: 如果未提供,则此新 Lint 的category
将默认为nursery
。
cargo dev new_lint
命令将创建一个新文件:clippy_lints/src/foo_functions.rs
以及 注册 Lint。
总的来说,您应该注意到以下文件被修改或创建
$ git status
On branch foo_functions
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CHANGELOG.md
modified: clippy_lints/src/lib.register_lints.rs
modified: clippy_lints/src/lib.register_pedantic.rs
modified: clippy_lints/src/lib.rs
Untracked files:
(use "git add <file>..." to include in what will be committed)
clippy_lints/src/foo_functions.rs
tests/ui/foo_functions.rs
特定类型
注意: Lint 类型在 "Lint 类型" 部分列出
如果您认为此新 Lint 属于特定类型的 Lint,则可以使用 --type
选项运行 cargo dev new_lint
。
由于我们的 foo_functions
Lint 与函数调用相关,因此有人可能会认为我们应该将其放入一组检测函数某些行为的 Lint 中,我们可以将其放入 functions
组。
让我们在您的 Clippy 项目中运行以下命令
$ cargo dev new_lint --name=foo_functions --type=functions --category=pedantic
此命令将创建(除其他外)一个新文件:clippy_lints/src/{type}/foo_functions.rs
。在我们的例子中,路径将是 clippy_lints/src/functions/foo_functions.rs
。
请注意,此命令具有 --type
标志而不是 --pass
。与独立定义不同,此 Lint 不会以传统方式注册。相反,您将从类型 Lint 传递(在 clippy_lints/src/{type}/mod.rs
中找到)中调用您的 Lint。
type 只是 clippy_lints/src
中的一个目录的名称,例如示例命令中的 functions
。Clippy 将一些具有共同行为的 Lint 分组在一起,因此如果您的 Lint 属于其中一种,最好将其添加到该类型中。
总的来说,您应该注意到以下文件被修改或创建
$ git status
On branch foo_functions
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CHANGELOG.md
modified: clippy_lints/src/declared_lints.rs
modified: clippy_lints/src/functions/mod.rs
Untracked files:
(use "git add <file>..." to include in what will be committed)
clippy_lints/src/functions/foo_functions.rs
tests/ui/foo_functions.rs
define_clippy_lints
宏
在 cargo dev new_lint
之后,您应该看到一个名为 define_clippy_lints
的宏。如果您定义了一个独立的 Lint,它将在同一个文件中,如果您定义了一个类型特定的 Lint,它将在 mod.rs
中。
宏看起来像这样
#![allow(unused)] fn main() { declare_clippy_lint! { /// ### What it does /// /// // Describe here what does the lint do. /// /// Triggers when detects... /// /// ### Why is this bad? /// /// // Describe why this pattern would be bad /// /// It can lead to... /// /// ### Example /// ```rust /// // example code where Clippy issues a warning /// ``` /// Use instead: /// ```rust /// // example code which does not raise Clippy warning /// ``` #[clippy::version = "1.70.0"] // <- In which version was this implemented, keep it up to date! pub LINT_NAME, // <- The lint name IN_ALL_CAPS pedantic, // <- The lint group "default lint description" // <- A lint description, e.g. "A function has an unit return type." } }
Lint 注册
如果我们为新的 Lint 运行 cargo dev new_lint
命令,则该 Lint 将自动注册,无需执行更多操作。
但是,有时我们可能想手动声明新的 Lint。在这种情况下,我们会之后使用 cargo dev update_lints
命令。
当手动声明 Lint 时,我们可能需要在 clippy_lints/src/lib.rs
中的 register_lints
函数中手动注册 Lint 传递
#![allow(unused)] fn main() { store.register_late_pass(|_| Box::new(foo_functions::FooFunctions)); }
您可能已经猜到了,有后期,就有早期:在 Clippy 中,也有一个 register_early_pass
方法。有关早期与后期传递的更多信息,请参阅 Lint 传递章节。
如果没有调用 register_early_pass
或 register_late_pass
之一,则不会运行有问题的 Lint 传递。