Skip to content

Commit 368c4a3

Browse files
committed
Add style= parameter to suggestion attributes
1 parent 629a414 commit 368c4a3

File tree

5 files changed

+214
-18
lines changed

5 files changed

+214
-18
lines changed

compiler/rustc_macros/src/diagnostics/utils.rs

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ pub(super) fn build_suggestion_code(
472472
}
473473

474474
/// Possible styles for suggestion subdiagnostics.
475-
#[derive(Clone, Copy)]
475+
#[derive(Clone, Copy, PartialEq)]
476476
pub(super) enum SuggestionKind {
477477
/// `#[suggestion]`
478478
Normal,
@@ -489,10 +489,10 @@ impl FromStr for SuggestionKind {
489489

490490
fn from_str(s: &str) -> Result<Self, Self::Err> {
491491
match s {
492-
"" => Ok(SuggestionKind::Normal),
493-
"_short" => Ok(SuggestionKind::Short),
494-
"_hidden" => Ok(SuggestionKind::Hidden),
495-
"_verbose" => Ok(SuggestionKind::Verbose),
492+
"normal" => Ok(SuggestionKind::Normal),
493+
"short" => Ok(SuggestionKind::Short),
494+
"hidden" => Ok(SuggestionKind::Hidden),
495+
"verbose" => Ok(SuggestionKind::Verbose),
496496
_ => Err(()),
497497
}
498498
}
@@ -515,6 +515,16 @@ impl SuggestionKind {
515515
}
516516
}
517517
}
518+
519+
fn from_suffix(s: &str) -> Option<Self> {
520+
match s {
521+
"" => Some(SuggestionKind::Normal),
522+
"_short" => Some(SuggestionKind::Short),
523+
"_hidden" => Some(SuggestionKind::Hidden),
524+
"_verbose" => Some(SuggestionKind::Verbose),
525+
_ => None,
526+
}
527+
}
518528
}
519529

520530
/// Types of subdiagnostics that can be created using attributes
@@ -565,25 +575,40 @@ impl SubdiagnosticKind {
565575
let name = name.as_str();
566576

567577
let meta = attr.parse_meta()?;
578+
579+
let mut opt_suggestion_kind = None;
568580
let mut kind = match name {
569581
"label" => SubdiagnosticKind::Label,
570582
"note" => SubdiagnosticKind::Note,
571583
"help" => SubdiagnosticKind::Help,
572584
"warning" => SubdiagnosticKind::Warn,
573585
_ => {
574586
if let Some(suggestion_kind) =
575-
name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
587+
name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
576588
{
589+
if suggestion_kind != SuggestionKind::Normal {
590+
// Plain `#[suggestion]` can have a `style = "..."` attribute later, so don't set it here
591+
opt_suggestion_kind.set_once(suggestion_kind, attr.path.span().unwrap());
592+
}
593+
577594
SubdiagnosticKind::Suggestion {
578-
suggestion_kind,
595+
suggestion_kind: SuggestionKind::Normal,
579596
applicability: None,
580597
code_field: new_code_ident(),
581598
code_init: TokenStream::new(),
582599
}
583600
} else if let Some(suggestion_kind) =
584-
name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
601+
name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
585602
{
586-
SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None }
603+
if suggestion_kind != SuggestionKind::Normal {
604+
// Plain `#[multipart_suggestion]` can have a `style = "..."` attribute later, so don't set it here
605+
opt_suggestion_kind.set_once(suggestion_kind, attr.path.span().unwrap());
606+
}
607+
608+
SubdiagnosticKind::MultipartSuggestion {
609+
suggestion_kind: SuggestionKind::Normal,
610+
applicability: None,
611+
}
587612
} else {
588613
throw_invalid_attr!(attr, &meta);
589614
}
@@ -682,16 +707,37 @@ impl SubdiagnosticKind {
682707
});
683708
applicability.set_once(value, span);
684709
}
710+
(
711+
"style",
712+
SubdiagnosticKind::Suggestion { .. }
713+
| SubdiagnosticKind::MultipartSuggestion { .. },
714+
) => {
715+
let Some(value) = string_value else {
716+
invalid_nested_attr(attr, &nested_attr).emit();
717+
continue;
718+
};
719+
720+
let value = value.value().parse().unwrap_or_else(|()| {
721+
span_err(value.span().unwrap(), "invalid suggestion style")
722+
.help("valid styles are `normal`, `short`, `hidden` and `verbose`")
723+
.emit();
724+
SuggestionKind::Normal
725+
});
726+
727+
opt_suggestion_kind.set_once(value, span);
728+
}
685729

686730
// Invalid nested attribute
687731
(_, SubdiagnosticKind::Suggestion { .. }) => {
688732
invalid_nested_attr(attr, &nested_attr)
689-
.help("only `code` and `applicability` are valid nested attributes")
733+
.help(
734+
"only `style`, `code` and `applicability` are valid nested attributes",
735+
)
690736
.emit();
691737
}
692738
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
693739
invalid_nested_attr(attr, &nested_attr)
694-
.help("only `applicability` is a valid nested attributes")
740+
.help("only `style` and `applicability` are valid nested attributes")
695741
.emit()
696742
}
697743
_ => {
@@ -701,19 +747,32 @@ impl SubdiagnosticKind {
701747
}
702748

703749
match kind {
704-
SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
750+
SubdiagnosticKind::Suggestion {
751+
ref code_field,
752+
ref mut code_init,
753+
ref mut suggestion_kind,
754+
..
755+
} => {
756+
if let Some(kind) = opt_suggestion_kind.value() {
757+
*suggestion_kind = kind;
758+
}
759+
705760
*code_init = if let Some(init) = code.value() {
706761
init
707762
} else {
708763
span_err(span, "suggestion without `code = \"...\"`").emit();
709764
quote! { let #code_field = std::iter::empty(); }
710765
};
711766
}
767+
SubdiagnosticKind::MultipartSuggestion { ref mut suggestion_kind, .. } => {
768+
if let Some(kind) = opt_suggestion_kind.value() {
769+
*suggestion_kind = kind;
770+
}
771+
}
712772
SubdiagnosticKind::Label
713773
| SubdiagnosticKind::Note
714774
| SubdiagnosticKind::Help
715-
| SubdiagnosticKind::Warn
716-
| SubdiagnosticKind::MultipartSuggestion { .. } => {}
775+
| SubdiagnosticKind::Warn => {}
717776
}
718777

719778
Ok(Some((kind, slug)))

src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,10 @@ struct SuggestionsInvalidLiteral {
796796
//~^ ERROR `code = "..."`/`code(...)` must contain only string literals
797797
sub: Span,
798798
}
799+
800+
#[derive(Diagnostic)]
801+
#[diag(compiletest_example)]
802+
struct SuggestionStyleGood {
803+
#[suggestion(code = "", style = "hidden")]
804+
sub: Span,
805+
}

src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ error: `#[suggestion(nonsense = ...)]` is not a valid attribute
272272
LL | #[suggestion(nonsense = "bar")]
273273
| ^^^^^^^^^^^^^^^^
274274
|
275-
= help: only `code` and `applicability` are valid nested attributes
275+
= help: only `style`, `code` and `applicability` are valid nested attributes
276276

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

291291
error: suggestion without `code = "..."`
292292
--> $DIR/diagnostic-derive.rs:240:5

src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,3 +706,81 @@ struct BQ {
706706
span: Span,
707707
r#type: String,
708708
}
709+
710+
#[derive(Subdiagnostic)]
711+
#[suggestion(parser_add_paren, code = "")]
712+
struct SuggestionStyleDefault {
713+
#[primary_span]
714+
sub: Span,
715+
}
716+
717+
#[derive(Subdiagnostic)]
718+
#[suggestion(parser_add_paren, code = "", style = "short")]
719+
struct SuggestionStyleShort {
720+
#[primary_span]
721+
sub: Span,
722+
}
723+
724+
#[derive(Subdiagnostic)]
725+
#[suggestion(parser_add_paren, code = "", style = "hidden")]
726+
struct SuggestionStyleHidden {
727+
#[primary_span]
728+
sub: Span,
729+
}
730+
731+
#[derive(Subdiagnostic)]
732+
#[suggestion(parser_add_paren, code = "", style = "verbose")]
733+
struct SuggestionStyleVerbose {
734+
#[primary_span]
735+
sub: Span,
736+
}
737+
738+
#[derive(Subdiagnostic)]
739+
#[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
740+
//~^ ERROR specified multiple times
741+
//~| NOTE previously specified here
742+
struct SuggestionStyleTwice {
743+
#[primary_span]
744+
sub: Span,
745+
}
746+
747+
#[derive(Subdiagnostic)]
748+
#[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
749+
//~^ ERROR specified multiple times
750+
//~| NOTE previously specified here
751+
struct SuggestionStyleTwiceExplicit {
752+
#[primary_span]
753+
sub: Span,
754+
}
755+
756+
#[derive(Subdiagnostic)]
757+
#[suggestion(parser_add_paren, code = "", style = "foo")]
758+
//~^ ERROR invalid suggestion style
759+
struct SuggestionStyleInvalid1 {
760+
#[primary_span]
761+
sub: Span,
762+
}
763+
764+
#[derive(Subdiagnostic)]
765+
#[suggestion(parser_add_paren, code = "", style = 42)]
766+
//~^ ERROR `#[suggestion(style = ...)]` is not a valid attribute
767+
struct SuggestionStyleInvalid2 {
768+
#[primary_span]
769+
sub: Span,
770+
}
771+
772+
#[derive(Subdiagnostic)]
773+
#[suggestion(parser_add_paren, code = "", style)]
774+
//~^ ERROR `#[suggestion(style)]` is not a valid attribute
775+
struct SuggestionStyleInvalid3 {
776+
#[primary_span]
777+
sub: Span,
778+
}
779+
780+
#[derive(Subdiagnostic)]
781+
#[suggestion(parser_add_paren, code = "", style("foo"))]
782+
//~^ ERROR `#[suggestion(style(...))]` is not a valid attribute
783+
struct SuggestionStyleInvalid4 {
784+
#[primary_span]
785+
sub: Span,
786+
}

src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
320320
LL | #[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
321321
| ^^^^^^^^^^^^
322322
|
323-
= help: only `applicability` is a valid nested attributes
323+
= help: only `style` and `applicability` are valid nested attributes
324324

325325
error: multipart suggestion without any `#[suggestion_part(...)]` fields
326326
--> $DIR/subdiagnostic-derive.rs:536:1
@@ -445,6 +445,58 @@ error: `code = "..."`/`code(...)` must contain only string literals
445445
LL | #[suggestion_part(code = 3)]
446446
| ^^^^^^^^
447447

448+
error: specified multiple times
449+
--> $DIR/subdiagnostic-derive.rs:739:61
450+
|
451+
LL | #[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
452+
| ^^^^^^^^^^^^^^^^
453+
|
454+
note: previously specified here
455+
--> $DIR/subdiagnostic-derive.rs:739:43
456+
|
457+
LL | #[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
458+
| ^^^^^^^^^^^^^^^^
459+
460+
error: specified multiple times
461+
--> $DIR/subdiagnostic-derive.rs:748:50
462+
|
463+
LL | #[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
464+
| ^^^^^^^^^^^^^^^^
465+
|
466+
note: previously specified here
467+
--> $DIR/subdiagnostic-derive.rs:748:3
468+
|
469+
LL | #[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
470+
| ^^^^^^^^^^^^^^^^^
471+
472+
error: invalid suggestion style
473+
--> $DIR/subdiagnostic-derive.rs:757:51
474+
|
475+
LL | #[suggestion(parser_add_paren, code = "", style = "foo")]
476+
| ^^^^^
477+
|
478+
= help: valid styles are `normal`, `short`, `hidden` and `verbose`
479+
480+
error: `#[suggestion(style = ...)]` is not a valid attribute
481+
--> $DIR/subdiagnostic-derive.rs:765:43
482+
|
483+
LL | #[suggestion(parser_add_paren, code = "", style = 42)]
484+
| ^^^^^^^^^^
485+
486+
error: `#[suggestion(style)]` is not a valid attribute
487+
--> $DIR/subdiagnostic-derive.rs:773:43
488+
|
489+
LL | #[suggestion(parser_add_paren, code = "", style)]
490+
| ^^^^^
491+
|
492+
= help: a diagnostic slug must be the first argument to the attribute
493+
494+
error: `#[suggestion(style(...))]` is not a valid attribute
495+
--> $DIR/subdiagnostic-derive.rs:781:43
496+
|
497+
LL | #[suggestion(parser_add_paren, code = "", style("foo"))]
498+
| ^^^^^^^^^^^^
499+
448500
error: cannot find attribute `foo` in this scope
449501
--> $DIR/subdiagnostic-derive.rs:63:3
450502
|
@@ -505,6 +557,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
505557
LL | #[label(slug)]
506558
| ^^^^ not found in `rustc_errors::fluent`
507559

508-
error: aborting due to 72 previous errors
560+
error: aborting due to 78 previous errors
509561

510562
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)