]> git.lizzy.rs Git - rust.git/blob - src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
Rollup merge of #85760 - ChrisDenton:path-doc-platform-specific, r=m-ou-se
[rust.git] / src / tools / clippy / clippy_lints / src / to_digit_is_some.rs
1 use clippy_utils::diagnostics::span_lint_and_sugg;
2 use clippy_utils::match_def_path;
3 use clippy_utils::source::snippet_with_applicability;
4 use if_chain::if_chain;
5 use rustc_errors::Applicability;
6 use rustc_hir as hir;
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_middle::ty;
9 use rustc_session::{declare_lint_pass, declare_tool_lint};
10
11 declare_clippy_lint! {
12     /// **What it does:** Checks for `.to_digit(..).is_some()` on `char`s.
13     ///
14     /// **Why is this bad?** This is a convoluted way of checking if a `char` is a digit. It's
15     /// more straight forward to use the dedicated `is_digit` method.
16     ///
17     /// **Example:**
18     /// ```rust
19     /// # let c = 'c';
20     /// # let radix = 10;
21     /// let is_digit = c.to_digit(radix).is_some();
22     /// ```
23     /// can be written as:
24     /// ```
25     /// # let c = 'c';
26     /// # let radix = 10;
27     /// let is_digit = c.is_digit(radix);
28     /// ```
29     pub TO_DIGIT_IS_SOME,
30     style,
31     "`char.is_digit()` is clearer"
32 }
33
34 declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]);
35
36 impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
37     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
38         if_chain! {
39             if let hir::ExprKind::MethodCall(is_some_path, _, is_some_args, _) = &expr.kind;
40             if is_some_path.ident.name.as_str() == "is_some";
41             if let [to_digit_expr] = &**is_some_args;
42             then {
43                 let match_result = match &to_digit_expr.kind {
44                     hir::ExprKind::MethodCall(to_digits_path, _, to_digit_args, _) => {
45                         if_chain! {
46                             if let [char_arg, radix_arg] = &**to_digit_args;
47                             if to_digits_path.ident.name.as_str() == "to_digit";
48                             let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg);
49                             if *char_arg_ty.kind() == ty::Char;
50                             then {
51                                 Some((true, char_arg, radix_arg))
52                             } else {
53                                 None
54                             }
55                         }
56                     }
57                     hir::ExprKind::Call(to_digits_call, to_digit_args) => {
58                         if_chain! {
59                             if let [char_arg, radix_arg] = &**to_digit_args;
60                             if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind;
61                             if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id);
62                             if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id();
63                             if match_def_path(cx, to_digits_def_id, &["core", "char", "methods", "<impl char>", "to_digit"]);
64                             then {
65                                 Some((false, char_arg, radix_arg))
66                             } else {
67                                 None
68                             }
69                         }
70                     }
71                     _ => None
72                 };
73
74                 if let Some((is_method_call, char_arg, radix_arg)) = match_result {
75                     let mut applicability = Applicability::MachineApplicable;
76                     let char_arg_snip = snippet_with_applicability(cx, char_arg.span, "_", &mut applicability);
77                     let radix_snip = snippet_with_applicability(cx, radix_arg.span, "_", &mut applicability);
78
79                     span_lint_and_sugg(
80                         cx,
81                         TO_DIGIT_IS_SOME,
82                         expr.span,
83                         "use of `.to_digit(..).is_some()`",
84                         "try this",
85                         if is_method_call {
86                             format!("{}.is_digit({})", char_arg_snip, radix_snip)
87                         } else {
88                             format!("char::is_digit({}, {})", char_arg_snip, radix_snip)
89                         },
90                         applicability,
91                     );
92                 }
93             }
94         }
95     }
96 }