@@ -213,110 +213,6 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
213213 // - `val` is `Default::default()`
214214 // - `val` is `0`
215215 // - `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- }
320216 if fields. iter ( ) . all ( |f| check_expr ( cx. tcx , f. expr . kind ) ) {
321217 cx. tcx . node_span_lint (
322218 DEFAULT_COULD_BE_DERIVED ,
@@ -339,8 +235,133 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
339235 ) ;
340236 }
341237 }
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+ }
342267 _ => { }
343268 }
344269 }
345270 }
346271}
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