@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
66use rustc_lint:: { EarlyContext , EarlyLintPass , LintContext } ;
77use rustc_middle:: lint:: in_external_macro;
88use rustc_session:: impl_lint_pass;
9- use rustc_span:: Span ;
109
1110declare_clippy_lint ! {
1211 /// ### What it does
@@ -41,61 +40,80 @@ impl AlmostCompleteRange {
4140}
4241impl EarlyLintPass for AlmostCompleteRange {
4342 fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & Expr ) {
44- if let ExprKind :: Range ( Some ( start) , Some ( end) , RangeLimits :: HalfOpen ) = & e. kind {
45- let ctxt = e. span . ctxt ( ) ;
46- let sugg = if let Some ( start) = walk_span_to_context ( start. span , ctxt)
47- && let Some ( end) = walk_span_to_context ( end. span , ctxt)
48- && self . msrv . meets ( msrvs:: RANGE_INCLUSIVE )
49- {
50- Some ( ( trim_span ( cx. sess ( ) . source_map ( ) , start. between ( end) ) , "..=" ) )
51- } else {
52- None
53- } ;
54- check_range ( cx, e. span , start, end, sugg) ;
43+ if let ExprKind :: Range ( Some ( start) , Some ( end) , RangeLimits :: HalfOpen ) = & e. kind
44+ && is_incomplete_range ( start, end)
45+ && !in_external_macro ( cx. sess ( ) , e. span )
46+ {
47+ span_lint_and_then (
48+ cx,
49+ ALMOST_COMPLETE_RANGE ,
50+ e. span ,
51+ "almost complete ascii range" ,
52+ |diag| {
53+ let ctxt = e. span . ctxt ( ) ;
54+ if let Some ( start) = walk_span_to_context ( start. span , ctxt)
55+ && let Some ( end) = walk_span_to_context ( end. span , ctxt)
56+ && self . msrv . meets ( msrvs:: RANGE_INCLUSIVE )
57+ {
58+ diag. span_suggestion (
59+ trim_span ( cx. sess ( ) . source_map ( ) , start. between ( end) ) ,
60+ "use an inclusive range" ,
61+ "..=" . to_owned ( ) ,
62+ Applicability :: MaybeIncorrect ,
63+ ) ;
64+ }
65+ } ,
66+ ) ;
5567 }
5668 }
5769
5870 fn check_pat ( & mut self , cx : & EarlyContext < ' _ > , p : & Pat ) {
5971 if let PatKind :: Range ( Some ( start) , Some ( end) , kind) = & p. kind
6072 && matches ! ( kind. node, RangeEnd :: Excluded )
73+ && is_incomplete_range ( start, end)
74+ && !in_external_macro ( cx. sess ( ) , p. span )
6175 {
62- let sugg = if self . msrv . meets ( msrvs:: RANGE_INCLUSIVE ) {
63- "..="
64- } else {
65- "..."
66- } ;
67- check_range ( cx, p. span , start, end, Some ( ( kind. span , sugg) ) ) ;
76+ span_lint_and_then (
77+ cx,
78+ ALMOST_COMPLETE_RANGE ,
79+ p. span ,
80+ "almost complete ascii range" ,
81+ |diag| {
82+ diag. span_suggestion (
83+ kind. span ,
84+ "use an inclusive range" ,
85+ if self . msrv . meets ( msrvs:: RANGE_INCLUSIVE ) {
86+ "..=" . to_owned ( )
87+ } else {
88+ "..." . to_owned ( )
89+ } ,
90+ Applicability :: MaybeIncorrect ,
91+ ) ;
92+ } ,
93+ ) ;
6894 }
6995 }
7096
7197 extract_msrv_attr ! ( EarlyContext ) ;
7298}
7399
74- fn check_range ( cx : & EarlyContext < ' _ > , span : Span , start : & Expr , end : & Expr , sugg : Option < ( Span , & str ) > ) {
75- if let ExprKind :: Lit ( start_token_lit) = start. peel_parens ( ) . kind
76- && let ExprKind :: Lit ( end_token_lit) = end. peel_parens ( ) . kind
77- && matches ! (
78- (
79- LitKind :: from_token_lit( start_token_lit) ,
80- LitKind :: from_token_lit( end_token_lit) ,
81- ) ,
82- (
83- Ok ( LitKind :: Byte ( b'a' ) | LitKind :: Char ( 'a' ) ) ,
84- Ok ( LitKind :: Byte ( b'z' ) | LitKind :: Char ( 'z' ) )
85- ) | (
86- Ok ( LitKind :: Byte ( b'A' ) | LitKind :: Char ( 'A' ) ) ,
87- Ok ( LitKind :: Byte ( b'Z' ) | LitKind :: Char ( 'Z' ) ) ,
88- ) | (
89- Ok ( LitKind :: Byte ( b'0' ) | LitKind :: Char ( '0' ) ) ,
90- Ok ( LitKind :: Byte ( b'9' ) | LitKind :: Char ( '9' ) ) ,
100+ fn is_incomplete_range ( start : & Expr , end : & Expr ) -> bool {
101+ match ( & start. peel_parens ( ) . kind , & end. peel_parens ( ) . kind ) {
102+ ( & ExprKind :: Lit ( start_lit) , & ExprKind :: Lit ( end_lit) ) => {
103+ matches ! (
104+ ( LitKind :: from_token_lit( start_lit) , LitKind :: from_token_lit( end_lit) , ) ,
105+ (
106+ Ok ( LitKind :: Byte ( b'a' ) | LitKind :: Char ( 'a' ) ) ,
107+ Ok ( LitKind :: Byte ( b'z' ) | LitKind :: Char ( 'z' ) )
108+ ) | (
109+ Ok ( LitKind :: Byte ( b'A' ) | LitKind :: Char ( 'A' ) ) ,
110+ Ok ( LitKind :: Byte ( b'Z' ) | LitKind :: Char ( 'Z' ) ) ,
111+ ) | (
112+ Ok ( LitKind :: Byte ( b'0' ) | LitKind :: Char ( '0' ) ) ,
113+ Ok ( LitKind :: Byte ( b'9' ) | LitKind :: Char ( '9' ) ) ,
114+ )
91115 )
92- )
93- && !in_external_macro ( cx. sess ( ) , span)
94- {
95- span_lint_and_then ( cx, ALMOST_COMPLETE_RANGE , span, "almost complete ascii range" , |diag| {
96- if let Some ( ( span, sugg) ) = sugg {
97- diag. span_suggestion ( span, "use an inclusive range" , sugg, Applicability :: MaybeIncorrect ) ;
98- }
99- } ) ;
116+ } ,
117+ _ => false ,
100118 }
101119}
0 commit comments