Skip to content

Commit cd7fc83

Browse files
committed
fix: unnecessary_cast suggests extra brackets when in macro
1 parent 8eed350 commit cd7fc83

File tree

4 files changed

+78
-24
lines changed

4 files changed

+78
-24
lines changed

clippy_lints/src/casts/unnecessary_cast.rs

+27-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use clippy_utils::diagnostics::span_lint_and_sugg;
1+
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
22
use clippy_utils::numeric_literal::NumericLiteral;
3-
use clippy_utils::source::{SpanRangeExt, snippet_opt};
3+
use clippy_utils::source::{SpanRangeExt, snippet_opt, snippet_with_applicability};
4+
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
45
use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
56
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
67
use rustc_ast::{LitFloatType, LitIntType, LitKind};
@@ -150,28 +151,35 @@ pub(super) fn check<'tcx>(
150151
return false;
151152
}
152153

153-
// If the whole cast expression is a unary expression (`(*x as T)`) or an addressof
154-
// expression (`(&x as T)`), then not surrounding the suggestion into a block risks us
155-
// changing the precedence of operators if the cast expression is followed by an operation
156-
// with higher precedence than the unary operator (`(*x as T).foo()` would become
157-
// `*x.foo()`, which changes what the `*` applies on).
158-
// The same is true if the expression encompassing the cast expression is a unary
159-
// expression or an addressof expression.
160-
let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))
161-
|| get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
162-
163-
span_lint_and_sugg(
154+
span_lint_and_then(
164155
cx,
165156
UNNECESSARY_CAST,
166157
expr.span,
167158
format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
168-
"try",
169-
if needs_block {
170-
format!("{{ {cast_str} }}")
171-
} else {
172-
cast_str
159+
|diag| {
160+
let mut applicability = Applicability::MachineApplicable;
161+
let sugg = Sugg::hir_with_applicability(cx, cast_expr, "..", &mut applicability);
162+
if applicability != Applicability::MachineApplicable {
163+
return;
164+
}
165+
166+
let snip = snippet_with_applicability(cx, expr.span, "..", &mut applicability);
167+
if applicability != Applicability::MachineApplicable {
168+
return;
169+
}
170+
171+
diag.span_suggestion(
172+
expr.span,
173+
"try",
174+
if has_enclosing_paren(&snip) {
175+
sugg.maybe_paren()
176+
} else {
177+
sugg
178+
}
179+
.to_string(),
180+
applicability,
181+
);
173182
},
174-
Applicability::MachineApplicable,
175183
);
176184
return true;
177185
}

tests/ui/unnecessary_cast.fixed

+16-2
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ mod fixable {
224224
let _ = &1 as &I32Alias;
225225

226226
let x = 1i32;
227-
let _ = &{ x };
227+
let _ = &x;
228228
//~^ unnecessary_cast
229229
}
230230

@@ -266,7 +266,21 @@ mod fixable {
266266
// Issue #11968: The suggestion for this lint removes the parentheses and leave the code as
267267
// `*x.pow(2)` which tries to dereference the return value rather than `x`.
268268
fn issue_11968(x: &usize) -> usize {
269-
{ *x }.pow(2)
269+
(*x).pow(2)
270+
//~^ unnecessary_cast
271+
}
272+
273+
#[allow(clippy::cast_lossless)]
274+
fn issue_14640() {
275+
let x = 5usize;
276+
let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
277+
assert_eq!(vec.len(), x);
278+
//~^ unnecessary_cast
279+
280+
let _ = (5i32 as i64).abs();
281+
//~^ unnecessary_cast
282+
283+
let _ = 5i32 as i64;
270284
//~^ unnecessary_cast
271285
}
272286
}

tests/ui/unnecessary_cast.rs

+14
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,18 @@ mod fixable {
269269
(*x as usize).pow(2)
270270
//~^ unnecessary_cast
271271
}
272+
273+
#[allow(clippy::cast_lossless)]
274+
fn issue_14640() {
275+
let x = 5usize;
276+
let vec: Vec<u64> = vec![1, 2, 3, 4, 5];
277+
assert_eq!(vec.len(), x as usize);
278+
//~^ unnecessary_cast
279+
280+
let _ = (5i32 as i64 as i64).abs();
281+
//~^ unnecessary_cast
282+
283+
let _ = 5i32 as i64 as i64;
284+
//~^ unnecessary_cast
285+
}
272286
}

tests/ui/unnecessary_cast.stderr

+21-3
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ error: casting to the same type is unnecessary (`i32` -> `i32`)
209209
--> tests/ui/unnecessary_cast.rs:227:18
210210
|
211211
LL | let _ = &(x as i32);
212-
| ^^^^^^^^^^ help: try: `{ x }`
212+
| ^^^^^^^^^^ help: try: `x`
213213

214214
error: casting integer literal to `i32` is unnecessary
215215
--> tests/ui/unnecessary_cast.rs:234:22
@@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`)
245245
--> tests/ui/unnecessary_cast.rs:269:9
246246
|
247247
LL | (*x as usize).pow(2)
248-
| ^^^^^^^^^^^^^ help: try: `{ *x }`
248+
| ^^^^^^^^^^^^^ help: try: `(*x)`
249249

250-
error: aborting due to 41 previous errors
250+
error: casting to the same type is unnecessary (`usize` -> `usize`)
251+
--> tests/ui/unnecessary_cast.rs:277:31
252+
|
253+
LL | assert_eq!(vec.len(), x as usize);
254+
| ^^^^^^^^^^ help: try: `x`
255+
256+
error: casting to the same type is unnecessary (`i64` -> `i64`)
257+
--> tests/ui/unnecessary_cast.rs:280:17
258+
|
259+
LL | let _ = (5i32 as i64 as i64).abs();
260+
| ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)`
261+
262+
error: casting to the same type is unnecessary (`i64` -> `i64`)
263+
--> tests/ui/unnecessary_cast.rs:283:17
264+
|
265+
LL | let _ = 5i32 as i64 as i64;
266+
| ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64`
267+
268+
error: aborting due to 44 previous errors
251269

0 commit comments

Comments
 (0)