@@ -18,30 +18,15 @@ use syn::{
18
18
} ;
19
19
use synstructure:: { BindingInfo , Structure } ;
20
20
21
- /// What kind of diagnostic is being derived - an error, a warning or a lint?
22
- #[ derive( Copy , Clone ) ]
21
+ /// What kind of diagnostic is being derived - a fatal/error/ warning or a lint?
22
+ #[ derive( Copy , Clone , PartialEq , Eq ) ]
23
23
pub ( crate ) enum DiagnosticDeriveKind {
24
- /// `#[error(..)]`
25
- Error ,
26
- /// `#[warn(..)]`
27
- Warn ,
28
- /// `#[lint(..)]`
29
- Lint ,
30
- }
31
-
32
- impl DiagnosticDeriveKind {
33
- /// Returns human-readable string corresponding to the kind.
34
- pub fn descr ( & self ) -> & ' static str {
35
- match self {
36
- DiagnosticDeriveKind :: Error => "error" ,
37
- DiagnosticDeriveKind :: Warn => "warning" ,
38
- DiagnosticDeriveKind :: Lint => "lint" ,
39
- }
40
- }
24
+ SessionDiagnostic ,
25
+ LintDiagnostic ,
41
26
}
42
27
43
28
/// Tracks persistent information required for building up individual calls to diagnostic methods
44
- /// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and
29
+ /// for generated diagnostic derives - both `SessionDiagnostic` for fatal/ errors/warnings and
45
30
/// `LintDiagnostic` for lints.
46
31
pub ( crate ) struct DiagnosticDeriveBuilder {
47
32
/// The identifier to use for the generated `DiagnosticBuilder` instance.
@@ -51,8 +36,8 @@ pub(crate) struct DiagnosticDeriveBuilder {
51
36
/// derive builder.
52
37
pub fields : HashMap < String , TokenStream > ,
53
38
54
- /// Kind of diagnostic requested via the struct attribute .
55
- pub kind : Option < ( DiagnosticDeriveKind , proc_macro :: Span ) > ,
39
+ /// Kind of diagnostic that should be derived .
40
+ pub kind : DiagnosticDeriveKind ,
56
41
/// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
57
42
/// has the actual diagnostic message.
58
43
pub slug : Option < ( Path , proc_macro:: Span ) > ,
@@ -143,7 +128,7 @@ impl DiagnosticDeriveBuilder {
143
128
}
144
129
145
130
/// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
146
- /// attributes like `#[error (..)`, such as the diagnostic kind and slug . Generates
131
+ /// attributes like `#[diag (..)] `, such as the slug and error code . Generates
147
132
/// diagnostic builder calls for setting error code and creating note/help messages.
148
133
fn generate_structure_code_for_attr (
149
134
& mut self ,
@@ -156,15 +141,15 @@ impl DiagnosticDeriveBuilder {
156
141
let name = name. as_str ( ) ;
157
142
let meta = attr. parse_meta ( ) ?;
158
143
159
- let is_help_note_or_warn = matches ! ( name, "help " | "note " | "warn_ " ) ;
144
+ let is_diag = matches ! ( name, "error " | "warning " | "lint" | "diag ") ;
160
145
161
146
let nested = match meta {
162
- // Most attributes are lists, like `#[error(..)]`/`#[warning (..)]` for most cases or
147
+ // Most attributes are lists, like `#[diag (..)]` for most cases or
163
148
// `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
164
149
Meta :: List ( MetaList { ref nested, .. } ) => nested,
165
150
// Subdiagnostics without spans can be applied to the type too, and these are just
166
- // paths: `#[help]` and `#[note ]`
167
- Meta :: Path ( _) if is_help_note_or_warn => {
151
+ // paths: `#[help]`, `#[note]` and `#[warn_ ]`
152
+ Meta :: Path ( _) if !is_diag => {
168
153
let fn_name = if name == "warn_" {
169
154
Ident :: new ( "warn" , attr. span ( ) )
170
155
} else {
@@ -178,23 +163,32 @@ impl DiagnosticDeriveBuilder {
178
163
// Check the kind before doing any further processing so that there aren't misleading
179
164
// "no kind specified" errors if there are failures later.
180
165
match name {
181
- "error" => self . kind . set_once ( ( DiagnosticDeriveKind :: Error , span) ) ,
182
- "warning" => self . kind . set_once ( ( DiagnosticDeriveKind :: Warn , span) ) ,
183
- "lint" => self . kind . set_once ( ( DiagnosticDeriveKind :: Lint , span) ) ,
184
- "help" | "note" | "warn_" => ( ) ,
166
+ "error" | "warning" => {
167
+ if self . kind == DiagnosticDeriveKind :: LintDiagnostic {
168
+ span_err ( span, "only `#[lint(..)]` is supported" )
169
+ . help ( "use the `#[lint(...)]` attribute to create a lint" )
170
+ . emit ( ) ;
171
+ }
172
+ }
173
+ "lint" => {
174
+ if self . kind == DiagnosticDeriveKind :: SessionDiagnostic {
175
+ span_err ( span, "only `#[error(..)]` and `#[warning(..)]` are supported" )
176
+ . help ( "use the `#[error(...)]` attribute to create a error" )
177
+ . emit ( ) ;
178
+ }
179
+ }
180
+ "diag" | "help" | "note" | "warn_" => ( ) ,
185
181
_ => throw_invalid_attr ! ( attr, & meta, |diag| {
186
- diag. help(
187
- "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes" ,
188
- )
182
+ diag. help( "only `diag`, `help`, `note` and `warn_` are valid attributes" )
189
183
} ) ,
190
184
}
191
185
192
- // First nested element should always be the path, e.g. `#[error (typeck::invalid)]` or
186
+ // First nested element should always be the path, e.g. `#[diag (typeck::invalid)]` or
193
187
// `#[help(typeck::another_help)]`.
194
188
let mut nested_iter = nested. into_iter ( ) ;
195
189
if let Some ( nested_attr) = nested_iter. next ( ) {
196
190
// Report an error if there are any other list items after the path.
197
- if is_help_note_or_warn && nested_iter. next ( ) . is_some ( ) {
191
+ if !is_diag && nested_iter. next ( ) . is_some ( ) {
198
192
throw_invalid_nested_attr ! ( attr, & nested_attr, |diag| {
199
193
diag. help(
200
194
"`help`, `note` and `warn_` struct attributes can only have one argument" ,
@@ -203,16 +197,16 @@ impl DiagnosticDeriveBuilder {
203
197
}
204
198
205
199
match nested_attr {
206
- NestedMeta :: Meta ( Meta :: Path ( path) ) if is_help_note_or_warn => {
207
- let fn_name = proc_macro2:: Ident :: new ( name, attr. span ( ) ) ;
208
- return Ok ( quote ! { #diag. #fn_name( rustc_errors:: fluent:: #path) ; } ) ;
209
- }
210
200
NestedMeta :: Meta ( Meta :: Path ( path) ) => {
211
- self . slug . set_once ( ( path. clone ( ) , span) ) ;
201
+ if is_diag {
202
+ self . slug . set_once ( ( path. clone ( ) , span) ) ;
203
+ } else {
204
+ let fn_name = proc_macro2:: Ident :: new ( name, attr. span ( ) ) ;
205
+ return Ok ( quote ! { #diag. #fn_name( rustc_errors:: fluent:: #path) ; } ) ;
206
+ }
212
207
}
213
208
NestedMeta :: Meta ( meta @ Meta :: NameValue ( _) )
214
- if !is_help_note_or_warn
215
- && meta. path ( ) . segments . last ( ) . unwrap ( ) . ident == "code" =>
209
+ if is_diag && meta. path ( ) . segments . last ( ) . unwrap ( ) . ident == "code" =>
216
210
{
217
211
// don't error for valid follow-up attributes
218
212
}
@@ -347,6 +341,7 @@ impl DiagnosticDeriveBuilder {
347
341
}
348
342
"primary_span" => {
349
343
report_error_if_not_applied_to_span ( attr, & info) ?;
344
+
350
345
Ok ( quote ! {
351
346
#diag. set_span( #binding) ;
352
347
} )
0 commit comments