From 4eab691db63c11ffeaea79c4ad4f3ff8b17564ef Mon Sep 17 00:00:00 2001 From: Vincent Dal Maso Date: Thu, 13 Jun 2019 10:58:35 +0200 Subject: [PATCH] Add recursion check on main function Changes: - Add MainRecursion lint to clippy - Check for no-std setup fixes #333 --- clippy_lints/src/lib.rs | 2 + clippy_lints/src/main_recursion.rs | 55 +++++++++++++++++++ .../no_std_main_recursion.rs | 31 +++++++++++ .../no_std_main_recursion.stderr | 0 .../crate_level_checks/std_main_recursion.rs | 5 ++ .../std_main_recursion.stderr | 11 ++++ 6 files changed, 104 insertions(+) create mode 100644 clippy_lints/src/main_recursion.rs create mode 100644 tests/ui/crate_level_checks/no_std_main_recursion.rs create mode 100644 tests/ui/crate_level_checks/no_std_main_recursion.stderr create mode 100644 tests/ui/crate_level_checks/std_main_recursion.rs create mode 100644 tests/ui/crate_level_checks/std_main_recursion.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8e234017541..325195caa3e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -208,6 +208,7 @@ pub mod let_if_seq; pub mod lifetimes; pub mod literal_representation; pub mod loops; +pub mod main_recursion; pub mod map_clone; pub mod map_unit_fn; pub mod matches; @@ -473,6 +474,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { reg.register_late_lint_pass(box types::LetUnitValue); reg.register_late_lint_pass(box types::UnitCmp); reg.register_late_lint_pass(box loops::Loops); + reg.register_early_lint_pass(box main_recursion::MainRecursion::new()); reg.register_late_lint_pass(box lifetimes::Lifetimes); reg.register_late_lint_pass(box entry::HashMapPass); reg.register_late_lint_pass(box ranges::Ranges); diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs new file mode 100644 index 00000000000..9ef4de21f5a --- /dev/null +++ b/clippy_lints/src/main_recursion.rs @@ -0,0 +1,55 @@ + +use syntax::ast::{Crate, Expr, ExprKind}; +use syntax::symbol::sym; +use rustc::lint::{LintArray, LintPass, EarlyLintPass, EarlyContext}; +use rustc::{declare_tool_lint, impl_lint_pass}; + +use if_chain::if_chain; +use crate::utils::span_help_and_lint; + +declare_clippy_lint! { + pub MAIN_RECURSION, + pedantic, + "function named `foo`, which is not a descriptive name" +} + +pub struct MainRecursion { + has_no_std_attr: bool +} + +impl_lint_pass!(MainRecursion => [MAIN_RECURSION]); + +impl MainRecursion { + pub fn new() -> MainRecursion { + MainRecursion { + has_no_std_attr: false + } + } +} + +impl EarlyLintPass for MainRecursion { + fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) { + self.has_no_std_attr = krate.attrs.iter().any(|attr| attr.path == sym::no_std); + } + + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if self.has_no_std_attr { + return; + } + + if_chain! { + if let ExprKind::Call(func, _) = &expr.node; + if let ExprKind::Path(_, path) = &func.node; + if *path == sym::main; + then { + span_help_and_lint( + cx, + MAIN_RECURSION, + expr.span, + "You are recursing into main()", + "Consider using another function for this recursion" + ) + } + } + } +} diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.rs b/tests/ui/crate_level_checks/no_std_main_recursion.rs new file mode 100644 index 00000000000..857af96a044 --- /dev/null +++ b/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -0,0 +1,31 @@ +#![feature(lang_items, link_args, start, libc)] +#![link_args="-nostartfiles"] +#![no_std] + +use core::panic::PanicInfo; +use core::sync::atomic::{AtomicUsize, Ordering}; + +static N: AtomicUsize = AtomicUsize::new(0); + +#[warn(clippy::main_recursion)] +#[allow(unconditional_recursion)] +#[start] +fn main(argc: isize, argv: *const *const u8) -> isize { + let x = N.load(Ordering::Relaxed); + N.store(x + 1, Ordering::Relaxed); + + if x < 3 { + main(argc, argv); + } + + 0 +} + +#[allow(clippy::empty_loop)] +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern fn eh_personality() {} diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.stderr b/tests/ui/crate_level_checks/no_std_main_recursion.stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/ui/crate_level_checks/std_main_recursion.rs b/tests/ui/crate_level_checks/std_main_recursion.rs new file mode 100644 index 00000000000..e7689ffb72d --- /dev/null +++ b/tests/ui/crate_level_checks/std_main_recursion.rs @@ -0,0 +1,5 @@ +#[warn(clippy::main_recursion)] +#[allow(unconditional_recursion)] +fn main() { + main(); +} diff --git a/tests/ui/crate_level_checks/std_main_recursion.stderr b/tests/ui/crate_level_checks/std_main_recursion.stderr new file mode 100644 index 00000000000..7979010eadf --- /dev/null +++ b/tests/ui/crate_level_checks/std_main_recursion.stderr @@ -0,0 +1,11 @@ +error: You are recursing into main() + --> $DIR/std_main_recursion.rs:4:5 + | +LL | main(); + | ^^^^^^ + | + = note: `-D clippy::main-recursion` implied by `-D warnings` + = help: Consider using another function for this recursion + +error: aborting due to previous error +