mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 07:00:55 +00:00
Split arg/method checking into its own function
This commit is contained in:
parent
103200967e
commit
10f3977eba
1 changed files with 58 additions and 52 deletions
|
@ -59,59 +59,65 @@ declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]);
|
|||
|
||||
impl LateLintPass<'_> for LinesFilterMapOk {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind &&
|
||||
is_trait_method(cx, expr, sym::Iterator) &&
|
||||
let fm_method_str = fm_method.ident.as_str() &&
|
||||
matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") &&
|
||||
is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
|
||||
if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
&& let fm_method_str = fm_method.ident.as_str()
|
||||
&& matches!(fm_method_str, "filter_map" | "flat_map" | "flatten")
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
|
||||
&& should_lint(cx, fm_args, fm_method_str)
|
||||
{
|
||||
let lint = match fm_args {
|
||||
[] => fm_method_str == "flatten",
|
||||
[fm_arg] => {
|
||||
match &fm_arg.kind {
|
||||
// Detect `Result::ok`
|
||||
ExprKind::Path(qpath) =>
|
||||
cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did|
|
||||
match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(),
|
||||
// Detect `|x| x.ok()`
|
||||
ExprKind::Closure(Closure { body, .. }) =>
|
||||
if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) &&
|
||||
let ExprKind::MethodCall(method, receiver, [], _) = value.kind &&
|
||||
path_to_local_id(receiver, param.pat.hir_id) &&
|
||||
let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
|
||||
{
|
||||
is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok"
|
||||
} else {
|
||||
false
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if lint {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
LINES_FILTER_MAP_OK,
|
||||
fm_span,
|
||||
&format!(
|
||||
"`{}()` will run forever if the iterator repeatedly produces an `Err`",
|
||||
fm_method.ident
|
||||
),
|
||||
|diag| {
|
||||
diag.span_note(
|
||||
fm_receiver.span,
|
||||
"this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error");
|
||||
diag.span_suggestion(
|
||||
fm_span,
|
||||
"replace with",
|
||||
"map_while(Result::ok)",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
LINES_FILTER_MAP_OK,
|
||||
fm_span,
|
||||
&format!(
|
||||
"`{}()` will run forever if the iterator repeatedly produces an `Err`",
|
||||
fm_method.ident
|
||||
),
|
||||
|diag| {
|
||||
diag.span_note(
|
||||
fm_receiver.span,
|
||||
"this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error");
|
||||
diag.span_suggestion(
|
||||
fm_span,
|
||||
"replace with",
|
||||
"map_while(Result::ok)",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_str: &str) -> bool {
|
||||
match args {
|
||||
[] => method_str == "flatten",
|
||||
[fm_arg] => {
|
||||
match &fm_arg.kind {
|
||||
// Detect `Result::ok`
|
||||
ExprKind::Path(qpath) => cx
|
||||
.qpath_res(qpath, fm_arg.hir_id)
|
||||
.opt_def_id()
|
||||
.map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD))
|
||||
.unwrap_or_default(),
|
||||
// Detect `|x| x.ok()`
|
||||
ExprKind::Closure(Closure { body, .. }) => {
|
||||
if let Body {
|
||||
params: [param], value, ..
|
||||
} = cx.tcx.hir().body(*body)
|
||||
&& let ExprKind::MethodCall(method, receiver, [], _) = value.kind
|
||||
&& path_to_local_id(receiver, param.pat.hir_id)
|
||||
&& let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
|
||||
{
|
||||
is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue