]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/literal_representation.rs
Merge commit '4911ab124c481430672a3833b37075e6435ec34d' into clippyup
[rust.git] / clippy_lints / src / literal_representation.rs
index ec7c4531ed7169c770ddb2ce0d17dae648d9ab60..87a957a9bd241728bd01fbaedaf06f08ee5836a7 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
     /// **What it does:** Warns if a long integral or floating-point constant does
     /// **Example:**
     ///
     /// ```rust
+    /// // Bad
     /// let x: u64 = 61864918973511;
+    ///
+    /// // Good
+    /// let x: u64 = 61_864_918_973_511;
     /// ```
     pub UNREADABLE_LITERAL,
     pedantic,
-    "long integer literal without underscores"
+    "long literal without underscores"
 }
 
 declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// // Probably mistyped
     /// 2_32;
+    ///
+    /// // Good
+    /// 2_i32;
     /// ```
     pub MISTYPED_LITERAL_SUFFIXES,
     correctness,
     /// **Example:**
     ///
     /// ```rust
+    /// // Bad
     /// let x: u64 = 618_64_9189_73_511;
+    ///
+    /// // Good
+    /// let x: u64 = 61_864_918_973_511;
     /// ```
     pub INCONSISTENT_DIGIT_GROUPING,
     style,
     "integer literals with digits grouped inconsistently"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Warns if hexadecimal or binary literals are not grouped
+    /// by nibble or byte.
+    ///
+    /// **Why is this bad?** Negatively impacts readability.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x: u32 = 0xFFF_FFF;
+    /// let y: u8 = 0b01_011_101;
+    /// ```
+    pub UNUSUAL_BYTE_GROUPINGS,
+    style,
+    "binary or hex literals that aren't grouped by four"
+}
+
 declare_clippy_lint! {
     /// **What it does:** Warns if the digits of an integral or floating-point
     /// constant are grouped into groups that
@@ -113,6 +144,7 @@ enum WarningType {
     LargeDigitGroups,
     DecimalRepresentation,
     MistypedLiteralSuffix,
+    UnusualByteGroupings,
 }
 
 impl WarningType {
@@ -163,15 +195,31 @@ fn display(&self, suggested_format: String, cx: &EarlyContext<'_>, span: rustc_s
                 suggested_format,
                 Applicability::MachineApplicable,
             ),
+            Self::UnusualByteGroupings => span_lint_and_sugg(
+                cx,
+                UNUSUAL_BYTE_GROUPINGS,
+                span,
+                "digits of hex or binary literal not grouped by four",
+                "consider",
+                suggested_format,
+                Applicability::MachineApplicable,
+            ),
         };
     }
 }
 
-declare_lint_pass!(LiteralDigitGrouping => [
+#[allow(clippy::module_name_repetitions)]
+#[derive(Copy, Clone)]
+pub struct LiteralDigitGrouping {
+    lint_fraction_readability: bool,
+}
+
+impl_lint_pass!(LiteralDigitGrouping => [
     UNREADABLE_LITERAL,
     INCONSISTENT_DIGIT_GROUPING,
     LARGE_DIGIT_GROUPS,
     MISTYPED_LITERAL_SUFFIXES,
+    UNUSUAL_BYTE_GROUPINGS,
 ]);
 
 impl EarlyLintPass for LiteralDigitGrouping {
@@ -181,7 +229,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            Self::check_lit(cx, lit)
+            self.check_lit(cx, lit)
         }
     }
 }
@@ -190,7 +238,13 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
 const UUID_GROUP_LENS: [usize; 5] = [8, 4, 4, 4, 12];
 
 impl LiteralDigitGrouping {
-    fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
+    pub fn new(lint_fraction_readability: bool) -> Self {
+        Self {
+            lint_fraction_readability,
+        }
+    }
+
+    fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
         if_chain! {
             if let Some(src) = snippet_opt(cx, lit.span);
             if let Some(mut num_lit) = NumericLiteral::from_lit(&src, &lit);
@@ -205,9 +259,12 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
 
                 let result = (|| {
 
-                    let integral_group_size = Self::get_group_size(num_lit.integer.split('_'))?;
+                    let integral_group_size = Self::get_group_size(num_lit.integer.split('_'), num_lit.radix, true)?;
                     if let Some(fraction) = num_lit.fraction {
-                        let fractional_group_size = Self::get_group_size(fraction.rsplit('_'))?;
+                        let fractional_group_size = Self::get_group_size(
+                            fraction.rsplit('_'),
+                            num_lit.radix,
+                            self.lint_fraction_readability)?;
 
                         let consistent = Self::parts_consistent(integral_group_size,
                                                                 fractional_group_size,
@@ -217,6 +274,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
                             return Err(WarningType::InconsistentDigitGrouping);
                         };
                     }
+
                     Ok(())
                 })();
 
@@ -225,6 +283,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
                     let should_warn = match warning_type {
                         | WarningType::UnreadableLiteral
                         | WarningType::InconsistentDigitGrouping
+                        | WarningType::UnusualByteGroupings
                         | WarningType::LargeDigitGroups => {
                             !in_macro(lit.span)
                         }
@@ -252,8 +311,8 @@ fn check_for_mistyped_suffix(
 
         let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent {
             (exponent, &["32", "64"][..], 'f')
-        } else if let Some(fraction) = &mut num_lit.fraction {
-            (fraction, &["32", "64"][..], 'f')
+        } else if num_lit.fraction.is_some() {
+            (&mut num_lit.integer, &["32", "64"][..], 'f')
         } else {
             (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i')
         };
@@ -319,11 +378,19 @@ fn parts_consistent(
 
     /// Returns the size of the digit groups (or None if ungrouped) if successful,
     /// otherwise returns a `WarningType` for linting.
-    fn get_group_size<'a>(groups: impl Iterator<Item = &'a str>) -> Result<Option<usize>, WarningType> {
+    fn get_group_size<'a>(
+        groups: impl Iterator<Item = &'a str>,
+        radix: Radix,
+        lint_unreadable: bool,
+    ) -> Result<Option<usize>, WarningType> {
         let mut groups = groups.map(str::len);
 
         let first = groups.next().expect("At least one group");
 
+        if (radix == Radix::Binary || radix == Radix::Hexadecimal) && groups.any(|i| i != 4 && i != 2) {
+            return Err(WarningType::UnusualByteGroupings);
+        }
+
         if let Some(second) = groups.next() {
             if !groups.all(|x| x == second) || first > second {
                 Err(WarningType::InconsistentDigitGrouping)
@@ -332,7 +399,7 @@ fn get_group_size<'a>(groups: impl Iterator<Item = &'a str>) -> Result<Option<us
             } else {
                 Ok(Some(second))
             }
-        } else if first > 5 {
+        } else if first > 5 && lint_unreadable {
             Err(WarningType::UnreadableLiteral)
         } else {
             Ok(None)