11use clippy_utils:: attrs:: span_contains_cfg;
22use clippy_utils:: diagnostics:: { span_lint_and_then, span_lint_hir_and_then} ;
3- use rustc_data_structures:: fx:: FxIndexMap ;
3+ use rustc_data_structures:: fx:: { FxIndexMap , IndexEntry } ;
44use rustc_errors:: Applicability ;
55use rustc_hir:: def:: DefKind :: Ctor ;
66use rustc_hir:: def:: Res :: Def ;
@@ -118,80 +118,51 @@ impl LateLintPass<'_> for EmptyWithBrackets {
118118 }
119119
120120 fn check_variant ( & mut self , cx : & LateContext < ' _ > , variant : & Variant < ' _ > ) {
121- // FIXME: handle `$name {}`
122121 if !variant. span . from_expansion ( )
123122 && !variant. ident . span . from_expansion ( )
124123 && let span_after_ident = variant. span . with_lo ( variant. ident . span . hi ( ) )
125124 && has_no_fields ( cx, & variant. data , span_after_ident)
126125 {
127126 match variant. data {
128127 VariantData :: Struct { .. } => {
129- // Empty struct variants can be linted immediately
130- span_lint_and_then (
131- cx,
132- EMPTY_ENUM_VARIANTS_WITH_BRACKETS ,
133- span_after_ident,
134- "enum variant has empty brackets" ,
135- |diagnostic| {
136- diagnostic. span_suggestion_hidden (
137- span_after_ident,
138- "remove the brackets" ,
139- "" ,
140- Applicability :: MaybeIncorrect ,
141- ) ;
142- } ,
143- ) ;
128+ self . add_enum_variant ( cx, variant, variant. def_id ) ;
144129 } ,
145130 VariantData :: Tuple ( .., local_def_id) => {
146- // Don't lint reachable tuple enums
147- if cx. effective_visibilities . is_reachable ( variant. def_id ) {
148- return ;
149- }
150- if let Some ( entry) = self . empty_tuple_enum_variants . get_mut ( & local_def_id) {
151- // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before the
152- // definition was encountered. Now that there's a definition, convert it
153- // to Usage::Unused.
154- if let Usage :: NoDefinition { redundant_use_sites } = entry {
155- * entry = Usage :: Unused {
156- redundant_use_sites : redundant_use_sites. clone ( ) ,
157- } ;
158- }
159- } else {
160- self . empty_tuple_enum_variants . insert (
161- local_def_id,
162- Usage :: Unused {
163- redundant_use_sites : vec ! [ ] ,
164- } ,
165- ) ;
166- }
131+ self . add_enum_variant ( cx, variant, local_def_id) ;
167132 } ,
168133 VariantData :: Unit ( ..) => { } ,
169134 }
170135 }
171136 }
172137
173138 fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
174- if let Some ( def_id) = check_expr_for_enum_as_function ( expr) {
175- if let Some ( parentheses_span) = call_parentheses_span ( cx. tcx , expr) {
139+ if let Some ( ( def_id, mut span) ) = check_expr_for_enum_as_function ( cx, expr) {
140+ if span. is_empty ( )
141+ && let Some ( parentheses_span) = call_parentheses_span ( cx. tcx , expr)
142+ {
143+ span = parentheses_span;
144+ }
145+
146+ if span. is_empty ( ) {
147+ // The parentheses are not redundant.
148+ self . empty_tuple_enum_variants . insert ( def_id, Usage :: Used ) ;
149+ } else {
176150 // Do not count expressions from macro expansion as a redundant use site.
177151 if expr. span . from_expansion ( ) {
178152 return ;
179153 }
180- self . update_enum_variant_usage ( def_id, parentheses_span) ;
181- } else {
182- // The parentheses are not redundant.
183- self . empty_tuple_enum_variants . insert ( def_id, Usage :: Used ) ;
154+ self . update_enum_variant_usage ( def_id, span) ;
184155 }
185156 }
186157 }
187158
188159 fn check_pat ( & mut self , cx : & LateContext < ' _ > , pat : & Pat < ' _ > ) {
189- if let Some ( ( def_id, parentheses_span ) ) = check_pat_for_enum_as_function ( cx, pat) {
160+ if let Some ( ( def_id, span ) ) = check_pat_for_enum_as_function ( cx, pat) {
190161 if pat. span . from_expansion ( ) {
191162 return ;
192163 }
193164
194- self . update_enum_variant_usage ( def_id, parentheses_span ) ;
165+ self . update_enum_variant_usage ( def_id, span ) ;
195166 }
196167 }
197168
@@ -201,13 +172,19 @@ impl LateLintPass<'_> for EmptyWithBrackets {
201172 let Usage :: Unused { redundant_use_sites } = usage else {
202173 continue ;
203174 } ;
175+
204176 // Attempt to fetch the Variant from LocalDefId.
205- let Node :: Variant ( variant) = cx. tcx . hir_node (
177+ let variant = if let Node :: Variant ( variant) = cx. tcx . hir_node ( cx. tcx . local_def_id_to_hir_id ( local_def_id) ) {
178+ variant
179+ } else if let Node :: Variant ( variant) = cx. tcx . hir_node (
206180 cx. tcx
207181 . local_def_id_to_hir_id ( cx. tcx . parent ( local_def_id. to_def_id ( ) ) . expect_local ( ) ) ,
208- ) else {
182+ ) {
183+ variant
184+ } else {
209185 continue ;
210186 } ;
187+
211188 // Span of the parentheses in variant definition
212189 let span = variant. span . with_lo ( variant. ident . span . hi ( ) ) ;
213190 span_lint_hir_and_then (
@@ -242,28 +219,43 @@ impl LateLintPass<'_> for EmptyWithBrackets {
242219}
243220
244221impl EmptyWithBrackets {
222+ fn add_enum_variant ( & mut self , cx : & LateContext < ' _ > , variant : & Variant < ' _ > , local_def_id : LocalDefId ) {
223+ // Don't lint reachable tuple enums
224+ if cx. effective_visibilities . is_reachable ( variant. def_id ) {
225+ return ;
226+ }
227+
228+ self . empty_tuple_enum_variants
229+ . entry ( local_def_id)
230+ . and_modify ( |entry| {
231+ // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before
232+ // the definition was encountered. Now that there's a
233+ // definition, convert it to Usage::Unused.
234+ if let Usage :: NoDefinition { redundant_use_sites } = entry {
235+ * entry = Usage :: Unused {
236+ redundant_use_sites : redundant_use_sites. clone ( ) ,
237+ } ;
238+ }
239+ } )
240+ . or_insert_with ( || Usage :: Unused {
241+ redundant_use_sites : vec ! [ ] ,
242+ } ) ;
243+ }
244+
245245 fn update_enum_variant_usage ( & mut self , def_id : LocalDefId , parentheses_span : Span ) {
246- match self . empty_tuple_enum_variants . get_mut ( & def_id) {
247- Some (
248- & mut ( Usage :: Unused {
249- ref mut redundant_use_sites,
246+ match self . empty_tuple_enum_variants . entry ( def_id) {
247+ IndexEntry :: Occupied ( mut e) => {
248+ if let Usage :: Unused { redundant_use_sites } | Usage :: NoDefinition { redundant_use_sites } = e. get_mut ( )
249+ {
250+ redundant_use_sites. push ( parentheses_span) ;
250251 }
251- | Usage :: NoDefinition {
252- ref mut redundant_use_sites,
253- } ) ,
254- ) => {
255- redundant_use_sites. push ( parentheses_span) ;
256252 } ,
257- None => {
253+ IndexEntry :: Vacant ( e ) => {
258254 // The variant isn't in the IndexMap which means its definition wasn't encountered yet.
259- self . empty_tuple_enum_variants . insert (
260- def_id,
261- Usage :: NoDefinition {
262- redundant_use_sites : vec ! [ parentheses_span] ,
263- } ,
264- ) ;
255+ e. insert ( Usage :: NoDefinition {
256+ redundant_use_sites : vec ! [ parentheses_span] ,
257+ } ) ;
265258 } ,
266- _ => { } ,
267259 }
268260 }
269261}
@@ -293,18 +285,27 @@ fn call_parentheses_span(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option<Span> {
293285}
294286
295287// Returns the LocalDefId of the variant being called as a function if it exists.
296- fn check_expr_for_enum_as_function ( expr : & Expr < ' _ > ) -> Option < LocalDefId > {
297- if let ExprKind :: Path ( QPath :: Resolved (
298- _,
299- Path {
300- res : Def ( Ctor ( CtorOf :: Variant , _) , def_id) ,
301- ..
288+ fn check_expr_for_enum_as_function ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) -> Option < ( LocalDefId , Span ) > {
289+ match expr. kind {
290+ ExprKind :: Path ( QPath :: Resolved (
291+ _,
292+ Path {
293+ res : Def ( Ctor ( CtorOf :: Variant , _) , def_id) ,
294+ span,
295+ ..
296+ } ,
297+ ) ) => def_id. as_local ( ) . map ( |id| ( id, span. with_lo ( expr. span . hi ( ) ) ) ) ,
298+ ExprKind :: Struct ( qpath, ..)
299+ if let Def ( DefKind :: Variant , mut def_id) = cx. typeck_results ( ) . qpath_res ( qpath, expr. hir_id ) =>
300+ {
301+ let ty = cx. tcx . type_of ( def_id) . instantiate_identity ( ) ;
302+ if let ty:: FnDef ( ctor_def_id, _) = ty. kind ( ) {
303+ def_id = * ctor_def_id;
304+ }
305+
306+ def_id. as_local ( ) . map ( |id| ( id, qpath. span ( ) . with_lo ( expr. span . hi ( ) ) ) )
302307 } ,
303- ) ) = expr. kind
304- {
305- def_id. as_local ( )
306- } else {
307- None
308+ _ => None ,
308309 }
309310}
310311
@@ -316,10 +317,13 @@ fn check_pat_for_enum_as_function(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option
316317 def_id. as_local ( ) . map ( |id| ( id, qpath. span ( ) . with_lo ( pat. span . hi ( ) ) ) )
317318 } ,
318319 PatKind :: Struct ( qpath, ..)
319- if let Def ( DefKind :: Variant , def_id) = cx. typeck_results ( ) . qpath_res ( & qpath, pat. hir_id )
320- && let ty = cx. tcx . type_of ( def_id) . instantiate_identity ( )
321- && let ty:: FnDef ( def_id, _) = ty. kind ( ) =>
320+ if let Def ( DefKind :: Variant , mut def_id) = cx. typeck_results ( ) . qpath_res ( & qpath, pat. hir_id ) =>
322321 {
322+ let ty = cx. tcx . type_of ( def_id) . instantiate_identity ( ) ;
323+ if let ty:: FnDef ( ctor_def_id, _) = ty. kind ( ) {
324+ def_id = * ctor_def_id;
325+ }
326+
323327 def_id. as_local ( ) . map ( |id| ( id, qpath. span ( ) . with_lo ( pat. span . hi ( ) ) ) )
324328 } ,
325329 _ => None ,
0 commit comments