@@ -2,8 +2,7 @@ use clippy_utils::attrs::is_doc_hidden;
2
2
use clippy_utils:: diagnostics:: span_lint_and_then;
3
3
use clippy_utils:: source:: snippet_opt;
4
4
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 } ;
7
6
use rustc_data_structures:: fx:: FxHashSet ;
8
7
use rustc_errors:: Applicability ;
9
8
use rustc_hir:: def:: { CtorKind , CtorOf , DefKind , Res } ;
@@ -104,67 +103,49 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
104
103
}
105
104
106
105
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 {
108
112
return ;
109
113
}
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
+ {
156
134
diag. span_suggestion (
157
135
header_span,
158
136
"add the attribute" ,
159
137
format ! ( "#[non_exhaustive] {}" , snippet) ,
160
138
Applicability :: Unspecified ,
161
139
) ;
162
140
}
141
+ diag. span_help ( field. span , "remove this field" ) ;
163
142
}
164
- diag . span_help ( marker . span , "remove this field" ) ;
165
- } ) ;
143
+ ) ;
144
+ }
166
145
}
167
146
}
147
+
148
+ extract_msrv_attr ! ( EarlyContext ) ;
168
149
}
169
150
170
151
impl < ' tcx > LateLintPass < ' tcx > for ManualNonExhaustiveEnum {
0 commit comments