Repository: rust-lang/rust-clippy (Rust)

Issue:
`filter_map_bool_then` should not show the macro definition in suggestions
### Summary

`filter_map_bool_then` wrongly showed the macro definition instead of its call site in suggestions

### Reproducer

I tried this code:

```rust
    tokenize_with_text(&snippet)
        .filter_map(|(t, s, inner)| {
            matches!(t, TokenKind::Ident if s == keyword).then(|| {
                span.split_at(inner.start as u32)
                    .1
                    .split_at((inner.end - inner.start) as u32)
                    .0
            })
        })
```

I expected to see this happen:

```rust
.filter(|&(t, s, inner)| matches!(t, TokenKind::Ident if s == keyword))
.map(..)
```

Instead, this happened:

```rust
.filter(|&(t, s, inner)| match $expression {
    $pattern $(if $guard)? => true,
    _ => false
}).map(..)
```

### Version

```text

```

### Additional Labels

@rustbot label + I-suggestion-causes-error

<!-- TRIAGEBOT_START -->

<!-- TRIAGEBOT_ASSIGN_START -->

<!-- TRIAGEBOT_ASSIGN_END -->
<!-- TRIAGEBOT_END -->


Discussion:
**Error**: Parsing relabel command in [comment](https://github.com/rust-lang/rust-clippy/issues/15047) failed: ...' label +' | error: empty label at >| ' I-suggest'...

Please file an issue on GitHub at [triagebot](https://github.com/rust-lang/triagebot) if there's a problem with this bot, or reach out on [#t-infra](https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra) on Zulip.

Looks like it can be fixed very quickly. I will take it myself then.
@rustbot claim
**Error**: Parsing relabel command in [comment](https://github.com/rust-lang/rust-clippy/issues/15047) failed: ...' label +' | error: empty label at >| ' I-suggest'...

Please file an issue on GitHub at [triagebot](https://github.com/rust-lang/triagebot) if there's a problem with this bot, or reach out on [#t-infra](https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra) on Zulip.




Patch:
diff --git a/clippy_lints/src/methods/filter_map_bool_then.rs b/clippy_lints/src/methods/filter_map_bool_then.rs
index 965993808f6b..94944bd9445b 100644
--- a/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -1,6 +1,6 @@
 use super::FILTER_MAP_BOOL_THEN;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::SpanRangeExt;
+use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::ty::is_copy;
 use clippy_utils::{
     CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks,
@@ -45,9 +45,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
             .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
             .count()
         && let Some(param_snippet) = param.span.get_source_text(cx)
-        && let Some(filter) = recv.span.get_source_text(cx)
-        && let Some(map) = then_body.span.get_source_text(cx)
     {
+        let mut applicability = Applicability::MachineApplicable;
+        let (filter, _) = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut applicability);
+        let (map, _) = snippet_with_context(cx, then_body.span, expr.span.ctxt(), "..", &mut applicability);
+
         span_lint_and_then(
             cx,
             FILTER_MAP_BOOL_THEN,
@@ -62,7 +64,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
                             "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})",
                             derefs = "*".repeat(needed_derefs)
                         ),
-                        Applicability::MachineApplicable,
+                        applicability,
                     );
                 } else {
                     diag.help("consider using `filter` then `map` instead");


Test patch:
diff --git a/tests/ui/filter_map_bool_then.fixed b/tests/ui/filter_map_bool_then.fixed
index b3e112f19eb4..d370b85a67ef 100644
--- a/tests/ui/filter_map_bool_then.fixed
+++ b/tests/ui/filter_map_bool_then.fixed
@@ -89,3 +89,24 @@ fn issue11503() {
     let _: Vec<usize> = bools.iter().enumerate().filter(|&(i, b)| ****b).map(|(i, b)| i).collect();
     //~^ filter_map_bool_then
 }
+
+fn issue15047() {
+    #[derive(Clone, Copy)]
+    enum MyEnum {
+        A,
+        B,
+        C,
+    }
+
+    macro_rules! foo {
+        ($e:expr) => {
+            $e + 1
+        };
+    }
+
+    let x = 1;
+    let _ = [(MyEnum::A, "foo", 1i32)]
+        .iter()
+        .filter(|&(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar"))).map(|(t, s, i)| foo!(x));
+    //~^ filter_map_bool_then
+}
diff --git a/tests/ui/filter_map_bool_then.rs b/tests/ui/filter_map_bool_then.rs
index d996b3cb3c52..12295cc24823 100644
--- a/tests/ui/filter_map_bool_then.rs
+++ b/tests/ui/filter_map_bool_then.rs
@@ -89,3 +89,24 @@ fn issue11503() {
     let _: Vec<usize> = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect();
     //~^ filter_map_bool_then
 }
+
+fn issue15047() {
+    #[derive(Clone, Copy)]
+    enum MyEnum {
+        A,
+        B,
+        C,
+    }
+
+    macro_rules! foo {
+        ($e:expr) => {
+            $e + 1
+        };
+    }
+
+    let x = 1;
+    let _ = [(MyEnum::A, "foo", 1i32)]
+        .iter()
+        .filter_map(|(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar")).then(|| foo!(x)));
+    //~^ filter_map_bool_then
+}
diff --git a/tests/ui/filter_map_bool_then.stderr b/tests/ui/filter_map_bool_then.stderr
index aeb1baeb35e6..edf6c6559396 100644
--- a/tests/ui/filter_map_bool_then.stderr
+++ b/tests/ui/filter_map_bool_then.stderr
@@ -61,5 +61,11 @@ error: usage of `bool::then` in `filter_map`
 LL |     let _: Vec<usize> = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect();
    |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ****b).map(|(i, b)| i)`
 
-error: aborting due to 10 previous errors
+error: usage of `bool::then` in `filter_map`
+  --> tests/ui/filter_map_bool_then.rs:110:10
+   |
+LL |         .filter_map(|(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar")).then(|| foo!(x)));
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(t, s, i)| matches!(t, MyEnum::A if s.starts_with("bar"))).map(|(t, s, i)| foo!(x))`
+
+error: aborting due to 11 previous errors