fix: correct suggestion for significant_drop_in_scrutinee in expressions (#14019)

This PR fixes an issue with the `significant_drop_in_scrutinee`, where
the lint generates invalid Rust syntax when suggesting fixes for match
expressions that are part of larger expressions, such as in assignment
contexts. For example:

```rust
    let mutex = Mutex::new(State {});
    let _ = match mutex.lock().unwrap().foo() {
        true => 0,
        false => 1,
    };
```
would suggest:
```rust
let _ = let value = mutex.lock().unwrap().foo();
match value {
```
With this PR, it now suggests:
```rust
let value = mutex.lock().unwrap().foo();
let _ = match value {
```

closes: #13986

changelog: [`significant_drop_in_scrutinee`] Fix incorrect suggestion
for `significant_drop_in_scrutinee` lint in expression context
This commit is contained in:
Timo 2025-01-21 02:28:23 +00:00 committed by GitHub
commit d1b5fa2416
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 33 additions and 3 deletions

View file

@ -2,7 +2,7 @@ use std::ops::ControlFlow;
use crate::FxHashSet;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{indent_of, snippet};
use clippy_utils::source::{first_line_of_span, indent_of, snippet};
use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
use clippy_utils::{get_attr, is_lint_allowed};
use itertools::Itertools;
@ -152,7 +152,7 @@ fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &
diag.multipart_suggestion(
suggestion_message,
vec![
(expr.span.shrink_to_lo(), replacement),
(first_line_of_span(cx, expr.span).shrink_to_lo(), replacement),
(found.found_span, scrutinee_replacement),
],
Applicability::MaybeIncorrect,

View file

@ -850,4 +850,18 @@ async fn should_not_trigger_lint_in_async_expansion(mutex: Mutex<i32>) -> i32 {
}
}
fn should_trigger_lint_in_match_expr() {
let mutex = Mutex::new(State {});
// Should trigger lint because the lifetime of the temporary MutexGuard is surprising because it
// is preserved until the end of the match, but there is no clear indication that this is the
// case.
let _ = match mutex.lock().unwrap().foo() {
//~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the
//~| NOTE: this might lead to deadlocks or other unexpected behavior
true => 0,
false => 1,
};
}
fn main() {}

View file

@ -584,5 +584,21 @@ LL ~ let value = *foo_async(&mutex).await.unwrap();
LL ~ match value {
|
error: aborting due to 30 previous errors
error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
--> tests/ui/significant_drop_in_scrutinee.rs:859:19
|
LL | let _ = match mutex.lock().unwrap().foo() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | };
| - temporary lives until here
|
= note: this might lead to deadlocks or other unexpected behavior
help: try moving the temporary above the match
|
LL ~ let value = mutex.lock().unwrap().foo();
LL ~ let _ = match value {
|
error: aborting due to 31 previous errors