about summary refs log tree commit diff
diff options
context:
space:
mode:
authorllogiq <bogusandre@gmail.com>2025-07-10 21:27:09 +0000
committerGitHub <noreply@github.com>2025-07-10 21:27:09 +0000
commitdf5a0ee919f8c22c88584694a1532e4eb1cd0fca (patch)
tree19d160654f08d9604c5f7f3dd3e115333b8cbe2b
parent4dcaa80651dff62de71cbd334f05810580eb9d48 (diff)
parent86a14967f73f4c073e448dbbba34d56c8c94484a (diff)
downloadrust-df5a0ee919f8c22c88584694a1532e4eb1cd0fca.tar.gz
rust-df5a0ee919f8c22c88584694a1532e4eb1cd0fca.zip
or_fun_call: lint method calls inside map_or first arg (#15074)
<strike>blocked on rust-lang/rust-clippy#15073</strike>

Lint method calls inside `map_or` too, so for this, lint will be showed:
```rust
Some(4).map_or("asd".to_string().len() as i32, f);
```
previously it worked only for:
```rust
Some(4).map_or(slow_fun(), f);
```

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=bfcda42a6af446e69bc883a8b45eb13c

Sorry for multiple `or_fun_call` PRs.

changelog: [`or_fun_call`]: lint method calls inside map_or first arg
-rw-r--r--clippy_lints/src/methods/or_fun_call.rs26
-rw-r--r--clippy_lints/src/needless_pass_by_value.rs12
-rw-r--r--clippy_utils/src/diagnostics.rs11
-rw-r--r--tests/ui/or_fun_call.fixed4
-rw-r--r--tests/ui/or_fun_call.rs4
-rw-r--r--tests/ui/or_fun_call.stderr50
6 files changed, 71 insertions, 36 deletions
diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs
index 6ce7dd3d4d0..04f0e3c0479 100644
--- a/clippy_lints/src/methods/or_fun_call.rs
+++ b/clippy_lints/src/methods/or_fun_call.rs
@@ -242,15 +242,23 @@ pub(super) fn check<'tcx>(
         let inner_arg = peel_blocks(arg);
         for_each_expr(cx, inner_arg, |ex| {
             let is_top_most_expr = ex.hir_id == inner_arg.hir_id;
-            if let hir::ExprKind::Call(fun, fun_args) = ex.kind {
-                let fun_span = if fun_args.is_empty() && is_top_most_expr {
-                    Some(fun.span)
-                } else {
-                    None
-                };
-                if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) {
-                    return ControlFlow::Break(());
-                }
+            match ex.kind {
+                hir::ExprKind::Call(fun, fun_args) => {
+                    let fun_span = if fun_args.is_empty() && is_top_most_expr {
+                        Some(fun.span)
+                    } else {
+                        None
+                    };
+                    if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, fun_span) {
+                        return ControlFlow::Break(());
+                    }
+                },
+                hir::ExprKind::MethodCall(..) => {
+                    if check_or_fn_call(cx, name, method_span, receiver, arg, Some(lambda), expr.span, None) {
+                        return ControlFlow::Break(());
+                    }
+                },
+                _ => {},
             }
             ControlFlow::Continue(())
         });
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index c97ecce75b4..2006a824402 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -246,8 +246,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                         for (span, suggestion) in clone_spans {
                             diag.span_suggestion(
                                 span,
-                                span.get_source_text(cx)
-                                    .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")),
+                                span.get_source_text(cx).map_or_else(
+                                    || "change the call to".to_owned(),
+                                    |src| format!("change `{src}` to"),
+                                ),
                                 suggestion,
                                 Applicability::Unspecified,
                             );
@@ -275,8 +277,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                         for (span, suggestion) in clone_spans {
                             diag.span_suggestion(
                                 span,
-                                span.get_source_text(cx)
-                                    .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")),
+                                span.get_source_text(cx).map_or_else(
+                                    || "change the call to".to_owned(),
+                                    |src| format!("change `{src}` to"),
+                                ),
                                 suggestion,
                                 Applicability::Unspecified,
                             );
diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs
index 8453165818b..625e1eead21 100644
--- a/clippy_utils/src/diagnostics.rs
+++ b/clippy_utils/src/diagnostics.rs
@@ -22,10 +22,13 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
     {
         diag.help(format!(
             "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
-            &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
-                // extract just major + minor version and ignore patch versions
-                format!("rust-{}", n.rsplit_once('.').unwrap().1)
-            })
+            &option_env!("RUST_RELEASE_NUM").map_or_else(
+                || "master".to_string(),
+                |n| {
+                    // extract just major + minor version and ignore patch versions
+                    format!("rust-{}", n.rsplit_once('.').unwrap().1)
+                }
+            )
         ));
     }
 }
diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed
index bcd2602edb6..0a8525a12f5 100644
--- a/tests/ui/or_fun_call.fixed
+++ b/tests/ui/or_fun_call.fixed
@@ -283,6 +283,8 @@ mod issue8993 {
         let _ = Some(4).map_or_else(g, f);
         //~^ or_fun_call
         let _ = Some(4).map_or(0, f);
+        let _ = Some(4).map_or_else(|| "asd".to_string().len() as i32, f);
+        //~^ or_fun_call
     }
 }
 
@@ -426,6 +428,8 @@ mod result_map_or {
         let _ = x.map_or_else(|_| g(), f);
         //~^ or_fun_call
         let _ = x.map_or(0, f);
+        let _ = x.map_or_else(|_| "asd".to_string().len() as i32, f);
+        //~^ or_fun_call
     }
 }
 
diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs
index 8d1202ebf91..b4f9b950a7f 100644
--- a/tests/ui/or_fun_call.rs
+++ b/tests/ui/or_fun_call.rs
@@ -283,6 +283,8 @@ mod issue8993 {
         let _ = Some(4).map_or(g(), f);
         //~^ or_fun_call
         let _ = Some(4).map_or(0, f);
+        let _ = Some(4).map_or("asd".to_string().len() as i32, f);
+        //~^ or_fun_call
     }
 }
 
@@ -426,6 +428,8 @@ mod result_map_or {
         let _ = x.map_or(g(), f);
         //~^ or_fun_call
         let _ = x.map_or(0, f);
+        let _ = x.map_or("asd".to_string().len() as i32, f);
+        //~^ or_fun_call
     }
 }
 
diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr
index 585ee2d0e19..3e4df772668 100644
--- a/tests/ui/or_fun_call.stderr
+++ b/tests/ui/or_fun_call.stderr
@@ -154,62 +154,68 @@ error: function call inside of `map_or`
 LL |         let _ = Some(4).map_or(g(), f);
    |                         ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
 
+error: function call inside of `map_or`
+  --> tests/ui/or_fun_call.rs:286:25
+   |
+LL |         let _ = Some(4).map_or("asd".to_string().len() as i32, f);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| "asd".to_string().len() as i32, f)`
+
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:315:18
+  --> tests/ui/or_fun_call.rs:317:18
    |
 LL |         with_new.unwrap_or_else(Vec::new);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:319:28
+  --> tests/ui/or_fun_call.rs:321:28
    |
 LL |         with_default_trait.unwrap_or_else(Default::default);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:323:27
+  --> tests/ui/or_fun_call.rs:325:27
    |
 LL |         with_default_type.unwrap_or_else(u64::default);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:327:22
+  --> tests/ui/or_fun_call.rs:329:22
    |
 LL |         real_default.unwrap_or_else(<FakeDefault as Default>::default);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:331:23
+  --> tests/ui/or_fun_call.rs:333:23
    |
 LL |         map.entry(42).or_insert_with(String::new);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `or_insert_with` to construct default value
-  --> tests/ui/or_fun_call.rs:335:25
+  --> tests/ui/or_fun_call.rs:337:25
    |
 LL |         btree.entry(42).or_insert_with(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
 
 error: use of `unwrap_or_else` to construct default value
-  --> tests/ui/or_fun_call.rs:339:25
+  --> tests/ui/or_fun_call.rs:341:25
    |
 LL |         let _ = stringy.unwrap_or_else(String::new);
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:381:17
+  --> tests/ui/or_fun_call.rs:383:17
    |
 LL |     let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:386:17
+  --> tests/ui/or_fun_call.rs:388:17
    |
 LL |     let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
    |                 ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:391:17
+  --> tests/ui/or_fun_call.rs:393:17
    |
 LL |       let _ = opt.unwrap_or({
    |  _________________^
@@ -229,52 +235,58 @@ LL ~     });
    |
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:397:17
+  --> tests/ui/or_fun_call.rs:399:17
    |
 LL |     let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
    |                 ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
 
 error: use of `unwrap_or` to construct default value
-  --> tests/ui/or_fun_call.rs:402:17
+  --> tests/ui/or_fun_call.rs:404:17
    |
 LL |     let _ = opt.unwrap_or({ i32::default() });
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
 
 error: function call inside of `unwrap_or`
-  --> tests/ui/or_fun_call.rs:409:21
+  --> tests/ui/or_fun_call.rs:411:21
    |
 LL |     let _ = opt_foo.unwrap_or(Foo { val: String::default() });
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:424:19
+  --> tests/ui/or_fun_call.rs:426:19
    |
 LL |         let _ = x.map_or(g(), |v| v);
    |                   ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), |v| v)`
 
 error: function call inside of `map_or`
-  --> tests/ui/or_fun_call.rs:426:19
+  --> tests/ui/or_fun_call.rs:428:19
    |
 LL |         let _ = x.map_or(g(), f);
    |                   ^^^^^^^^^^^^^^ help: try: `map_or_else(|_| g(), f)`
 
+error: function call inside of `map_or`
+  --> tests/ui/or_fun_call.rs:431:19
+   |
+LL |         let _ = x.map_or("asd".to_string().len() as i32, f);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|_| "asd".to_string().len() as i32, f)`
+
 error: function call inside of `get_or_insert`
-  --> tests/ui/or_fun_call.rs:438:15
+  --> tests/ui/or_fun_call.rs:442:15
    |
 LL |     let _ = x.get_or_insert(g());
    |               ^^^^^^^^^^^^^^^^^^ help: try: `get_or_insert_with(g)`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:448:15
+  --> tests/ui/or_fun_call.rs:452:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
 
 error: function call inside of `and`
-  --> tests/ui/or_fun_call.rs:458:15
+  --> tests/ui/or_fun_call.rs:462:15
    |
 LL |     let _ = x.and(g());
    |               ^^^^^^^^ help: try: `and_then(|_| g())`
 
-error: aborting due to 43 previous errors
+error: aborting due to 45 previous errors