|
1 | 1 | use clippy_utils::msrvs::{self, Msrv}; |
2 | | -use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet}; |
| 2 | +use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet}; |
3 | 3 | use rustc_ast::LitKind::{Byte, Char}; |
4 | 4 | use rustc_errors::Applicability; |
5 | 5 | use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd}; |
6 | 6 | use rustc_lint::{LateContext, LateLintPass}; |
7 | 7 | use rustc_session::{declare_tool_lint, impl_lint_pass}; |
8 | | -use rustc_span::{def_id::DefId, sym}; |
| 8 | +use rustc_span::{def_id::DefId, sym, Span}; |
9 | 9 |
|
10 | 10 | declare_clippy_lint! { |
11 | 11 | /// ### What it does |
@@ -75,47 +75,54 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { |
75 | 75 | return; |
76 | 76 | } |
77 | 77 |
|
78 | | - let Some(macro_call) = root_macro_call(expr.span) else { return }; |
79 | | - |
80 | | - if is_matches_macro(cx, macro_call.def_id) { |
| 78 | + if let Some(macro_call) = root_macro_call(expr.span) |
| 79 | + && is_matches_macro(cx, macro_call.def_id) { |
81 | 80 | if let ExprKind::Match(recv, [arm, ..], _) = expr.kind { |
82 | 81 | let range = check_pat(&arm.pat.kind); |
83 | | - |
84 | | - if let Some(sugg) = match range { |
85 | | - CharRange::UpperChar => Some("is_ascii_uppercase"), |
86 | | - CharRange::LowerChar => Some("is_ascii_lowercase"), |
87 | | - CharRange::FullChar => Some("is_ascii_alphabetic"), |
88 | | - CharRange::Digit => Some("is_ascii_digit"), |
89 | | - CharRange::Otherwise => None, |
90 | | - } { |
91 | | - let default_snip = ".."; |
92 | | - // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for |
93 | | - // macro span, so we check applicability manually by comparing `recv` is not default. |
94 | | - let recv = snippet(cx, recv.span, default_snip); |
95 | | - |
96 | | - let applicability = if recv == default_snip { |
97 | | - Applicability::HasPlaceholders |
98 | | - } else { |
99 | | - Applicability::MachineApplicable |
100 | | - }; |
101 | | - |
102 | | - span_lint_and_sugg( |
103 | | - cx, |
104 | | - MANUAL_IS_ASCII_CHECK, |
105 | | - macro_call.span, |
106 | | - "manual check for common ascii range", |
107 | | - "try", |
108 | | - format!("{recv}.{sugg}()"), |
109 | | - applicability, |
110 | | - ); |
111 | | - } |
| 82 | + check_is_ascii(cx, macro_call.span, recv, &range); |
112 | 83 | } |
| 84 | + } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind |
| 85 | + && path.ident.name == sym!(contains) |
| 86 | + && let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(receiver) { |
| 87 | + let range = check_range(start, end); |
| 88 | + check_is_ascii(cx, expr.span, arg, &range); |
113 | 89 | } |
114 | 90 | } |
115 | 91 |
|
116 | 92 | extract_msrv_attr!(LateContext); |
117 | 93 | } |
118 | 94 |
|
| 95 | +fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) { |
| 96 | + if let Some(sugg) = match range { |
| 97 | + CharRange::UpperChar => Some("is_ascii_uppercase"), |
| 98 | + CharRange::LowerChar => Some("is_ascii_lowercase"), |
| 99 | + CharRange::FullChar => Some("is_ascii_alphabetic"), |
| 100 | + CharRange::Digit => Some("is_ascii_digit"), |
| 101 | + CharRange::Otherwise => None, |
| 102 | + } { |
| 103 | + let default_snip = ".."; |
| 104 | + // `snippet_with_applicability` may set applicability to `MaybeIncorrect` for |
| 105 | + // macro span, so we check applicability manually by comparing `recv` is not default. |
| 106 | + let recv = snippet(cx, recv.span, default_snip); |
| 107 | + |
| 108 | + let applicability = if recv == default_snip { |
| 109 | + Applicability::HasPlaceholders |
| 110 | + } else { |
| 111 | + Applicability::MachineApplicable |
| 112 | + }; |
| 113 | + |
| 114 | + span_lint_and_sugg( |
| 115 | + cx, |
| 116 | + MANUAL_IS_ASCII_CHECK, |
| 117 | + span, |
| 118 | + "manual check for common ascii range", |
| 119 | + "try", |
| 120 | + format!("{recv}.{sugg}()"), |
| 121 | + applicability, |
| 122 | + ); |
| 123 | + } |
| 124 | +} |
| 125 | + |
119 | 126 | fn check_pat(pat_kind: &PatKind<'_>) -> CharRange { |
120 | 127 | match pat_kind { |
121 | 128 | PatKind::Or(pats) => { |
|
0 commit comments