3
3
use std:: cell:: RefCell ;
4
4
5
5
use proc_macro2:: TokenStream ;
6
- use quote:: quote;
6
+ use quote:: { quote, quote_spanned } ;
7
7
use syn:: spanned:: Spanned ;
8
8
use synstructure:: Structure ;
9
9
10
+ use super :: utils:: FieldInnerTy ;
10
11
use crate :: diagnostics:: diagnostic_builder:: DiagnosticDeriveKind ;
11
12
use crate :: diagnostics:: error:: { DiagnosticDeriveError , span_err} ;
12
13
use crate :: diagnostics:: utils:: SetOnce ;
@@ -17,15 +18,16 @@ pub(crate) struct DiagnosticDerive<'a> {
17
18
}
18
19
19
20
impl < ' a > DiagnosticDerive < ' a > {
21
+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: Diagnostic ;
22
+
20
23
pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
21
24
Self { structure }
22
25
}
23
26
24
27
pub ( crate ) fn into_tokens ( self ) -> TokenStream {
25
28
let DiagnosticDerive { mut structure } = self ;
26
- let kind = DiagnosticDeriveKind :: Diagnostic ;
27
29
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| {
29
31
let preamble = builder. preamble ( variant) ;
30
32
let body = builder. body ( variant) ;
31
33
@@ -101,15 +103,16 @@ pub(crate) struct LintDiagnosticDerive<'a> {
101
103
}
102
104
103
105
impl < ' a > LintDiagnosticDerive < ' a > {
106
+ const KIND : DiagnosticDeriveKind = DiagnosticDeriveKind :: LintDiagnostic ;
107
+
104
108
pub ( crate ) fn new ( structure : Structure < ' a > ) -> Self {
105
109
Self { structure }
106
110
}
107
111
108
112
pub ( crate ) fn into_tokens ( self ) -> TokenStream {
109
113
let LintDiagnosticDerive { mut structure } = self ;
110
- let kind = DiagnosticDeriveKind :: LintDiagnostic ;
111
114
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| {
113
116
let preamble = builder. preamble ( variant) ;
114
117
let body = builder. body ( variant) ;
115
118
@@ -151,6 +154,41 @@ impl<'a> LintDiagnosticDerive<'a> {
151
154
}
152
155
} ) ;
153
156
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
+
154
192
// FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
155
193
#[ allow( keyword_idents_2024) ]
156
194
let mut imp = structure. gen_impl ( quote ! {
@@ -162,6 +200,10 @@ impl<'a> LintDiagnosticDerive<'a> {
162
200
) {
163
201
#implementation;
164
202
}
203
+
204
+ fn span( & self ) -> std:: option:: Option <rustc_errors:: MultiSpan > {
205
+ #span
206
+ }
165
207
}
166
208
} ) ;
167
209
for test in slugs. borrow ( ) . iter ( ) . map ( |s| generate_test ( s, & structure) ) {
0 commit comments