Skip to content

Commit d18d47c

Browse files
committed
Lint unused parentheses around method receiver
1 parent a60d12c commit d18d47c

File tree

9 files changed

+109
-10
lines changed

9 files changed

+109
-10
lines changed

compiler/rustc_lint/src/unused.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
623623
enum UnusedDelimsCtx {
624624
FunctionArg,
625625
MethodArg,
626+
MethodReceiver,
626627
AssignedValue,
627628
AssignedValueLetElse,
628629
IfCond,
@@ -645,6 +646,7 @@ impl From<UnusedDelimsCtx> for &'static str {
645646
match ctx {
646647
UnusedDelimsCtx::FunctionArg => "function argument",
647648
UnusedDelimsCtx::MethodArg => "method argument",
649+
UnusedDelimsCtx::MethodReceiver => "method receiver",
648650
UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => {
649651
"assigned value"
650652
}
@@ -710,6 +712,18 @@ trait UnusedDelimLint {
710712
}
711713
}
712714

715+
// For method receivers, only lint simple path expressions like `(x).method()`.
716+
// Keep parens for all other cases to avoid false positives with complex expressions
717+
// like `(1..10).sum()`, `(*ptr).method()`, `({ block }).method()`, etc.
718+
// Only lint simple variable names like `(x).method()`, not qualified paths like
719+
// `(Float::MIN).method()` which are clearer with parentheses.
720+
if ctx == UnusedDelimsCtx::MethodReceiver {
721+
match &inner.kind {
722+
ast::ExprKind::Path(None, path) if path.segments.len() == 1 => {}
723+
_ => return true,
724+
}
725+
}
726+
713727
// Check it's range in LetScrutineeExpr
714728
if let ast::ExprKind::Range(..) = inner.kind
715729
&& matches!(ctx, UnusedDelimsCtx::LetScrutineeExpr)
@@ -976,13 +990,15 @@ trait UnusedDelimLint {
976990
}
977991
// either function/method call, or something this lint doesn't care about
978992
ref call_or_other => {
979-
let (args_to_check, ctx) = match *call_or_other {
980-
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
981-
MethodCall(ref call) => (&call.args[..], UnusedDelimsCtx::MethodArg),
993+
let (args_to_check, ctx, receiver) = match *call_or_other {
994+
Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg, None),
995+
MethodCall(ref call) => {
996+
(&call.args[..], UnusedDelimsCtx::MethodArg, Some(&call.receiver))
997+
}
982998
Closure(ref closure)
983999
if matches!(closure.fn_decl.output, FnRetTy::Default(_)) =>
9841000
{
985-
(&[closure.body.clone()][..], UnusedDelimsCtx::ClosureBody)
1001+
(&[closure.body.clone()][..], UnusedDelimsCtx::ClosureBody, None)
9861002
}
9871003
// actual catch-all arm
9881004
_ => {
@@ -999,6 +1015,17 @@ trait UnusedDelimLint {
9991015
for arg in args_to_check {
10001016
self.check_unused_delims_expr(cx, arg, ctx, false, None, None, false);
10011017
}
1018+
if let Some(recv) = receiver {
1019+
self.check_unused_delims_expr(
1020+
cx,
1021+
recv,
1022+
UnusedDelimsCtx::MethodReceiver,
1023+
false,
1024+
None,
1025+
None,
1026+
false,
1027+
);
1028+
}
10021029
return;
10031030
}
10041031
};
@@ -1584,6 +1611,7 @@ impl UnusedDelimLint for UnusedBraces {
15841611
if let [stmt] = inner.stmts.as_slice()
15851612
&& let ast::StmtKind::Expr(ref expr) = stmt.kind
15861613
&& !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
1614+
&& ctx != UnusedDelimsCtx::MethodReceiver
15871615
&& (ctx != UnusedDelimsCtx::AnonConst
15881616
|| (matches!(expr.kind, ast::ExprKind::Lit(_))
15891617
&& !expr.span.from_expansion()))

library/compiler-builtins/libm/src/math/cbrt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ pub fn cbrt_round(x: f64, round: Round) -> FpResult<f64> {
194194
let mut cvt4: u64 = y1.to_bits();
195195
cvt4 = (cvt4 + (164 << 15)) & 0xffffffffffff0000u64;
196196

197-
if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || (zz).abs() == 1.0 {
197+
if ((f64::from_bits(cvt4) - y1) - dy).abs() < hf64!("0x1p-60") || zz.abs() == 1.0 {
198198
cvt3 = (cvt3 + (1u64 << 15)) & 0xffffffffffff0000u64;
199199
}
200200
}

library/core/src/ptr/const_ptr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl<T: PointeeSized> *const T {
2727
@capture { ptr: *const u8 } -> bool:
2828
// This use of `const_raw_ptr_comparison` has been explicitly blessed by t-lang.
2929
if const #[rustc_allow_const_fn_unstable(const_raw_ptr_comparison)] {
30-
match (ptr).guaranteed_eq(null_mut()) {
30+
match ptr.guaranteed_eq(null_mut()) {
3131
Some(res) => res,
3232
// To remain maximally conservative, we stop execution when we don't
3333
// know whether the pointer is null or not.

src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub fn intern_const_ref<'a>(
9696
BuiltinUint::U16 => Box::new((i as u16).to_le_bytes()),
9797
BuiltinUint::U32 => Box::new((i as u32).to_le_bytes()),
9898
BuiltinUint::U64 => Box::new((i as u64).to_le_bytes()),
99-
BuiltinUint::U128 => Box::new((i).to_le_bytes()),
99+
BuiltinUint::U128 => Box::new(i.to_le_bytes()),
100100
BuiltinUint::Usize => Box::new((i as usize).to_le_bytes()),
101101
},
102102
_ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),
@@ -136,7 +136,7 @@ pub fn intern_const_ref<'a>(
136136
BuiltinInt::I16 => Box::new((i as i16).to_le_bytes()),
137137
BuiltinInt::I32 => Box::new((i as i32).to_le_bytes()),
138138
BuiltinInt::I64 => Box::new((i as i64).to_le_bytes()),
139-
BuiltinInt::I128 => Box::new((i).to_le_bytes()),
139+
BuiltinInt::I128 => Box::new(i.to_le_bytes()),
140140
BuiltinInt::Isize => Box::new((i as isize).to_le_bytes()),
141141
},
142142
_ => return Const::new(interner, rustc_type_ir::ConstKind::Error(ErrorGuaranteed)),

src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
336336
id,
337337
mode,
338338
next_place,
339-
(slice).into(),
339+
slice.into(),
340340
current,
341341
current_else,
342342
)?;

src/tools/test-float-parse/src/validate.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ impl Constants {
7171
let neg_inf_cutoff = -&inf_cutoff;
7272

7373
let powers_of_two: BTreeMap<i32, _> =
74-
(POWERS_OF_TWO_RANGE).map(|n| (n, two.pow(n))).collect();
74+
POWERS_OF_TWO_RANGE.map(|n| (n, two.pow(n))).collect();
7575
let mut half_ulp = powers_of_two.clone();
7676
half_ulp.iter_mut().for_each(|(_k, v)| *v = &*v / two_int);
7777

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ run-rustfix
2+
3+
#![deny(unused_parens)]
4+
5+
struct Thing;
6+
impl Thing {
7+
fn method(self) {}
8+
}
9+
10+
fn main() {
11+
// Unnecessary parens - should warn
12+
let x = Thing;
13+
x.method(); //~ ERROR unnecessary parentheses around method receiver
14+
15+
// Necessary parens - should NOT warn
16+
let _ = (1..10).sum::<i32>(); // Range expression
17+
let _ = (1_i32 + 2).abs(); // Binary expression
18+
let _ = (-1_i32).abs(); // Unary expression
19+
let _ = (true as i32).abs(); // Cast expression
20+
let _ = (&42).clone(); // AddrOf expression
21+
let _ = (&mut 42).clone(); // AddrOf mut expression
22+
23+
// Block expressions - should NOT warn
24+
let _ = ({ 1_i32 }).abs(); // Block expression
25+
let _ = (unsafe { std::mem::zeroed::<i32>() }).abs(); // Unsafe block expression
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//@ run-rustfix
2+
3+
#![deny(unused_parens)]
4+
5+
struct Thing;
6+
impl Thing {
7+
fn method(self) {}
8+
}
9+
10+
fn main() {
11+
// Unnecessary parens - should warn
12+
let x = Thing;
13+
(x).method(); //~ ERROR unnecessary parentheses around method receiver
14+
15+
// Necessary parens - should NOT warn
16+
let _ = (1..10).sum::<i32>(); // Range expression
17+
let _ = (1_i32 + 2).abs(); // Binary expression
18+
let _ = (-1_i32).abs(); // Unary expression
19+
let _ = (true as i32).abs(); // Cast expression
20+
let _ = (&42).clone(); // AddrOf expression
21+
let _ = (&mut 42).clone(); // AddrOf mut expression
22+
23+
// Block expressions - should NOT warn
24+
let _ = ({ 1_i32 }).abs(); // Block expression
25+
let _ = (unsafe { std::mem::zeroed::<i32>() }).abs(); // Unsafe block expression
26+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: unnecessary parentheses around method receiver
2+
--> $DIR/unused-parens-method-receiver-issue-151985.rs:13:5
3+
|
4+
LL | (x).method();
5+
| ^ ^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/unused-parens-method-receiver-issue-151985.rs:3:9
9+
|
10+
LL | #![deny(unused_parens)]
11+
| ^^^^^^^^^^^^^
12+
help: remove these parentheses
13+
|
14+
LL - (x).method();
15+
LL + x.method();
16+
|
17+
18+
error: aborting due to 1 previous error
19+

0 commit comments

Comments
 (0)