@@ -515,11 +515,11 @@ declare_clippy_lint! {
515
515
}
516
516
517
517
declare_clippy_lint ! {
518
- /// **What it does:** Checks for an iterator search (such as `find()`,
518
+ /// **What it does:** Checks for an iterator or string search (such as `find()`,
519
519
/// `position()`, or `rposition()`) followed by a call to `is_some()`.
520
520
///
521
521
/// **Why is this bad?** Readability, this can be written more concisely as
522
- /// `_.any(_)`.
522
+ /// `_.any(_)` or `_.contains(_)` .
523
523
///
524
524
/// **Known problems:** None.
525
525
///
@@ -535,7 +535,7 @@ declare_clippy_lint! {
535
535
/// ```
536
536
pub SEARCH_IS_SOME ,
537
537
complexity,
538
- "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`"
538
+ "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains ()`"
539
539
}
540
540
541
541
declare_clippy_lint ! {
@@ -3041,6 +3041,7 @@ fn lint_flat_map_identity<'tcx>(
3041
3041
}
3042
3042
3043
3043
/// lint searching an Iterator followed by `is_some()`
3044
+ /// or calling `find()` on a string followed by `is_some()`
3044
3045
fn lint_search_is_some < ' tcx > (
3045
3046
cx : & LateContext < ' tcx > ,
3046
3047
expr : & ' tcx hir:: Expr < ' _ > ,
@@ -3052,10 +3053,10 @@ fn lint_search_is_some<'tcx>(
3052
3053
// lint if caller of search is an Iterator
3053
3054
if match_trait_method ( cx, & is_some_args[ 0 ] , & paths:: ITERATOR ) {
3054
3055
let msg = format ! (
3055
- "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \
3056
- expressed by calling `any()`.",
3056
+ "called `is_some()` after searching an `Iterator` with `{}`" ,
3057
3057
search_method
3058
3058
) ;
3059
+ let hint = "this is more succinctly expressed by calling `any()`" ;
3059
3060
let search_snippet = snippet ( cx, search_args[ 1 ] . span , ".." ) ;
3060
3061
if search_snippet. lines ( ) . count ( ) <= 1 {
3061
3062
// suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()`
@@ -3083,15 +3084,44 @@ fn lint_search_is_some<'tcx>(
3083
3084
SEARCH_IS_SOME ,
3084
3085
method_span. with_hi ( expr. span . hi ( ) ) ,
3085
3086
& msg,
3086
- "try this " ,
3087
+ "use `any()` instead " ,
3087
3088
format ! (
3088
3089
"any({})" ,
3089
3090
any_search_snippet. as_ref( ) . map_or( & * search_snippet, String :: as_str)
3090
3091
) ,
3091
3092
Applicability :: MachineApplicable ,
3092
3093
) ;
3093
3094
} else {
3094
- span_lint ( cx, SEARCH_IS_SOME , expr. span , & msg) ;
3095
+ span_lint_and_help ( cx, SEARCH_IS_SOME , expr. span , & msg, None , hint) ;
3096
+ }
3097
+ }
3098
+ // lint if `find()` is called by `String` or `&str`
3099
+ else if search_method == "find" {
3100
+ let is_string_or_str_slice = |e| {
3101
+ let self_ty = cx. typeck_results ( ) . expr_ty ( e) . peel_refs ( ) ;
3102
+ if is_type_diagnostic_item ( cx, self_ty, sym ! ( string_type) ) {
3103
+ true
3104
+ } else {
3105
+ * self_ty. kind ( ) == ty:: Str
3106
+ }
3107
+ } ;
3108
+ if_chain ! {
3109
+ if is_string_or_str_slice( & search_args[ 0 ] ) ;
3110
+ if is_string_or_str_slice( & search_args[ 1 ] ) ;
3111
+ then {
3112
+ let msg = "called `is_some()` after calling `find()` on a string" ;
3113
+ let mut applicability = Applicability :: MachineApplicable ;
3114
+ let find_arg = snippet_with_applicability( cx, search_args[ 1 ] . span, ".." , & mut applicability) ;
3115
+ span_lint_and_sugg(
3116
+ cx,
3117
+ SEARCH_IS_SOME ,
3118
+ method_span. with_hi( expr. span. hi( ) ) ,
3119
+ msg,
3120
+ "use `contains()` instead" ,
3121
+ format!( "contains({})" , find_arg) ,
3122
+ applicability,
3123
+ ) ;
3124
+ }
3095
3125
}
3096
3126
}
3097
3127
}
0 commit comments