@@ -2,8 +2,7 @@ use clippy_utils::attrs::is_doc_hidden;
22use clippy_utils:: diagnostics:: span_lint_and_then;
33use clippy_utils:: source:: snippet_opt;
44use 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 } ;
76use rustc_data_structures:: fx:: FxHashSet ;
87use rustc_errors:: Applicability ;
98use 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
170151impl < ' tcx > LateLintPass < ' tcx > for ManualNonExhaustiveEnum {
0 commit comments