Skip to content

Commit 908fd36

Browse files
committed
add --explain subcommand
1 parent cc637ba commit 908fd36

File tree

583 files changed

+11212
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

583 files changed

+11212
-0
lines changed

src/docs.rs

+601
Large diffs are not rendered by default.
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
### What it does
2+
Checks for comparisons where one side of the relation is
3+
either the minimum or maximum value for its type and warns if it involves a
4+
case that is always true or always false. Only integer and boolean types are
5+
checked.
6+
### Why is this bad?
7+
An expression like `min <= x` may misleadingly imply
8+
that it is possible for `x` to be less than the minimum. Expressions like
9+
`max < x` are probably mistakes.
10+
### Known problems
11+
For `usize` the size of the current compile target will
12+
be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such
13+
a comparison to detect target pointer width will trigger this lint. One can
14+
use `mem::sizeof` and compare its value or conditional compilation
15+
attributes
16+
like `#[cfg(target_pointer_width = "64")] ..` instead.
17+
### Example
18+
19+
let vec: Vec<isize> = Vec::new();
20+
if vec.len() <= 0 {}
21+
if 100 > i32::MAX {}

src/docs/alloc_instead_of_core.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### What it does
2+
Finds items imported through `alloc` when available through `core`.
3+
### Why is this bad?
4+
Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are
5+
imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint
6+
is also useful for crates migrating to become `no_std` compatible.
7+
### Example
8+
9+
use alloc::slice::from_ref;
10+
11+
Use instead:
12+
13+
use core::slice::from_ref;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
### What it does
2+
Checks for attributes that allow lints without a reason.
3+
(This requires the `lint_reasons` feature)
4+
### Why is this bad?
5+
Allowing a lint should always have a reason. This reason should be documented to
6+
ensure that others understand the reasoning
7+
### Example
8+
9+
#![feature(lint_reasons)]
10+
#![allow(clippy::some_lint)]
11+
12+
Use instead:
13+
14+
#![feature(lint_reasons)]
15+
#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### What it does
2+
Checks for ranges which almost include the entire range of letters from 'a' to 'z', but
3+
don't because they're a half open range.
4+
### Why is this bad?
5+
This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
6+
### Example
7+
8+
let _ = 'a'..'z';
9+
10+
Use instead:
11+
12+
let _ = 'a'..='z';

src/docs/almost_swapped.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### What it does
2+
Checks for `foo = bar; bar = foo` sequences.
3+
### Why is this bad?
4+
This looks like a failed attempt to swap.
5+
### Example
6+
7+
a = b;
8+
b = a;
9+
10+
If swapping is intended, use `swap()` instead:
11+
12+
std::mem::swap(&mut a, &mut b);

src/docs/approx_constant.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
### What it does
2+
Checks for floating point literals that approximate
3+
constants which are defined in
4+
[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)
5+
or
6+
[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),
7+
respectively, suggesting to use the predefined constant.
8+
### Why is this bad?
9+
Usually, the definition in the standard library is more
10+
precise than what people come up with. If you find that your definition is
11+
actually more precise, please [file a Rust
12+
issue](https://github.com/rust-lang/rust/issues).
13+
### Example
14+
15+
let x = 3.14;
16+
let y = 1_f64 / x;
17+
18+
Use instead:
19+
20+
let x = std::f32::consts::PI;
21+
let y = std::f64::consts::FRAC_1_PI;

src/docs/arithmetic.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
### What it does
2+
Checks for any kind of arithmetic operation of any type.
3+
Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust
4+
Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),
5+
or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered
6+
away.
7+
### Why is this bad?
8+
Integer overflow will trigger a panic in debug builds or will wrap in
9+
release mode. Division by zero will cause a panic in either mode. In some applications one
10+
wants explicitly checked, wrapping or saturating arithmetic.
11+
#### Example
12+
13+
a + 1;
14+
15+
Third-party types also tend to overflow.
16+
#### Example
17+
18+
use rust_decimal::Decimal;
19+
let _n = Decimal::MAX + Decimal::MAX;
20+
21+
### Allowed types
22+
Custom allowed types can be specified through the "arithmetic-allowed" filter.

src/docs/as_conversions.md

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
### What it does
2+
Checks for usage of `as` conversions.
3+
Note that this lint is specialized in linting *every single* use of `as`
4+
regardless of whether good alternatives exist or not.
5+
If you want more precise lints for `as`, please consider using these separate lints:
6+
`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`,
7+
`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
8+
There is a good explanation the reason why this lint should work in this way and how it is useful
9+
[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
10+
### Why is this bad?
11+
`as` conversions will perform many kinds of
12+
conversions, including silently lossy conversions and dangerous coercions.
13+
There are cases when it makes sense to use `as`, so the lint is
14+
Allow by default.
15+
### Example
16+
17+
let a: u32;
18+
...
19+
f(a as u16);
20+
21+
Use instead:
22+
23+
f(a.try_into()?);
24+
// or
25+
f(a.try_into().expect("Unexpected u16 overflow in f"));

src/docs/as_underscore.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### What it does
2+
Check for the usage of `as _` conversion using inferred type.
3+
### Why is this bad?
4+
The conversion might include lossy conversion and dangerous cast that might go
5+
undetected due to the type being inferred.
6+
The lint is allowed by default as using `_` is less wordy than always specifying the type.
7+
### Example
8+
9+
fn foo(n: usize) {}
10+
let n: u16 = 256;
11+
foo(n as _);
12+
13+
Use instead:
14+
15+
fn foo(n: usize) {}
16+
let n: u16 = 256;
17+
foo(n as usize);

src/docs/assertions_on_constants.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
### What it does
2+
Checks for `assert!(true)` and `assert!(false)` calls.
3+
### Why is this bad?
4+
Will be optimized out by the compiler or should probably be replaced by a
5+
`panic!()` or `unreachable!()`
6+
### Example
7+
8+
assert!(false)
9+
assert!(true)
10+
const B: bool = false;
11+
assert!(B)
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
### What it does
2+
Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls.
3+
### Why is this bad?
4+
An assertion failure cannot output an useful message of the error.
5+
### Known problems
6+
The suggested replacement decreases the readability of code and log output.
7+
### Example
8+
9+
assert!(r.is_ok());
10+
assert!(r.is_err());

src/docs/assign_op_pattern.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
### What it does
2+
Checks for `a = a op b` or `a = b commutative_op a`
3+
patterns.
4+
### Why is this bad?
5+
These can be written as the shorter `a op= b`.
6+
### Known problems
7+
While forbidden by the spec, `OpAssign` traits may have
8+
implementations that differ from the regular `Op` impl.
9+
### Example
10+
11+
let mut a = 5;
12+
let b = 0;
13+
// ...
14+
a = a + b;
15+
16+
Use instead:
17+
18+
let mut a = 5;
19+
let b = 0;
20+
// ...
21+
a += b;

src/docs/async_yields_async.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
### What it does
2+
Checks for async blocks that yield values of types
3+
that can themselves be awaited.
4+
### Why is this bad?
5+
An await is likely missing.
6+
### Example
7+
8+
async fn foo() {}
9+
fn bar() {
10+
let x = async {
11+
foo()
12+
};
13+
}
14+
15+
Use instead:
16+
17+
async fn foo() {}
18+
fn bar() {
19+
let x = async {
20+
foo().await
21+
};
22+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
### What it does
2+
Allows users to configure types which should not be held across `await`
3+
suspension points.
4+
### Why is this bad?
5+
There are some types which are perfectly "safe" to be used concurrently
6+
from a memory access perspective but will cause bugs at runtime if they
7+
are held in such a way.
8+
### Example
9+
10+
await-holding-invalid-types = [
11+
# You can specify a type name
12+
"CustomLockType",
13+
# You can (optionally) specify a reason
14+
{ path = "OtherCustomLockType", reason = "Relies on a thread local" }
15+
]
16+
17+
18+
struct CustomLockType;
19+
struct OtherCustomLockType;
20+
async fn foo() {
21+
let _x = CustomLockType;
22+
let _y = OtherCustomLockType;
23+
baz().await; // Lint violation
24+
}

src/docs/await_holding_lock.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
### What it does
2+
Checks for calls to await while holding a non-async-aware MutexGuard.
3+
### Why is this bad?
4+
The Mutex types found in std::sync and parking_lot
5+
are not designed to operate in an async context across await points.
6+
There are two potential solutions. One is to use an async-aware Mutex
7+
type. Many asynchronous foundation crates provide such a Mutex type. The
8+
other solution is to ensure the mutex is unlocked before calling await,
9+
either by introducing a scope or an explicit call to Drop::drop.
10+
### Known problems
11+
Will report false positive for explicitly dropped guards
12+
([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
13+
to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
14+
### Example
15+
16+
async fn foo(x: &Mutex<u32>) {
17+
let mut guard = x.lock().unwrap();
18+
*guard += 1;
19+
baz().await;
20+
}
21+
async fn bar(x: &Mutex<u32>) {
22+
let mut guard = x.lock().unwrap();
23+
*guard += 1;
24+
drop(guard); // explicit drop
25+
baz().await;
26+
}
27+
28+
Use instead:
29+
30+
async fn foo(x: &Mutex<u32>) {
31+
{
32+
let mut guard = x.lock().unwrap();
33+
*guard += 1;
34+
}
35+
baz().await;
36+
}
37+
async fn bar(x: &Mutex<u32>) {
38+
{
39+
let mut guard = x.lock().unwrap();
40+
*guard += 1;
41+
} // guard dropped here at end of scope
42+
baz().await;
43+
}

src/docs/await_holding_refcell_ref.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
### What it does
2+
Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
3+
### Why is this bad?
4+
`RefCell` refs only check for exclusive mutable access
5+
at runtime. Holding onto a `RefCell` ref across an `await` suspension point
6+
risks panics from a mutable ref shared while other refs are outstanding.
7+
### Known problems
8+
Will report false positive for explicitly dropped refs
9+
([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is
10+
to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
11+
### Example
12+
13+
async fn foo(x: &RefCell<u32>) {
14+
let mut y = x.borrow_mut();
15+
*y += 1;
16+
baz().await;
17+
}
18+
async fn bar(x: &RefCell<u32>) {
19+
let mut y = x.borrow_mut();
20+
*y += 1;
21+
drop(y); // explicit drop
22+
baz().await;
23+
}
24+
25+
Use instead:
26+
27+
async fn foo(x: &RefCell<u32>) {
28+
{
29+
let mut y = x.borrow_mut();
30+
*y += 1;
31+
}
32+
baz().await;
33+
}
34+
async fn bar(x: &RefCell<u32>) {
35+
{
36+
let mut y = x.borrow_mut();
37+
*y += 1;
38+
} // y dropped here at end of scope
39+
baz().await;
40+
}

src/docs/bad_bit_mask.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
### What it does
2+
Checks for incompatible bit masks in comparisons.
3+
The formula for detecting if an expression of the type `_ <bit_op> m
4+
<cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of
5+
{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
6+
table:
7+
|Comparison |Bit Op|Example |is always|Formula |
8+
|------------|------|-------------|---------|----------------------|
9+
|`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` |
10+
|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |
11+
|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |
12+
|`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` |
13+
|`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` |
14+
|`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` |
15+
### Why is this bad?
16+
If the bits that the comparison cares about are always
17+
set to zero or one by the bit mask, the comparison is constant `true` or
18+
`false` (depending on mask, compared value, and operators).
19+
So the code is actively misleading, and the only reason someone would write
20+
this intentionally is to win an underhanded Rust contest or create a
21+
test-case for this lint.
22+
### Example
23+
24+
if (x & 1 == 2) { }

src/docs/bind_instead_of_map.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### What it does
2+
Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
3+
`_.or_else(|x| Err(y))`.
4+
### Why is this bad?
5+
Readability, this can be written more concisely as
6+
`_.map(|x| y)` or `_.map_err(|x| y)`.
7+
### Example
8+
9+
let _ = opt().and_then(|s| Some(s.len()));
10+
let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) });
11+
let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) });
12+
13+
The correct use would be:
14+
15+
let _ = opt().map(|s| s.len());
16+
let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 });
17+
let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 });

0 commit comments

Comments
 (0)