Skip to content

Commit 8bf5637

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

File tree

4 files changed

+68
-16
lines changed

4 files changed

+68
-16
lines changed

clippy_lints/src/casts/unnecessary_cast.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -150,26 +150,32 @@ pub(super) fn check<'tcx>(
150150
return false;
151151
}
152152

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(..)));
153+
enum MaybeParenOrBlock {
154+
Paren,
155+
Block,
156+
Nothing,
157+
}
158+
159+
let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) {
160+
// Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates
161+
// a reference to the temporary while the latter creates a reference to the original value.
162+
Node::Expr(parent) if !parent.span.from_expansion() && matches!(parent.kind, ExprKind::AddrOf(..)) => {
163+
MaybeParenOrBlock::Block
164+
},
165+
Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren,
166+
_ => MaybeParenOrBlock::Nothing,
167+
};
162168

163169
span_lint_and_sugg(
164170
cx,
165171
UNNECESSARY_CAST,
166172
expr.span,
167173
format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"),
168174
"try",
169-
if needs_block {
170-
format!("{{ {cast_str} }}")
171-
} else {
172-
cast_str
175+
match surrounding {
176+
MaybeParenOrBlock::Paren => format!("({cast_str})"),
177+
MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"),
178+
MaybeParenOrBlock::Nothing => cast_str,
173179
},
174180
Applicability::MachineApplicable,
175181
);

tests/ui/unnecessary_cast.fixed

+15-1
Original file line numberDiff line numberDiff line change
@@ -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

+20-2
Original file line numberDiff line numberDiff line change
@@ -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)