Skip to content

Commit 5f871f8

Browse files
Add known_log_bases lint
Add lint to detect logarithm function calls with explicit bases 2, 10 and e and suggest usage of methods `log2`, `log10` and `ln`.
1 parent d82debb commit 5f871f8

File tree

7 files changed

+181
-2
lines changed

7 files changed

+181
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,6 +1058,7 @@ Released 2018-09-13
10581058
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
10591059
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
10601060
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
1061+
[`known_log_bases`]: https://rust-lang.github.io/rust-clippy/master/index.html#known_log_bases
10611062
[`large_digit_groups`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_digit_groups
10621063
[`large_enum_variant`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_enum_variant
10631064
[`large_stack_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_stack_arrays

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
88

9-
[There are 340 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
9+
[There are 341 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
1010

1111
We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
1212

clippy_lints/src/float_functions.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use crate::consts::{constant, Constant};
2+
use crate::utils::*;
3+
use rustc::declare_lint_pass;
4+
use rustc::hir::*;
5+
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
6+
use rustc_errors::Applicability;
7+
use rustc_session::declare_tool_lint;
8+
use std::f32::consts as f32_consts;
9+
use std::f64::consts as f64_consts;
10+
11+
declare_clippy_lint! {
12+
/// **What it does:** Looks for calls to `std::{f32,f64}::log` with
13+
/// bases 2, 10 and e and suggests usage of methods `log2`, `log10`
14+
/// and `ln` instead
15+
///
16+
/// **Why is this bad?** Using `std::{f32,f64}::log` with bases 2, 10
17+
/// and e is less accurate than using the methods `log2`, `log10` and
18+
/// `ln` respectively
19+
///
20+
/// **Known problems:** None
21+
///
22+
/// **Example:**
23+
///
24+
/// ```rust
25+
/// use std::f32::consts::E;
26+
///
27+
/// let a = 1f32.log(2.0);
28+
/// let b = 1f32.log(10.0);
29+
/// let c = 1f32.log(E);
30+
/// ```
31+
///
32+
/// can be written as
33+
///
34+
/// ```rust
35+
/// let a = 1f32.log2();
36+
/// let b = 1f32.log10();
37+
/// let c = 1f32.ln();
38+
/// ```
39+
pub KNOWN_LOG_BASES,
40+
nursery,
41+
"checks for logarithm function calls with bases 2, 10 and e"
42+
}
43+
44+
declare_lint_pass!(FloatFunctions => [KNOWN_LOG_BASES]);
45+
46+
fn check_log_base(cx: &LateContext<'_, '_>, expr: &Expr, args: &HirVec<Expr>) {
47+
let recv = &args[0];
48+
let arg = sugg::Sugg::hir(cx, recv, "..").maybe_par();
49+
let mut needs_lint = false;
50+
let mut suggestion = String::new();
51+
52+
if let Some((value, _)) = constant(cx, cx.tables, &args[1]) {
53+
if Constant::F32(2.0) == value || Constant::F64(2.0) == value {
54+
needs_lint = true;
55+
suggestion = format!("{}.log2()", arg);
56+
} else if Constant::F32(10.0) == value || Constant::F64(10.0) == value {
57+
needs_lint = true;
58+
suggestion = format!("{}.log10()", arg);
59+
} else if Constant::F32(f32_consts::E) == value || Constant::F64(f64_consts::E) == value {
60+
needs_lint = true;
61+
suggestion = format!("{}.ln()", arg);
62+
}
63+
}
64+
65+
if needs_lint {
66+
span_lint_and_sugg(
67+
cx,
68+
KNOWN_LOG_BASES,
69+
expr.span,
70+
"logarithm for bases 2, 10 and e can be computed more accurately",
71+
"consider using",
72+
suggestion,
73+
Applicability::MachineApplicable,
74+
);
75+
}
76+
}
77+
78+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for FloatFunctions {
79+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
80+
match &expr.kind {
81+
ExprKind::MethodCall(ref path, _, args) => {
82+
let recv_ty = cx.tables.expr_ty(&args[0]);
83+
84+
if recv_ty.is_floating_point() {
85+
match &*path.ident.name.as_str() {
86+
"log" => check_log_base(cx, expr, args),
87+
_ => {},
88+
}
89+
}
90+
},
91+
_ => {},
92+
}
93+
}
94+
}

clippy_lints/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ pub mod excessive_precision;
200200
pub mod exit;
201201
pub mod explicit_write;
202202
pub mod fallible_impl_from;
203+
pub mod float_functions;
203204
pub mod format;
204205
pub mod formatting;
205206
pub mod functions;
@@ -520,6 +521,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
520521
&exit::EXIT,
521522
&explicit_write::EXPLICIT_WRITE,
522523
&fallible_impl_from::FALLIBLE_IMPL_FROM,
524+
&float_functions::KNOWN_LOG_BASES,
523525
&format::USELESS_FORMAT,
524526
&formatting::POSSIBLE_MISSING_COMMA,
525527
&formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
@@ -968,6 +970,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
968970
store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
969971
let array_size_threshold = conf.array_size_threshold;
970972
store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
973+
store.register_late_pass(move || box float_functions::FloatFunctions);
971974
store.register_early_pass(|| box as_conversions::AsConversions);
972975
store.register_early_pass(|| box utils::internal_lints::ProduceIce);
973976

@@ -1582,6 +1585,7 @@ pub fn register_plugins(store: &mut lint::LintStore, sess: &Session, conf: &Conf
15821585
store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
15831586
LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
15841587
LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
1588+
LintId::of(&float_functions::KNOWN_LOG_BASES),
15851589
LintId::of(&missing_const_for_fn::MISSING_CONST_FOR_FN),
15861590
LintId::of(&mul_add::MANUAL_MUL_ADD),
15871591
LintId::of(&mutex_atomic::MUTEX_INTEGER),

src/lintlist/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub use lint::Lint;
66
pub use lint::LINT_LEVELS;
77

88
// begin lint list, do not remove this comment, it’s used in `update_lints`
9-
pub const ALL_LINTS: [Lint; 340] = [
9+
pub const ALL_LINTS: [Lint; 341] = [
1010
Lint {
1111
name: "absurd_extreme_comparisons",
1212
group: "correctness",
@@ -896,6 +896,13 @@ pub const ALL_LINTS: [Lint; 340] = [
896896
deprecation: None,
897897
module: "non_expressive_names",
898898
},
899+
Lint {
900+
name: "known_log_bases",
901+
group: "nursery",
902+
desc: "checks for logarithm function calls with bases 2, 10 and e",
903+
deprecation: None,
904+
module: "float_functions",
905+
},
899906
Lint {
900907
name: "large_digit_groups",
901908
group: "pedantic",

tests/ui/float_functions.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#![allow(dead_code)]
2+
3+
const TWO: f32 = 2.0;
4+
const E: f32 = std::f32::consts::E;
5+
6+
#[warn(clippy::known_log_bases)]
7+
fn check_log_base() {
8+
let x = 1f32;
9+
let _ = x.log(2f32);
10+
let _ = x.log(10f32);
11+
let _ = x.log(std::f32::consts::E);
12+
let _ = x.log(TWO);
13+
let _ = x.log(E);
14+
15+
let x = 1f64;
16+
let _ = x.log(2f64);
17+
let _ = x.log(10f64);
18+
let _ = x.log(std::f64::consts::E);
19+
}
20+
21+
fn main() {}

tests/ui/float_functions.stderr

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
error: logarithm for bases 2, 10 and e can be computed more accurately
2+
--> $DIR/float_functions.rs:9:13
3+
|
4+
LL | let _ = x.log(2f32);
5+
| ^^^^^^^^^^^ help: consider using: `x.log2()`
6+
|
7+
= note: `-D clippy::known-log-bases` implied by `-D warnings`
8+
9+
error: logarithm for bases 2, 10 and e can be computed more accurately
10+
--> $DIR/float_functions.rs:10:13
11+
|
12+
LL | let _ = x.log(10f32);
13+
| ^^^^^^^^^^^^ help: consider using: `x.log10()`
14+
15+
error: logarithm for bases 2, 10 and e can be computed more accurately
16+
--> $DIR/float_functions.rs:11:13
17+
|
18+
LL | let _ = x.log(std::f32::consts::E);
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
20+
21+
error: logarithm for bases 2, 10 and e can be computed more accurately
22+
--> $DIR/float_functions.rs:12:13
23+
|
24+
LL | let _ = x.log(TWO);
25+
| ^^^^^^^^^^ help: consider using: `x.log2()`
26+
27+
error: logarithm for bases 2, 10 and e can be computed more accurately
28+
--> $DIR/float_functions.rs:13:13
29+
|
30+
LL | let _ = x.log(E);
31+
| ^^^^^^^^ help: consider using: `x.ln()`
32+
33+
error: logarithm for bases 2, 10 and e can be computed more accurately
34+
--> $DIR/float_functions.rs:16:13
35+
|
36+
LL | let _ = x.log(2f64);
37+
| ^^^^^^^^^^^ help: consider using: `x.log2()`
38+
39+
error: logarithm for bases 2, 10 and e can be computed more accurately
40+
--> $DIR/float_functions.rs:17:13
41+
|
42+
LL | let _ = x.log(10f64);
43+
| ^^^^^^^^^^^^ help: consider using: `x.log10()`
44+
45+
error: logarithm for bases 2, 10 and e can be computed more accurately
46+
--> $DIR/float_functions.rs:18:13
47+
|
48+
LL | let _ = x.log(std::f64::consts::E);
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()`
50+
51+
error: aborting due to 8 previous errors
52+

0 commit comments

Comments
 (0)