11use rustc_data_structures:: fx:: FxHashMap ;
22use rustc_errors:: { Applicability , Diag } ;
33use rustc_hir as hir;
4- use rustc_hir:: attrs:: AttributeKind ;
5- use rustc_hir:: find_attr;
64use rustc_middle:: ty;
75use rustc_middle:: ty:: TyCtxt ;
8- use rustc_session:: { declare_lint, impl_lint_pass} ;
9- use rustc_span:: Symbol ;
6+ use rustc_session:: { declare_lint, declare_lint_pass} ;
107use rustc_span:: def_id:: DefId ;
118use rustc_span:: symbol:: sym;
9+ use rustc_span:: { Span , Symbol } ;
1210
1311use crate :: { LateContext , LateLintPass } ;
1412
@@ -52,27 +50,24 @@ declare_lint! {
5250 @feature_gate = default_field_values;
5351}
5452
55- #[ derive( Default ) ]
56- pub ( crate ) struct DefaultCouldBeDerived ;
57-
58- impl_lint_pass ! ( DefaultCouldBeDerived => [ DEFAULT_OVERRIDES_DEFAULT_FIELDS ] ) ;
53+ declare_lint_pass ! ( DefaultCouldBeDerived => [ DEFAULT_OVERRIDES_DEFAULT_FIELDS ] ) ;
5954
6055impl < ' tcx > LateLintPass < ' tcx > for DefaultCouldBeDerived {
6156 fn check_impl_item ( & mut self , cx : & LateContext < ' _ > , impl_item : & hir:: ImplItem < ' _ > ) {
6257 // Look for manual implementations of `Default`.
63- let Some ( default_def_id) = cx. tcx . get_diagnostic_item ( sym:: Default ) else { return } ;
64- let hir:: ImplItemKind :: Fn ( _sig, body_id) = impl_item. kind else { return } ;
65- let parent = cx. tcx . parent ( impl_item. owner_id . to_def_id ( ) ) ;
66- if find_attr ! ( cx. tcx. get_all_attrs( parent) , AttributeKind :: AutomaticallyDerived ( ..) ) {
67- // We don't care about what `#[derive(Default)]` produces in this lint.
58+ let hir:: ImplItemImplKind :: Trait { trait_item_def_id, .. } = impl_item. impl_kind else {
59+ return ;
60+ } ;
61+ if !trait_item_def_id. is_ok_and ( |id| cx. tcx . is_diagnostic_item ( sym:: default_fn, id) ) {
6862 return ;
6963 }
70- let Some ( trait_ref) = cx. tcx . impl_trait_ref ( parent) else { return } ;
71- let trait_ref = trait_ref. instantiate_identity ( ) ;
72- if trait_ref. def_id != default_def_id {
64+ let hir:: ImplItemKind :: Fn ( _sig, body_id) = impl_item. kind else { return } ;
65+ let impl_id = cx. tcx . local_parent ( impl_item. owner_id . def_id ) ;
66+ if cx. tcx . is_automatically_derived ( impl_id. to_def_id ( ) ) {
67+ // We don't care about what `#[derive(Default)]` produces in this lint.
7368 return ;
7469 }
75- let ty = trait_ref . self_ty ( ) ;
70+ let ty = cx . tcx . type_of ( impl_id ) . instantiate_identity ( ) ;
7671 let ty:: Adt ( def, _) = ty. kind ( ) else { return } ;
7772
7873 // We now know we have a manually written definition of a `<Type as Default>::default()`.
@@ -150,11 +145,10 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived {
150145 return ;
151146 }
152147
153- let Some ( local) = parent. as_local ( ) else { return } ;
154- let hir_id = cx. tcx . local_def_id_to_hir_id ( local) ;
155- let hir:: Node :: Item ( item) = cx. tcx . hir_node ( hir_id) else { return } ;
156- cx. tcx . node_span_lint ( DEFAULT_OVERRIDES_DEFAULT_FIELDS , hir_id, item. span , |diag| {
157- mk_lint ( cx. tcx , diag, type_def_id, parent, orig_fields, fields) ;
148+ let hir_id = cx. tcx . local_def_id_to_hir_id ( impl_id) ;
149+ let span = cx. tcx . hir_span_with_body ( hir_id) ;
150+ cx. tcx . node_span_lint ( DEFAULT_OVERRIDES_DEFAULT_FIELDS , hir_id, span, |diag| {
151+ mk_lint ( cx. tcx , diag, type_def_id, orig_fields, fields, span) ;
158152 } ) ;
159153 }
160154}
@@ -163,9 +157,9 @@ fn mk_lint(
163157 tcx : TyCtxt < ' _ > ,
164158 diag : & mut Diag < ' _ , ( ) > ,
165159 type_def_id : DefId ,
166- impl_def_id : DefId ,
167160 orig_fields : FxHashMap < Symbol , & hir:: FieldDef < ' _ > > ,
168161 fields : & [ hir:: ExprField < ' _ > ] ,
162+ impl_span : Span ,
169163) {
170164 diag. primary_message ( "`Default` impl doesn't use the declared default field values" ) ;
171165
@@ -186,18 +180,14 @@ fn mk_lint(
186180 if removed_all_fields {
187181 let msg = "to avoid divergence in behavior between `Struct { .. }` and \
188182 `<Struct as Default>::default()`, derive the `Default`";
189- if let Some ( hir:: Node :: Item ( impl_) ) = tcx. hir_get_if_local ( impl_def_id) {
190- diag. multipart_suggestion_verbose (
191- msg,
192- vec ! [
193- ( tcx. def_span( type_def_id) . shrink_to_lo( ) , "#[derive(Default)] " . to_string( ) ) ,
194- ( impl_. span, String :: new( ) ) ,
195- ] ,
196- Applicability :: MachineApplicable ,
197- ) ;
198- } else {
199- diag. help ( msg) ;
200- }
183+ diag. multipart_suggestion_verbose (
184+ msg,
185+ vec ! [
186+ ( tcx. def_span( type_def_id) . shrink_to_lo( ) , "#[derive(Default)] " . to_string( ) ) ,
187+ ( impl_span, String :: new( ) ) ,
188+ ] ,
189+ Applicability :: MachineApplicable ,
190+ ) ;
201191 } else {
202192 let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \
203193 avoid them diverging over time";
0 commit comments