]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/exhaustive_items.rs
Merge tag 'debian/1.52.1+dfsg1-1_exp2' into proxmox/buster
[rustc.git] / src / tools / clippy / clippy_lints / src / exhaustive_items.rs
CommitLineData
f20569fa
XL
1use crate::utils::{indent_of, span_lint_and_then};
2use if_chain::if_chain;
3use rustc_errors::Applicability;
4use rustc_hir::{Item, ItemKind};
5use rustc_lint::{LateContext, LateLintPass};
6use rustc_session::{declare_lint_pass, declare_tool_lint};
7use rustc_span::sym;
8
9declare_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
39declare_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
69declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
70
71impl 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 let attrs = cx.tcx.hir().attrs(item.hir_id());
77 if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
78 then {
79 let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
80 if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
81 // skip structs with private fields
82 return;
83 }
84 (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
85 } else {
86 (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
87 };
88 let suggestion_span = item.span.shrink_to_lo();
89 let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
90 span_lint_and_then(
91 cx,
92 lint,
93 item.span,
94 msg,
95 |diag| {
96 let sugg = format!("#[non_exhaustive]\n{}", indent);
97 diag.span_suggestion(suggestion_span,
98 "try adding #[non_exhaustive]",
99 sugg,
100 Applicability::MaybeIncorrect);
101 }
102 );
103
104 }
105 }
106 }
107}