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