Skip to content

Commit c236c0f

Browse files
author
Michael Wright
committed
Fix false positive in PRECEDENCE lint
Extend the lint to handle chains of methods combined with unary negation. Closes rust-lang#5924
1 parent 6220dff commit c236c0f

File tree

4 files changed

+65
-30
lines changed

4 files changed

+65
-30
lines changed

clippy_lints/src/precedence.rs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::utils::{snippet_with_applicability, span_lint_and_sugg};
2+
use if_chain::if_chain;
23
use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
34
use rustc_errors::Applicability;
45
use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -102,36 +103,36 @@ impl EarlyLintPass for Precedence {
102103
}
103104
}
104105

105-
if let ExprKind::Unary(UnOp::Neg, ref rhs) = expr.kind {
106-
if let ExprKind::MethodCall(ref path_segment, ref args, _) = rhs.kind {
106+
if let ExprKind::Unary(UnOp::Neg, operand) = &expr.kind {
107+
let mut arg = operand;
108+
109+
let mut all_odd = true;
110+
while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
107111
let path_segment_str = path_segment.ident.name.as_str();
108-
if let Some(slf) = args.first() {
109-
if let ExprKind::Lit(ref lit) = slf.kind {
110-
match lit.kind {
111-
LitKind::Int(..) | LitKind::Float(..) => {
112-
if ALLOWED_ODD_FUNCTIONS
113-
.iter()
114-
.any(|odd_function| **odd_function == *path_segment_str)
115-
{
116-
return;
117-
}
118-
let mut applicability = Applicability::MachineApplicable;
119-
span_lint_and_sugg(
120-
cx,
121-
PRECEDENCE,
122-
expr.span,
123-
"unary minus has lower precedence than method call",
124-
"consider adding parentheses to clarify your intent",
125-
format!(
126-
"-({})",
127-
snippet_with_applicability(cx, rhs.span, "..", &mut applicability)
128-
),
129-
applicability,
130-
);
131-
},
132-
_ => (),
133-
}
134-
}
112+
all_odd &= ALLOWED_ODD_FUNCTIONS
113+
.iter()
114+
.any(|odd_function| **odd_function == *path_segment_str);
115+
arg = args.first().expect("A method always has a receiver.");
116+
}
117+
118+
if_chain! {
119+
if !all_odd;
120+
if let ExprKind::Lit(lit) = &arg.kind;
121+
if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind;
122+
then {
123+
let mut applicability = Applicability::MachineApplicable;
124+
span_lint_and_sugg(
125+
cx,
126+
PRECEDENCE,
127+
expr.span,
128+
"unary minus has lower precedence than method call",
129+
"consider adding parentheses to clarify your intent",
130+
format!(
131+
"-({})",
132+
snippet_with_applicability(cx, operand.span, "..", &mut applicability)
133+
),
134+
applicability,
135+
);
135136
}
136137
}
137138
}

tests/ui/precedence.fixed

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ fn main() {
4848
let _ = -1f64.to_degrees();
4949
let _ = -1f64.to_radians();
5050

51+
// Chains containing any non-odd function should trigger (issue #5924)
52+
let _ = -(1.0_f64.cos().cos());
53+
let _ = -(1.0_f64.cos().sin());
54+
let _ = -(1.0_f64.sin().cos());
55+
56+
// Chains of odd functions shouldn't trigger
57+
let _ = -1f64.sin().sin();
58+
5159
let b = 3;
5260
trip!(b * 8);
5361
}

tests/ui/precedence.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ fn main() {
4848
let _ = -1f64.to_degrees();
4949
let _ = -1f64.to_radians();
5050

51+
// Chains containing any non-odd function should trigger (issue #5924)
52+
let _ = -1.0_f64.cos().cos();
53+
let _ = -1.0_f64.cos().sin();
54+
let _ = -1.0_f64.sin().cos();
55+
56+
// Chains of odd functions shouldn't trigger
57+
let _ = -1f64.sin().sin();
58+
5159
let b = 3;
5260
trip!(b * 8);
5361
}

tests/ui/precedence.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,23 @@ error: unary minus has lower precedence than method call
5454
LL | -1f32.abs();
5555
| ^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1f32.abs())`
5656

57-
error: aborting due to 9 previous errors
57+
error: unary minus has lower precedence than method call
58+
--> $DIR/precedence.rs:52:13
59+
|
60+
LL | let _ = -1.0_f64.cos().cos();
61+
| ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().cos())`
62+
63+
error: unary minus has lower precedence than method call
64+
--> $DIR/precedence.rs:53:13
65+
|
66+
LL | let _ = -1.0_f64.cos().sin();
67+
| ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.cos().sin())`
68+
69+
error: unary minus has lower precedence than method call
70+
--> $DIR/precedence.rs:54:13
71+
|
72+
LL | let _ = -1.0_f64.sin().cos();
73+
| ^^^^^^^^^^^^^^^^^^^^ help: consider adding parentheses to clarify your intent: `-(1.0_f64.sin().cos())`
74+
75+
error: aborting due to 12 previous errors
5876

0 commit comments

Comments
 (0)