]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/exhaustive_items.rs
Fix indentation of suggestion
[rust.git] / clippy_lints / src / exhaustive_items.rs
1 use crate::utils::{indent_of, snippet_opt, span_lint_and_help, span_lint_and_sugg};
2 use if_chain::if_chain;
3 use rustc_errors::Applicability;
4 use rustc_hir::{Item, ItemKind};
5 use rustc_lint::{LateContext, LateLintPass};
6 use rustc_session::{declare_lint_pass, declare_tool_lint};
7 use rustc_span::sym;
8
9 declare_clippy_lint! {
10     /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
11     ///
12     /// **Why is this bad?** Exhaustive enums are typically fine, but a project which does
13     /// not wish to make a stability commitment around exported enums may wish to
14     /// disable them by default.
15     ///
16     /// **Known problems:** None.
17     ///
18     /// **Example:**
19     ///
20     /// ```rust
21     /// enum Foo {
22     ///     Bar,
23     ///     Baz
24     /// }
25     /// ```
26     /// Use instead:
27     /// ```rust
28     /// #[non_exhaustive]
29     /// enum Foo {
30     ///     Bar,
31     ///     Baz
32     /// }
33     /// ```
34     pub EXHAUSTIVE_ENUMS,
35     restriction,
36     "detects exported enums that have not been marked #[non_exhaustive]"
37 }
38
39 declare_clippy_lint! {
40     /// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
41     ///
42     /// **Why is this bad?** Exhaustive structs are typically fine, but a project which does
43     /// not wish to make a stability commitment around exported structs may wish to
44     /// disable them by default.
45     ///
46     /// **Known problems:** None.
47     ///
48     /// **Example:**
49     ///
50     /// ```rust
51     /// struct Foo {
52     ///     bar: u8,
53     ///     baz: String,
54     /// }
55     /// ```
56     /// Use instead:
57     /// ```rust
58     /// #[non_exhaustive]
59     /// struct Foo {
60     ///     bar: u8,
61     ///     baz: String,
62     /// }
63     /// ```
64     pub EXHAUSTIVE_STRUCTS,
65     restriction,
66     "detects exported structs that have not been marked #[non_exhaustive]"
67 }
68
69 declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
70
71 impl LateLintPass<'_> for ExhaustiveItems {
72     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
73         if_chain! {
74             if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
75             if cx.access_levels.is_exported(item.hir_id);
76             if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
77             then {
78                 let lint = if let ItemKind::Enum(..) = item.kind {
79                     EXHAUSTIVE_ENUMS
80                 } else {
81                     EXHAUSTIVE_STRUCTS
82                 };
83
84                 if let Some(snippet) = snippet_opt(cx, item.span) {
85                     let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
86                     span_lint_and_sugg(
87                         cx,
88                         lint,
89                         item.span,
90                         "enums should not be exhaustive",
91                         "try adding #[non_exhaustive]",
92                         format!("#[non_exhaustive]\n{}{}", indent, snippet),
93                         Applicability::MaybeIncorrect,
94                     );
95                 } else {
96                     span_lint_and_help(
97                         cx,
98                         lint,
99                         item.span,
100                         "enums should not be exhaustive",
101                         None,
102                         "try adding #[non_exhaustive]",
103                     );
104                 }
105             }
106         }
107     }
108 }