From 23336adf849bc975e157f4034ee968d7fc40dc37 Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sun, 25 Aug 2019 07:10:45 +0200 Subject: [PATCH] Fix `match_as_ref` bad suggestion Fixes #4437 --- clippy_lints/src/matches.rs | 23 +++++++++++++++++++++-- tests/ui/match_as_ref.fixed | 21 +++++++++++++++++++++ tests/ui/match_as_ref.rs | 24 ++++++++++++++++++++++++ tests/ui/match_as_ref.stderr | 11 ++++++++++- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 6b6fd2bb208..2a65ea000db 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -624,6 +624,24 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: & } else { "as_mut" }; + + let output_ty = cx.tables.expr_ty(expr); + let input_ty = cx.tables.expr_ty(ex); + + let cast = if_chain! { + if let ty::Adt(_, substs) = input_ty.sty; + let input_ty = substs.type_at(0); + if let ty::Adt(_, substs) = output_ty.sty; + let output_ty = substs.type_at(0); + if let ty::Ref(_, output_ty, _) = output_ty.sty; + if input_ty != output_ty; + then { + ".map(|x| x as _)" + } else { + "" + } + }; + let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -632,9 +650,10 @@ fn check_match_as_ref(cx: &LateContext<'_, '_>, ex: &Expr, arms: &[Arm], expr: & &format!("use {}() instead", suggestion), "try this", format!( - "{}.{}()", + "{}.{}(){}", snippet_with_applicability(cx, ex.span, "_", &mut applicability), - suggestion + suggestion, + cast, ), applicability, ) diff --git a/tests/ui/match_as_ref.fixed b/tests/ui/match_as_ref.fixed index 75085367f96..c61eb921664 100644 --- a/tests/ui/match_as_ref.fixed +++ b/tests/ui/match_as_ref.fixed @@ -11,4 +11,25 @@ fn match_as_ref() { let borrow_mut: Option<&mut ()> = mut_owned.as_mut(); } +mod issue4437 { + use std::{error::Error, fmt, num::ParseIntError}; + + #[derive(Debug)] + struct E { + source: Option, + } + + impl Error for E { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.source.as_ref().map(|x| x as _) + } + } + + impl fmt::Display for E { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } + } +} + fn main() {} diff --git a/tests/ui/match_as_ref.rs b/tests/ui/match_as_ref.rs index 62c06f35251..2fbd0b255fa 100644 --- a/tests/ui/match_as_ref.rs +++ b/tests/ui/match_as_ref.rs @@ -17,4 +17,28 @@ fn match_as_ref() { }; } +mod issue4437 { + use std::{error::Error, fmt, num::ParseIntError}; + + #[derive(Debug)] + struct E { + source: Option, + } + + impl Error for E { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self.source { + Some(ref s) => Some(s), + None => None, + } + } + } + + impl fmt::Display for E { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } + } +} + fn main() {} diff --git a/tests/ui/match_as_ref.stderr b/tests/ui/match_as_ref.stderr index 09115b85d35..dd4739d1ff2 100644 --- a/tests/ui/match_as_ref.stderr +++ b/tests/ui/match_as_ref.stderr @@ -20,5 +20,14 @@ LL | | Some(ref mut v) => Some(v), LL | | }; | |_____^ help: try this: `mut_owned.as_mut()` -error: aborting due to 2 previous errors +error: use as_ref() instead + --> $DIR/match_as_ref.rs:30:13 + | +LL | / match self.source { +LL | | Some(ref s) => Some(s), +LL | | None => None, +LL | | } + | |_____________^ help: try this: `self.source.as_ref().map(|x| x as _)` + +error: aborting due to 3 previous errors