@@ -110,6 +110,7 @@ mod unit_hash;
110110mod unnecessary_fallible_conversions;
111111mod unnecessary_filter_map;
112112mod unnecessary_fold;
113+ mod unnecessary_get_then_check;
113114mod unnecessary_iter_cloned;
114115mod unnecessary_join;
115116mod unnecessary_lazy_eval;
@@ -4011,6 +4012,35 @@ declare_clippy_lint! {
40114012 r#"creating a `CStr` through functions when `c""` literals can be used"#
40124013}
40134014
4015+ declare_clippy_lint ! {
4016+ /// ### What it does
4017+ /// Checks the usage of `.get().is_some()` or `.get().is_none()` on std map types.
4018+ ///
4019+ /// ### Why is this bad?
4020+ /// It can be done in one call with `.contains()`/`.contains_keys()`.
4021+ ///
4022+ /// ### Example
4023+ /// ```no_run
4024+ /// # use std::collections::HashSet;
4025+ /// let s: HashSet<String> = HashSet::new();
4026+ /// if s.get("a").is_some() {
4027+ /// // code
4028+ /// }
4029+ /// ```
4030+ /// Use instead:
4031+ /// ```no_run
4032+ /// # use std::collections::HashSet;
4033+ /// let s: HashSet<String> = HashSet::new();
4034+ /// if s.contains("a") {
4035+ /// // code
4036+ /// }
4037+ /// ```
4038+ #[ clippy:: version = "1.78.0" ]
4039+ pub UNNECESSARY_GET_THEN_CHECK ,
4040+ suspicious,
4041+ "calling `.get().is_some()` or `.get().is_none()` instead of `.contains()` or `.contains_key()`"
4042+ }
4043+
40144044pub struct Methods {
40154045 avoid_breaking_exported_api : bool ,
40164046 msrv : Msrv ,
@@ -4171,6 +4201,7 @@ impl_lint_pass!(Methods => [
41714201 OPTION_AS_REF_CLONED ,
41724202 UNNECESSARY_RESULT_MAP_OR_ELSE ,
41734203 MANUAL_C_STR_LITERALS ,
4204+ UNNECESSARY_GET_THEN_CHECK ,
41744205] ) ;
41754206
41764207/// Extracts a method call name, args, and `Span` of the method name.
@@ -4587,8 +4618,8 @@ impl Methods {
45874618 } ,
45884619 ( "is_file" , [ ] ) => filetype_is_file:: check ( cx, expr, recv) ,
45894620 ( "is_digit" , [ radix] ) => is_digit_ascii_radix:: check ( cx, expr, recv, radix, & self . msrv ) ,
4590- ( "is_none" , [ ] ) => check_is_some_is_none ( cx, expr, recv, false ) ,
4591- ( "is_some" , [ ] ) => check_is_some_is_none ( cx, expr, recv, true ) ,
4621+ ( "is_none" , [ ] ) => check_is_some_is_none ( cx, expr, recv, call_span , false ) ,
4622+ ( "is_some" , [ ] ) => check_is_some_is_none ( cx, expr, recv, call_span , true ) ,
45924623 ( "iter" | "iter_mut" | "into_iter" , [ ] ) => {
45934624 iter_on_single_or_empty_collections:: check ( cx, expr, name, recv) ;
45944625 } ,
@@ -4899,9 +4930,15 @@ impl Methods {
48994930 }
49004931}
49014932
4902- fn check_is_some_is_none ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , recv : & Expr < ' _ > , is_some : bool ) {
4903- if let Some ( ( name @ ( "find" | "position" | "rposition" ) , f_recv, [ arg] , span, _) ) = method_call ( recv) {
4904- search_is_some:: check ( cx, expr, name, is_some, f_recv, arg, recv, span) ;
4933+ fn check_is_some_is_none ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , recv : & Expr < ' _ > , call_span : Span , is_some : bool ) {
4934+ match method_call ( recv) {
4935+ Some ( ( name @ ( "find" | "position" | "rposition" ) , f_recv, [ arg] , span, _) ) => {
4936+ search_is_some:: check ( cx, expr, name, is_some, f_recv, arg, recv, span) ;
4937+ } ,
4938+ Some ( ( "get" , f_recv, [ arg] , _, _) ) => {
4939+ unnecessary_get_then_check:: check ( cx, call_span, recv, f_recv, arg, is_some) ;
4940+ } ,
4941+ _ => { } ,
49054942 }
49064943}
49074944
0 commit comments