diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 386b2403613f..f1e213ea5140 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -469,7 +469,8 @@ 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_early_lint_pass(box main_recursion::MainRecursion::new()); + reg.register_late_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); @@ -916,6 +917,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry<'_>, conf: &Conf) { let_if_seq::USELESS_LET_IF_SEQ, literal_representation::INCONSISTENT_DIGIT_GROUPING, literal_representation::UNREADABLE_LITERAL, + main_recursion::MAIN_RECURSION, loops::EMPTY_LOOP, loops::FOR_KV_MAP, loops::NEEDLESS_RANGE_LOOP, diff --git a/clippy_lints/src/main_recursion.rs b/clippy_lints/src/main_recursion.rs index 9ef4de21f5a9..75b618319bd6 100644 --- a/clippy_lints/src/main_recursion.rs +++ b/clippy_lints/src/main_recursion.rs @@ -1,16 +1,30 @@ -use syntax::ast::{Crate, Expr, ExprKind}; use syntax::symbol::sym; -use rustc::lint::{LintArray, LintPass, EarlyLintPass, EarlyContext}; +use rustc::lint::{LintArray, LintPass, LateLintPass, LateContext}; +use rustc::hir::{Crate, Expr, ExprKind, QPath}; +use rustc::hir::def::Res; use rustc::{declare_tool_lint, impl_lint_pass}; use if_chain::if_chain; -use crate::utils::span_help_and_lint; +use crate::utils::{span_help_and_lint, is_entrypoint_fn}; declare_clippy_lint! { + /// **What it does:** Checks for recursion using the entrypoint. + /// + /// **Why is this bad?** Apart from special setups (which we could detect following attributes like #![no_std]), + /// recursing into main() seems like an unintuitive antipattern we should be able to detect. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```no_run + /// fn main() { + /// main(); + /// } + /// ``` pub MAIN_RECURSION, - pedantic, - "function named `foo`, which is not a descriptive name" + style, + "recursion using the entrypoint" } pub struct MainRecursion { @@ -27,27 +41,29 @@ impl MainRecursion { } } -impl EarlyLintPass for MainRecursion { - fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) { +impl LateLintPass<'_, '_> for MainRecursion { + fn check_crate(&mut self, _: &LateContext<'_, '_>, 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) { + fn check_expr_post(&mut self, cx: &LateContext<'_, '_>, 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; + if let ExprKind::Path(path) = &func.node; + if let QPath::Resolved(_, ptr) = &path; + if let Res::Def(_, def_id) = &ptr.res; + if is_entrypoint_fn(cx, *def_id); then { span_help_and_lint( cx, MAIN_RECURSION, - expr.span, - "You are recursing into main()", - "Consider using another function for this recursion" + func.span, + "recursing into `main()`", + "consider using another function for this recursion" ) } } diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.rs b/tests/ui/crate_level_checks/entrypoint_recursion.rs new file mode 100644 index 000000000000..c0bbb44b729a --- /dev/null +++ b/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -0,0 +1,9 @@ +#![feature(main)] + +#[warn(clippy::main_recursion)] +#[allow(unconditional_recursion)] +#[main] +fn a() { + println!("Hello, World!"); + a(); +} diff --git a/tests/ui/crate_level_checks/entrypoint_recursion.stderr b/tests/ui/crate_level_checks/entrypoint_recursion.stderr new file mode 100644 index 000000000000..ca8090d6441d --- /dev/null +++ b/tests/ui/crate_level_checks/entrypoint_recursion.stderr @@ -0,0 +1,11 @@ +error: recursing into `main()` + --> $DIR/entrypoint_recursion.rs:8:5 + | +LL | a(); + | ^ + | + = note: `-D clippy::main-recursion` implied by `-D warnings` + = help: consider using another function for this recursion + +error: aborting due to previous error + diff --git a/tests/ui/crate_level_checks/no_std_main_recursion.stderr b/tests/ui/crate_level_checks/no_std_main_recursion.stderr deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/tests/ui/crate_level_checks/std_main_recursion.rs b/tests/ui/crate_level_checks/std_main_recursion.rs index e7689ffb72d3..89ff6609934d 100644 --- a/tests/ui/crate_level_checks/std_main_recursion.rs +++ b/tests/ui/crate_level_checks/std_main_recursion.rs @@ -1,5 +1,6 @@ #[warn(clippy::main_recursion)] #[allow(unconditional_recursion)] fn main() { + println!("Hello, World!"); main(); } diff --git a/tests/ui/crate_level_checks/std_main_recursion.stderr b/tests/ui/crate_level_checks/std_main_recursion.stderr index 7979010eadf0..8107d632884f 100644 --- a/tests/ui/crate_level_checks/std_main_recursion.stderr +++ b/tests/ui/crate_level_checks/std_main_recursion.stderr @@ -1,11 +1,11 @@ -error: You are recursing into main() - --> $DIR/std_main_recursion.rs:4:5 +error: recursing into `main()` + --> $DIR/std_main_recursion.rs:5:5 | LL | main(); - | ^^^^^^ + | ^^^^ | = note: `-D clippy::main-recursion` implied by `-D warnings` - = help: Consider using another function for this recursion + = help: consider using another function for this recursion error: aborting due to previous error