@@ -15,19 +15,21 @@ use rustc_span::{sym, Span};
1515declare_clippy_lint ! {
1616 /// ### What it does
1717 /// Suggests to use dedicated built-in methods,
18- /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
18+ /// `is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding
19+ /// ascii range
1920 ///
2021 /// ### Why is this bad?
2122 /// Using the built-in functions is more readable and makes it
2223 /// clear that it's not a specific subset of characters, but all
23- /// ASCII (lowercase|uppercase|digit) characters.
24+ /// ASCII (lowercase|uppercase|digit|hexdigit ) characters.
2425 /// ### Example
2526 /// ```rust
2627 /// fn main() {
2728 /// assert!(matches!('x', 'a'..='z'));
2829 /// assert!(matches!(b'X', b'A'..=b'Z'));
2930 /// assert!(matches!('2', '0'..='9'));
3031 /// assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
32+ /// assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F'));
3133 ///
3234 /// ('0'..='9').contains(&'0');
3335 /// ('a'..='z').contains(&'a');
@@ -41,6 +43,7 @@ declare_clippy_lint! {
4143 /// assert!(b'X'.is_ascii_uppercase());
4244 /// assert!('2'.is_ascii_digit());
4345 /// assert!('x'.is_ascii_alphabetic());
46+ /// assert!('C'.is_ascii_hexdigit());
4447 ///
4548 /// '0'.is_ascii_digit();
4649 /// 'a'.is_ascii_lowercase();
@@ -75,6 +78,12 @@ enum CharRange {
7578 FullChar ,
7679 /// '0..=9'
7780 Digit ,
81+ /// 'a..=f'
82+ LowerHexLetter ,
83+ /// 'A..=F'
84+ UpperHexLetter ,
85+ /// '0..=9' | 'a..=f' | 'A..=F'
86+ HexDigit ,
7887 Otherwise ,
7988}
8089
@@ -116,7 +125,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha
116125 CharRange :: LowerChar => Some ( "is_ascii_lowercase" ) ,
117126 CharRange :: FullChar => Some ( "is_ascii_alphabetic" ) ,
118127 CharRange :: Digit => Some ( "is_ascii_digit" ) ,
119- CharRange :: Otherwise => None ,
128+ CharRange :: HexDigit => Some ( "is_ascii_hexdigit" ) ,
129+ CharRange :: Otherwise | CharRange :: LowerHexLetter | CharRange :: UpperHexLetter => None ,
120130 } {
121131 let default_snip = ".." ;
122132 let mut app = Applicability :: MachineApplicable ;
@@ -141,6 +151,12 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
141151
142152 if ranges. len ( ) == 2 && ranges. contains ( & CharRange :: UpperChar ) && ranges. contains ( & CharRange :: LowerChar ) {
143153 CharRange :: FullChar
154+ } else if ranges. len ( ) == 3
155+ && ranges. contains ( & CharRange :: Digit )
156+ && ranges. contains ( & CharRange :: LowerHexLetter )
157+ && ranges. contains ( & CharRange :: UpperHexLetter )
158+ {
159+ CharRange :: HexDigit
144160 } else {
145161 CharRange :: Otherwise
146162 }
@@ -156,6 +172,8 @@ fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
156172 match ( & start_lit. node , & end_lit. node ) {
157173 ( Char ( 'a' ) , Char ( 'z' ) ) | ( Byte ( b'a' ) , Byte ( b'z' ) ) => CharRange :: LowerChar ,
158174 ( Char ( 'A' ) , Char ( 'Z' ) ) | ( Byte ( b'A' ) , Byte ( b'Z' ) ) => CharRange :: UpperChar ,
175+ ( Char ( 'a' ) , Char ( 'f' ) ) | ( Byte ( b'a' ) , Byte ( b'f' ) ) => CharRange :: LowerHexLetter ,
176+ ( Char ( 'A' ) , Char ( 'F' ) ) | ( Byte ( b'A' ) , Byte ( b'F' ) ) => CharRange :: UpperHexLetter ,
159177 ( Char ( '0' ) , Char ( '9' ) ) | ( Byte ( b'0' ) , Byte ( b'9' ) ) => CharRange :: Digit ,
160178 _ => CharRange :: Otherwise ,
161179 }
0 commit comments