1+ use clippy_config:: Conf ;
12use clippy_utils:: diagnostics:: span_lint_hir_and_then;
2- use clippy_utils:: ty:: is_type_diagnostic_item;
3+ use clippy_utils:: msrvs:: Msrv ;
4+ use clippy_utils:: ty:: get_type_diagnostic_name;
35use clippy_utils:: usage:: is_potentially_local_place;
4- use clippy_utils:: { higher, path_to_local, sym} ;
6+ use clippy_utils:: { can_use_if_let_chains , higher, path_to_local, sym} ;
57use rustc_errors:: Applicability ;
68use rustc_hir:: intravisit:: { FnKind , Visitor , walk_expr, walk_fn} ;
79use rustc_hir:: { BinOpKind , Body , Expr , ExprKind , FnDecl , HirId , Node , UnOp } ;
@@ -10,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
1012use rustc_middle:: hir:: nested_filter;
1113use rustc_middle:: mir:: FakeReadCause ;
1214use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
13- use rustc_session:: declare_lint_pass ;
15+ use rustc_session:: impl_lint_pass ;
1416use rustc_span:: def_id:: LocalDefId ;
1517use rustc_span:: { Span , Symbol } ;
1618
@@ -72,10 +74,21 @@ declare_clippy_lint! {
7274 "checks for calls of `unwrap[_err]()` that will always fail"
7375}
7476
77+ pub ( crate ) struct Unwrap {
78+ msrv : Msrv ,
79+ }
80+
81+ impl Unwrap {
82+ pub fn new ( conf : & ' static Conf ) -> Self {
83+ Self { msrv : conf. msrv }
84+ }
85+ }
86+
7587/// Visitor that keeps track of which variables are unwrappable.
7688struct UnwrappableVariablesVisitor < ' a , ' tcx > {
7789 unwrappables : Vec < UnwrapInfo < ' tcx > > ,
7890 cx : & ' a LateContext < ' tcx > ,
91+ msrv : Msrv ,
7992}
8093
8194/// What kind of unwrappable this is.
@@ -133,12 +146,14 @@ fn collect_unwrap_info<'tcx>(
133146 invert : bool ,
134147 is_entire_condition : bool ,
135148) -> Vec < UnwrapInfo < ' tcx > > {
136- fn is_relevant_option_call ( cx : & LateContext < ' _ > , ty : Ty < ' _ > , method_name : Symbol ) -> bool {
137- is_type_diagnostic_item ( cx, ty, sym:: Option ) && matches ! ( method_name, sym:: is_none | sym:: is_some)
138- }
139-
140- fn is_relevant_result_call ( cx : & LateContext < ' _ > , ty : Ty < ' _ > , method_name : Symbol ) -> bool {
141- is_type_diagnostic_item ( cx, ty, sym:: Result ) && matches ! ( method_name, sym:: is_err | sym:: is_ok)
149+ fn option_or_result_call ( cx : & LateContext < ' _ > , ty : Ty < ' _ > , method_name : Symbol ) -> Option < ( UnwrappableKind , bool ) > {
150+ match ( get_type_diagnostic_name ( cx, ty) ?, method_name) {
151+ ( sym:: Option , sym:: is_some) => Some ( ( UnwrappableKind :: Option , true ) ) ,
152+ ( sym:: Option , sym:: is_none) => Some ( ( UnwrappableKind :: Option , false ) ) ,
153+ ( sym:: Result , sym:: is_ok) => Some ( ( UnwrappableKind :: Result , true ) ) ,
154+ ( sym:: Result , sym:: is_err) => Some ( ( UnwrappableKind :: Result , false ) ) ,
155+ _ => None ,
156+ }
142157 }
143158
144159 match expr. kind {
@@ -157,15 +172,9 @@ fn collect_unwrap_info<'tcx>(
157172 if let Some ( local_id) = path_to_local ( receiver)
158173 && let ty = cx. typeck_results ( ) . expr_ty ( receiver)
159174 && let name = method_name. ident . name
160- && ( is_relevant_option_call ( cx , ty , name ) || is_relevant_result_call ( cx, ty, name) ) =>
175+ && let Some ( ( kind , unwrappable ) ) = option_or_result_call ( cx, ty, name) =>
161176 {
162- let unwrappable = matches ! ( name, sym:: is_some | sym:: is_ok) ;
163177 let safe_to_unwrap = unwrappable != invert;
164- let kind = if is_type_diagnostic_item ( cx, ty, sym:: Option ) {
165- UnwrappableKind :: Option
166- } else {
167- UnwrappableKind :: Result
168- } ;
169178
170179 vec ! [ UnwrapInfo {
171180 local_id,
@@ -357,7 +366,11 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
357366 ) ;
358367 } else {
359368 diag. span_label ( unwrappable. check . span , "the check is happening here" ) ;
360- diag. help ( "try using `if let` or `match`" ) ;
369+ if can_use_if_let_chains ( self . cx , self . msrv ) {
370+ diag. help ( "try using `if let` or `match`" ) ;
371+ } else {
372+ diag. help ( "try using `match`" ) ;
373+ }
361374 }
362375 } ,
363376 ) ;
@@ -383,7 +396,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
383396 }
384397}
385398
386- declare_lint_pass ! ( Unwrap => [ PANICKING_UNWRAP , UNNECESSARY_UNWRAP ] ) ;
399+ impl_lint_pass ! ( Unwrap => [ PANICKING_UNWRAP , UNNECESSARY_UNWRAP ] ) ;
387400
388401impl < ' tcx > LateLintPass < ' tcx > for Unwrap {
389402 fn check_fn (
@@ -402,6 +415,7 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
402415 let mut v = UnwrappableVariablesVisitor {
403416 unwrappables : Vec :: new ( ) ,
404417 cx,
418+ msrv : self . msrv ,
405419 } ;
406420
407421 walk_fn ( & mut v, kind, decl, body. id ( ) , fn_id) ;
0 commit comments