@@ -82,6 +82,25 @@ declare_clippy_lint! {
8282 "integer literals with digits grouped inconsistently"
8383}
8484
85+ declare_clippy_lint ! {
86+ /// **What it does:** Warns if hexadecimal or binary literals are not grouped
87+ /// by nibble or byte.
88+ ///
89+ /// **Why is this bad?** Negatively impacts readability.
90+ ///
91+ /// **Known problems:** None.
92+ ///
93+ /// **Example:**
94+ ///
95+ /// ```rust
96+ /// let x: u32 = 0xFFF_FFF;
97+ /// let y: u8 = 0b01_011_101;
98+ /// ```
99+ pub UNUSUAL_BYTE_GROUPINGS ,
100+ style,
101+ "binary or hex literals that aren't grouped by four"
102+ }
103+
85104declare_clippy_lint ! {
86105 /// **What it does:** Warns if the digits of an integral or floating-point
87106 /// constant are grouped into groups that
@@ -125,6 +144,7 @@ enum WarningType {
125144 LargeDigitGroups ,
126145 DecimalRepresentation ,
127146 MistypedLiteralSuffix ,
147+ UnusualByteGroupings ,
128148}
129149
130150impl WarningType {
@@ -175,6 +195,15 @@ impl WarningType {
175195 suggested_format,
176196 Applicability :: MachineApplicable ,
177197 ) ,
198+ Self :: UnusualByteGroupings => span_lint_and_sugg (
199+ cx,
200+ UNUSUAL_BYTE_GROUPINGS ,
201+ span,
202+ "digits of hex or binary literal not grouped by four" ,
203+ "consider" ,
204+ suggested_format,
205+ Applicability :: MachineApplicable ,
206+ ) ,
178207 } ;
179208 }
180209}
@@ -184,6 +213,7 @@ declare_lint_pass!(LiteralDigitGrouping => [
184213 INCONSISTENT_DIGIT_GROUPING ,
185214 LARGE_DIGIT_GROUPS ,
186215 MISTYPED_LITERAL_SUFFIXES ,
216+ UNUSUAL_BYTE_GROUPINGS ,
187217] ) ;
188218
189219impl EarlyLintPass for LiteralDigitGrouping {
@@ -217,9 +247,9 @@ impl LiteralDigitGrouping {
217247
218248 let result = ( || {
219249
220- let integral_group_size = Self :: get_group_size( num_lit. integer. split( '_' ) ) ?;
250+ let integral_group_size = Self :: get_group_size( num_lit. integer. split( '_' ) , num_lit . radix ) ?;
221251 if let Some ( fraction) = num_lit. fraction {
222- let fractional_group_size = Self :: get_group_size( fraction. rsplit( '_' ) ) ?;
252+ let fractional_group_size = Self :: get_group_size( fraction. rsplit( '_' ) , num_lit . radix ) ?;
223253
224254 let consistent = Self :: parts_consistent( integral_group_size,
225255 fractional_group_size,
@@ -229,6 +259,7 @@ impl LiteralDigitGrouping {
229259 return Err ( WarningType :: InconsistentDigitGrouping ) ;
230260 } ;
231261 }
262+
232263 Ok ( ( ) )
233264 } ) ( ) ;
234265
@@ -237,6 +268,7 @@ impl LiteralDigitGrouping {
237268 let should_warn = match warning_type {
238269 | WarningType :: UnreadableLiteral
239270 | WarningType :: InconsistentDigitGrouping
271+ | WarningType :: UnusualByteGroupings
240272 | WarningType :: LargeDigitGroups => {
241273 !in_macro( lit. span)
242274 }
@@ -331,11 +363,15 @@ impl LiteralDigitGrouping {
331363
332364 /// Returns the size of the digit groups (or None if ungrouped) if successful,
333365 /// otherwise returns a `WarningType` for linting.
334- fn get_group_size < ' a > ( groups : impl Iterator < Item = & ' a str > ) -> Result < Option < usize > , WarningType > {
366+ fn get_group_size < ' a > ( groups : impl Iterator < Item = & ' a str > , radix : Radix ) -> Result < Option < usize > , WarningType > {
335367 let mut groups = groups. map ( str:: len) ;
336368
337369 let first = groups. next ( ) . expect ( "At least one group" ) ;
338370
371+ if ( radix == Radix :: Binary || radix == Radix :: Hexadecimal ) && groups. any ( |i| i != 4 && i != 2 ) {
372+ return Err ( WarningType :: UnusualByteGroupings ) ;
373+ }
374+
339375 if let Some ( second) = groups. next ( ) {
340376 if !groups. all ( |x| x == second) || first > second {
341377 Err ( WarningType :: InconsistentDigitGrouping )
0 commit comments