]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 | 1 | use clippy_utils::diagnostics::span_lint; |
ed00b5ec | 2 | use clippy_utils::is_entrypoint_fn; |
f20569fa XL |
3 | use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node}; |
4 | use rustc_lint::{LateContext, LateLintPass}; | |
4b012472 | 5 | use rustc_session::declare_lint_pass; |
ed00b5ec | 6 | use rustc_span::sym; |
f20569fa XL |
7 | |
8 | declare_clippy_lint! { | |
94222f64 | 9 | /// ### What it does |
487cf647 | 10 | /// Detects calls to the `exit()` function which terminates the program. |
f20569fa | 11 | /// |
94222f64 | 12 | /// ### Why is this bad? |
487cf647 | 13 | /// Exit terminates the program at the location it is called. For unrecoverable |
353b0b11 | 14 | /// errors `panics` should be used to provide a stacktrace and potentially other |
487cf647 | 15 | /// information. A normal termination or one with an error code should happen in |
f20569fa XL |
16 | /// the main function. |
17 | /// | |
94222f64 | 18 | /// ### Example |
ed00b5ec | 19 | /// ```no_run |
f20569fa XL |
20 | /// std::process::exit(0) |
21 | /// ``` | |
487cf647 FG |
22 | /// |
23 | /// Use instead: | |
24 | /// | |
25 | /// ```ignore | |
26 | /// // To provide a stacktrace and additional information | |
27 | /// panic!("message"); | |
28 | /// | |
29 | /// // or a main method with a return | |
30 | /// fn main() -> Result<(), i32> { | |
31 | /// Ok(()) | |
32 | /// } | |
33 | /// ``` | |
a2a8927a | 34 | #[clippy::version = "1.41.0"] |
f20569fa XL |
35 | pub EXIT, |
36 | restriction, | |
487cf647 | 37 | "detects `std::process::exit` calls" |
f20569fa XL |
38 | } |
39 | ||
40 | declare_lint_pass!(Exit => [EXIT]); | |
41 | ||
42 | impl<'tcx> LateLintPass<'tcx> for Exit { | |
43 | fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { | |
4b012472 FG |
44 | if let ExprKind::Call(path_expr, _args) = e.kind |
45 | && let ExprKind::Path(ref path) = path_expr.kind | |
46 | && let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id() | |
47 | && cx.tcx.is_diagnostic_item(sym::process_exit, def_id) | |
48 | && let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id | |
49 | && let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.opt_hir_node_by_def_id(parent) | |
cdc7bbd5 XL |
50 | // If the next item up is a function we check if it is an entry point |
51 | // and only then emit a linter warning | |
4b012472 FG |
52 | && !is_entrypoint_fn(cx, parent.to_def_id()) |
53 | { | |
54 | span_lint(cx, EXIT, e.span, "usage of `process::exit`"); | |
f20569fa XL |
55 | } |
56 | } | |
57 | } |