From b2ea5eef445f16f02b9aea08a0bb8ff3e193762e Mon Sep 17 00:00:00 2001 From: Yuxiang Qiu Date: Thu, 4 Jan 2024 14:41:38 -0500 Subject: [PATCH] fix: incorrect suggestions when `.then` and `.then_some` is used --- clippy_lints/src/methods/search_is_some.rs | 35 +++++++++++++++++---- tests/ui/search_is_some_fixable_none.fixed | 16 ++++++++++ tests/ui/search_is_some_fixable_none.rs | 16 ++++++++++ tests/ui/search_is_some_fixable_none.stderr | 14 ++++++++- 4 files changed, 74 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/methods/search_is_some.rs b/clippy_lints/src/methods/search_is_some.rs index ac5cc2f01e5..1ea2e93c9de 100644 --- a/clippy_lints/src/methods/search_is_some.rs +++ b/clippy_lints/src/methods/search_is_some.rs @@ -2,7 +2,8 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::deref_closure_args; use clippy_utils::ty::is_type_lang_item; -use clippy_utils::{is_trait_method, strip_pat_refs}; +use clippy_utils::{get_parent_expr, is_trait_method, strip_pat_refs}; +use hir::ExprKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::PatKind; @@ -72,16 +73,24 @@ pub(super) fn check<'tcx>( ); } else { let iter = snippet(cx, search_recv.span, ".."); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!( + "(!{iter}.any({}))", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + } else { + format!( + "!{iter}.any({})", + any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) + ) + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!( - "!{iter}.any({})", - any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) - ), + sugg, applicability, ); } @@ -127,13 +136,18 @@ pub(super) fn check<'tcx>( let string = snippet(cx, search_recv.span, ".."); let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_arg.span, "..", &mut applicability); + let sugg = if is_receiver_of_method_call(cx, expr) { + format!("(!{string}.contains({find_arg}))") + } else { + format!("!{string}.contains({find_arg})") + }; span_lint_and_sugg( cx, SEARCH_IS_SOME, expr.span, msg, "consider using", - format!("!{string}.contains({find_arg})"), + sugg, applicability, ); }, @@ -142,3 +156,12 @@ pub(super) fn check<'tcx>( } } } + +fn is_receiver_of_method_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::MethodCall(..) = parent_expr.kind + { + return true; + } + false +} diff --git a/tests/ui/search_is_some_fixable_none.fixed b/tests/ui/search_is_some_fixable_none.fixed index 51636392f2b..3e5b3fab5ff 100644 --- a/tests/ui/search_is_some_fixable_none.fixed +++ b/tests/ui/search_is_some_fixable_none.fixed @@ -213,3 +213,19 @@ mod issue7392 { let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + fn test_then() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then(computations); + } + + fn test_then_some() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + (!v.iter().any(|x| *x == 42)).then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.rs b/tests/ui/search_is_some_fixable_none.rs index c7d773e18a3..e77ae5cecc2 100644 --- a/tests/ui/search_is_some_fixable_none.rs +++ b/tests/ui/search_is_some_fixable_none.rs @@ -219,3 +219,19 @@ struct FieldProjection<'a> { let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); } } + +mod issue_11910 { + fn computations() -> u32 { + 0 + } + + fn test_then() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then(computations); + } + + fn test_then_some() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + v.iter().find(|x| **x == 42).is_none().then_some(0); + } +} diff --git a/tests/ui/search_is_some_fixable_none.stderr b/tests/ui/search_is_some_fixable_none.stderr index 4ad1e2508c4..240eb245cdd 100644 --- a/tests/ui/search_is_some_fixable_none.stderr +++ b/tests/ui/search_is_some_fixable_none.stderr @@ -282,5 +282,17 @@ error: called `is_none()` after searching an `Iterator` with `find` LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` -error: aborting due to 43 previous errors +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:230:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then(computations); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `(!v.iter().any(|x| *x == 42))` + +error: called `is_none()` after searching an `Iterator` with `find` + --> $DIR/search_is_some_fixable_none.rs:235:9 + | +LL | v.iter().find(|x| **x == 42).is_none().then_some(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `(!v.iter().any(|x| *x == 42))` + +error: aborting due to 45 previous errors