mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 21:47:04 +00:00
check ranges with .contains calls
This commit is contained in:
parent
911864df46
commit
25c9718c04
@ -1,11 +1,11 @@
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, in_constant, macros::root_macro_call, source::snippet};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
|
||||
use rustc_ast::LitKind::{Byte, Char};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, RangeEnd};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{def_id::DefId, sym};
|
||||
use rustc_span::{def_id::DefId, sym, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
@ -75,47 +75,54 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(macro_call) = root_macro_call(expr.span) else { return };
|
||||
|
||||
if is_matches_macro(cx, macro_call.def_id) {
|
||||
if let Some(macro_call) = root_macro_call(expr.span)
|
||||
&& is_matches_macro(cx, macro_call.def_id) {
|
||||
if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
|
||||
let range = check_pat(&arm.pat.kind);
|
||||
|
||||
if let Some(sugg) = match range {
|
||||
CharRange::UpperChar => Some("is_ascii_uppercase"),
|
||||
CharRange::LowerChar => Some("is_ascii_lowercase"),
|
||||
CharRange::FullChar => Some("is_ascii_alphabetic"),
|
||||
CharRange::Digit => Some("is_ascii_digit"),
|
||||
CharRange::Otherwise => None,
|
||||
} {
|
||||
let default_snip = "..";
|
||||
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
|
||||
// macro span, so we check applicability manually by comparing `recv` is not default.
|
||||
let recv = snippet(cx, recv.span, default_snip);
|
||||
|
||||
let applicability = if recv == default_snip {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_IS_ASCII_CHECK,
|
||||
macro_call.span,
|
||||
"manual check for common ascii range",
|
||||
"try",
|
||||
format!("{recv}.{sugg}()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
check_is_ascii(cx, macro_call.span, recv, &range);
|
||||
}
|
||||
} else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
|
||||
&& path.ident.name == sym!(contains)
|
||||
&& let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(receiver) {
|
||||
let range = check_range(start, end);
|
||||
check_is_ascii(cx, expr.span, arg, &range);
|
||||
}
|
||||
}
|
||||
|
||||
extract_msrv_attr!(LateContext);
|
||||
}
|
||||
|
||||
fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &CharRange) {
|
||||
if let Some(sugg) = match range {
|
||||
CharRange::UpperChar => Some("is_ascii_uppercase"),
|
||||
CharRange::LowerChar => Some("is_ascii_lowercase"),
|
||||
CharRange::FullChar => Some("is_ascii_alphabetic"),
|
||||
CharRange::Digit => Some("is_ascii_digit"),
|
||||
CharRange::Otherwise => None,
|
||||
} {
|
||||
let default_snip = "..";
|
||||
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
|
||||
// macro span, so we check applicability manually by comparing `recv` is not default.
|
||||
let recv = snippet(cx, recv.span, default_snip);
|
||||
|
||||
let applicability = if recv == default_snip {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_IS_ASCII_CHECK,
|
||||
span,
|
||||
"manual check for common ascii range",
|
||||
"try",
|
||||
format!("{recv}.{sugg}()"),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
|
||||
match pat_kind {
|
||||
PatKind::Or(pats) => {
|
||||
|
@ -15,6 +15,7 @@ fn main() {
|
||||
assert!('x'.is_ascii_alphabetic());
|
||||
|
||||
assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
|
||||
assert!(&b'0'.is_ascii_digit());
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.23"]
|
||||
|
@ -15,6 +15,7 @@ fn main() {
|
||||
assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
|
||||
assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_'));
|
||||
assert!((b'0'..=b'9').contains(&b'0'));
|
||||
}
|
||||
|
||||
#[clippy::msrv = "1.23"]
|
||||
|
@ -43,28 +43,34 @@ LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:29:13
|
||||
--> $DIR/manual_is_ascii_check.rs:18:13
|
||||
|
|
||||
LL | assert!((b'0'..=b'9').contains(&b'0'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&b'0'.is_ascii_digit()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:30:13
|
||||
|
|
||||
LL | assert!(matches!(b'1', b'0'..=b'9'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:30:13
|
||||
--> $DIR/manual_is_ascii_check.rs:31:13
|
||||
|
|
||||
LL | assert!(matches!('X', 'A'..='Z'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:31:13
|
||||
--> $DIR/manual_is_ascii_check.rs:32:13
|
||||
|
|
||||
LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
|
||||
|
||||
error: manual check for common ascii range
|
||||
--> $DIR/manual_is_ascii_check.rs:41:23
|
||||
--> $DIR/manual_is_ascii_check.rs:42:23
|
||||
|
|
||||
LL | const FOO: bool = matches!('x', '0'..='9');
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user