1
- use crate :: utils:: { in_macro_or_desugar, is_expn_of, snippet_opt, span_lint_and_then} ;
2
- use rustc:: hir:: { intravisit:: FnKind , Body , ExprKind , FnDecl , HirId , MatchSource } ;
3
- use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
4
- use rustc:: { declare_lint_pass, declare_tool_lint} ;
1
+ use crate :: utils:: {
2
+ in_macro_or_desugar, match_def_path,
3
+ paths:: { BEGIN_PANIC , BEGIN_PANIC_FMT } ,
4
+ resolve_node, snippet_opt, span_lint_and_then,
5
+ } ;
6
+ use if_chain:: if_chain;
7
+ use rustc:: {
8
+ declare_lint_pass, declare_tool_lint,
9
+ hir:: { intravisit:: FnKind , Body , Expr , ExprKind , FnDecl , HirId , MatchSource , StmtKind } ,
10
+ lint:: { LateContext , LateLintPass , LintArray , LintPass } ,
11
+ } ;
5
12
use rustc_errors:: Applicability ;
6
13
use syntax:: source_map:: Span ;
7
14
@@ -35,71 +42,92 @@ declare_clippy_lint! {
35
42
36
43
declare_lint_pass ! ( ImplicitReturn => [ IMPLICIT_RETURN ] ) ;
37
44
38
- impl ImplicitReturn {
39
- fn lint ( cx : & LateContext < ' _ , ' _ > , outer_span : syntax_pos:: Span , inner_span : syntax_pos:: Span , msg : & str ) {
40
- span_lint_and_then ( cx, IMPLICIT_RETURN , outer_span, "missing return statement" , |db| {
41
- if let Some ( snippet) = snippet_opt ( cx, inner_span) {
42
- db. span_suggestion (
43
- outer_span,
44
- msg,
45
- format ! ( "return {}" , snippet) ,
46
- Applicability :: MachineApplicable ,
47
- ) ;
48
- }
49
- } ) ;
45
+ static LINT_BREAK : & str = "change `break` to `return` as shown" ;
46
+ static LINT_RETURN : & str = "add `return` as shown" ;
47
+
48
+ fn lint ( cx : & LateContext < ' _ , ' _ > , outer_span : Span , inner_span : Span , msg : & str ) {
49
+ let outer_span = span_to_outer_expn ( outer_span) ;
50
+ let inner_span = span_to_outer_expn ( inner_span) ;
51
+
52
+ span_lint_and_then ( cx, IMPLICIT_RETURN , outer_span, "missing return statement" , |db| {
53
+ if let Some ( snippet) = snippet_opt ( cx, inner_span) {
54
+ db. span_suggestion (
55
+ outer_span,
56
+ msg,
57
+ format ! ( "return {}" , snippet) ,
58
+ Applicability :: MachineApplicable ,
59
+ ) ;
60
+ }
61
+ } ) ;
62
+ }
63
+
64
+ fn span_to_outer_expn ( span : Span ) -> Span {
65
+ if let Some ( expr) = span. ctxt ( ) . outer_expn_info ( ) {
66
+ span_to_outer_expn ( expr. call_site )
67
+ } else {
68
+ span
50
69
}
70
+ }
51
71
52
- fn expr_match ( cx : & LateContext < ' _ , ' _ > , expr : & rustc :: hir :: Expr ) {
53
- match & expr. node {
54
- // loops could be using `break` instead of `return`
55
- ExprKind :: Block ( block, ..) | ExprKind :: Loop ( block, ..) => {
56
- if let Some ( expr) = & block. expr {
57
- Self :: expr_match ( cx, expr) ;
58
- }
59
- // only needed in the case of `break` with `;` at the end
60
- else if let Some ( stmt) = block. stmts . last ( ) {
61
- if let rustc :: hir :: StmtKind :: Semi ( expr , .. ) = & stmt . node {
62
- // make sure it's a break, otherwise we want to skip
63
- if let ExprKind :: Break ( .. , break_expr ) = & expr . node {
64
- if let Some ( break_expr) = break_expr {
65
- Self :: lint ( cx , expr . span , break_expr. span , "change `break` to `return` as shown" ) ;
66
- }
67
- }
72
+ fn expr_match ( cx : & LateContext < ' _ , ' _ > , expr : & Expr ) {
73
+ match & expr. node {
74
+ // loops could be using `break` instead of `return`
75
+ ExprKind :: Block ( block, ..) | ExprKind :: Loop ( block, ..) => {
76
+ if let Some ( expr) = & block. expr {
77
+ expr_match ( cx, expr) ;
78
+ }
79
+ // only needed in the case of `break` with `;` at the end
80
+ else if let Some ( stmt) = block. stmts . last ( ) {
81
+ if_chain ! {
82
+ if let StmtKind :: Semi ( expr , .. ) = & stmt . node ;
83
+ // make sure it's a break, otherwise we want to skip
84
+ if let ExprKind :: Break ( .. , break_expr) = & expr . node ;
85
+ if let Some ( break_expr) = break_expr ;
86
+ then {
87
+ lint ( cx , expr . span , break_expr . span , LINT_BREAK ) ;
68
88
}
69
89
}
70
- } ,
71
- // use `return` instead of `break`
72
- ExprKind :: Break ( .., break_expr) => {
73
- if let Some ( break_expr) = break_expr {
74
- Self :: lint ( cx, expr. span , break_expr. span , "change `break` to `return` as shown" ) ;
75
- }
76
- } ,
77
- ExprKind :: Match ( .., arms, source) => {
78
- let check_all_arms = match source {
79
- MatchSource :: IfLetDesugar {
80
- contains_else_clause : has_else,
81
- } => * has_else,
82
- _ => true ,
83
- } ;
90
+ }
91
+ } ,
92
+ // use `return` instead of `break`
93
+ ExprKind :: Break ( .., break_expr) => {
94
+ if let Some ( break_expr) = break_expr {
95
+ lint ( cx, expr. span , break_expr. span , LINT_BREAK ) ;
96
+ }
97
+ } ,
98
+ ExprKind :: Match ( .., arms, source) => {
99
+ let check_all_arms = match source {
100
+ MatchSource :: IfLetDesugar {
101
+ contains_else_clause : has_else,
102
+ } => * has_else,
103
+ _ => true ,
104
+ } ;
84
105
85
- if check_all_arms {
86
- for arm in arms {
87
- Self :: expr_match ( cx, & arm. body ) ;
88
- }
89
- } else {
90
- Self :: expr_match ( cx, & arms. first ( ) . expect ( "if let doesn't have a single arm" ) . body ) ;
106
+ if check_all_arms {
107
+ for arm in arms {
108
+ expr_match ( cx, & arm. body ) ;
91
109
}
92
- } ,
93
- // skip if it already has a return statement
94
- ExprKind :: Ret ( ..) => ( ) ,
95
- // everything else is missing `return`
96
- _ => {
97
- // make sure it's not just an unreachable expression
98
- if is_expn_of ( expr. span , "unreachable" ) . is_none ( ) {
99
- Self :: lint ( cx, expr. span , expr. span , "add `return` as shown" )
110
+ } else {
111
+ expr_match ( cx, & arms. first ( ) . expect ( "if let doesn't have a single arm" ) . body ) ;
112
+ }
113
+ } ,
114
+ // skip if it already has a return statement
115
+ ExprKind :: Ret ( ..) => ( ) ,
116
+ // make sure it's not a call that panics
117
+ ExprKind :: Call ( expr, ..) => {
118
+ if_chain ! {
119
+ if let ExprKind :: Path ( qpath) = & expr. node;
120
+ if let Some ( path_def_id) = resolve_node( cx, qpath, expr. hir_id) . opt_def_id( ) ;
121
+ if match_def_path( cx, path_def_id, & BEGIN_PANIC ) ||
122
+ match_def_path( cx, path_def_id, & BEGIN_PANIC_FMT ) ;
123
+ then { }
124
+ else {
125
+ lint( cx, expr. span, expr. span, LINT_RETURN )
100
126
}
101
- } ,
102
- }
127
+ }
128
+ } ,
129
+ // everything else is missing `return`
130
+ _ => lint ( cx, expr. span , expr. span , LINT_RETURN ) ,
103
131
}
104
132
}
105
133
@@ -119,7 +147,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
119
147
// checking return type through MIR, HIR is not able to determine inferred closure return types
120
148
// make sure it's not a macro
121
149
if !mir. return_ty ( ) . is_unit ( ) && !in_macro_or_desugar ( span) {
122
- Self :: expr_match ( cx, & body. value ) ;
150
+ expr_match ( cx, & body. value ) ;
123
151
}
124
152
}
125
153
}
0 commit comments