Skip to content

Commit 2f0ed0a

Browse files
committed
Move MapErrIgnore into Methods lint pass
1 parent 4523954 commit 2f0ed0a

File tree

6 files changed

+140
-158
lines changed

6 files changed

+140
-158
lines changed

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ store.register_lints(&[
246246
manual_rem_euclid::MANUAL_REM_EUCLID,
247247
manual_retain::MANUAL_RETAIN,
248248
manual_strip::MANUAL_STRIP,
249-
map_err_ignore::MAP_ERR_IGNORE,
250249
map_unit_fn::OPTION_MAP_UNIT_FN,
251250
map_unit_fn::RESULT_MAP_UNIT_FN,
252251
match_result_ok::MATCH_RESULT_OK,
@@ -326,6 +325,7 @@ store.register_lints(&[
326325
methods::MANUAL_STR_REPEAT,
327326
methods::MAP_CLONE,
328327
methods::MAP_COLLECT_RESULT_UNIT,
328+
methods::MAP_ERR_IGNORE,
329329
methods::MAP_FLATTEN,
330330
methods::MAP_IDENTITY,
331331
methods::MAP_UNWRAP_OR,

clippy_lints/src/lib.register_restriction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
3030
LintId::of(large_include_file::LARGE_INCLUDE_FILE),
3131
LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE),
3232
LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION),
33-
LintId::of(map_err_ignore::MAP_ERR_IGNORE),
3433
LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS),
3534
LintId::of(matches::TRY_ERR),
3635
LintId::of(matches::WILDCARD_ENUM_MATCH_ARM),
@@ -39,6 +38,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
3938
LintId::of(methods::EXPECT_USED),
4039
LintId::of(methods::FILETYPE_IS_FILE),
4140
LintId::of(methods::GET_UNWRAP),
41+
LintId::of(methods::MAP_ERR_IGNORE),
4242
LintId::of(methods::UNWRAP_USED),
4343
LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
4444
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ mod manual_non_exhaustive;
273273
mod manual_rem_euclid;
274274
mod manual_retain;
275275
mod manual_strip;
276-
mod map_err_ignore;
277276
mod map_unit_fn;
278277
mod match_result_ok;
279278
mod matches;
@@ -636,7 +635,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
636635
msrv,
637636
))
638637
});
639-
store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
640638
store.register_late_pass(|| Box::new(shadow::Shadow::default()));
641639
store.register_late_pass(|| Box::new(unit_types::UnitTypes));
642640
store.register_late_pass(|| Box::new(loops::Loops));

clippy_lints/src/map_err_ignore.rs

Lines changed: 0 additions & 154 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use clippy_utils::diagnostics::span_lint_and_help;
2+
use clippy_utils::ty::is_type_diagnostic_item;
3+
use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind};
4+
use rustc_lint::LateContext;
5+
use rustc_span::sym;
6+
7+
use super::MAP_ERR_IGNORE;
8+
9+
pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) {
10+
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
11+
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
12+
&& is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result)
13+
&& let ExprKind::Closure(&Closure {
14+
capture_clause: CaptureBy::Ref,
15+
body,
16+
fn_decl_span,
17+
..
18+
}) = arg.kind
19+
&& let closure_body = cx.tcx.hir().body(body)
20+
&& let [param] = closure_body.params
21+
&& let PatKind::Wild = param.pat.kind
22+
{
23+
// span the area of the closure capture and warn that the
24+
// original error will be thrown away
25+
span_lint_and_help(
26+
cx,
27+
MAP_ERR_IGNORE,
28+
fn_decl_span,
29+
"`map_err(|_|...` wildcard pattern discards the original error",
30+
None,
31+
"consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)",
32+
);
33+
}
34+
}

clippy_lints/src/methods/mod.rs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ mod manual_saturating_arithmetic;
4747
mod manual_str_repeat;
4848
mod map_clone;
4949
mod map_collect_result_unit;
50+
mod map_err_ignore;
5051
mod map_flatten;
5152
mod map_identity;
5253
mod map_unwrap_or;
@@ -2541,6 +2542,106 @@ declare_clippy_lint! {
25412542
"using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
25422543
}
25432544

2545+
declare_clippy_lint! {
2546+
/// ### What it does
2547+
/// Checks for instances of `map_err(|_| Some::Enum)`
2548+
///
2549+
/// ### Why is this bad?
2550+
/// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error
2551+
///
2552+
/// ### Example
2553+
/// Before:
2554+
/// ```rust
2555+
/// use std::fmt;
2556+
///
2557+
/// #[derive(Debug)]
2558+
/// enum Error {
2559+
/// Indivisible,
2560+
/// Remainder(u8),
2561+
/// }
2562+
///
2563+
/// impl fmt::Display for Error {
2564+
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2565+
/// match self {
2566+
/// Error::Indivisible => write!(f, "could not divide input by three"),
2567+
/// Error::Remainder(remainder) => write!(
2568+
/// f,
2569+
/// "input is not divisible by three, remainder = {}",
2570+
/// remainder
2571+
/// ),
2572+
/// }
2573+
/// }
2574+
/// }
2575+
///
2576+
/// impl std::error::Error for Error {}
2577+
///
2578+
/// fn divisible_by_3(input: &str) -> Result<(), Error> {
2579+
/// input
2580+
/// .parse::<i32>()
2581+
/// .map_err(|_| Error::Indivisible)
2582+
/// .map(|v| v % 3)
2583+
/// .and_then(|remainder| {
2584+
/// if remainder == 0 {
2585+
/// Ok(())
2586+
/// } else {
2587+
/// Err(Error::Remainder(remainder as u8))
2588+
/// }
2589+
/// })
2590+
/// }
2591+
/// ```
2592+
///
2593+
/// After:
2594+
/// ```rust
2595+
/// use std::{fmt, num::ParseIntError};
2596+
///
2597+
/// #[derive(Debug)]
2598+
/// enum Error {
2599+
/// Indivisible(ParseIntError),
2600+
/// Remainder(u8),
2601+
/// }
2602+
///
2603+
/// impl fmt::Display for Error {
2604+
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2605+
/// match self {
2606+
/// Error::Indivisible(_) => write!(f, "could not divide input by three"),
2607+
/// Error::Remainder(remainder) => write!(
2608+
/// f,
2609+
/// "input is not divisible by three, remainder = {}",
2610+
/// remainder
2611+
/// ),
2612+
/// }
2613+
/// }
2614+
/// }
2615+
///
2616+
/// impl std::error::Error for Error {
2617+
/// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
2618+
/// match self {
2619+
/// Error::Indivisible(source) => Some(source),
2620+
/// _ => None,
2621+
/// }
2622+
/// }
2623+
/// }
2624+
///
2625+
/// fn divisible_by_3(input: &str) -> Result<(), Error> {
2626+
/// input
2627+
/// .parse::<i32>()
2628+
/// .map_err(Error::Indivisible)
2629+
/// .map(|v| v % 3)
2630+
/// .and_then(|remainder| {
2631+
/// if remainder == 0 {
2632+
/// Ok(())
2633+
/// } else {
2634+
/// Err(Error::Remainder(remainder as u8))
2635+
/// }
2636+
/// })
2637+
/// }
2638+
/// ```
2639+
#[clippy::version = "1.48.0"]
2640+
pub MAP_ERR_IGNORE,
2641+
restriction,
2642+
"`map_err` should not ignore the original error"
2643+
}
2644+
25442645
pub struct Methods {
25452646
avoid_breaking_exported_api: bool,
25462647
msrv: Option<RustcVersion>,
@@ -2651,6 +2752,7 @@ impl_lint_pass!(Methods => [
26512752
GET_FIRST,
26522753
MANUAL_OK_OR,
26532754
MAP_CLONE,
2755+
MAP_ERR_IGNORE,
26542756
]);
26552757

26562758
/// Extracts a method call name, args, and `Span` of the method name.
@@ -2982,6 +3084,8 @@ impl Methods {
29823084
(name @ ("map" | "map_err"), [m_arg]) => {
29833085
if name == "map" {
29843086
map_clone::check(cx, expr, recv, m_arg, self.msrv);
3087+
} else {
3088+
map_err_ignore::check(cx, expr, m_arg);
29853089
}
29863090
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
29873091
match (name, args) {

0 commit comments

Comments
 (0)