33use std:: cell:: RefCell ;
44
55use proc_macro2:: TokenStream ;
6- use quote:: quote;
6+ use quote:: { quote, quote_spanned } ;
77use syn:: spanned:: Spanned ;
88use synstructure:: Structure ;
99
10+ use super :: utils:: FieldInnerTy ;
1011use crate :: diagnostics:: diagnostic_builder:: DiagnosticDeriveKind ;
1112use crate :: diagnostics:: error:: { DiagnosticDeriveError , span_err} ;
1213use crate :: diagnostics:: utils:: SetOnce ;
@@ -17,15 +18,16 @@ pub(crate) struct DiagnosticDerive<'a> {
1718}
1819
1920impl < ' a > DiagnosticDerive < ' a > {
21+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: Diagnostic ;
22+
2023 pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
2124 Self { structure }
2225 }
2326
2427 pub ( crate ) fn into_tokens ( self ) -> TokenStream {
2528 let DiagnosticDerive { mut structure } = self ;
26- let kind = DiagnosticDeriveKind :: Diagnostic ;
2729 let slugs = RefCell :: new ( Vec :: new ( ) ) ;
28- let implementation = kind . each_variant ( & mut structure, |mut builder, variant| {
30+ let implementation = Self :: KIND . each_variant ( & mut structure, |mut builder, variant| {
2931 let preamble = builder. preamble ( variant) ;
3032 let body = builder. body ( variant) ;
3133
@@ -101,15 +103,16 @@ pub(crate) struct LintDiagnosticDerive<'a> {
101103}
102104
103105impl < ' a > LintDiagnosticDerive < ' a > {
106+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: LintDiagnostic ;
107+
104108 pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
105109 Self { structure }
106110 }
107111
108112 pub ( crate ) fn into_tokens ( self ) -> TokenStream {
109113 let LintDiagnosticDerive { mut structure } = self ;
110- let kind = DiagnosticDeriveKind :: LintDiagnostic ;
111114 let slugs = RefCell :: new ( Vec :: new ( ) ) ;
112- let implementation = kind . each_variant ( & mut structure, |mut builder, variant| {
115+ let implementation = Self :: KIND . each_variant ( & mut structure, |mut builder, variant| {
113116 let preamble = builder. preamble ( variant) ;
114117 let body = builder. body ( variant) ;
115118
@@ -151,6 +154,41 @@ impl<'a> LintDiagnosticDerive<'a> {
151154 }
152155 } ) ;
153156
157+ let span = Self :: KIND . each_variant ( & mut structure, |_, variant| {
158+ variant
159+ . bindings ( )
160+ . iter ( )
161+ . find_map ( |binding_info| {
162+ let field = binding_info. ast ( ) ;
163+
164+ field. attrs . iter ( ) . find_map ( |attr| {
165+ if attr. path ( ) . segments . last ( ) . unwrap ( ) . ident != "primary_span"
166+ || !matches ! ( attr. meta, syn:: Meta :: Path ( _) )
167+ {
168+ return None ;
169+ }
170+
171+ let ident = & binding_info. binding ;
172+
173+ // Generate `.clone()` unconditionally as the inner type may
174+ // contain a `MultiSpan` which is not `Copy`.
175+ Some ( match FieldInnerTy :: from_type ( & field. ty ) {
176+ FieldInnerTy :: Plain ( _) | FieldInnerTy :: Vec ( _) => {
177+ quote_spanned ! { field. ty. span( ) =>
178+ std:: option:: Option :: Some ( #ident. clone( ) . into( ) )
179+ }
180+ }
181+ FieldInnerTy :: Option ( _) => {
182+ quote_spanned ! { field. ty. span( ) =>
183+ #ident. clone( ) . into( )
184+ }
185+ }
186+ } )
187+ } )
188+ } )
189+ . unwrap_or_else ( || quote ! { std:: option:: Option :: None } )
190+ } ) ;
191+
154192 // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
155193 #[ allow( keyword_idents_2024) ]
156194 let mut imp = structure. gen_impl ( quote ! {
@@ -162,6 +200,10 @@ impl<'a> LintDiagnosticDerive<'a> {
162200 ) {
163201 #implementation;
164202 }
203+
204+ fn span( & self ) -> std:: option:: Option <rustc_errors:: MultiSpan > {
205+ #span
206+ }
165207 }
166208 } ) ;
167209 for test in slugs. borrow ( ) . iter ( ) . map ( |s| generate_test ( s, & structure) ) {
0 commit comments