Ensure #[suggestion] is only applied to correct tuple types

This commit is contained in:
Xiretza 2022-09-10 14:43:07 +02:00
parent 2e72387fd0
commit ec85a1b263
3 changed files with 79 additions and 48 deletions

View File

@ -571,46 +571,37 @@ impl DiagnosticDeriveBuilder {
let mut span_idx = None; let mut span_idx = None;
let mut applicability_idx = None; let mut applicability_idx = None;
fn type_err(span: &Span) -> Result<!, DiagnosticDeriveError> {
span_err(span.unwrap(), "wrong types for suggestion")
.help(
"`#[suggestion(...)]` on a tuple field must be applied to fields \
of type `(Span, Applicability)`",
)
.emit();
Err(DiagnosticDeriveError::ErrorHandled)
}
for (idx, elem) in tup.elems.iter().enumerate() { for (idx, elem) in tup.elems.iter().enumerate() {
if type_matches_path(elem, &["rustc_span", "Span"]) { if type_matches_path(elem, &["rustc_span", "Span"]) {
if span_idx.is_none() { span_idx.set_once((syn::Index::from(idx), elem.span().unwrap()));
span_idx = Some(syn::Index::from(idx));
} else {
throw_span_err!(
info.span.unwrap(),
"type of field annotated with `#[suggestion(...)]` contains more \
than one `Span`"
);
}
} else if type_matches_path(elem, &["rustc_errors", "Applicability"]) { } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
if applicability_idx.is_none() { applicability_idx.set_once((syn::Index::from(idx), elem.span().unwrap()));
applicability_idx = Some(syn::Index::from(idx)); } else {
} else { type_err(&elem.span())?;
throw_span_err!(
info.span.unwrap(),
"type of field annotated with `#[suggestion(...)]` contains more \
than one Applicability"
);
}
} }
} }
if let Some(span_idx) = span_idx { let Some((span_idx, _)) = span_idx else {
let binding = &info.binding.binding; type_err(&tup.span())?;
let span = quote!(#binding.#span_idx); };
let applicability = applicability_idx let Some((applicability_idx, _applicability_span)) = applicability_idx else {
.map(|applicability_idx| quote!(#binding.#applicability_idx)) type_err(&tup.span())?;
.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified)); };
let binding = &info.binding.binding;
let span = quote!(#binding.#span_idx);
let applicability = quote!(#binding.#applicability_idx);
return Ok((span, Some(applicability))); Ok((span, Some(applicability)))
}
throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
diag.help(
"`#[suggestion(...)]` on a tuple field must be applied to fields of type \
`(Span, Applicability)`",
)
});
} }
// If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error. // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
_ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| { _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {

View File

@ -269,16 +269,16 @@ struct SuggestWithSpanOnly {
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
struct SuggestWithDuplicateSpanAndApplicability { struct SuggestWithDuplicateSpanAndApplicability {
#[suggestion(typeck::suggestion, code = "This is suggested code")] #[suggestion(typeck::suggestion, code = "This is suggested code")]
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one `Span`
suggestion: (Span, Span, Applicability), suggestion: (Span, Span, Applicability),
//~^ ERROR specified multiple times
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")] #[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
struct SuggestWithDuplicateApplicabilityAndSpan { struct SuggestWithDuplicateApplicabilityAndSpan {
#[suggestion(typeck::suggestion, code = "This is suggested code")] #[suggestion(typeck::suggestion, code = "This is suggested code")]
//~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one
suggestion: (Applicability, Applicability, Span), suggestion: (Applicability, Applicability, Span),
//~^ ERROR specified multiple times
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -589,3 +589,19 @@ struct DuplicatedSuggestionCode {
//~^ ERROR specified multiple times //~^ ERROR specified multiple times
suggestion: Span, suggestion: Span,
} }
#[derive(Diagnostic)]
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
struct InvalidTypeInSuggestionTuple {
#[suggestion(typeck::suggestion, code = "...")]
suggestion: (Span, usize),
//~^ ERROR wrong types for suggestion
}
#[derive(Diagnostic)]
#[diag(typeck::ambiguous_lifetime_bound, code = "E0123")]
struct MissingApplicabilityInSuggestionTuple {
#[suggestion(typeck::suggestion, code = "...")]
suggestion: (Span,),
//~^ ERROR wrong types for suggestion
}

View File

@ -263,21 +263,29 @@ LL | | suggestion: Applicability,
| |
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
error: type of field annotated with `#[suggestion(...)]` contains more than one `Span` error: specified multiple times
--> $DIR/diagnostic-derive.rs:271:5 --> $DIR/diagnostic-derive.rs:272:24
| |
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | suggestion: (Span, Span, Applicability),
LL | | | ^^^^
LL | | suggestion: (Span, Span, Applicability), |
| |___________________________________________^ note: previously specified here
--> $DIR/diagnostic-derive.rs:272:18
|
LL | suggestion: (Span, Span, Applicability),
| ^^^^
error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability error: specified multiple times
--> $DIR/diagnostic-derive.rs:279:5 --> $DIR/diagnostic-derive.rs:280:33
| |
LL | / #[suggestion(typeck::suggestion, code = "This is suggested code")] LL | suggestion: (Applicability, Applicability, Span),
LL | | | ^^^^^^^^^^^^^
LL | | suggestion: (Applicability, Applicability, Span), |
| |____________________________________________________^ note: previously specified here
--> $DIR/diagnostic-derive.rs:280:18
|
LL | suggestion: (Applicability, Applicability, Span),
| ^^^^^^^^^^^^^
error: `#[label = ...]` is not a valid attribute error: `#[label = ...]` is not a valid attribute
--> $DIR/diagnostic-derive.rs:287:5 --> $DIR/diagnostic-derive.rs:287:5
@ -415,6 +423,22 @@ note: previously specified here
LL | #[suggestion(typeck::suggestion, code = "...", code = ",,,")] LL | #[suggestion(typeck::suggestion, code = "...", code = ",,,")]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
error: wrong types for suggestion
--> $DIR/diagnostic-derive.rs:597:24
|
LL | suggestion: (Span, usize),
| ^^^^^
|
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
error: wrong types for suggestion
--> $DIR/diagnostic-derive.rs:605:17
|
LL | suggestion: (Span,),
| ^^^^^^^
|
= help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
error: cannot find attribute `nonsense` in this scope error: cannot find attribute `nonsense` in this scope
--> $DIR/diagnostic-derive.rs:53:3 --> $DIR/diagnostic-derive.rs:53:3
| |
@ -471,7 +495,7 @@ LL | arg: impl IntoDiagnosticArg,
| ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
= note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 56 previous errors error: aborting due to 58 previous errors
Some errors have detailed explanations: E0277, E0425. Some errors have detailed explanations: E0277, E0425.
For more information about an error, try `rustc --explain E0277`. For more information about an error, try `rustc --explain E0277`.