|
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