11use crate :: utils:: { match_def_path, paths, qpath_res, span_lint} ;
22use if_chain:: if_chain;
3- use rustc:: hir:: { Expr , ExprKind } ;
3+ use rustc:: hir:: { Expr , ExprKind , Item , ItemKind , Node } ;
44use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
55use rustc:: { declare_lint_pass, declare_tool_lint} ;
66
@@ -11,8 +11,7 @@ declare_clippy_lint! {
1111 /// **Why is this bad?** Ideally a program is terminated by finishing
1212 /// the main function.
1313 ///
14- /// **Known problems:** This can be valid code in main() to return
15- /// errors
14+ /// **Known problems:** None.
1615 ///
1716 /// **Example:**
1817 /// ```ignore
@@ -33,7 +32,29 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Exit {
3332 if let Some ( def_id) = qpath_res( cx, path, path_expr. hir_id) . opt_def_id( ) ;
3433 if match_def_path( cx, def_id, & paths:: EXIT ) ;
3534 then {
36- span_lint( cx, EXIT , e. span, "usage of `process::exit`" ) ;
35+ let mut parent = cx. tcx. hir( ) . get_parent_item( e. hir_id) ;
36+ // We have to traverse the parents upwards until we find a function
37+ // otherwise a exit in a let or if in main would still trigger this
38+ loop {
39+ match cx. tcx. hir( ) . find( parent) {
40+ Some ( Node :: Item ( Item { ident, kind: ItemKind :: Fn ( ..) , ..} ) ) => {
41+ // If we found a function we check it's name if it is
42+ // `main` we emit a lint.
43+ if ident. name. as_str( ) != "main" {
44+ span_lint( cx, EXIT , e. span, "usage of `process::exit`" ) ;
45+ }
46+ // We found any kind of function and can end our loop
47+ break ;
48+ }
49+ // If we found anything but a funciton we continue with the
50+ // loop and go one parent up
51+ Some ( _) => {
52+ cx. tcx. hir( ) . get_parent_item( parent) ;
53+ } ,
54+ // If we found nothing we break.
55+ None => break ,
56+ }
57+ }
3758 }
3859
3960 }
0 commit comments