about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/lib.rs2
-rw-r--r--clippy_lints/src/main_recursion.rs55
-rw-r--r--tests/ui/crate_level_checks/no_std_main_recursion.rs31
-rw-r--r--tests/ui/crate_level_checks/no_std_main_recursion.stderr0
-rw-r--r--tests/ui/crate_level_checks/std_main_recursion.rs5
-rw-r--r--tests/ui/crate_level_checks/std_main_recursion.stderr11
6 files changed, 104 insertions, 0 deletions
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
--- /dev/null
+++ b/tests/ui/crate_level_checks/no_std_main_recursion.stderr
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
+