@@ -213,110 +213,6 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
213
213
// - `val` is `Default::default()`
214
214
// - `val` is `0`
215
215
// - `val` is `false`
216
- fn check_expr ( tcx : TyCtxt < ' _ > , kind : hir:: ExprKind < ' _ > ) -> bool {
217
- let Some ( default_def_id) = tcx. get_diagnostic_item ( sym:: Default ) else {
218
- return false ;
219
- } ;
220
- match kind {
221
- hir:: ExprKind :: Lit ( spanned_lit) => match spanned_lit. node {
222
- LitKind :: Int ( val, _) if val == 0 => true , // field: 0,
223
- LitKind :: Bool ( false ) => true , // field: false,
224
- _ => false ,
225
- } ,
226
- hir:: ExprKind :: Call ( expr, [ ] )
227
- if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
228
- expr. kind
229
- && let Some ( def_id) = path. res . opt_def_id ( )
230
- && tcx. is_diagnostic_item ( sym:: default_fn, def_id) =>
231
- {
232
- // field: Default::default(),
233
- true
234
- }
235
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
236
- if let Res :: Def (
237
- DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const ) ,
238
- ctor_def_id,
239
- ) = path. res =>
240
- {
241
- // FIXME: We should use a better check where we explore existing
242
- // `impl Default for def_id` of the found type when `def_id` is not
243
- // local and see compare them against what we have here. For now,
244
- // we special case `Option::None` and only check unit variants of
245
- // local `Default` impls.
246
- let var_def_id = tcx. parent ( ctor_def_id) ; // From Ctor to variant
247
-
248
- // We explicitly check for `Option::<T>::None`. If `Option` was
249
- // local, it would be accounted by the logic further down, but
250
- // because the analysis uses purely the HIR, that doesn't work
251
- // accross crates.
252
- //
253
- // field: None,
254
- let mut found =
255
- tcx. is_lang_item ( var_def_id, hir:: LangItem :: OptionNone ) ;
256
-
257
- // Look at the local `impl Default for ty` of the field's `ty`.
258
- let ty_def_id = tcx. parent ( var_def_id) ; // From variant to enum
259
- let ty = tcx. type_of ( ty_def_id) . instantiate_identity ( ) ;
260
- tcx. for_each_relevant_impl ( default_def_id, ty, |impl_did| {
261
- let hir = tcx. hir ( ) ;
262
- let Some ( hir:: Node :: Item ( impl_item) ) =
263
- hir. get_if_local ( impl_did)
264
- else {
265
- return ;
266
- } ;
267
- let hir:: ItemKind :: Impl ( impl_item) = impl_item. kind else {
268
- return ;
269
- } ;
270
- for assoc in impl_item. items {
271
- let hir:: AssocItemKind :: Fn { has_self : false } = assoc. kind
272
- else {
273
- continue ;
274
- } ;
275
- if assoc. ident . name != kw:: Default {
276
- continue ;
277
- }
278
- let assoc = hir. impl_item ( assoc. id ) ;
279
- let hir:: ImplItemKind :: Fn ( _ty, body) = assoc. kind else {
280
- continue ;
281
- } ;
282
- let body = hir. body ( body) ;
283
- let hir:: ExprKind :: Block (
284
- hir:: Block { stmts : [ ] , expr : Some ( expr) , .. } ,
285
- None ,
286
- ) = body. value . kind
287
- else {
288
- continue ;
289
- } ;
290
- // Look at a specific implementation of `Default::default()`
291
- // for their content and see if they are requivalent to what
292
- // the user wrote in their manual `impl` for a given field.
293
- match expr. kind {
294
- hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
295
- if let Res :: Def (
296
- DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const ) ,
297
- orig_def_id,
298
- ) = path. res =>
299
- {
300
- // We found
301
- //
302
- // field: Foo::Unit,
303
- //
304
- // and
305
- //
306
- // impl Default for Foo {
307
- // fn default() -> Foo { Foo::Unit }
308
- // }
309
- found |= orig_def_id == ctor_def_id
310
- }
311
- _ => { }
312
- }
313
- }
314
- } ) ;
315
- found
316
- }
317
- _ => false ,
318
- }
319
- }
320
216
if fields. iter ( ) . all ( |f| check_expr ( cx. tcx , f. expr . kind ) ) {
321
217
cx. tcx . node_span_lint (
322
218
DEFAULT_COULD_BE_DERIVED ,
@@ -339,8 +235,133 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
339
235
) ;
340
236
}
341
237
}
238
+ hir:: ExprKind :: Call ( expr, args) => {
239
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = expr. kind
240
+ && let Res :: Def ( DefKind :: Ctor ( CtorOf :: Struct , CtorKind :: Fn ) , ctor_def_id) =
241
+ path. res
242
+ {
243
+ let type_def_id = cx. tcx . parent ( ctor_def_id) ; // From Ctor to struct
244
+ if args. iter ( ) . all ( |expr| check_expr ( cx. tcx , expr. kind ) ) {
245
+ cx. tcx . node_span_lint (
246
+ DEFAULT_COULD_BE_DERIVED ,
247
+ item. hir_id ( ) ,
248
+ item. span ,
249
+ |diag| {
250
+ diag. primary_message ( "`impl Default` that could be derived" ) ;
251
+ diag. multipart_suggestion_verbose (
252
+ "you don't need to manually `impl Default`, you can derive it" ,
253
+ vec ! [
254
+ (
255
+ cx. tcx. def_span( type_def_id) . shrink_to_lo( ) ,
256
+ "#[derive(Default)] " . to_string( ) ,
257
+ ) ,
258
+ ( item. span, String :: new( ) ) ,
259
+ ] ,
260
+ Applicability :: MachineApplicable ,
261
+ ) ;
262
+ } ,
263
+ ) ;
264
+ }
265
+ }
266
+ }
342
267
_ => { }
343
268
}
344
269
}
345
270
}
346
271
}
272
+
273
+ fn check_expr ( tcx : TyCtxt < ' _ > , kind : hir:: ExprKind < ' _ > ) -> bool {
274
+ let Some ( default_def_id) = tcx. get_diagnostic_item ( sym:: Default ) else {
275
+ return false ;
276
+ } ;
277
+ match kind {
278
+ hir:: ExprKind :: Lit ( spanned_lit) => match spanned_lit. node {
279
+ LitKind :: Int ( val, _) if val == 0 => true , // field: 0,
280
+ LitKind :: Bool ( false ) => true , // field: false,
281
+ _ => false ,
282
+ } ,
283
+ hir:: ExprKind :: Call ( expr, [ ] )
284
+ if let hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = expr. kind
285
+ && let Some ( def_id) = path. res . opt_def_id ( )
286
+ && tcx. is_diagnostic_item ( sym:: default_fn, def_id) =>
287
+ {
288
+ // field: Default::default(),
289
+ true
290
+ }
291
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
292
+ if let Res :: Def ( DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const ) , ctor_def_id) =
293
+ path. res =>
294
+ {
295
+ // FIXME: We should use a better check where we explore existing
296
+ // `impl Default for def_id` of the found type when `def_id` is not
297
+ // local and see compare them against what we have here. For now,
298
+ // we special case `Option::None` and only check unit variants of
299
+ // local `Default` impls.
300
+ let var_def_id = tcx. parent ( ctor_def_id) ; // From Ctor to variant
301
+
302
+ // We explicitly check for `Option::<T>::None`. If `Option` was
303
+ // local, it would be accounted by the logic further down, but
304
+ // because the analysis uses purely the HIR, that doesn't work
305
+ // accross crates.
306
+ //
307
+ // field: None,
308
+ let mut found = tcx. is_lang_item ( var_def_id, hir:: LangItem :: OptionNone ) ;
309
+
310
+ // Look at the local `impl Default for ty` of the field's `ty`.
311
+ let ty_def_id = tcx. parent ( var_def_id) ; // From variant to enum
312
+ let ty = tcx. type_of ( ty_def_id) . instantiate_identity ( ) ;
313
+ tcx. for_each_relevant_impl ( default_def_id, ty, |impl_did| {
314
+ let hir = tcx. hir ( ) ;
315
+ let Some ( hir:: Node :: Item ( impl_item) ) = hir. get_if_local ( impl_did) else {
316
+ return ;
317
+ } ;
318
+ let hir:: ItemKind :: Impl ( impl_item) = impl_item. kind else {
319
+ return ;
320
+ } ;
321
+ for assoc in impl_item. items {
322
+ let hir:: AssocItemKind :: Fn { has_self : false } = assoc. kind else {
323
+ continue ;
324
+ } ;
325
+ if assoc. ident . name != kw:: Default {
326
+ continue ;
327
+ }
328
+ let assoc = hir. impl_item ( assoc. id ) ;
329
+ let hir:: ImplItemKind :: Fn ( _ty, body) = assoc. kind else {
330
+ continue ;
331
+ } ;
332
+ let body = hir. body ( body) ;
333
+ let hir:: ExprKind :: Block ( hir:: Block { stmts : [ ] , expr : Some ( expr) , .. } , None ) =
334
+ body. value . kind
335
+ else {
336
+ continue ;
337
+ } ;
338
+ // Look at a specific implementation of `Default::default()`
339
+ // for their content and see if they are requivalent to what
340
+ // the user wrote in their manual `impl` for a given field.
341
+ match expr. kind {
342
+ hir:: ExprKind :: Path ( hir:: QPath :: Resolved ( _, path) )
343
+ if let Res :: Def (
344
+ DefKind :: Ctor ( CtorOf :: Variant , CtorKind :: Const ) ,
345
+ orig_def_id,
346
+ ) = path. res =>
347
+ {
348
+ // We found
349
+ //
350
+ // field: Foo::Unit,
351
+ //
352
+ // and
353
+ //
354
+ // impl Default for Foo {
355
+ // fn default() -> Foo { Foo::Unit }
356
+ // }
357
+ found |= orig_def_id == ctor_def_id
358
+ }
359
+ _ => { }
360
+ }
361
+ }
362
+ } ) ;
363
+ found
364
+ }
365
+ _ => false ,
366
+ }
367
+ }
0 commit comments