@@ -2,12 +2,14 @@ use crate::utils;
2
2
use if_chain:: if_chain;
3
3
use rustc_errors:: Applicability ;
4
4
use rustc_hir:: { def, Arm , Expr , ExprKind , PatKind , QPath } ;
5
+ use rustc_lint:: LintContext ;
5
6
use rustc_lint:: { LateContext , LateLintPass } ;
7
+ use rustc_middle:: lint:: in_external_macro;
6
8
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
7
9
8
10
declare_clippy_lint ! {
9
11
/// **What it does:**
10
- /// Finds patterns that can be encoded more concisely with `Option::unwrap_or`.
12
+ /// Finds patterns that reimplement `Option::unwrap_or`.
11
13
///
12
14
/// **Why is this bad?**
13
15
/// Concise code helps focusing on behavior instead of boilerplate.
@@ -16,47 +18,43 @@ declare_clippy_lint! {
16
18
///
17
19
/// **Example:**
18
20
/// ```rust
19
- /// match int_optional {
21
+ /// match int_option {
20
22
/// Some(v) => v,
21
23
/// None => 1,
22
24
/// }
23
25
/// ```
24
26
///
25
27
/// Use instead:
26
28
/// ```rust
27
- /// int_optional .unwrap_or(1)
29
+ /// int_option .unwrap_or(1)
28
30
/// ```
29
- pub LESS_CONCISE_THAN_OPTION_UNWRAP_OR ,
30
- pedantic ,
31
- "finds patterns that can be encoded more concisely with `Option::unwrap_or`"
31
+ pub MANUAL_UNWRAP_OR ,
32
+ complexity ,
33
+ "finds patterns that can be encoded more concisely with `Option::unwrap_or(_else) `"
32
34
}
33
35
34
- declare_lint_pass ! ( LessConciseThan => [ LESS_CONCISE_THAN_OPTION_UNWRAP_OR ] ) ;
36
+ declare_lint_pass ! ( ManualUnwrapOr => [ MANUAL_UNWRAP_OR ] ) ;
35
37
36
- impl LateLintPass < ' _ > for LessConciseThan {
38
+ impl LateLintPass < ' _ > for ManualUnwrapOr {
37
39
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
38
- if utils:: in_macro ( expr. span ) {
39
- return ;
40
- }
41
- if lint_option_unwrap_or_case ( cx, expr) {
40
+ if in_external_macro ( cx. sess ( ) , expr. span ) {
42
41
return ;
43
42
}
43
+ lint_option_unwrap_or_case ( cx, expr) ;
44
44
}
45
45
}
46
46
47
47
fn lint_option_unwrap_or_case < ' tcx > ( cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) -> bool {
48
- #[ allow( clippy:: needless_bool) ]
49
48
fn applicable_none_arm < ' a > ( arms : & ' a [ Arm < ' a > ] ) -> Option < & ' a Arm < ' a > > {
50
49
if_chain ! {
51
50
if arms. len( ) == 2 ;
52
51
if arms. iter( ) . all( |arm| arm. guard. is_none( ) ) ;
53
52
if let Some ( ( idx, none_arm) ) = arms. iter( ) . enumerate( ) . find( |( _, arm) |
54
- if_chain! {
55
- if let PatKind :: Path ( ref qpath) = arm. pat. kind;
56
- if utils:: match_qpath( qpath, & utils:: paths:: OPTION_NONE ) ;
57
- then { true }
58
- else { false }
59
- }
53
+ if let PatKind :: Path ( ref qpath) = arm. pat. kind {
54
+ utils:: match_qpath( qpath, & utils:: paths:: OPTION_NONE )
55
+ } else {
56
+ false
57
+ }
60
58
) ;
61
59
let some_arm = & arms[ 1 - idx] ;
62
60
if let PatKind :: TupleStruct ( ref some_qpath, & [ some_binding] , _) = some_arm. pat. kind;
@@ -65,43 +63,50 @@ fn lint_option_unwrap_or_case<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tc
65
63
if let ExprKind :: Path ( QPath :: Resolved ( _, body_path) ) = some_arm. body. kind;
66
64
if let def:: Res :: Local ( body_path_hir_id) = body_path. res;
67
65
if body_path_hir_id == binding_hir_id;
68
- then { Some ( none_arm) }
69
- else { None }
66
+ if !utils:: usage:: contains_return_break_continue_macro( none_arm. body) ;
67
+ then {
68
+ Some ( none_arm)
69
+ }
70
+ else {
71
+ None
72
+ }
70
73
}
71
74
}
75
+
72
76
if_chain ! {
73
- if !utils:: usage:: contains_return_break_continue_macro( expr) ;
74
- if let ExprKind :: Match ( match_expr, match_arms, _) = expr. kind;
75
- let ty = cx. typeck_results( ) . expr_ty( match_expr) ;
76
- if utils:: is_type_diagnostic_item( cx, ty, sym!( option_type) ) ;
77
- if let Some ( none_arm) = applicable_none_arm( match_arms) ;
78
- if let Some ( match_expr_snippet) = utils:: snippet_opt( cx, match_expr. span) ;
79
- if let Some ( none_body_snippet) = utils:: snippet_opt( cx, none_arm. body. span) ;
80
- if let Some ( indent) = utils:: indent_of( cx, expr. span) ;
81
- then {
82
- let reindented_none_body =
83
- utils:: reindent_multiline( none_body_snippet. into( ) , true , Some ( indent) ) ;
84
- let eager_eval = utils:: eager_or_lazy:: is_eagerness_candidate( cx, none_arm. body) ;
85
- let method = if eager_eval {
86
- "unwrap_or"
87
- } else {
88
- "unwrap_or_else"
89
- } ;
90
- utils:: span_lint_and_sugg(
91
- cx,
92
- LESS_CONCISE_THAN_OPTION_UNWRAP_OR , expr. span,
93
- "this pattern can be more concisely encoded with `Option::unwrap_or`" ,
94
- "replace with" ,
95
- format!(
96
- "{}.{}({}{})" ,
97
- match_expr_snippet,
98
- method,
99
- if eager_eval { "" } else { "|| " } ,
100
- reindented_none_body
101
- ) ,
102
- Applicability :: MachineApplicable ,
103
- ) ;
104
- true
105
- } else { false }
77
+ if let ExprKind :: Match ( scrutinee, match_arms, _) = expr. kind;
78
+ let ty = cx. typeck_results( ) . expr_ty( scrutinee) ;
79
+ if utils:: is_type_diagnostic_item( cx, ty, sym!( option_type) ) ;
80
+ if let Some ( none_arm) = applicable_none_arm( match_arms) ;
81
+ if let Some ( scrutinee_snippet) = utils:: snippet_opt( cx, scrutinee. span) ;
82
+ if let Some ( none_body_snippet) = utils:: snippet_opt( cx, none_arm. body. span) ;
83
+ if let Some ( indent) = utils:: indent_of( cx, expr. span) ;
84
+ then {
85
+ let reindented_none_body =
86
+ utils:: reindent_multiline( none_body_snippet. into( ) , true , Some ( indent) ) ;
87
+ let eager_eval = utils:: eager_or_lazy:: is_eagerness_candidate( cx, none_arm. body) ;
88
+ let method = if eager_eval {
89
+ "unwrap_or"
90
+ } else {
91
+ "unwrap_or_else"
92
+ } ;
93
+ utils:: span_lint_and_sugg(
94
+ cx,
95
+ MANUAL_UNWRAP_OR , expr. span,
96
+ & format!( "this pattern reimplements `Option::{}`" , & method) ,
97
+ "replace with" ,
98
+ format!(
99
+ "{}.{}({}{})" ,
100
+ scrutinee_snippet,
101
+ method,
102
+ if eager_eval { "" } else { "|| " } ,
103
+ reindented_none_body
104
+ ) ,
105
+ Applicability :: MachineApplicable ,
106
+ ) ;
107
+ true
108
+ } else {
109
+ false
110
+ }
106
111
}
107
112
}
0 commit comments