@@ -6,25 +6,28 @@ use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
6
6
use crate :: diagnostics:: error:: { span_err, DiagnosticDeriveError } ;
7
7
use crate :: diagnostics:: utils:: SetOnce ;
8
8
use proc_macro2:: TokenStream ;
9
- use quote:: quote;
9
+ use quote:: { quote, quote_spanned } ;
10
10
use syn:: spanned:: Spanned ;
11
11
use synstructure:: Structure ;
12
12
13
+ use super :: utils:: FieldInnerTy ;
14
+
13
15
/// The central struct for constructing the `into_diag` method from an annotated struct.
14
16
pub ( crate ) struct DiagnosticDerive < ' a > {
15
17
structure : Structure < ' a > ,
16
18
}
17
19
18
20
impl < ' a > DiagnosticDerive < ' a > {
21
+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: Diagnostic ;
22
+
19
23
pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
20
24
Self { structure }
21
25
}
22
26
23
27
pub ( crate ) fn into_tokens ( self ) -> TokenStream {
24
28
let DiagnosticDerive { mut structure } = self ;
25
- let kind = DiagnosticDeriveKind :: Diagnostic ;
26
29
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| {
28
31
let preamble = builder. preamble ( variant) ;
29
32
let body = builder. body ( variant) ;
30
33
@@ -98,14 +101,15 @@ pub(crate) struct LintDiagnosticDerive<'a> {
98
101
}
99
102
100
103
impl < ' a > LintDiagnosticDerive < ' a > {
104
+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: LintDiagnostic ;
105
+
101
106
pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
102
107
Self { structure }
103
108
}
104
109
105
110
pub ( crate ) fn into_tokens ( self ) -> TokenStream {
106
111
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| {
109
113
let preamble = builder. preamble ( variant) ;
110
114
let body = builder. body ( variant) ;
111
115
@@ -119,7 +123,7 @@ impl<'a> LintDiagnosticDerive<'a> {
119
123
} ) ;
120
124
121
125
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| {
123
127
// Collect the slug by generating the preamble.
124
128
let _ = builder. preamble ( variant) ;
125
129
@@ -152,6 +156,41 @@ impl<'a> LintDiagnosticDerive<'a> {
152
156
}
153
157
} ) ;
154
158
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
+
155
194
let mut imp = structure. gen_impl ( quote ! {
156
195
gen impl <' __a> rustc_errors:: LintDiagnostic <' __a, ( ) > for @Self {
157
196
#[ track_caller]
@@ -165,6 +204,10 @@ impl<'a> LintDiagnosticDerive<'a> {
165
204
fn msg( & self ) -> rustc_errors:: DiagMessage {
166
205
#msg
167
206
}
207
+
208
+ fn span( & self ) -> std:: option:: Option <rustc_errors:: MultiSpan > {
209
+ #span
210
+ }
168
211
}
169
212
} ) ;
170
213
for test in slugs. borrow ( ) . iter ( ) . map ( |s| generate_test ( s, & structure) ) {
0 commit comments