Skip to content

Commit 778da58

Browse files
committed
suggest adjusting the type ascription
1 parent e5fd571 commit 778da58

File tree

6 files changed

+177
-27
lines changed

6 files changed

+177
-27
lines changed

clippy_lints/src/mutex_atomic.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::res::MaybeDef;
3+
use clippy_utils::source::{IntoSpan, SpanRangeExt};
34
use clippy_utils::sugg::Sugg;
45
use clippy_utils::ty::ty_from_hir_ty;
56
use rustc_errors::{Applicability, Diag};
6-
use rustc_hir::{Expr, ExprKind, Item, ItemKind, LetStmt, QPath};
7-
use rustc_lint::{LateContext, LateLintPass};
7+
use rustc_hir::{self as hir, Expr, ExprKind, Item, ItemKind, LetStmt, QPath};
8+
use rustc_lint::{LateContext, LateLintPass, LintContext};
89
use rustc_middle::mir::Mutability;
910
use rustc_middle::ty::{self, IntTy, Ty, UintTy};
1011
use rustc_session::declare_lint_pass;
@@ -101,20 +102,34 @@ impl<'tcx> LateLintPass<'tcx> for Mutex {
101102
{
102103
let body = cx.tcx.hir_body(body_id);
103104
let mid_ty = ty_from_hir_ty(cx, ty);
104-
check_expr(cx, body.value.peel_blocks(), mid_ty);
105+
check_expr(cx, body.value.peel_blocks(), &TypeAscriptionKind::Required(ty), mid_ty);
105106
}
106107
}
107108
fn check_local(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx LetStmt<'_>) {
108109
if !stmt.span.from_expansion()
109110
&& let Some(init) = stmt.init
110111
{
111112
let mid_ty = cx.typeck_results().expr_ty(init);
112-
check_expr(cx, init.peel_blocks(), mid_ty);
113+
check_expr(cx, init.peel_blocks(), &TypeAscriptionKind::Optional(stmt.ty), mid_ty);
113114
}
114115
}
115116
}
116117

117-
fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty: Ty<'tcx>) {
118+
/// Whether the type ascription `: Mutex<X>` (which we'll suggest replacing with `AtomicX`) is
119+
/// required
120+
enum TypeAscriptionKind<'tcx> {
121+
/// Yes; for us, this is the case for statics
122+
Required(&'tcx hir::Ty<'tcx>),
123+
/// No; the ascription might've been necessary in an expression like:
124+
/// ```ignore
125+
/// let mutex: Mutex<u64> = Mutex::new(0);
126+
/// ```
127+
/// to specify the type of `0`, but since `AtomicX` already refers to a concrete type, we won't
128+
/// need this ascription anymore.
129+
Optional(Option<&'tcx hir::Ty<'tcx>>),
130+
}
131+
132+
fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty_ascription: &TypeAscriptionKind<'tcx>, ty: Ty<'tcx>) {
118133
if let ty::Adt(_, subst) = ty.kind()
119134
&& ty.is_diag_item(cx, sym::Mutex)
120135
&& let mutex_param = subst.type_at(0)
@@ -129,8 +144,22 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, ty: Ty<'tcx>) {
129144
{
130145
let mut applicability = Applicability::MaybeIncorrect;
131146
let arg = Sugg::hir_with_applicability(cx, arg, "_", &mut applicability);
132-
133-
let suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))];
147+
let mut suggs = vec![(expr.span, format!("std::sync::atomic::{atomic_name}::new({arg})"))];
148+
match ty_ascription {
149+
TypeAscriptionKind::Required(ty_ascription) => {
150+
suggs.push((ty_ascription.span, format!("std::sync::atomic::{atomic_name}")));
151+
},
152+
TypeAscriptionKind::Optional(Some(ty_ascription)) => {
153+
// See https://github.com/rust-lang/rust-clippy/pull/15386 for why this is
154+
// required
155+
let colon_ascription = (cx.sess().source_map())
156+
.span_extend_to_prev_char_before(ty_ascription.span, ':', true)
157+
.with_leading_whitespace(cx)
158+
.into_span();
159+
suggs.push((colon_ascription, String::new()));
160+
},
161+
TypeAscriptionKind::Optional(None) => {}, // nothing to remove/replace
162+
}
134163
diag.multipart_suggestion("try", suggs, applicability);
135164
} else {
136165
diag.help(format!("consider using an `{atomic_name}` instead"));

tests/ui/mutex_atomic.fixed

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#![warn(clippy::mutex_integer)]
2+
#![warn(clippy::mutex_atomic)]
3+
#![allow(clippy::borrow_as_ptr)]
4+
5+
use std::sync::Mutex;
6+
7+
fn main() {
8+
let _ = std::sync::atomic::AtomicBool::new(true);
9+
//~^ mutex_atomic
10+
11+
let _ = std::sync::atomic::AtomicUsize::new(5usize);
12+
//~^ mutex_atomic
13+
14+
let _ = std::sync::atomic::AtomicIsize::new(9isize);
15+
//~^ mutex_atomic
16+
17+
let mut x = 4u32;
18+
// `AtomicPtr` only accepts `*mut T`, so this should not lint
19+
let _ = Mutex::new(&x as *const u32);
20+
21+
let _ = std::sync::atomic::AtomicPtr::new(&mut x as *mut u32);
22+
//~^ mutex_atomic
23+
24+
let _ = std::sync::atomic::AtomicU32::new(0u32);
25+
//~^ mutex_integer
26+
27+
let _ = std::sync::atomic::AtomicI32::new(0i32);
28+
//~^ mutex_integer
29+
30+
let _ = Mutex::new(0f32); // there are no float atomics, so this should not lint
31+
let _ = std::sync::atomic::AtomicU8::new(0u8);
32+
//~^ mutex_integer
33+
34+
let _ = std::sync::atomic::AtomicI16::new(0i16);
35+
//~^ mutex_integer
36+
37+
let _x = std::sync::atomic::AtomicI8::new(0);
38+
//~^ mutex_integer
39+
40+
const X: i64 = 0;
41+
let _ = std::sync::atomic::AtomicI64::new(X);
42+
//~^ mutex_integer
43+
44+
// there are no 128 atomics, so these two should not lint
45+
{
46+
let _ = Mutex::new(0u128);
47+
let _x: Mutex<i128> = Mutex::new(0);
48+
}
49+
}
50+
51+
// don't lint on _use_, only declaration
52+
fn issue13378() {
53+
static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
54+
//~^ mutex_integer
55+
56+
let mtx = std::sync::atomic::AtomicI32::new(0);
57+
//~^ mutex_integer
58+
// This will still lint, since we're reassigning the mutex to a variable -- oh well.
59+
// But realistically something like this won't really come up.
60+
let reassigned = mtx;
61+
//~^ mutex_integer
62+
63+
// don't eat the `)` when removing the type ascription -- see
64+
// https://github.com/rust-lang/rust-clippy/issues/15377
65+
let (funky_mtx) = std::sync::atomic::AtomicU64::new(0);
66+
//~^ mutex_integer
67+
}

tests/ui/mutex_atomic.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//@no-rustfix
21
#![warn(clippy::mutex_integer)]
32
#![warn(clippy::mutex_atomic)]
43
#![allow(clippy::borrow_as_ptr)]
@@ -54,13 +53,15 @@ fn issue13378() {
5453
static MTX: Mutex<u32> = Mutex::new(0);
5554
//~^ mutex_integer
5655

57-
let mut guard = MTX.lock().unwrap();
58-
*guard += 1;
59-
6056
let mtx = Mutex::new(0);
6157
//~^ mutex_integer
6258
// This will still lint, since we're reassigning the mutex to a variable -- oh well.
6359
// But realistically something like this won't really come up.
6460
let reassigned = mtx;
6561
//~^ mutex_integer
62+
63+
// don't eat the `)` when removing the type ascription -- see
64+
// https://github.com/rust-lang/rust-clippy/issues/15377
65+
let (funky_mtx): Mutex<u64> = Mutex::new(0);
66+
//~^ mutex_integer
6667
}

tests/ui/mutex_atomic.stderr

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: using a `Mutex` where an atomic would do
2-
--> tests/ui/mutex_atomic.rs:9:13
2+
--> tests/ui/mutex_atomic.rs:8:13
33
|
44
LL | let _ = Mutex::new(true);
55
| ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicBool::new(true)`
@@ -9,31 +9,31 @@ LL | let _ = Mutex::new(true);
99
= help: to override `-D warnings` add `#[allow(clippy::mutex_atomic)]`
1010

1111
error: using a `Mutex` where an atomic would do
12-
--> tests/ui/mutex_atomic.rs:12:13
12+
--> tests/ui/mutex_atomic.rs:11:13
1313
|
1414
LL | let _ = Mutex::new(5usize);
1515
| ^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicUsize::new(5usize)`
1616
|
1717
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
1818

1919
error: using a `Mutex` where an atomic would do
20-
--> tests/ui/mutex_atomic.rs:15:13
20+
--> tests/ui/mutex_atomic.rs:14:13
2121
|
2222
LL | let _ = Mutex::new(9isize);
2323
| ^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicIsize::new(9isize)`
2424
|
2525
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
2626

2727
error: using a `Mutex` where an atomic would do
28-
--> tests/ui/mutex_atomic.rs:22:13
28+
--> tests/ui/mutex_atomic.rs:21:13
2929
|
3030
LL | let _ = Mutex::new(&mut x as *mut u32);
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicPtr::new(&mut x as *mut u32)`
3232
|
3333
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
3434

3535
error: using a `Mutex` where an atomic would do
36-
--> tests/ui/mutex_atomic.rs:25:13
36+
--> tests/ui/mutex_atomic.rs:24:13
3737
|
3838
LL | let _ = Mutex::new(0u32);
3939
| ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0u32)`
@@ -43,69 +43,92 @@ LL | let _ = Mutex::new(0u32);
4343
= help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
4444

4545
error: using a `Mutex` where an atomic would do
46-
--> tests/ui/mutex_atomic.rs:28:13
46+
--> tests/ui/mutex_atomic.rs:27:13
4747
|
4848
LL | let _ = Mutex::new(0i32);
4949
| ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0i32)`
5050
|
5151
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
5252

5353
error: using a `Mutex` where an atomic would do
54-
--> tests/ui/mutex_atomic.rs:32:13
54+
--> tests/ui/mutex_atomic.rs:31:13
5555
|
5656
LL | let _ = Mutex::new(0u8);
5757
| ^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU8::new(0u8)`
5858
|
5959
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
6060

6161
error: using a `Mutex` where an atomic would do
62-
--> tests/ui/mutex_atomic.rs:35:13
62+
--> tests/ui/mutex_atomic.rs:34:13
6363
|
6464
LL | let _ = Mutex::new(0i16);
6565
| ^^^^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI16::new(0i16)`
6666
|
6767
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
6868

6969
error: using a `Mutex` where an atomic would do
70-
--> tests/ui/mutex_atomic.rs:38:25
70+
--> tests/ui/mutex_atomic.rs:37:25
7171
|
7272
LL | let _x: Mutex<i8> = Mutex::new(0);
73-
| ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI8::new(0)`
73+
| ^^^^^^^^^^^^^
7474
|
7575
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
76+
help: try
77+
|
78+
LL - let _x: Mutex<i8> = Mutex::new(0);
79+
LL + let _x = std::sync::atomic::AtomicI8::new(0);
80+
|
7681

7782
error: using a `Mutex` where an atomic would do
78-
--> tests/ui/mutex_atomic.rs:42:13
83+
--> tests/ui/mutex_atomic.rs:41:13
7984
|
8085
LL | let _ = Mutex::new(X);
8186
| ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI64::new(X)`
8287
|
8388
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
8489

8590
error: using a `Mutex` where an atomic would do
86-
--> tests/ui/mutex_atomic.rs:54:30
91+
--> tests/ui/mutex_atomic.rs:53:30
8792
|
8893
LL | static MTX: Mutex<u32> = Mutex::new(0);
89-
| ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicU32::new(0)`
94+
| ^^^^^^^^^^^^^
9095
|
9196
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
97+
help: try
98+
|
99+
LL - static MTX: Mutex<u32> = Mutex::new(0);
100+
LL + static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
101+
|
92102

93103
error: using a `Mutex` where an atomic would do
94-
--> tests/ui/mutex_atomic.rs:60:15
104+
--> tests/ui/mutex_atomic.rs:56:15
95105
|
96106
LL | let mtx = Mutex::new(0);
97107
| ^^^^^^^^^^^^^ help: try: `std::sync::atomic::AtomicI32::new(0)`
98108
|
99109
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
100110

101111
error: using a `Mutex` where an atomic would do
102-
--> tests/ui/mutex_atomic.rs:64:22
112+
--> tests/ui/mutex_atomic.rs:60:22
103113
|
104114
LL | let reassigned = mtx;
105115
| ^^^
106116
|
107117
= help: consider using an `AtomicI32` instead
108118
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
109119

110-
error: aborting due to 13 previous errors
120+
error: using a `Mutex` where an atomic would do
121+
--> tests/ui/mutex_atomic.rs:65:35
122+
|
123+
LL | let (funky_mtx): Mutex<u64> = Mutex::new(0);
124+
| ^^^^^^^^^^^^^
125+
|
126+
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
127+
help: try
128+
|
129+
LL - let (funky_mtx): Mutex<u64> = Mutex::new(0);
130+
LL + let (funky_mtx) = std::sync::atomic::AtomicU64::new(0);
131+
|
132+
133+
error: aborting due to 14 previous errors
111134

tests/ui/mutex_atomic_unfixable.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//@no-rustfix
2+
#![warn(clippy::mutex_atomic, clippy::mutex_integer)]
3+
4+
use std::sync::Mutex;
5+
6+
fn issue13378() {
7+
static MTX: Mutex<u32> = Mutex::new(0);
8+
//~^ mutex_integer
9+
10+
// unfixable because we don't fix this `lock`
11+
let mut guard = MTX.lock().unwrap();
12+
*guard += 1;
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: using a `Mutex` where an atomic would do
2+
--> tests/ui/mutex_atomic_unfixable.rs:7:30
3+
|
4+
LL | static MTX: Mutex<u32> = Mutex::new(0);
5+
| ^^^^^^^^^^^^^
6+
|
7+
= help: if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
8+
= note: `-D clippy::mutex-integer` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
10+
help: try
11+
|
12+
LL - static MTX: Mutex<u32> = Mutex::new(0);
13+
LL + static MTX: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
14+
|
15+
16+
error: aborting due to 1 previous error
17+

0 commit comments

Comments
 (0)