1
+ use clippy_config:: Conf ;
1
2
use 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;
3
5
use 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} ;
5
7
use rustc_errors:: Applicability ;
6
8
use rustc_hir:: intravisit:: { FnKind , Visitor , walk_expr, walk_fn} ;
7
9
use rustc_hir:: { BinOpKind , Body , Expr , ExprKind , FnDecl , HirId , Node , UnOp } ;
@@ -10,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
10
12
use rustc_middle:: hir:: nested_filter;
11
13
use rustc_middle:: mir:: FakeReadCause ;
12
14
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
13
- use rustc_session:: declare_lint_pass ;
15
+ use rustc_session:: impl_lint_pass ;
14
16
use rustc_span:: def_id:: LocalDefId ;
15
17
use rustc_span:: { Span , Symbol } ;
16
18
@@ -72,10 +74,21 @@ declare_clippy_lint! {
72
74
"checks for calls of `unwrap[_err]()` that will always fail"
73
75
}
74
76
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
+
75
87
/// Visitor that keeps track of which variables are unwrappable.
76
88
struct UnwrappableVariablesVisitor < ' a , ' tcx > {
77
89
unwrappables : Vec < UnwrapInfo < ' tcx > > ,
78
90
cx : & ' a LateContext < ' tcx > ,
91
+ msrv : Msrv ,
79
92
}
80
93
81
94
/// What kind of unwrappable this is.
@@ -133,12 +146,14 @@ fn collect_unwrap_info<'tcx>(
133
146
invert : bool ,
134
147
is_entire_condition : bool ,
135
148
) -> 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
+ }
142
157
}
143
158
144
159
match expr. kind {
@@ -157,15 +172,9 @@ fn collect_unwrap_info<'tcx>(
157
172
if let Some ( local_id) = path_to_local ( receiver)
158
173
&& let ty = cx. typeck_results ( ) . expr_ty ( receiver)
159
174
&& 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) =>
161
176
{
162
- let unwrappable = matches ! ( name, sym:: is_some | sym:: is_ok) ;
163
177
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
- } ;
169
178
170
179
vec ! [ UnwrapInfo {
171
180
local_id,
@@ -357,7 +366,11 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
357
366
) ;
358
367
} else {
359
368
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
+ }
361
374
}
362
375
} ,
363
376
) ;
@@ -383,7 +396,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> {
383
396
}
384
397
}
385
398
386
- declare_lint_pass ! ( Unwrap => [ PANICKING_UNWRAP , UNNECESSARY_UNWRAP ] ) ;
399
+ impl_lint_pass ! ( Unwrap => [ PANICKING_UNWRAP , UNNECESSARY_UNWRAP ] ) ;
387
400
388
401
impl < ' tcx > LateLintPass < ' tcx > for Unwrap {
389
402
fn check_fn (
@@ -402,6 +415,7 @@ impl<'tcx> LateLintPass<'tcx> for Unwrap {
402
415
let mut v = UnwrappableVariablesVisitor {
403
416
unwrappables : Vec :: new ( ) ,
404
417
cx,
418
+ msrv : self . msrv ,
405
419
} ;
406
420
407
421
walk_fn ( & mut v, kind, decl, body. id ( ) , fn_id) ;
0 commit comments