about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david.wood@huawei.com>2022-03-30 03:08:58 +0100
committerDavid Wood <david.wood@huawei.com>2022-04-05 07:01:02 +0100
commit8677fef192a1d121b9123aa481422505833b57fe (patch)
tree578f640f1ea3afea288717b5cce32e696fda2e1c
parent2bf64d64832be674f26fa6e92740ac71c00c2ee5 (diff)
downloadrust-8677fef192a1d121b9123aa481422505833b57fe.tar.gz
rust-8677fef192a1d121b9123aa481422505833b57fe.zip
macros: move suggestion type handling to fn
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>
-rw-r--r--compiler/rustc_macros/src/session_diagnostic.rs129
1 files changed, 61 insertions, 68 deletions
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs
index b32eee6decc..5e221875b10 100644
--- a/compiler/rustc_macros/src/session_diagnostic.rs
+++ b/compiler/rustc_macros/src/session_diagnostic.rs
@@ -430,74 +430,8 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
                     | 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 @@ impl<'a> SessionDiagnosticDeriveBuilder<'a> {
         })
     }
 
+    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:
     ///