1 use if_chain::if_chain;
2 use rustc_errors::Applicability;
4 use rustc_lint::{LateContext, LateLintPass};
5 use rustc_session::{declare_lint_pass, declare_tool_lint};
7 use crate::utils::span_lint_and_sugg;
8 use crate::utils::sugg::Sugg;
10 declare_clippy_lint! {
12 /// Checks for function invocations of the form `primitive::from_str_radix(s, 10)`
14 /// **Why is this bad?**
15 /// This specific common use case can be rewritten as `s.parse::<primitive>()`
16 /// (and in most cases, the turbofish can be removed), which reduces code length
19 /// **Known problems:** None.
24 /// let input: &str = get_input();
25 /// let num = u16::from_str_radix(input, 10)?;
29 /// let input: &str = get_input();
30 /// let num: u16 = input.parse()?;
32 pub FROM_STR_RADIX_10,
34 "from_str_radix with radix 10"
37 declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
39 impl LateLintPass<'tcx> for FromStrRadix10 {
40 fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
42 if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
43 if let ExprKind::Path(qpath) = &maybe_path.kind;
44 if let QPath::TypeRelative(ty, pathseg) = &qpath;
46 // check if the first part of the path is some integer primitive
47 if let TyKind::Path(ty_qpath) = &ty.kind;
48 let ty_res = cx.qpath_res(ty_qpath, ty.hir_id);
49 if let def::Res::PrimTy(prim_ty) = ty_res;
50 if matches!(prim_ty, PrimTy::Int(_) | PrimTy::Uint(_));
52 // check if the second part of the path indeed calls the associated
53 // function `from_str_radix`
54 if pathseg.ident.name.as_str() == "from_str_radix";
56 // check if the second argument is a primitive `10`
57 if arguments.len() == 2;
58 if let ExprKind::Lit(lit) = &arguments[1].kind;
59 if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;
62 let sugg = Sugg::hir_with_applicability(
66 &mut Applicability::MachineApplicable
73 "this call to `from_str_radix` can be replaced with a call to `str::parse`",
75 format!("{}.parse::<{}>()", sugg, prim_ty.name_str()),
76 Applicability::MaybeIncorrect