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+ } ;
512use rustc_errors:: Applicability ;
613use syntax:: source_map:: Span ;
714
@@ -35,71 +42,92 @@ declare_clippy_lint! {
3542
3643declare_lint_pass ! ( ImplicitReturn => [ IMPLICIT_RETURN ] ) ;
3744
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
5069 }
70+ }
5171
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 ) ;
6888 }
6989 }
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+ } ;
84105
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 ) ;
91109 }
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 )
100126 }
101- } ,
102- }
127+ }
128+ } ,
129+ // everything else is missing `return`
130+ _ => lint ( cx, expr. span , expr. span , LINT_RETURN ) ,
103131 }
104132}
105133
@@ -119,7 +147,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
119147 // checking return type through MIR, HIR is not able to determine inferred closure return types
120148 // make sure it's not a macro
121149 if !mir. return_ty ( ) . is_unit ( ) && !in_macro_or_desugar ( span) {
122- Self :: expr_match ( cx, & body. value ) ;
150+ expr_match ( cx, & body. value ) ;
123151 }
124152 }
125153}
0 commit comments