1 use crate::utils::{indent_of, span_lint_and_then};
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};
10 /// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
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.
16 /// **Known problems:** None.
36 "detects exported enums that have not been marked #[non_exhaustive]"
39 declare_clippy_lint! {
40 /// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
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.
46 /// **Known problems:** None.
64 pub EXHAUSTIVE_STRUCTS,
66 "detects exported structs that have not been marked #[non_exhaustive]"
69 declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
71 impl LateLintPass<'_> for ExhaustiveItems {
72 fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
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));
78 let (lint, msg) = if let ItemKind::Struct(ref v, ..) = item.kind {
79 if v.fields().iter().any(|f| !f.vis.node.is_pub()) {
80 // skip structs with private fields
83 (EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
85 (EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
87 let suggestion_span = item.span.shrink_to_lo();
88 let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
95 let sugg = format!("#[non_exhaustive]\n{}", indent);
96 diag.span_suggestion(suggestion_span,
97 "try adding #[non_exhaustive]",
99 Applicability::MaybeIncorrect);