@@ -6,25 +6,28 @@ use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
66use crate :: diagnostics:: error:: { span_err, DiagnosticDeriveError } ;
77use crate :: diagnostics:: utils:: SetOnce ;
88use proc_macro2:: TokenStream ;
9- use quote:: quote;
9+ use quote:: { quote, quote_spanned } ;
1010use syn:: spanned:: Spanned ;
1111use synstructure:: Structure ;
1212
13+ use super :: utils:: FieldInnerTy ;
14+
1315/// The central struct for constructing the `into_diag` method from an annotated struct.
1416pub ( crate ) struct DiagnosticDerive < ' a > {
1517 structure : Structure < ' a > ,
1618}
1719
1820impl < ' a > DiagnosticDerive < ' a > {
21+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: Diagnostic ;
22+
1923 pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
2024 Self { structure }
2125 }
2226
2327 pub ( crate ) fn into_tokens ( self ) -> TokenStream {
2428 let DiagnosticDerive { mut structure } = self ;
25- let kind = DiagnosticDeriveKind :: Diagnostic ;
2629 let slugs = RefCell :: new ( Vec :: new ( ) ) ;
27- let implementation = kind . each_variant ( & mut structure, |mut builder, variant| {
30+ let implementation = Self :: KIND . each_variant ( & mut structure, |mut builder, variant| {
2831 let preamble = builder. preamble ( variant) ;
2932 let body = builder. body ( variant) ;
3033
@@ -98,14 +101,15 @@ pub(crate) struct LintDiagnosticDerive<'a> {
98101}
99102
100103impl < ' a > LintDiagnosticDerive < ' a > {
104+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: LintDiagnostic ;
105+
101106 pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
102107 Self { structure }
103108 }
104109
105110 pub ( crate ) fn into_tokens ( self ) -> TokenStream {
106111 let LintDiagnosticDerive { mut structure } = self ;
107- let kind = DiagnosticDeriveKind :: LintDiagnostic ;
108- let implementation = kind. each_variant ( & mut structure, |mut builder, variant| {
112+ let implementation = Self :: KIND . each_variant ( & mut structure, |mut builder, variant| {
109113 let preamble = builder. preamble ( variant) ;
110114 let body = builder. body ( variant) ;
111115
@@ -119,7 +123,7 @@ impl<'a> LintDiagnosticDerive<'a> {
119123 } ) ;
120124
121125 let slugs = RefCell :: new ( Vec :: new ( ) ) ;
122- let msg = kind . each_variant ( & mut structure, |mut builder, variant| {
126+ let msg = Self :: KIND . each_variant ( & mut structure, |mut builder, variant| {
123127 // Collect the slug by generating the preamble.
124128 let _ = builder. preamble ( variant) ;
125129
@@ -152,6 +156,41 @@ impl<'a> LintDiagnosticDerive<'a> {
152156 }
153157 } ) ;
154158
159+ let span = Self :: KIND . each_variant ( & mut structure, |_, variant| {
160+ variant
161+ . bindings ( )
162+ . iter ( )
163+ . find_map ( |binding_info| {
164+ let field = binding_info. ast ( ) ;
165+
166+ field. attrs . iter ( ) . find_map ( |attr| {
167+ if attr. path ( ) . segments . last ( ) . unwrap ( ) . ident != "primary_span"
168+ || !matches ! ( attr. meta, syn:: Meta :: Path ( _) )
169+ {
170+ return None ;
171+ }
172+
173+ let ident = & binding_info. binding ;
174+
175+ // Generate `.clone()` unconditionally as the inner type may
176+ // contain a `MultiSpan` which is not `Copy`.
177+ Some ( match FieldInnerTy :: from_type ( & field. ty ) {
178+ FieldInnerTy :: Plain ( _) | FieldInnerTy :: Vec ( _) => {
179+ quote_spanned ! { field. ty. span( ) =>
180+ std:: option:: Option :: Some ( #ident. clone( ) . into( ) )
181+ }
182+ }
183+ FieldInnerTy :: Option ( _) => {
184+ quote_spanned ! { field. ty. span( ) =>
185+ #ident. clone( ) . into( )
186+ }
187+ }
188+ } )
189+ } )
190+ } )
191+ . unwrap_or_else ( || quote ! { std:: option:: Option :: None } )
192+ } ) ;
193+
155194 let mut imp = structure. gen_impl ( quote ! {
156195 gen impl <' __a> rustc_errors:: LintDiagnostic <' __a, ( ) > for @Self {
157196 #[ track_caller]
@@ -165,6 +204,10 @@ impl<'a> LintDiagnosticDerive<'a> {
165204 fn msg( & self ) -> rustc_errors:: DiagMessage {
166205 #msg
167206 }
207+
208+ fn span( & self ) -> std:: option:: Option <rustc_errors:: MultiSpan > {
209+ #span
210+ }
168211 }
169212 } ) ;
170213 for test in slugs. borrow ( ) . iter ( ) . map ( |s| generate_test ( s, & structure) ) {
0 commit comments