about summary refs log tree commit diff
diff options
context:
space:
mode:
authorXiretza <xiretza@xiretza.xyz>2022-10-20 20:28:24 +0200
committerXiretza <xiretza@xiretza.xyz>2022-10-26 15:04:09 +0200
commit368c4a35b9acd7c66400855b9d2d4dfff016220b (patch)
tree73d32cca74e6f04b806bcafad5a00787d0570fc6
parent629a414d7ba4caa3ca28b0a46c478e2ecb4c0059 (diff)
downloadrust-368c4a35b9acd7c66400855b9d2d4dfff016220b.tar.gz
rust-368c4a35b9acd7c66400855b9d2d4dfff016220b.zip
Add style= parameter to suggestion attributes
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs87
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs7
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr4
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs78
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr56
5 files changed, 214 insertions, 18 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 374c795d0a6..aaeb0e1aba9 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -472,7 +472,7 @@ pub(super) fn build_suggestion_code(
 }
 
 /// Possible styles for suggestion subdiagnostics.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 pub(super) enum SuggestionKind {
     /// `#[suggestion]`
     Normal,
@@ -489,10 +489,10 @@ impl FromStr for SuggestionKind {
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
-            "" => Ok(SuggestionKind::Normal),
-            "_short" => Ok(SuggestionKind::Short),
-            "_hidden" => Ok(SuggestionKind::Hidden),
-            "_verbose" => Ok(SuggestionKind::Verbose),
+            "normal" => Ok(SuggestionKind::Normal),
+            "short" => Ok(SuggestionKind::Short),
+            "hidden" => Ok(SuggestionKind::Hidden),
+            "verbose" => Ok(SuggestionKind::Verbose),
             _ => 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
@@ -565,6 +575,8 @@ impl SubdiagnosticKind {
         let name = name.as_str();
 
         let meta = attr.parse_meta()?;
+
+        let mut opt_suggestion_kind = None;
         let mut kind = match name {
             "label" => SubdiagnosticKind::Label,
             "note" => SubdiagnosticKind::Note,
@@ -572,18 +584,31 @@ impl SubdiagnosticKind {
             "warning" => SubdiagnosticKind::Warn,
             _ => {
                 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 {
-                        suggestion_kind,
+                        suggestion_kind: SuggestionKind::Normal,
                         applicability: None,
                         code_field: new_code_ident(),
                         code_init: TokenStream::new(),
                     }
                 } 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 {
                     throw_invalid_attr!(attr, &meta);
                 }
@@ -682,16 +707,37 @@ impl SubdiagnosticKind {
                     });
                     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
                 (_, SubdiagnosticKind::Suggestion { .. }) => {
                     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();
                 }
                 (_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
                     invalid_nested_attr(attr, &nested_attr)
-                        .help("only `applicability` is a valid nested attributes")
+                        .help("only `style` and `applicability` are valid nested attributes")
                         .emit()
                 }
                 _ => {
@@ -701,7 +747,16 @@ impl SubdiagnosticKind {
         }
 
         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() {
                     init
                 } else {
@@ -709,11 +764,15 @@ impl SubdiagnosticKind {
                     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::Note
             | SubdiagnosticKind::Help
-            | SubdiagnosticKind::Warn
-            | SubdiagnosticKind::MultipartSuggestion { .. } => {}
+            | SubdiagnosticKind::Warn => {}
         }
 
         Ok(Some((kind, slug)))
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index ca77e483d6f..6cd76582795 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -796,3 +796,10 @@ struct SuggestionsInvalidLiteral {
     //~^ ERROR `code = "..."`/`code(...)` must contain only string literals
     sub: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionStyleGood {
+    #[suggestion(code = "", style = "hidden")]
+    sub: Span,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 859c272b6ba..5a0948e4dcb 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -272,7 +272,7 @@ error: `#[suggestion(nonsense = ...)]` is not a valid attribute
 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 = "..."`
   --> $DIR/diagnostic-derive.rs:231:5
@@ -286,7 +286,7 @@ error: `#[suggestion(msg = ...)]` is not a valid attribute
 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 = "..."`
   --> $DIR/diagnostic-derive.rs:240:5
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
index efec85eb52c..9a1a57e2eaf 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs
@@ -706,3 +706,81 @@ struct BQ {
     span: Span,
     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,
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index a85a8711eac..d5e136fa40c 100644
--- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -320,7 +320,7 @@ error: `#[multipart_suggestion(code = ...)]` is not a valid attribute
 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
   --> $DIR/subdiagnostic-derive.rs:536:1
@@ -445,6 +445,58 @@ error: `code = "..."`/`code(...)` must contain only string literals
 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
   --> $DIR/subdiagnostic-derive.rs:63:3
    |
@@ -505,6 +557,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent`
 LL | #[label(slug)]
    |         ^^^^ 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`.