Lint 级别
在 rustc
中,lint 被分为六个*级别*
- allow
- expect
- warn
- force-warn
- deny
- forbid
每个 lint 都有一个默认级别(在本章后面的 lint 列表中解释),并且编译器有一个默认的警告级别。首先,让我们解释这些级别是什么意思,然后再讨论配置。
allow
这些 lint 存在,但默认情况下什么也不做。例如,考虑以下源代码:
pub fn foo() {}
编译此文件不会产生警告
$ rustc lib.rs --crate-type=lib
$
但是这段代码违反了 missing_docs
lint。
这些 lint 的存在主要是为了通过配置手动开启,我们将在本节后面讨论。
expect
有时,抑制 lint 会很有帮助,但同时要确保相关代码仍然触发它们。“expect”级别正是这样做的。如果相关 lint 没有触发,unfulfilled_lint_expectation
lint 会在 expect
属性上触发,通知你期望不再满足。
fn main() {
#[expect(unused_variables)]
let unused = "Everyone ignores me";
#[expect(unused_variables)] // `unused_variables` lint is not emitted
let used = "I'm useful"; // the expectation is therefore unfulfilled
println!("The `used` value is equal to: {:?}", used);
}
这将产生以下警告:
warning: this lint expectation is unfulfilled
--> src/main.rs:7:14
|
7 | #[expect(unused_variables)]
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
此级别只能通过 #[expect]
属性定义,没有等效的命令行标志。具有特殊“force-warn”级别的 lint 仍会照常触发。
warn
“warn” lint 级别会在你违反 lint 时产生警告。例如,这段代码触犯了 unused_variables
lint:
pub fn foo() {
let x = 5;
}
这将产生此警告:
$ rustc lib.rs --crate-type=lib
warning: unused variable: `x`
--> lib.rs:2:9
|
2 | let x = 5;
| ^
|
= note: `#[warn(unused_variables)]` on by default
= note: to avoid this warning, consider using `_x` instead
force-warn
'force-warn' 是一个特殊的 lint 级别。它与“warn”相同,此级别的 lint 会产生警告,但与“warn”级别不同的是,“force-warn”级别无法被覆盖。如果一个 lint 设置为“force-warn”,它就保证会警告:不多也不少。即使通过 `cap-lints` 对总体 lint 级别进行了封顶,这也是如此。
deny
“deny” lint 会在你违反它时产生错误。例如,这段代码触犯了 exceeding_bitshifts
lint。
fn main() {
100u8 << 10;
}
$ rustc main.rs
error: bitshift exceeds the type's number of bits
--> main.rs:2:13
|
2 | 100u8 << 10;
| ^^^^^^^^^^^
|
= note: `#[deny(exceeding_bitshifts)]` on by default
来自 lint 的错误与常规错误有什么区别?Lint 是可通过级别配置的,因此与“allow” lint 类似,默认情况下为“deny”的警告允许你允许它们。同样,你可能希望将默认设置为“warn”的 lint 设置为产生错误。此 lint 级别为你提供了这种能力。
forbid
'forbid' 是一个特殊的 lint 级别,它对“deny”起的作用与“force-warn”对“warn”起的作用相同。它与“deny”相同,此级别的 lint 会产生错误,但与“deny”级别不同的是,“forbid”级别不能被覆盖为低于错误的任何级别。然而,lint 级别仍可能通过 --cap-lints
进行封顶(见下文),因此 rustc --cap-lints warn
会使设置为“forbid”的 lint 仅产生警告。
配置警告级别
还记得我们在“allow” lint 级别中使用的 missing_docs
示例吗?
$ cat lib.rs
pub fn foo() {}
$ rustc lib.rs --crate-type=lib
$
我们可以通过编译器标志以及源代码中的属性,将此 lint 配置到更高的级别。
你还可以“封顶” lint,以便编译器可以选择忽略某些 lint 级别。我们最后讨论这一点。
通过编译器标志
-A
、-W
、--force-warn
、-D
和 -F
标志允许你将一个或多个 lint 级别设置为允许、警告、强制警告、拒绝或禁止,如下所示:
$ rustc lib.rs --crate-type=lib -W missing-docs
warning: missing documentation for crate
--> lib.rs:1:1
|
1 | pub fn foo() {}
| ^^^^^^^^^^^^
|
= note: requested on the command line with `-W missing-docs`
warning: missing documentation for a function
--> lib.rs:1:1
|
1 | pub fn foo() {}
| ^^^^^^^^^^^^
$ rustc lib.rs --crate-type=lib -D missing-docs
error: missing documentation for crate
--> lib.rs:1:1
|
1 | pub fn foo() {}
| ^^^^^^^^^^^^
|
= note: requested on the command line with `-D missing-docs`
error: missing documentation for a function
--> lib.rs:1:1
|
1 | pub fn foo() {}
| ^^^^^^^^^^^^
error: aborting due to 2 previous errors
你也可以多次传递每个标志来更改多个 lint:
$ rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables
当然,你也可以将这五个标志混合使用:
$ rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables
这些命令行参数的顺序会被考虑在内。以下示例允许了 unused-variables
lint,因为它是该 lint 的最后一个参数:
$ rustc lib.rs --crate-type=lib -D unused-variables -A unused-variables
你可以利用此行为来覆盖 lint 组中某个特定 lint 的级别。以下示例拒绝了 unused
组中的所有 lint,但明确允许了该组中的 unused-variables
lint(无论顺序如何,forbid
仍然凌驾于一切之上):
$ rustc lib.rs --crate-type=lib -D unused -A unused-variables
由于 force-warn
和 forbid
无法被覆盖,设置其中一个将阻止针对同一 lint 的任何后续级别生效。
通过属性
你也可以使用 crate 范围的属性修改 lint 级别:
$ cat lib.rs
#![warn(missing_docs)]
pub fn foo() {}
$ rustc lib.rs --crate-type=lib
warning: missing documentation for crate
--> lib.rs:1:1
|
1 | / #![warn(missing_docs)]
2 | |
3 | | pub fn foo() {}
| |_______________^
|
note: lint level defined here
--> lib.rs:1:9
|
1 | #![warn(missing_docs)]
| ^^^^^^^^^^^^
warning: missing documentation for a function
--> lib.rs:3:1
|
3 | pub fn foo() {}
| ^^^^^^^^^^^^
warn
、allow
、deny
和 forbid
都以这种方式工作。无法使用属性将 lint 设置为 force-warn
。
你也可以在每个属性中传递多个 lint:
#![warn(missing_docs, unused_variables)]
pub fn foo() {}
并一起使用多个属性:
#![warn(missing_docs)]
#![deny(unused_variables)]
pub fn foo() {}
所有 lint 属性都支持一个额外的 reason
参数,以提供添加特定属性的原因。如果 lint 在定义的级别触发,此原因将作为 lint 消息的一部分显示。
use std::path::PathBuf;
pub fn get_path() -> PathBuf {
#[allow(unused_mut, reason = "this is only modified on some platforms")]
let mut file_name = PathBuf::from("git");
#[cfg(target_os = "windows")]
file_name.set_extension("exe");
file_name
}
封顶 lint
rustc
支持一个标志 --cap-lints LEVEL
,用于设置“lint 封顶级别”。这是所有 lint 的最高级别。因此,例如,如果我们使用上面“deny” lint 级别中的代码示例:
fn main() {
100u8 << 10;
}
并且我们编译它,将 lint 封顶到警告级别:
$ rustc lib.rs --cap-lints warn
warning: bitshift exceeds the type's number of bits
--> lib.rs:2:5
|
2 | 100u8 << 10;
| ^^^^^^^^^^^
|
= note: `#[warn(exceeding_bitshifts)]` on by default
warning: this expression will panic at run-time
--> lib.rs:2:5
|
2 | 100u8 << 10;
| ^^^^^^^^^^^ attempt to shift left with overflow
现在它只产生警告,而不是错误。我们可以进一步允许所有 lint:
$ rustc lib.rs --cap-lints allow
$
Cargo 大量使用此功能;它在编译你的依赖项时会传递 --cap-lints allow
,这样如果它们有任何警告,就不会污染你的构建输出。