diff --git a/Cargo.toml b/Cargo.toml index d8ab94910..802e77339 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ cargo_metadata = "0.2" regex = "0.2" [dev-dependencies] -compiletest_rs = "0.3.6" +compiletest_rs = "0.3.7" duct = "0.8.2" lazy_static = "1.0" serde_derive = "1.0" diff --git a/clippy_lints/src/literal_representation.rs b/clippy_lints/src/literal_representation.rs index 1b93f6bf3..8b8d7903f 100644 --- a/clippy_lints/src/literal_representation.rs +++ b/clippy_lints/src/literal_representation.rs @@ -134,7 +134,7 @@ impl<'a> DigitInfo<'a> { let mut last_d = '\0'; for (d_idx, d) in sans_prefix.char_indices() { - if !float && (d == 'i' || d == 'u') || float && d == 'f' { + if !float && (d == 'i' || d == 'u') || float && (d == 'f' || d == 'e' || d == 'E') { let suffix_start = if last_d == '_' { d_idx - 1 } else { d_idx }; let (digits, suffix) = sans_prefix.split_at(suffix_start); return Self { @@ -285,60 +285,64 @@ impl EarlyLintPass for LiteralDigitGrouping { impl LiteralDigitGrouping { fn check_lit(&self, cx: &EarlyContext, lit: &Lit) { - // Lint integral literals. - if_chain! { - if let LitKind::Int(..) = lit.node; - if let Some(src) = snippet_opt(cx, lit.span); - if let Some(firstch) = src.chars().next(); - if char::to_digit(firstch, 10).is_some(); - then { - let digit_info = DigitInfo::new(&src, false); - let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| { - warning_type.display(&digit_info.grouping_hint(), cx, &lit.span) - }); - } - } + match lit.node { + LitKind::Int(..) => { + // Lint integral literals. + if_chain! { + if let Some(src) = snippet_opt(cx, lit.span); + if let Some(firstch) = src.chars().next(); + if char::to_digit(firstch, 10).is_some(); + then { + let digit_info = DigitInfo::new(&src, false); + let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| { + warning_type.display(&digit_info.grouping_hint(), cx, &lit.span) + }); + } + } + }, + LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => { + // Lint floating-point literals. + if_chain! { + if let Some(src) = snippet_opt(cx, lit.span); + if let Some(firstch) = src.chars().next(); + if char::to_digit(firstch, 10).is_some(); + then { + let digit_info = DigitInfo::new(&src, true); + // Separate digits into integral and fractional parts. + let parts: Vec<&str> = digit_info + .digits + .split_terminator('.') + .collect(); - // Lint floating-point literals. - if_chain! { - if let LitKind::Float(..) = lit.node; - if let Some(src) = snippet_opt(cx, lit.span); - if let Some(firstch) = src.chars().next(); - if char::to_digit(firstch, 10).is_some(); - then { - let digit_info = DigitInfo::new(&src, true); - // Separate digits into integral and fractional parts. - let parts: Vec<&str> = digit_info - .digits - .split_terminator('.') - .collect(); - - // Lint integral and fractional parts separately, and then check consistency of digit - // groups if both pass. - let _ = Self::do_lint(parts[0]) - .map(|integral_group_size| { - if parts.len() > 1 { - // Lint the fractional part of literal just like integral part, but reversed. - let fractional_part = &parts[1].chars().rev().collect::(); - let _ = Self::do_lint(fractional_part) - .map(|fractional_group_size| { - let consistent = Self::parts_consistent(integral_group_size, - fractional_group_size, - parts[0].len(), - parts[1].len()); - if !consistent { - WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), - cx, - &lit.span); - } - }) - .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), - cx, - &lit.span)); - } - }) - .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)); - } + // Lint integral and fractional parts separately, and then check consistency of digit + // groups if both pass. + let _ = Self::do_lint(parts[0]) + .map(|integral_group_size| { + if parts.len() > 1 { + // Lint the fractional part of literal just like integral part, but reversed. + let fractional_part = &parts[1].chars().rev().collect::(); + let _ = Self::do_lint(fractional_part) + .map(|fractional_group_size| { + let consistent = Self::parts_consistent(integral_group_size, + fractional_group_size, + parts[0].len(), + parts[1].len()); + if !consistent { + WarningType::InconsistentDigitGrouping.display(&digit_info.grouping_hint(), + cx, + &lit.span); + } + }) + .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), + cx, + &lit.span)); + } + }) + .map_err(|warning_type| warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)); + } + } + }, + _ => (), } } diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index ca1d987db..085cbaf9b 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -1624,7 +1624,8 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // a range index op if let ExprMethodCall(ref meth, _, ref args) = expr.node; - if meth.name == "index" || meth.name == "index_mut"; + if (meth.name == "index" && match_trait_method(self.cx, expr, &paths::INDEX)) + || (meth.name == "index_mut" && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(&args[1], &args[0], expr); then { return } } diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 20244a19f..81c402ab4 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -33,6 +33,8 @@ pub const HASH: [&str; 2] = ["hash", "Hash"]; pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"]; pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"]; pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"]; +pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; +pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; pub const INIT: [&str; 4] = ["core", "intrinsics", "", "init"]; pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 4] = ["core", "iter", "traits", "IntoIterator"]; diff --git a/tests/ui/approx_const.rs b/tests/ui/approx_const.rs index f2239ecb4..394aa9d1e 100644 --- a/tests/ui/approx_const.rs +++ b/tests/ui/approx_const.rs @@ -2,7 +2,7 @@ #[warn(approx_constant)] -#[allow(unused, shadow_unrelated, similar_names)] +#[allow(unused, shadow_unrelated, similar_names, unreadable_literal)] fn main() { let my_e = 2.7182; let almost_e = 2.718; diff --git a/tests/ui/for_loop.rs b/tests/ui/for_loop.rs index d606e7a15..92f95e09d 100644 --- a/tests/ui/for_loop.rs +++ b/tests/ui/for_loop.rs @@ -556,3 +556,18 @@ pub fn manual_copy_same_destination(dst: &mut [i32], d: usize, s: usize) { dst[d + i] = dst[s + i]; } } + +mod issue_2496 { + pub trait Handle { + fn new_for_index(index: usize) -> Self; + fn index(&self) -> usize; + } + + pub fn test() -> H { + for x in 0..5 { + let next_handle = H::new_for_index(x); + println!("{}", next_handle.index()); + } + unimplemented!() + } +} diff --git a/tests/ui/unreadable_literal.rs b/tests/ui/unreadable_literal.rs index 327fea254..94b53f80b 100644 --- a/tests/ui/unreadable_literal.rs +++ b/tests/ui/unreadable_literal.rs @@ -5,4 +5,6 @@ fn main() { let good = (0b1011_i64, 0o1_234_u32, 0x1_234_567, 1_2345_6789, 1234_f32, 1_234.12_f32, 1_234.123_f32, 1.123_4_f32); let bad = (0b10110_i64, 0x12345678901_usize, 12345_f32, 1.23456_f32); + let good_sci = 1.1234e1; + let bad_sci = 1.12345e1; } diff --git a/tests/ui/unreadable_literal.stderr b/tests/ui/unreadable_literal.stderr index 4fcae9bf7..b16a58ec2 100644 --- a/tests/ui/unreadable_literal.stderr +++ b/tests/ui/unreadable_literal.stderr @@ -24,5 +24,11 @@ error: long literal lacking separators 7 | let bad = (0b10110_i64, 0x12345678901_usize, 12345_f32, 1.23456_f32); | ^^^^^^^^^^^ help: consider: `1.234_56_f32` -error: aborting due to 4 previous errors +error: long literal lacking separators + --> $DIR/unreadable_literal.rs:9:19 + | +9 | let bad_sci = 1.12345e1; + | ^^^^^^^^^ help: consider: `1.123_45e1` + +error: aborting due to 5 previous errors