]>
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}; | |
4 | use if_chain::if_chain; | |
f20569fa XL |
5 | use rustc_hir::{Crate, Expr, ExprKind, QPath}; |
6 | use rustc_lint::{LateContext, LateLintPass}; | |
7 | use rustc_session::{declare_tool_lint, impl_lint_pass}; | |
8 | ||
f20569fa | 9 | declare_clippy_lint! { |
94222f64 XL |
10 | /// ### What it does |
11 | /// Checks for recursion using the entrypoint. | |
f20569fa | 12 | /// |
94222f64 XL |
13 | /// ### Why is this bad? |
14 | /// Apart from special setups (which we could detect following attributes like #![no_std]), | |
f20569fa XL |
15 | /// recursing into main() seems like an unintuitive antipattern we should be able to detect. |
16 | /// | |
94222f64 | 17 | /// ### Example |
f20569fa XL |
18 | /// ```no_run |
19 | /// fn main() { | |
20 | /// main(); | |
21 | /// } | |
22 | /// ``` | |
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 { | |
36 | fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { | |
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 | ||
45 | if_chain! { | |
46 | if let ExprKind::Call(func, _) = &expr.kind; | |
47 | if let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind; | |
48 | if let Some(def_id) = path.res.opt_def_id(); | |
49 | if is_entrypoint_fn(cx, def_id); | |
50 | then { | |
51 | span_lint_and_help( | |
52 | cx, | |
53 | MAIN_RECURSION, | |
54 | func.span, | |
55 | &format!("recursing into entrypoint `{}`", snippet(cx, func.span, "main")), | |
56 | None, | |
57 | "consider using another function for this recursion" | |
58 | ) | |
59 | } | |
60 | } | |
61 | } | |
62 | } |