Repository: rust-lang/rust
Pull request: Split AttributeParserError Diagnostic implementation into subfunctions

<!-- homu-ignore:start -->
<!--
If this PR is related to an unstable feature or an otherwise tracked effort,
please link to the relevant tracking issue here. If you don't know of a related
tracking issue or there are none, feel free to ignore this.

This PR will get automatically assigned to a reviewer. In case you would like
a specific user to review your work, you can assign it to them by using

    r? <reviewer name>
-->
Second commit alters the oracles a bit. I tried to blame the initial code to figure out why `ExpectedStringLiteral` was special cased but couldn't find anything. I think it is ok to remove this special case.
<!-- homu-ignore:end -->


Changed files:
filename: compiler/rustc_attr_parsing/src/session_diagnostics.rs
patch: @@ -594,29 +594,108 @@ pub(crate) struct AttributeParseError<'a> {
     pub(crate) suggestions: Vec<String>,
 }
 
+impl<'a> AttributeParseError<'a> {
+    fn render_expected_specific_argument<G>(
+        &self,
+        diag: &mut Diag<'_, G>,
+        possibilities: &[Symbol],
+        strings: bool,
+    ) where
+        G: EmissionGuarantee,
+    {
+        let quote = if strings { '"' } else { '`' };
+        match possibilities {
+            &[] => {}
+            &[x] => {
+                diag.span_label(
+                    self.span,
+                    format!("the only valid argument here is {quote}{x}{quote}"),
+                );
+            }
+            [first, second] => {
+                diag.span_label(
+                    self.span,
+                    format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"),
+                );
+            }
+            [first @ .., second_to_last, last] => {
+                let mut res = String::new();
+                for i in first {
+                    res.push_str(&format!("{quote}{i}{quote}, "));
+                }
+                res.push_str(&format!("{quote}{second_to_last}{quote} or {quote}{last}{quote}"));
+
+                diag.span_label(self.span, format!("valid arguments are {res}"));
+            }
+        }
+    }
+
+    fn render_expected_specific_argument_list<G>(
+        &self,
+        diag: &mut Diag<'_, G>,
+        possibilities: &[Symbol],
+        strings: bool,
+    ) where
+        G: EmissionGuarantee,
+    {
+        let description = self.description();
+
+        let quote = if strings { '"' } else { '`' };
+        match possibilities {
+            &[] => {}
+            &[x] => {
+                diag.span_label(
+                    self.span,
+                    format!(
+                        "this {description} is only valid with {quote}{x}{quote} as an argument"
+                    ),
+                );
+            }
+            [first, second] => {
+                diag.span_label(self.span, format!("this {description} is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
+            }
+            [first @ .., second_to_last, last] => {
+                let mut res = String::new();
+                for i in first {
+                    res.push_str(&format!("{quote}{i}{quote}, "));
+                }
+                res.push_str(&format!("{quote}{second_to_last}{quote} or {quote}{last}{quote}"));
+
+                diag.span_label(self.span, format!("this {description} is only valid with one of the following arguments: {res}"));
+            }
+        }
+    }
+
+    fn description(&self) -> &'static str {
+        match self.description {
+            ParsedDescription::Attribute => "attribute",
+            ParsedDescription::Macro => "macro",
+        }
+    }
+}
+
 impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
     fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
         let name = self.path.to_string();
 
-        let description = match self.description {
-            ParsedDescription::Attribute => "attribute",
-            ParsedDescription::Macro => "macro",
-        };
+        let description = self.description();
 
         let mut diag = Diag::new(dcx, level, format!("malformed `{name}` {description} input"));
         diag.span(self.attr_span);
         diag.code(E0539);
-        match self.reason {
+        match &self.reason {
             AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
                 if let Some(start_point_span) = byte_string {
                     diag.span_suggestion(
-                        start_point_span,
+                        *start_point_span,
                         "consider removing the prefix",
                         "",
                         Applicability::MaybeIncorrect,
                     );
                     diag.note("expected a normal string literal, not a byte string literal");
 
+                    // Avoid emitting an "attribute must be of the form" suggestion, as the
+                    // attribute is likely to be well-formed already.
                     return diag;
                 } else {
                     diag.span_label(self.span, "expected a string literal here");
@@ -693,62 +772,14 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
                 strings,
                 list: false,
             } => {
-                let quote = if strings { '"' } else { '`' };
-                match possibilities {
-                    &[] => {}
-                    &[x] => {
-                        diag.span_label(
-                            self.span,
-                            format!("the only valid argument here is {quote}{x}{quote}"),
-                        );
-                    }
-                    [first, second] => {
-                        diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
-                    }
-                    [first @ .., second_to_last, last] => {
-                        let mut res = String::new();
-                        for i in first {
-                            res.push_str(&format!("{quote}{i}{quote}, "));
-                        }
-                        res.push_str(&format!(
-                            "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
-                        ));
-
-                        diag.span_label(self.span, format!("valid arguments are {res}"));
-                    }
-                }
+                self.render_expected_specific_argument(&mut diag, *possibilities, *strings);
             }
             AttributeParseErrorReason::ExpectedSpecificArgument {
                 possibilities,
                 strings,
                 list: true,
             } => {
-                let quote = if strings { '"' } else { '`' };
-                match possibilities {
-                    &[] => {}
-                    &[x] => {
-                        diag.span_label(
-                            self.span,
-                            format!(
-                                "this {description} is only valid with {quote}{x}{quote} as an argument"
-                            ),
-                        );
-                    }
-                    [first, second] => {
-                        diag.span_label(self.span, format!("this {description} is only valid with either {quote}{first}{quote} or {quote}{second}{quote} as an argument"));
-                    }
-                    [first @ .., second_to_last, last] => {
-                        let mut res = String::new();
-                        for i in first {
-                            res.push_str(&format!("{quote}{i}{quote}, "));
-                        }
-                        res.push_str(&format!(
-                            "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
-                        ));
-
-                        diag.span_label(self.span, format!("this {description} is only valid with one of the following arguments: {res}"));
-                    }
-                }
+                self.render_expected_specific_argument_list(&mut diag, *possibilities, *strings);
             }
             AttributeParseErrorReason::ExpectedIdentifier => {
                 diag.span_label(self.span, "expected a valid identifier here");