Add style= parameter to suggestion attributes

This commit is contained in:
Xiretza
2022-10-20 20:28:24 +02:00
parent 629a414d7b
commit 368c4a35b9
5 changed files with 214 additions and 18 deletions

View File

@@ -472,7 +472,7 @@ pub(super) fn build_suggestion_code(
} }
/// Possible styles for suggestion subdiagnostics. /// Possible styles for suggestion subdiagnostics.
#[derive(Clone, Copy)] #[derive(Clone, Copy, PartialEq)]
pub(super) enum SuggestionKind { pub(super) enum SuggestionKind {
/// `#[suggestion]` /// `#[suggestion]`
Normal, Normal,
@@ -489,10 +489,10 @@ impl FromStr for SuggestionKind {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s { match s {
"" => Ok(SuggestionKind::Normal), "normal" => Ok(SuggestionKind::Normal),
"_short" => Ok(SuggestionKind::Short), "short" => Ok(SuggestionKind::Short),
"_hidden" => Ok(SuggestionKind::Hidden), "hidden" => Ok(SuggestionKind::Hidden),
"_verbose" => Ok(SuggestionKind::Verbose), "verbose" => Ok(SuggestionKind::Verbose),
_ => Err(()), _ => Err(()),
} }
} }
@@ -515,6 +515,16 @@ impl SuggestionKind {
} }
} }
} }
fn from_suffix(s: &str) -> Option<Self> {
match s {
"" => Some(SuggestionKind::Normal),
"_short" => Some(SuggestionKind::Short),
"_hidden" => Some(SuggestionKind::Hidden),
"_verbose" => Some(SuggestionKind::Verbose),
_ => None,
}
}
} }
/// Types of subdiagnostics that can be created using attributes /// Types of subdiagnostics that can be created using attributes
@@ -565,6 +575,8 @@ impl SubdiagnosticKind {
let name = name.as_str(); let name = name.as_str();
let meta = attr.parse_meta()?; let meta = attr.parse_meta()?;
let mut opt_suggestion_kind = None;
let mut kind = match name { let mut kind = match name {
"label" => SubdiagnosticKind::Label, "label" => SubdiagnosticKind::Label,
"note" => SubdiagnosticKind::Note, "note" => SubdiagnosticKind::Note,
@@ -572,18 +584,31 @@ impl SubdiagnosticKind {
"warning" => SubdiagnosticKind::Warn, "warning" => SubdiagnosticKind::Warn,
_ => { _ => {
if let Some(suggestion_kind) = if let Some(suggestion_kind) =
name.strip_prefix("suggestion").and_then(|s| s.parse().ok()) name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
{ {
if suggestion_kind != SuggestionKind::Normal {
// Plain `#[suggestion]` can have a `style = "..."` attribute later, so don't set it here
opt_suggestion_kind.set_once(suggestion_kind, attr.path.span().unwrap());
}
SubdiagnosticKind::Suggestion { SubdiagnosticKind::Suggestion {
suggestion_kind, suggestion_kind: SuggestionKind::Normal,
applicability: None, applicability: None,
code_field: new_code_ident(), code_field: new_code_ident(),
code_init: TokenStream::new(), code_init: TokenStream::new(),
} }
} else if let Some(suggestion_kind) = } else if let Some(suggestion_kind) =
name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok()) name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
{ {
SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None } if suggestion_kind != SuggestionKind::Normal {
// Plain `#[multipart_suggestion]` can have a `style = "..."` attribute later, so don't set it here
opt_suggestion_kind.set_once(suggestion_kind, attr.path.span().unwrap());
}
SubdiagnosticKind::MultipartSuggestion {
suggestion_kind: SuggestionKind::Normal,
applicability: None,
}
} else { } else {
throw_invalid_attr!(attr, &meta); throw_invalid_attr!(attr, &meta);
} }
@@ -682,16 +707,37 @@ impl SubdiagnosticKind {
}); });
applicability.set_once(value, span); applicability.set_once(value, span);
} }
(
"style",
SubdiagnosticKind::Suggestion { .. }
| SubdiagnosticKind::MultipartSuggestion { .. },
) => {
let Some(value) = string_value else {
invalid_nested_attr(attr, &nested_attr).emit();
continue;
};
let value = value.value().parse().unwrap_or_else(|()| {
span_err(value.span().unwrap(), "invalid suggestion style")
.help("valid styles are `normal`, `short`, `hidden` and `verbose`")
.emit();
SuggestionKind::Normal
});
opt_suggestion_kind.set_once(value, span);
}
// Invalid nested attribute // Invalid nested attribute
(_, SubdiagnosticKind::Suggestion { .. }) => { (_, SubdiagnosticKind::Suggestion { .. }) => {
invalid_nested_attr(attr, &nested_attr) invalid_nested_attr(attr, &nested_attr)
.help("only `code` and `applicability` are valid nested attributes") .help(
"only `style`, `code` and `applicability` are valid nested attributes",
)
.emit(); .emit();
} }
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => { (_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
invalid_nested_attr(attr, &nested_attr) invalid_nested_attr(attr, &nested_attr)
.help("only `applicability` is a valid nested attributes") .help("only `style` and `applicability` are valid nested attributes")
.emit() .emit()
} }
_ => { _ => {
@@ -701,7 +747,16 @@ impl SubdiagnosticKind {
} }
match kind { match kind {
SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => { SubdiagnosticKind::Suggestion {
ref code_field,
ref mut code_init,
ref mut suggestion_kind,
..
} => {
if let Some(kind) = opt_suggestion_kind.value() {
*suggestion_kind = kind;
}
*code_init = if let Some(init) = code.value() { *code_init = if let Some(init) = code.value() {
init init
} else { } else {
@@ -709,11 +764,15 @@ impl SubdiagnosticKind {
quote! { let #code_field = std::iter::empty(); } quote! { let #code_field = std::iter::empty(); }
}; };
} }
SubdiagnosticKind::MultipartSuggestion { ref mut suggestion_kind, .. } => {
if let Some(kind) = opt_suggestion_kind.value() {
*suggestion_kind = kind;
}
}
SubdiagnosticKind::Label SubdiagnosticKind::Label
| SubdiagnosticKind::Note | SubdiagnosticKind::Note
| SubdiagnosticKind::Help | SubdiagnosticKind::Help
| SubdiagnosticKind::Warn | SubdiagnosticKind::Warn => {}
| SubdiagnosticKind::MultipartSuggestion { .. } => {}
} }
Ok(Some((kind, slug))) Ok(Some((kind, slug)))

View File

@@ -796,3 +796,10 @@ struct SuggestionsInvalidLiteral {
//~^ ERROR `code = "..."`/`code(...)` must contain only string literals //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
sub: Span, sub: Span,
} }
#[derive(Diagnostic)]
#[diag(compiletest_example)]
struct SuggestionStyleGood {
#[suggestion(code = "", style = "hidden")]
sub: Span,
}

View File

@@ -272,7 +272,7 @@ error: `#[suggestion(nonsense = ...)]` is not a valid attribute
LL | #[suggestion(nonsense = "bar")] LL | #[suggestion(nonsense = "bar")]
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
| |
= help: only `code` and `applicability` are valid nested attributes = help: only `style`, `code` and `applicability` are valid nested attributes
error: suggestion without `code = "..."` error: suggestion without `code = "..."`
--> $DIR/diagnostic-derive.rs:231:5 --> $DIR/diagnostic-derive.rs:231:5
@@ -286,7 +286,7 @@ error: `#[suggestion(msg = ...)]` is not a valid attribute
LL | #[suggestion(msg = "bar")] LL | #[suggestion(msg = "bar")]
| ^^^^^^^^^^^ | ^^^^^^^^^^^
| |
= help: only `code` and `applicability` are valid nested attributes = help: only `style`, `code` and `applicability` are valid nested attributes
error: suggestion without `code = "..."` error: suggestion without `code = "..."`
--> $DIR/diagnostic-derive.rs:240:5 --> $DIR/diagnostic-derive.rs:240:5

View File

@@ -706,3 +706,81 @@ struct BQ {
span: Span, span: Span,
r#type: String, r#type: String,
} }
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "")]
struct SuggestionStyleDefault {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style = "short")]
struct SuggestionStyleShort {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style = "hidden")]
struct SuggestionStyleHidden {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style = "verbose")]
struct SuggestionStyleVerbose {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
//~^ ERROR specified multiple times
//~| NOTE previously specified here
struct SuggestionStyleTwice {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
//~^ ERROR specified multiple times
//~| NOTE previously specified here
struct SuggestionStyleTwiceExplicit {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style = "foo")]
//~^ ERROR invalid suggestion style
struct SuggestionStyleInvalid1 {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style = 42)]
//~^ ERROR `#[suggestion(style = ...)]` is not a valid attribute
struct SuggestionStyleInvalid2 {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style)]
//~^ ERROR `#[suggestion(style)]` is not a valid attribute
struct SuggestionStyleInvalid3 {
#[primary_span]
sub: Span,
}
#[derive(Subdiagnostic)]
#[suggestion(parser_add_paren, code = "", style("foo"))]
//~^ ERROR `#[suggestion(style(...))]` is not a valid attribute
struct SuggestionStyleInvalid4 {
#[primary_span]
sub: Span,
}

View File

@@ -320,7 +320,7 @@ error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
LL | #[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")] LL | #[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
| |
= help: only `applicability` is a valid nested attributes = help: only `style` and `applicability` are valid nested attributes
error: multipart suggestion without any `#[suggestion_part(...)]` fields error: multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive.rs:536:1 --> $DIR/subdiagnostic-derive.rs:536:1
@@ -445,6 +445,58 @@ error: `code = "..."`/`code(...)` must contain only string literals
LL | #[suggestion_part(code = 3)] LL | #[suggestion_part(code = 3)]
| ^^^^^^^^ | ^^^^^^^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:739:61
|
LL | #[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
| ^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:739:43
|
LL | #[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
| ^^^^^^^^^^^^^^^^
error: specified multiple times
--> $DIR/subdiagnostic-derive.rs:748:50
|
LL | #[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
| ^^^^^^^^^^^^^^^^
|
note: previously specified here
--> $DIR/subdiagnostic-derive.rs:748:3
|
LL | #[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
| ^^^^^^^^^^^^^^^^^
error: invalid suggestion style
--> $DIR/subdiagnostic-derive.rs:757:51
|
LL | #[suggestion(parser_add_paren, code = "", style = "foo")]
| ^^^^^
|
= help: valid styles are `normal`, `short`, `hidden` and `verbose`
error: `#[suggestion(style = ...)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:765:43
|
LL | #[suggestion(parser_add_paren, code = "", style = 42)]
| ^^^^^^^^^^
error: `#[suggestion(style)]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:773:43
|
LL | #[suggestion(parser_add_paren, code = "", style)]
| ^^^^^
|
= help: a diagnostic slug must be the first argument to the attribute
error: `#[suggestion(style(...))]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:781:43
|
LL | #[suggestion(parser_add_paren, code = "", style("foo"))]
| ^^^^^^^^^^^^
error: cannot find attribute `foo` in this scope error: cannot find attribute `foo` in this scope
--> $DIR/subdiagnostic-derive.rs:63:3 --> $DIR/subdiagnostic-derive.rs:63:3
| |
@@ -505,6 +557,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
LL | #[label(slug)] LL | #[label(slug)]
| ^^^^ not found in `rustc_errors::fluent` | ^^^^ not found in `rustc_errors::fluent`
error: aborting due to 72 previous errors error: aborting due to 78 previous errors
For more information about this error, try `rustc --explain E0425`. For more information about this error, try `rustc --explain E0425`.