]>
Commit | Line | Data |
---|---|---|
cdc7bbd5 XL |
1 | use clippy_utils::diagnostics::span_lint_and_help; |
2 | use clippy_utils::source::snippet; | |
3 | use clippy_utils::{is_entrypoint_fn, is_no_std_crate}; | |
c295e0f8 | 4 | use rustc_hir::{Expr, ExprKind, QPath}; |
f20569fa | 5 | use rustc_lint::{LateContext, LateLintPass}; |
4b012472 | 6 | use rustc_session::impl_lint_pass; |
f20569fa | 7 | |
f20569fa | 8 | declare_clippy_lint! { |
94222f64 XL |
9 | /// ### What it does |
10 | /// Checks for recursion using the entrypoint. | |
f20569fa | 11 | /// |
94222f64 XL |
12 | /// ### Why is this bad? |
13 | /// Apart from special setups (which we could detect following attributes like #![no_std]), | |
923072b8 | 14 | /// recursing into main() seems like an unintuitive anti-pattern we should be able to detect. |
f20569fa | 15 | /// |
94222f64 | 16 | /// ### Example |
f20569fa XL |
17 | /// ```no_run |
18 | /// fn main() { | |
19 | /// main(); | |
20 | /// } | |
21 | /// ``` | |
a2a8927a | 22 | #[clippy::version = "1.38.0"] |
f20569fa XL |
23 | pub MAIN_RECURSION, |
24 | style, | |
25 | "recursion using the entrypoint" | |
26 | } | |
27 | ||
28 | #[derive(Default)] | |
29 | pub struct MainRecursion { | |
30 | has_no_std_attr: bool, | |
31 | } | |
32 | ||
33 | impl_lint_pass!(MainRecursion => [MAIN_RECURSION]); | |
34 | ||
35 | impl LateLintPass<'_> for MainRecursion { | |
c295e0f8 | 36 | fn check_crate(&mut self, cx: &LateContext<'_>) { |
f20569fa XL |
37 | self.has_no_std_attr = is_no_std_crate(cx); |
38 | } | |
39 | ||
40 | fn check_expr_post(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { | |
41 | if self.has_no_std_attr { | |
42 | return; | |
43 | } | |
44 | ||
4b012472 FG |
45 | if let ExprKind::Call(func, _) = &expr.kind |
46 | && let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind | |
47 | && let Some(def_id) = path.res.opt_def_id() | |
48 | && is_entrypoint_fn(cx, def_id) | |
49 | { | |
50 | span_lint_and_help( | |
51 | cx, | |
52 | MAIN_RECURSION, | |
53 | func.span, | |
e8be2606 | 54 | format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), |
4b012472 FG |
55 | None, |
56 | "consider using another function for this recursion", | |
57 | ); | |
f20569fa XL |
58 | } |
59 | } | |
60 | } |