]> git.lizzy.rs Git - rust.git/commitdiff
macros: move suggestion type handling to fn
authorDavid Wood <david.wood@huawei.com>
Wed, 30 Mar 2022 02:08:58 +0000 (03:08 +0100)
committerDavid Wood <david.wood@huawei.com>
Tue, 5 Apr 2022 06:01:02 +0000 (07:01 +0100)
Move the handling of `Span` or `(Span, Applicability)` types in
`#[suggestion]` attributes to its own function.

Signed-off-by: David Wood <david.wood@huawei.com>
compiler/rustc_macros/src/session_diagnostic.rs

index b32eee6decc169fe2fd3743436379395f3d3c9a0..5e221875b108072c8a060bbd4b6a834263272fef 100644 (file)
@@ -430,74 +430,8 @@ fn generate_non_option_field_code(
                     | suggestion_kind @ "suggestion_short"
                     | suggestion_kind @ "suggestion_hidden"
                     | suggestion_kind @ "suggestion_verbose" => {
-                        // For suggest, we need to ensure we are running on a (Span,
-                        // Applicability) pair.
-                        let (span, applicability) = (|| match &info.ty {
-                            ty @ syn::Type::Path(..)
-                                if type_matches_path(ty, &["rustc_span", "Span"]) =>
-                            {
-                                let binding = &info.binding.binding;
-                                Ok((
-                                    quote!(*#binding),
-                                    quote!(rustc_errors::Applicability::Unspecified),
-                                ))
-                            }
-                            syn::Type::Tuple(tup) => {
-                                let mut span_idx = None;
-                                let mut applicability_idx = None;
-                                for (idx, elem) in tup.elems.iter().enumerate() {
-                                    if type_matches_path(elem, &["rustc_span", "Span"]) {
-                                        if span_idx.is_none() {
-                                            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"],
-                                    ) {
-                                        if applicability_idx.is_none() {
-                                            applicability_idx = Some(syn::Index::from(idx));
-                                        } else {
-                                            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 binding = &info.binding.binding;
-                                    let span = quote!(#binding.#span_idx);
-                                    let applicability = applicability_idx
-                                        .map(
-                                            |applicability_idx| quote!(#binding.#applicability_idx),
-                                        )
-                                        .unwrap_or_else(|| {
-                                            quote!(rustc_errors::Applicability::Unspecified)
-                                        });
-                                    return Ok((span, 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)")
-                                    }
-                                );
-                            }
-                            _ => throw_span_err!(
-                                info.span.unwrap(),
-                                "wrong field type for suggestion",
-                                |diag| {
-                                    diag.help("#[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)")
-                                }
-                            ),
-                        })()?;
-                        // Now read the key-value pairs.
+                        let (span, applicability) = self.span_and_applicability_of_ty(info)?;
+
                         let mut msg = None;
                         let mut code = None;
 
@@ -562,6 +496,65 @@ fn generate_non_option_field_code(
         })
     }
 
+    fn span_and_applicability_of_ty(
+        &self,
+        info: FieldInfo<'_>,
+    ) -> Result<(proc_macro2::TokenStream, proc_macro2::TokenStream), SessionDiagnosticDeriveError>
+    {
+        match &info.ty {
+            // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
+            ty @ syn::Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
+                let binding = &info.binding.binding;
+                Ok((quote!(*#binding), quote!(rustc_errors::Applicability::Unspecified)))
+            }
+            // If `ty` is `(Span, Applicability)` then return tokens accessing those.
+            syn::Type::Tuple(tup) => {
+                let mut span_idx = None;
+                let mut applicability_idx = None;
+
+                for (idx, elem) in tup.elems.iter().enumerate() {
+                    if type_matches_path(elem, &["rustc_span", "Span"]) {
+                        if span_idx.is_none() {
+                            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"]) {
+                        if applicability_idx.is_none() {
+                            applicability_idx = Some(syn::Index::from(idx));
+                        } else {
+                            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 binding = &info.binding.binding;
+                    let span = quote!(#binding.#span_idx);
+                    let applicability = applicability_idx
+                        .map(|applicability_idx| quote!(#binding.#applicability_idx))
+                        .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+
+                    return Ok((span, 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.
+            _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
+                diag.help("#[suggestion(...)] should be applied to fields of type `Span` or `(Span, Applicability)`")
+            }),
+        }
+    }
+
     /// In the strings in the attributes supplied to this macro, we want callers to be able to
     /// reference fields in the format string. For example:
     ///