From 64729390a1b2b6b05f8a4407658163ddff4d017e Mon Sep 17 00:00:00 2001 From: boolean_coercion Date: Thu, 11 Feb 2021 02:30:37 +0200 Subject: [PATCH] Implemented majority of from_str_radix_10 --- clippy_lints/src/from_str_radix_10.rs | 59 +++++++++++++++++++++++++-- clippy_lints/src/lib.rs | 1 + tests/ui/from_str_radix_10.rs | 32 ++++++++++++++- 3 files changed, 86 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index ec2a60ec47c..612ea9ae62c 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -1,6 +1,10 @@ -use rustc_lint::{EarlyLintPass, EarlyContext}; +use rustc_lint::{LateLintPass, LateContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_ast::ast::*; +use rustc_hir::*; +use rustc_errors::Applicability; +use if_chain::if_chain; + +use crate::utils::span_lint_and_sugg; declare_clippy_lint! { /// **What it does:** @@ -26,9 +30,56 @@ /// ``` pub FROM_STR_RADIX_10, style, - "default lint description" + "from_str_radix with radix 10" } declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]); -impl EarlyLintPass for FromStrRadix10 {} +impl LateLintPass<'tcx> for FromStrRadix10 { + fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { + if_chain! { + if let ExprKind::Call(maybe_path, arguments) = &exp.kind; + if let ExprKind::Path(qpath) = &maybe_path.kind; + if let QPath::TypeRelative(ty, pathseg) = &qpath; + + // check if the first part of the path is some integer primitive + if let TyKind::Path(ty_qpath) = &ty.kind; + let ty_res = cx.qpath_res(ty_qpath, ty.hir_id); + if let def::Res::PrimTy(prim_ty) = ty_res; + if is_primitive_integer_ty(prim_ty); + + // check if the second part of the path indeed calls the associated + // function `from_str_radix` + if pathseg.ident.name.as_str() == "from_str_radix"; + + // check if the second argument resolves to a constant `10` + if arguments.len() == 2; + if is_constant_10(&arguments[1]); + + then { + span_lint_and_sugg( + cx, + FROM_STR_RADIX_10, + exp.span, + "This call to `from_str_radix` can be shortened to a call to str::parse", + "try", + format!("TODO"), + Applicability::MachineApplicable + ); + } + } + } +} + +fn is_primitive_integer_ty(ty: PrimTy) -> bool { + match ty { + PrimTy::Int(_) => true, + PrimTy::Uint(_) => true, + _ => false + } +} + +fn is_constant_10<'tcx>(expr: &Expr<'tcx>) -> bool { + // TODO + true +} \ No newline at end of file diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5b84422458f..dae686b1229 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1258,6 +1258,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box types::PtrAsPtr::new(msrv)); store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons); store.register_late_pass(|| box redundant_slicing::RedundantSlicing); + store.register_late_pass(|| box from_str_radix_10::FromStrRadix10); store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(&arithmetic::FLOAT_ARITHMETIC), diff --git a/tests/ui/from_str_radix_10.rs b/tests/ui/from_str_radix_10.rs index 70eaa8d666c..086616d09ff 100644 --- a/tests/ui/from_str_radix_10.rs +++ b/tests/ui/from_str_radix_10.rs @@ -1,5 +1,33 @@ #![warn(clippy::from_str_radix_10)] -fn main() { - // test code goes here +mod some_mod { + // fake function that shouldn't trigger the lint + pub fn from_str_radix(_: &str, _: u32) -> Result<(), std::num::ParseIntError> { + unimplemented!() + } } + +// fake function that shouldn't trigger the lint +fn from_str_radix(_: &str, _: u32) -> Result<(), std::num::ParseIntError> { + unimplemented!() +} + +fn main() -> Result<(), Box> { + // all of these should trigger the lint + u32::from_str_radix("30", 10)?; + i64::from_str_radix("24", 10)?; + isize::from_str_radix("100", 10)?; + u8::from_str_radix("7", 10)?; + + // none of these should trigger the lint + u16::from_str_radix("20", 3)?; + i32::from_str_radix("45", 12)?; + usize::from_str_radix("10", 16)?; + i128::from_str_radix("10", 13)?; + some_mod::from_str_radix("50", 10)?; + some_mod::from_str_radix("50", 6)?; + from_str_radix("50", 10)?; + from_str_radix("50", 6)?; + + Ok(()) +} \ No newline at end of file