Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::excessive_nesting::EXCESSIVE_NESTING_INFO,
crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
crate::exit::EXIT_INFO,
crate::explicit_write::EXPLICIT_WRITE_INFO,
crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
Expand Down Expand Up @@ -382,6 +381,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO,
crate::methods::DRAIN_COLLECT_INFO,
crate::methods::ERR_EXPECT_INFO,
crate::methods::EXIT_INFO,
crate::methods::EXPECT_FUN_CALL_INFO,
crate::methods::EXPECT_USED_INFO,
crate::methods::EXTEND_WITH_DRAIN_INFO,
Expand Down
76 changes: 0 additions & 76 deletions clippy_lints/src/exit.rs

This file was deleted.

2 changes: 0 additions & 2 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ mod eta_reduction;
mod excessive_bools;
mod excessive_nesting;
mod exhaustive_items;
mod exit;
mod explicit_write;
mod extra_unused_type_parameters;
mod fallible_impl_from;
Expand Down Expand Up @@ -688,7 +687,6 @@ rustc_lint::late_lint_methods!(
Default: default::Default = <default::Default>::default(),
UnusedSelf: unused_self::UnusedSelf = unused_self::UnusedSelf::new(conf),
DebugAssertWithMutCall: mutable_debug_assertion::DebugAssertWithMutCall = mutable_debug_assertion::DebugAssertWithMutCall,
Exit: exit::Exit = exit::Exit,
ToDigitIsSome: to_digit_is_some::ToDigitIsSome = to_digit_is_some::ToDigitIsSome::new(conf),
LargeStackArrays: large_stack_arrays::LargeStackArrays = large_stack_arrays::LargeStackArrays::new(conf),
LargeConstArrays: large_const_arrays::LargeConstArrays = large_const_arrays::LargeConstArrays::new(conf),
Expand Down
24 changes: 24 additions & 0 deletions clippy_lints/src/methods/exit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::res::{MaybeDef as _, MaybeQPath as _};
use clippy_utils::sym;
use rustc_hir::{Expr, Item, ItemKind, OwnerNode};
use rustc_lint::LateContext;

use super::EXIT;

pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, func: &'tcx Expr<'_>) {
if func.res(cx).is_diag_item(cx, sym::process_exit)
&& let parent = cx.tcx.hir_get_parent_item(expr.hir_id)
&& let OwnerNode::Item(Item{kind: ItemKind::Fn{ ident, .. }, ..}) = cx.tcx.hir_owner_node(parent)
// If the next item up is a function we check if it isn't named "main"
// and only then emit a linter warning

// if you instead check for the parent of the `exit()` call being the entrypoint function, as this worked before,
// in compilation contexts like --all-targets (which include --tests), you get false positives
// because in a test context, main is not the entrypoint function
&& ident.name != sym::main
&& !expr.span.in_external_macro(cx.tcx.sess.source_map())
{
span_lint(cx, EXIT, expr.span, "usage of `process::exit`");
}
}
55 changes: 55 additions & 0 deletions clippy_lints/src/methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod collapsible_str_replace;
mod double_ended_iterator_last;
mod drain_collect;
mod err_expect;
mod exit;
mod expect_fun_call;
mod extend_with_drain;
mod filetype_is_file;
Expand Down Expand Up @@ -625,6 +626,54 @@ declare_clippy_lint! {
r#"using `.err().expect("")` when `.expect_err("")` can be used"#
}

declare_clippy_lint! {
/// ### What it does
/// Detects calls to the `exit()` function that are not in the `main` function. Calls to `exit()`
/// immediately terminate the program.
///
/// ### Why restrict this?
/// `exit()` immediately terminates the program with no information other than an exit code.
/// This provides no means to troubleshoot a problem, and may be an unexpected side effect.
///
/// Codebases may use this lint to require that all exits are performed either by panicking
/// (which produces a message, a code location, and optionally a backtrace)
/// or by calling `exit()` from `main()` (which is a single place to look).
///
/// ### Good example
/// ```no_run
/// fn main() {
/// std::process::exit(0);
/// }
/// ```
///
/// ### Bad example
/// ```no_run
/// fn main() {
/// other_function();
/// }
///
/// fn other_function() {
/// std::process::exit(0);
/// }
/// ```
///
/// Use instead:
///
/// ```ignore
/// // To provide a stacktrace and additional information
/// panic!("message");
///
/// // or a main method with a return
/// fn main() -> Result<(), i32> {
/// Ok(())
/// }
/// ```
#[clippy::version = "1.41.0"]
pub EXIT,
restriction,
"detects `std::process::exit` calls outside of `main`"
}

declare_clippy_lint! {
/// ### What it does
/// Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,
Expand Down Expand Up @@ -4970,6 +5019,7 @@ impl_lint_pass!(Methods => [
DOUBLE_ENDED_ITERATOR_LAST,
DRAIN_COLLECT,
ERR_EXPECT,
EXIT,
EXPECT_FUN_CALL,
EXPECT_USED,
EXTEND_WITH_DRAIN,
Expand Down Expand Up @@ -5180,6 +5230,11 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
}

fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Call(func, _) = expr.kind {
// The functions from this block perform their own macro context checks
exit::check(cx, expr, func);
}

if expr.span.from_expansion() {
return;
}
Expand Down