]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/literal_representation.rs
Merge branch 'macro-use' into HEAD
[rust.git] / clippy_lints / src / literal_representation.rs
index a0c4f537a1550c3445a4a722a16ca07bedddabf8..bb5a923eaf9ca9ed2dd78ee4073092538fcb9a7d 100644 (file)
@@ -2,9 +2,11 @@
 //! floating-point literal expressions.
 
 use rustc::lint::*;
+use rustc::{declare_lint, lint_array};
+use if_chain::if_chain;
 use syntax::ast::*;
 use syntax_pos;
-use utils::{in_external_macro, snippet_opt, span_help_and_lint};
+use crate::utils::{in_external_macro, snippet_opt, span_lint_and_sugg};
 
 /// **What it does:** Warns if a long integral or floating-point constant does
 /// not contain underscores.
@@ -18,9 +20,9 @@
 /// ```rust
 /// 61864918973511
 /// ```
-declare_lint! {
+declare_clippy_lint! {
     pub UNREADABLE_LITERAL,
-    Warn,
+    style,
     "long integer literal without underscores"
 }
 
@@ -37,9 +39,9 @@
 /// ```rust
 /// 618_64_9189_73_511
 /// ```
-declare_lint! {
+declare_clippy_lint! {
     pub INCONSISTENT_DIGIT_GROUPING,
-    Warn,
+    style,
     "integer literals with digits grouped inconsistently"
 }
 
@@ -56,9 +58,9 @@
 /// ```rust
 /// 6186491_8973511
 /// ```
-declare_lint! {
+declare_clippy_lint! {
     pub LARGE_DIGIT_GROUPS,
-    Warn,
+    style,
     "grouping digits into groups that are too large"
 }
 
 /// `255` => `0xFF`
 /// `65_535` => `0xFFFF`
 /// `4_042_322_160` => `0xF0F0_F0F0`
-declare_lint! {
+declare_clippy_lint! {
     pub DECIMAL_LITERAL_REPRESENTATION,
-    Warn,
+    restriction,
     "using decimal representation when hexadecimal would be better"
 }
 
 #[derive(Debug, PartialEq)]
-enum Radix {
+pub(super) enum Radix {
     Binary,
     Octal,
     Decimal,
@@ -90,7 +92,7 @@ enum Radix {
 
 impl Radix {
     /// Return a reasonable digit group size for this radix.
-    pub fn suggest_grouping(&self) -> usize {
+    crate fn suggest_grouping(&self) -> usize {
         match *self {
             Radix::Binary | Radix::Hexadecimal => 4,
             Radix::Octal | Radix::Decimal => 3,
@@ -99,21 +101,21 @@ pub fn suggest_grouping(&self) -> usize {
 }
 
 #[derive(Debug)]
-struct DigitInfo<'a> {
+pub(super) struct DigitInfo<'a> {
     /// Characters of a literal between the radix prefix and type suffix.
-    pub digits: &'a str,
+    crate digits: &'a str,
     /// Which radix the literal was represented in.
-    pub radix: Radix,
+    crate radix: Radix,
     /// The radix prefix, if present.
-    pub prefix: Option<&'a str>,
+    crate prefix: Option<&'a str>,
     /// The type suffix, including preceding underscore if present.
-    pub suffix: Option<&'a str>,
+    crate suffix: Option<&'a str>,
     /// True for floating-point literals.
-    pub float: bool,
+    crate float: bool,
 }
 
 impl<'a> DigitInfo<'a> {
-    pub fn new(lit: &'a str, float: bool) -> Self {
+    crate fn new(lit: &'a str, float: bool) -> Self {
         // Determine delimiter for radix prefix, if present, and radix.
         let radix = if lit.starts_with("0x") {
             Radix::Hexadecimal
@@ -135,15 +137,15 @@ pub fn new(lit: &'a str, float: bool) -> Self {
 
         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 {
-                    digits: digits,
-                    radix: radix,
-                    prefix: prefix,
+                    digits,
+                    radix,
+                    prefix,
                     suffix: Some(suffix),
-                    float: float,
+                    float,
                 };
             }
             last_d = d
@@ -152,15 +154,15 @@ pub fn new(lit: &'a str, float: bool) -> Self {
         // No suffix found
         Self {
             digits: sans_prefix,
-            radix: radix,
-            prefix: prefix,
+            radix,
+            prefix,
             suffix: None,
-            float: float,
+            float,
         }
     }
 
     /// Returns digits grouped in a sensible way.
-    fn grouping_hint(&self) -> String {
+    crate fn grouping_hint(&self) -> String {
         let group_size = self.radix.suggest_grouping();
         if self.digits.contains('.') {
             let mut parts = self.digits.split('.');
@@ -193,16 +195,22 @@ fn grouping_hint(&self) -> String {
                 self.suffix.unwrap_or("")
             )
         } else {
-            let hint = self.digits
+            let filtered_digits_vec = self.digits
                 .chars()
-                .rev()
                 .filter(|&c| c != '_')
-                .collect::<Vec<_>>()
+                .rev()
+                .collect::<Vec<_>>();
+            let mut hint = filtered_digits_vec
                 .chunks(group_size)
                 .map(|chunk| chunk.into_iter().rev().collect())
                 .rev()
                 .collect::<Vec<String>>()
                 .join("_");
+            // Forces hexadecimal values to be grouped by 4 being filled with zeroes (e.g 0x00ab_cdef)
+            let nb_digits_to_fill = filtered_digits_vec.len() % 4;
+            if self.radix == Radix::Hexadecimal && nb_digits_to_fill != 0 {
+                hint = format!("{:0>4}{}", &hint[..nb_digits_to_fill], &hint[nb_digits_to_fill..]);
+            }
             format!(
                 "{}{}{}",
                 self.prefix.unwrap_or(""),
@@ -221,35 +229,39 @@ enum WarningType {
 }
 
 impl WarningType {
-    pub fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: &syntax_pos::Span) {
-        match *self {
-            WarningType::UnreadableLiteral => span_help_and_lint(
+    crate fn display(&self, grouping_hint: &str, cx: &EarlyContext, span: syntax_pos::Span) {
+        match self {
+            WarningType::UnreadableLiteral => span_lint_and_sugg(
                 cx,
                 UNREADABLE_LITERAL,
-                *span,
+                span,
                 "long literal lacking separators",
-                &format!("consider: {}", grouping_hint),
+                "consider",
+                grouping_hint.to_owned(),
             ),
-            WarningType::LargeDigitGroups => span_help_and_lint(
+            WarningType::LargeDigitGroups => span_lint_and_sugg(
                 cx,
                 LARGE_DIGIT_GROUPS,
-                *span,
+                span,
                 "digit groups should be smaller",
-                &format!("consider: {}", grouping_hint),
+                "consider",
+                grouping_hint.to_owned(),
             ),
-            WarningType::InconsistentDigitGrouping => span_help_and_lint(
+            WarningType::InconsistentDigitGrouping => span_lint_and_sugg(
                 cx,
                 INCONSISTENT_DIGIT_GROUPING,
-                *span,
+                span,
                 "digits grouped inconsistently by underscores",
-                &format!("consider: {}", grouping_hint),
+                "consider",
+                grouping_hint.to_owned(),
             ),
-            WarningType::DecimalRepresentation => span_help_and_lint(
+            WarningType::DecimalRepresentation => span_lint_and_sugg(
                 cx,
                 DECIMAL_LITERAL_REPRESENTATION,
-                *span,
+                span,
                 "integer literal has a better hexadecimal representation",
-                &format!("consider: {}", grouping_hint),
+                "consider",
+                grouping_hint.to_owned(),
             ),
         };
     }
@@ -281,61 +293,65 @@ fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
 }
 
 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)
-                });
-            }
-        }
-
-        // 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::<String>();
-                            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));
-            }
+    fn check_lit(self, cx: &EarlyContext, lit: &Lit) {
+        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 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::<String>();
+                                    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));
+                    }
+                }
+            },
+            _ => (),
         }
     }
 
@@ -368,7 +384,7 @@ fn do_lint(digits: &str) -> Result<usize, WarningType> {
 
         if underscore_positions.is_empty() {
             // Check if literal needs underscores.
-            if digits.len() > 4 {
+            if digits.len() > 5 {
                 Err(WarningType::UnreadableLiteral)
             } else {
                 Ok(0)
@@ -419,10 +435,10 @@ fn check_expr(&mut self, cx: &EarlyContext, expr: &Expr) {
 impl LiteralRepresentation {
     pub fn new(threshold: u64) -> Self {
         Self {
-            threshold: threshold,
+            threshold,
         }
     }
-    fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
+    fn check_lit(self, cx: &EarlyContext, lit: &Lit) {
         // Lint integral literals.
         if_chain! {
             if let LitKind::Int(..) = lit.node;
@@ -437,13 +453,13 @@ fn check_lit(&self, cx: &EarlyContext, lit: &Lit) {
                         .filter(|&c| c != '_')
                         .collect::<String>()
                         .parse::<u128>().unwrap();
-                    if val < self.threshold as u128 {
+                    if val < u128::from(self.threshold) {
                         return
                     }
                     let hex = format!("{:#X}", val);
                     let digit_info = DigitInfo::new(&hex[..], false);
                     let _ = Self::do_lint(digit_info.digits).map_err(|warning_type| {
-                        warning_type.display(&digit_info.grouping_hint(), cx, &lit.span)
+                        warning_type.display(&digit_info.grouping_hint(), cx, lit.span)
                     });
                 }
             }