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}
;
10 declare_clippy_lint
! {
12 /// Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
14 /// ### Why is this bad?
15 /// Exhaustive enums are typically fine, but a project which does
16 /// not wish to make a stability commitment around exported enums may wish to
17 /// disable them by default.
36 "detects exported enums that have not been marked #[non_exhaustive]"
39 declare_clippy_lint
! {
41 /// Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
43 /// ### Why is this bad?
44 /// Exhaustive structs are typically fine, but a project which does
45 /// not wish to make a stability commitment around exported structs may wish to
46 /// disable them by default.
63 pub EXHAUSTIVE_STRUCTS
,
65 "detects exported structs that have not been marked #[non_exhaustive]"
68 declare_lint_pass
!(ExhaustiveItems
=> [EXHAUSTIVE_ENUMS
, EXHAUSTIVE_STRUCTS
]);
70 impl LateLintPass
<'_
> for ExhaustiveItems
{
71 fn check_item(&mut self, cx
: &LateContext
<'_
>, item
: &Item
<'_
>) {
73 if let ItemKind
::Enum(..) | ItemKind
::Struct(..) = item
.kind
;
74 if cx
.access_levels
.is_exported(item
.def_id
);
75 let attrs
= cx
.tcx
.hir().attrs(item
.hir_id());
76 if !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
);