Skip to content

Commit fd2506b

Browse files
Add type suffixes to unsuffixed method receiver suggestions
1 parent de07c84 commit fd2506b

File tree

5 files changed

+177
-49
lines changed

5 files changed

+177
-49
lines changed

clippy_lints/src/floating_point_arithmetic.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ use if_chain::if_chain;
77
use rustc::declare_lint_pass;
88
use rustc::hir::*;
99
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
10+
use rustc::ty;
1011
use rustc_errors::Applicability;
1112
use rustc_session::declare_tool_lint;
1213
use std::f32::consts as f32_consts;
1314
use std::f64::consts as f64_consts;
15+
use sugg::Sugg;
16+
use syntax::ast;
1417

1518
declare_clippy_lint! {
1619
/// **What it does:** Looks for floating-point expressions that
@@ -80,15 +83,53 @@ fn get_specialized_log_method(cx: &LateContext<'_, '_>, base: &Expr) -> Option<&
8083
None
8184
}
8285

83-
fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
86+
// Adds type suffixes and parenthesis to method receivers if necessary
87+
fn prepare_receiver_sugg<'a>(cx: &LateContext<'_, '_>, mut expr: &'a Expr<'a>) -> Sugg<'a> {
88+
let mut suggestion = Sugg::hir(cx, expr, "..");
89+
90+
if let ExprKind::Unary(UnOp::UnNeg, inner_expr) = &expr.kind {
91+
expr = &inner_expr;
92+
}
93+
94+
if_chain! {
95+
// if the expression is a float literal and it is unsuffixed then
96+
// add a suffix so the suggestion is valid and unambiguous
97+
if let ty::Float(float_ty) = cx.tables.expr_ty(expr).kind;
98+
if let ExprKind::Lit(lit) = &expr.kind;
99+
if let ast::LitKind::Float(sym, ast::LitFloatType::Unsuffixed) = lit.node;
100+
then {
101+
let op = format!(
102+
"{}{}{}",
103+
suggestion,
104+
// Check for float literals without numbers following the decimal
105+
// separator such as `2.` and adds a trailing zero
106+
if sym.as_str().ends_with('.') {
107+
"0"
108+
} else {
109+
""
110+
},
111+
float_ty.name_str()
112+
).into();
113+
114+
suggestion = match suggestion {
115+
Sugg::MaybeParen(_) => Sugg::MaybeParen(op),
116+
_ => Sugg::NonParen(op)
117+
};
118+
}
119+
}
120+
121+
suggestion.maybe_par()
122+
}
123+
124+
fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
84125
if let Some(method) = get_specialized_log_method(cx, &args[1]) {
85126
span_lint_and_sugg(
86127
cx,
87128
FLOATING_POINT_IMPROVEMENTS,
88129
expr.span,
89130
"logarithm for bases 2, 10 and e can be computed more accurately",
90131
"consider using",
91-
format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method),
132+
format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method),
92133
Applicability::MachineApplicable,
93134
);
94135
}
@@ -113,7 +154,7 @@ fn check_ln1p(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
113154
expr.span,
114155
"ln(1 + x) can be computed more accurately",
115156
"consider using",
116-
format!("{}.ln_1p()", sugg::Sugg::hir(cx, recv, "..").maybe_par()),
157+
format!("{}.ln_1p()", prepare_receiver_sugg(cx, recv)),
117158
Applicability::MachineApplicable,
118159
);
119160
}
@@ -164,7 +205,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
164205
expr.span,
165206
"exponent for bases 2 and e can be computed more accurately",
166207
"consider using",
167-
format!("{}.{}()", sugg::Sugg::hir(cx, &args[1], "..").maybe_par(), method),
208+
format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method),
168209
Applicability::MachineApplicable,
169210
);
170211
}
@@ -187,7 +228,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
187228
expr.span,
188229
"exponentiation with integer powers can be computed more efficiently",
189230
"consider using",
190-
format!("{}.powi({})", sugg::Sugg::hir(cx, &args[0], ".."), exponent),
231+
format!("{}.powi({})", Sugg::hir(cx, &args[0], ".."), exponent),
191232
Applicability::MachineApplicable,
192233
);
193234

@@ -202,7 +243,7 @@ fn check_powf(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
202243
expr.span,
203244
help,
204245
"consider using",
205-
format!("{}.{}()", sugg::Sugg::hir(cx, &args[0], ".."), method),
246+
format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method),
206247
Applicability::MachineApplicable,
207248
);
208249
}
@@ -218,6 +259,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) {
218259
if let Some((value, _)) = constant(cx, cx.tables, rhs);
219260
if F32(1.0) == value || F64(1.0) == value;
220261
if let ExprKind::MethodCall(ref path, _, ref method_args) = lhs.kind;
262+
if cx.tables.expr_ty(&method_args[0]).is_floating_point();
221263
if path.ident.name.as_str() == "exp";
222264
then {
223265
span_lint_and_sugg(
@@ -228,7 +270,7 @@ fn check_expm1(cx: &LateContext<'_, '_>, expr: &Expr) {
228270
"consider using",
229271
format!(
230272
"{}.exp_m1()",
231-
sugg::Sugg::hir(cx, &method_args[0], "..")
273+
Sugg::hir(cx, &method_args[0], "..")
232274
),
233275
Applicability::MachineApplicable,
234276
);
@@ -275,7 +317,9 @@ fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) {
275317
if op.node == BinOpKind::Div;
276318
if cx.tables.expr_ty(lhs).is_floating_point();
277319
if let ExprKind::MethodCall(left_path, _, left_args) = &lhs.kind;
320+
if cx.tables.expr_ty(&left_args[0]).is_floating_point();
278321
if let ExprKind::MethodCall(right_path, _, right_args) = &rhs.kind;
322+
if cx.tables.expr_ty(&right_args[0]).is_floating_point();
279323
let left_method = left_path.ident.name.as_str();
280324
if left_method == right_path.ident.name.as_str();
281325
if log_methods.iter().any(|&method| left_method == method);
@@ -290,12 +334,12 @@ fn check_log_division(cx: &LateContext<'_, '_>, expr: &Expr) {
290334

291335
// Reduce the expression further for bases 2, 10 and e
292336
let suggestion = if let Some(method) = get_specialized_log_method(cx, right_recv) {
293-
format!("{}.{}()", sugg::Sugg::hir(cx, left_recv, ".."), method)
337+
format!("{}.{}()", Sugg::hir(cx, left_recv, ".."), method)
294338
} else {
295339
format!(
296340
"{}.log({})",
297-
sugg::Sugg::hir(cx, left_recv, ".."),
298-
sugg::Sugg::hir(cx, right_recv, "..")
341+
Sugg::hir(cx, left_recv, ".."),
342+
Sugg::hir(cx, right_recv, "..")
299343
)
300344
};
301345

tests/ui/floating_point_log.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ fn check_log_base() {
2020

2121
fn check_ln1p() {
2222
let x = 1f32;
23+
let _ = (1f32 + 2.).ln();
24+
let _ = (1f32 + 2.0).ln();
2325
let _ = (1.0 + x).ln();
2426
let _ = (1.0 + x * 2.0).ln();
2527
let _ = (1.0 + x.powi(2)).ln();
@@ -36,6 +38,8 @@ fn check_ln1p() {
3638
let _ = (1.0 + x - 2.0).ln();
3739

3840
let x = 1f64;
41+
let _ = (1f64 + 2.).ln();
42+
let _ = (1f64 + 2.0).ln();
3943
let _ = (1.0 + x).ln();
4044
let _ = (1.0 + x * 2.0).ln();
4145
let _ = (1.0 + x.powi(2)).ln();

tests/ui/floating_point_log.stderr

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,170 +51,194 @@ LL | let _ = x.log(std::f64::consts::E);
5151
error: ln(1 + x) can be computed more accurately
5252
--> $DIR/floating_point_log.rs:23:13
5353
|
54+
LL | let _ = (1f32 + 2.).ln();
55+
| ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
56+
57+
error: ln(1 + x) can be computed more accurately
58+
--> $DIR/floating_point_log.rs:24:13
59+
|
60+
LL | let _ = (1f32 + 2.0).ln();
61+
| ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()`
62+
63+
error: ln(1 + x) can be computed more accurately
64+
--> $DIR/floating_point_log.rs:25:13
65+
|
5466
LL | let _ = (1.0 + x).ln();
5567
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
5668

5769
error: ln(1 + x) can be computed more accurately
58-
--> $DIR/floating_point_log.rs:24:13
70+
--> $DIR/floating_point_log.rs:26:13
5971
|
6072
LL | let _ = (1.0 + x * 2.0).ln();
6173
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()`
6274

6375
error: ln(1 + x) can be computed more accurately
64-
--> $DIR/floating_point_log.rs:25:13
76+
--> $DIR/floating_point_log.rs:27:13
6577
|
6678
LL | let _ = (1.0 + x.powi(2)).ln();
6779
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
6880

6981
error: ln(1 + x) can be computed more accurately
70-
--> $DIR/floating_point_log.rs:26:13
82+
--> $DIR/floating_point_log.rs:28:13
7183
|
7284
LL | let _ = (1.0 + x.powi(2) * 2.0).ln();
7385
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(2) * 2.0).ln_1p()`
7486

7587
error: ln(1 + x) can be computed more accurately
76-
--> $DIR/floating_point_log.rs:27:13
88+
--> $DIR/floating_point_log.rs:29:13
7789
|
7890
LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln();
7991
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `((std::f32::consts::E - 1.0)).ln_1p()`
8092

8193
error: ln(1 + x) can be computed more accurately
82-
--> $DIR/floating_point_log.rs:28:13
94+
--> $DIR/floating_point_log.rs:30:13
8395
|
8496
LL | let _ = (x + 1.0).ln();
8597
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
8698

8799
error: ln(1 + x) can be computed more accurately
88-
--> $DIR/floating_point_log.rs:29:13
100+
--> $DIR/floating_point_log.rs:31:13
89101
|
90102
LL | let _ = (x.powi(2) + 1.0).ln();
91103
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
92104

93105
error: ln(1 + x) can be computed more accurately
94-
--> $DIR/floating_point_log.rs:30:13
106+
--> $DIR/floating_point_log.rs:32:13
95107
|
96108
LL | let _ = (x + 2.0 + 1.0).ln();
97109
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
98110

99111
error: ln(1 + x) can be computed more accurately
100-
--> $DIR/floating_point_log.rs:31:13
112+
--> $DIR/floating_point_log.rs:33:13
101113
|
102114
LL | let _ = (x * 2.0 + 1.0).ln();
103115
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()`
104116

105117
error: ln(1 + x) can be computed more accurately
106-
--> $DIR/floating_point_log.rs:39:13
118+
--> $DIR/floating_point_log.rs:41:13
119+
|
120+
LL | let _ = (1f64 + 2.).ln();
121+
| ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
122+
123+
error: ln(1 + x) can be computed more accurately
124+
--> $DIR/floating_point_log.rs:42:13
125+
|
126+
LL | let _ = (1f64 + 2.0).ln();
127+
| ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()`
128+
129+
error: ln(1 + x) can be computed more accurately
130+
--> $DIR/floating_point_log.rs:43:13
107131
|
108132
LL | let _ = (1.0 + x).ln();
109133
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
110134

111135
error: ln(1 + x) can be computed more accurately
112-
--> $DIR/floating_point_log.rs:40:13
136+
--> $DIR/floating_point_log.rs:44:13
113137
|
114138
LL | let _ = (1.0 + x * 2.0).ln();
115139
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()`
116140

117141
error: ln(1 + x) can be computed more accurately
118-
--> $DIR/floating_point_log.rs:41:13
142+
--> $DIR/floating_point_log.rs:45:13
119143
|
120144
LL | let _ = (1.0 + x.powi(2)).ln();
121145
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
122146

123147
error: ln(1 + x) can be computed more accurately
124-
--> $DIR/floating_point_log.rs:42:13
148+
--> $DIR/floating_point_log.rs:46:13
125149
|
126150
LL | let _ = (x + 1.0).ln();
127151
| ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()`
128152

129153
error: ln(1 + x) can be computed more accurately
130-
--> $DIR/floating_point_log.rs:43:13
154+
--> $DIR/floating_point_log.rs:47:13
131155
|
132156
LL | let _ = (x.powi(2) + 1.0).ln();
133157
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2).ln_1p()`
134158

135159
error: ln(1 + x) can be computed more accurately
136-
--> $DIR/floating_point_log.rs:44:13
160+
--> $DIR/floating_point_log.rs:48:13
137161
|
138162
LL | let _ = (x + 2.0 + 1.0).ln();
139163
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()`
140164

141165
error: ln(1 + x) can be computed more accurately
142-
--> $DIR/floating_point_log.rs:45:13
166+
--> $DIR/floating_point_log.rs:49:13
143167
|
144168
LL | let _ = (x * 2.0 + 1.0).ln();
145169
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x * 2.0).ln_1p()`
146170

147171
error: x.log(b) / y.log(b) can be reduced to x.log(y)
148-
--> $DIR/floating_point_log.rs:58:13
172+
--> $DIR/floating_point_log.rs:62:13
149173
|
150174
LL | let _ = x.log2() / y.log2();
151175
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
152176

153177
error: x.log(b) / y.log(b) can be reduced to x.log(y)
154-
--> $DIR/floating_point_log.rs:59:13
178+
--> $DIR/floating_point_log.rs:63:13
155179
|
156180
LL | let _ = x.log10() / y.log10();
157181
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
158182

159183
error: x.log(b) / y.log(b) can be reduced to x.log(y)
160-
--> $DIR/floating_point_log.rs:60:13
184+
--> $DIR/floating_point_log.rs:64:13
161185
|
162186
LL | let _ = x.ln() / y.ln();
163187
| ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
164188

165189
error: x.log(b) / y.log(b) can be reduced to x.log(y)
166-
--> $DIR/floating_point_log.rs:61:13
190+
--> $DIR/floating_point_log.rs:65:13
167191
|
168192
LL | let _ = x.log(4.0) / y.log(4.0);
169193
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
170194

171195
error: x.log(b) / y.log(b) can be reduced to x.log(y)
172-
--> $DIR/floating_point_log.rs:62:13
196+
--> $DIR/floating_point_log.rs:66:13
173197
|
174198
LL | let _ = x.log(b) / y.log(b);
175199
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
176200

177201
error: x.log(b) / y.log(b) can be reduced to x.log(y)
178-
--> $DIR/floating_point_log.rs:64:13
202+
--> $DIR/floating_point_log.rs:68:13
179203
|
180204
LL | let _ = x.log(b) / 2f32.log(b);
181205
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()`
182206

183207
error: x.log(b) / y.log(b) can be reduced to x.log(y)
184-
--> $DIR/floating_point_log.rs:70:13
208+
--> $DIR/floating_point_log.rs:74:13
185209
|
186210
LL | let _ = x.log2() / y.log2();
187211
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
188212

189213
error: x.log(b) / y.log(b) can be reduced to x.log(y)
190-
--> $DIR/floating_point_log.rs:71:13
214+
--> $DIR/floating_point_log.rs:75:13
191215
|
192216
LL | let _ = x.log10() / y.log10();
193217
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
194218

195219
error: x.log(b) / y.log(b) can be reduced to x.log(y)
196-
--> $DIR/floating_point_log.rs:72:13
220+
--> $DIR/floating_point_log.rs:76:13
197221
|
198222
LL | let _ = x.ln() / y.ln();
199223
| ^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
200224

201225
error: x.log(b) / y.log(b) can be reduced to x.log(y)
202-
--> $DIR/floating_point_log.rs:73:13
226+
--> $DIR/floating_point_log.rs:77:13
203227
|
204228
LL | let _ = x.log(4.0) / y.log(4.0);
205229
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
206230

207231
error: x.log(b) / y.log(b) can be reduced to x.log(y)
208-
--> $DIR/floating_point_log.rs:74:13
232+
--> $DIR/floating_point_log.rs:78:13
209233
|
210234
LL | let _ = x.log(b) / y.log(b);
211235
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)`
212236

213237
error: x.log(b) / y.log(b) can be reduced to x.log(y)
214-
--> $DIR/floating_point_log.rs:76:13
238+
--> $DIR/floating_point_log.rs:80:13
215239
|
216240
LL | let _ = x.log(b) / 2f64.log(b);
217241
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log2()`
218242

219-
error: aborting due to 36 previous errors
243+
error: aborting due to 40 previous errors
220244

0 commit comments

Comments
 (0)