Skip to content

Commit b0f8a31

Browse files
committed
Cleanup manual_non_exhaustive
1 parent 6e20a63 commit b0f8a31

File tree

1 file changed

+32
-51
lines changed

1 file changed

+32
-51
lines changed

clippy_lints/src/manual_non_exhaustive.rs

Lines changed: 32 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use clippy_utils::attrs::is_doc_hidden;
22
use clippy_utils::diagnostics::span_lint_and_then;
33
use clippy_utils::source::snippet_opt;
44
use clippy_utils::{is_lint_allowed, meets_msrv, msrvs};
5-
use if_chain::if_chain;
6-
use rustc_ast::ast::{self, FieldDef, VisibilityKind};
5+
use rustc_ast::ast::{self, VisibilityKind};
76
use rustc_data_structures::fx::FxHashSet;
87
use rustc_errors::Applicability;
98
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -104,67 +103,49 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
104103
}
105104

106105
if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
107-
if let ast::VariantData::Unit(..) = variant_data {
106+
let (fields, delimiter) = match variant_data {
107+
ast::VariantData::Struct(fields, _) => (&**fields, '{'),
108+
ast::VariantData::Tuple(fields, _) => (&**fields, '('),
109+
ast::VariantData::Unit(_) => return,
110+
};
111+
if fields.len() <= 1 {
108112
return;
109113
}
110-
111-
check_manual_non_exhaustive_struct(cx, item, variant_data);
112-
}
113-
}
114-
115-
extract_msrv_attr!(EarlyContext);
116-
}
117-
118-
fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &ast::Item, data: &ast::VariantData) {
119-
fn is_private(field: &FieldDef) -> bool {
120-
matches!(field.vis.kind, VisibilityKind::Inherited)
121-
}
122-
123-
fn is_non_exhaustive_marker(field: &FieldDef) -> bool {
124-
is_private(field) && field.ty.kind.is_unit() && field.ident.map_or(true, |n| n.as_str().starts_with('_'))
125-
}
126-
127-
fn find_header_span(cx: &EarlyContext<'_>, item: &ast::Item, data: &ast::VariantData) -> Span {
128-
let delimiter = match data {
129-
ast::VariantData::Struct(..) => '{',
130-
ast::VariantData::Tuple(..) => '(',
131-
ast::VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"),
132-
};
133-
134-
cx.sess().source_map().span_until_char(item.span, delimiter)
135-
}
136-
137-
let fields = data.fields();
138-
let private_fields = fields.iter().filter(|f| is_private(f)).count();
139-
let public_fields = fields.iter().filter(|f| f.vis.kind.is_pub()).count();
140-
141-
if_chain! {
142-
if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1;
143-
if let Some(marker) = fields.iter().find(|f| is_non_exhaustive_marker(f));
144-
then {
145-
span_lint_and_then(
146-
cx,
147-
MANUAL_NON_EXHAUSTIVE,
148-
item.span,
149-
"this seems like a manual implementation of the non-exhaustive pattern",
150-
|diag| {
151-
if_chain! {
152-
if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
153-
let header_span = find_header_span(cx, item, data);
154-
if let Some(snippet) = snippet_opt(cx, header_span);
155-
then {
114+
let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
115+
VisibilityKind::Public => None,
116+
VisibilityKind::Inherited => Some(Ok(f)),
117+
_ => Some(Err(())),
118+
});
119+
if let Some(Ok(field)) = iter.next()
120+
&& iter.next().is_none()
121+
&& field.ty.kind.is_unit()
122+
&& field.ident.map_or(true, |name| name.as_str().starts_with('_'))
123+
{
124+
span_lint_and_then(
125+
cx,
126+
MANUAL_NON_EXHAUSTIVE,
127+
item.span,
128+
"this seems like a manual implementation of the non-exhaustive pattern",
129+
|diag| {
130+
if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive))
131+
&& let header_span = cx.sess().source_map().span_until_char(item.span, delimiter)
132+
&& let Some(snippet) = snippet_opt(cx, header_span)
133+
{
156134
diag.span_suggestion(
157135
header_span,
158136
"add the attribute",
159137
format!("#[non_exhaustive] {}", snippet),
160138
Applicability::Unspecified,
161139
);
162140
}
141+
diag.span_help(field.span, "remove this field");
163142
}
164-
diag.span_help(marker.span, "remove this field");
165-
});
143+
);
144+
}
166145
}
167146
}
147+
148+
extract_msrv_attr!(EarlyContext);
168149
}
169150

170151
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {

0 commit comments

Comments
 (0)