Auto merge of #11016 - y21:issue10029, r=blyxyas,dswij
[`filter_next`]: suggest making binding mutable if it needs to be Fixes #10029 changelog: [`filter_next`]: suggest making binding mutable if it needs to be and adjust applicability
This commit is contained in:
commit
3be3fb7231
@ -1,6 +1,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_ast::{BindingAnnotation, Mutability};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
@ -8,6 +9,21 @@
|
||||
|
||||
use super::FILTER_NEXT;
|
||||
|
||||
fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> {
|
||||
match expr.kind {
|
||||
hir::ExprKind::Field(f, _) => path_to_local(f),
|
||||
hir::ExprKind::Index(recv, _) => path_to_local(recv),
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: rustc_hir::def::Res::Local(local),
|
||||
..
|
||||
},
|
||||
)) => Some(*local),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `filter().next()` for `Iterators`
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
@ -26,15 +42,30 @@ pub(super) fn check<'tcx>(
|
||||
if filter_snippet.lines().count() <= 1 {
|
||||
let iter_snippet = snippet(cx, recv.span, "..");
|
||||
// add note if not multi-line
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
FILTER_NEXT,
|
||||
expr.span,
|
||||
msg,
|
||||
"try",
|
||||
format!("{iter_snippet}.find({filter_snippet})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| {
|
||||
let (applicability, pat) = if let Some(id) = path_to_local(recv)
|
||||
&& let Some(hir::Node::Pat(pat)) = cx.tcx.hir().find(id)
|
||||
&& let hir::PatKind::Binding(BindingAnnotation(_, Mutability::Not), _, ident, _) = pat.kind
|
||||
{
|
||||
(Applicability::Unspecified, Some((pat.span, ident)))
|
||||
} else {
|
||||
(Applicability::MachineApplicable, None)
|
||||
};
|
||||
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"try",
|
||||
format!("{iter_snippet}.find({filter_snippet})"),
|
||||
applicability,
|
||||
);
|
||||
|
||||
if let Some((pat_span, ident)) = pat {
|
||||
diag.span_help(
|
||||
pat_span,
|
||||
format!("you will also need to make `{ident}` mutable, because `find` takes `&mut self`"),
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
span_lint(cx, FILTER_NEXT, expr.span, msg);
|
||||
}
|
||||
|
10
tests/ui/methods_unfixable.rs
Normal file
10
tests/ui/methods_unfixable.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#![warn(clippy::filter_next)]
|
||||
|
||||
fn main() {
|
||||
issue10029();
|
||||
}
|
||||
|
||||
pub fn issue10029() {
|
||||
let iter = (0..10);
|
||||
let _ = iter.filter(|_| true).next();
|
||||
}
|
15
tests/ui/methods_unfixable.stderr
Normal file
15
tests/ui/methods_unfixable.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
|
||||
--> $DIR/methods_unfixable.rs:9:13
|
||||
|
|
||||
LL | let _ = iter.filter(|_| true).next();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `iter.find(|_| true)`
|
||||
|
|
||||
help: you will also need to make `iter` mutable, because `find` takes `&mut self`
|
||||
--> $DIR/methods_unfixable.rs:8:9
|
||||
|
|
||||
LL | let iter = (0..10);
|
||||
| ^^^^
|
||||
= note: `-D clippy::filter-next` implied by `-D warnings`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user