about summary refs log tree commit diff
path: root/compiler/rustc_macros/src/diagnostics
diff options
context:
space:
mode:
authorDavid Wood <david.wood@huawei.com>2022-04-27 05:43:36 +0100
committerDavid Wood <david.wood@huawei.com>2022-04-29 02:12:10 +0100
commite5d9371b302ff0d368ea6e075769eb4b2709b2ba (patch)
tree6a5de85fdcd1e9a5286819c4d1b2bada3784cbb7 /compiler/rustc_macros/src/diagnostics
parente8ee0d7a20432bafaa59c04a9ad99c3b040d395f (diff)
downloadrust-e5d9371b302ff0d368ea6e075769eb4b2709b2ba.tar.gz
rust-e5d9371b302ff0d368ea6e075769eb4b2709b2ba.zip
macros: allow setting applicability in attribute
In the initial implementation of the `SessionSubdiagnostic`, the
`Applicability` of a suggestion can be set both as a field and as part
of the attribute, this commit adds the same support to the original
`SessionDiagnostic` derive.

Signed-off-by: David Wood <david.wood@huawei.com>
Diffstat (limited to 'compiler/rustc_macros/src/diagnostics')
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs39
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs44
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs43
3 files changed, 75 insertions, 51 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 032e0cecbc7..c163f233b47 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -5,12 +5,13 @@ use crate::diagnostics::error::{
     SessionDiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
-    option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, FieldInfo,
-    HasFieldMap, SetOnce,
+    option_inner_ty, report_error_if_not_applied_to_span, type_matches_path, Applicability,
+    FieldInfo, HasFieldMap, SetOnce,
 };
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
 use std::collections::HashMap;
+use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, Type};
 use synstructure::Structure;
 
@@ -430,7 +431,7 @@ impl SessionDiagnosticDeriveBuilder {
                     }),
                 };
 
-                let (span_, applicability) = self.span_and_applicability_of_ty(info)?;
+                let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
 
                 let mut msg = None;
                 let mut code = None;
@@ -445,6 +446,7 @@ impl SessionDiagnosticDeriveBuilder {
                     let nested_name = nested_name.as_str();
                     match meta {
                         Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                            let span = meta.span().unwrap();
                             match nested_name {
                                 "message" => {
                                     msg = Some(s.value());
@@ -453,9 +455,27 @@ impl SessionDiagnosticDeriveBuilder {
                                     let formatted_str = self.build_format(&s.value(), s.span());
                                     code = Some(formatted_str);
                                 }
+                                "applicability" => {
+                                    applicability = match applicability {
+                                        Some(v) => {
+                                            span_err(
+                                                span,
+                                                "applicability cannot be set in both the field and attribute"
+                                            ).emit();
+                                            Some(v)
+                                        }
+                                        None => match Applicability::from_str(&s.value()) {
+                                            Ok(v) => Some(quote! { #v }),
+                                            Err(()) => {
+                                                span_err(span, "invalid applicability").emit();
+                                                None
+                                            }
+                                        },
+                                    }
+                                }
                                 _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                                     diag.help(
-                                        "only `message` and `code` are valid field attributes",
+                                        "only `message`, `code` and `applicability` are valid field attributes",
                                     )
                                 }),
                             }
@@ -464,6 +484,9 @@ impl SessionDiagnosticDeriveBuilder {
                     }
                 }
 
+                let applicability = applicability
+                    .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+
                 let method = format_ident!("span_{}", name);
 
                 let slug = self
@@ -475,7 +498,7 @@ impl SessionDiagnosticDeriveBuilder {
                 let msg = quote! { rustc_errors::DiagnosticMessage::fluent_attr(#slug, #msg) };
                 let code = code.unwrap_or_else(|| quote! { String::new() });
 
-                Ok(quote! { #diag.#method(#span_, #msg, #code, #applicability); })
+                Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
             }
             _ => throw_invalid_attr!(attr, &meta),
         }
@@ -505,12 +528,12 @@ impl SessionDiagnosticDeriveBuilder {
     fn span_and_applicability_of_ty(
         &self,
         info: FieldInfo<'_>,
-    ) -> Result<(TokenStream, TokenStream), SessionDiagnosticDeriveError> {
+    ) -> Result<(TokenStream, Option<TokenStream>), SessionDiagnosticDeriveError> {
         match &info.ty {
             // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
             ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
                 let binding = &info.binding.binding;
-                Ok((quote!(*#binding), quote!(rustc_errors::Applicability::Unspecified)))
+                Ok((quote!(*#binding), None))
             }
             // If `ty` is `(Span, Applicability)` then return tokens accessing those.
             Type::Tuple(tup) => {
@@ -546,7 +569,7 @@ impl SessionDiagnosticDeriveBuilder {
                         .map(|applicability_idx| quote!(#binding.#applicability_idx))
                         .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
 
-                    return Ok((span, applicability));
+                    return Ok((span, Some(applicability)));
                 }
 
                 throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index e8c0bfd6651..961b42f424f 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -6,7 +6,7 @@ use crate::diagnostics::error::{
 };
 use crate::diagnostics::utils::{
     option_inner_ty, report_error_if_not_applied_to_applicability,
-    report_error_if_not_applied_to_span, FieldInfo, HasFieldMap, SetOnce,
+    report_error_if_not_applied_to_span, Applicability, FieldInfo, HasFieldMap, SetOnce,
 };
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
@@ -16,48 +16,6 @@ use std::str::FromStr;
 use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue};
 use synstructure::{BindingInfo, Structure, VariantInfo};
 
-/// `Applicability` of a suggestion - mirrors `rustc_errors::Applicability` - and used to represent
-/// the user's selection of applicability if specified in an attribute.
-enum Applicability {
-    MachineApplicable,
-    MaybeIncorrect,
-    HasPlaceholders,
-    Unspecified,
-}
-
-impl FromStr for Applicability {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "machine-applicable" => Ok(Applicability::MachineApplicable),
-            "maybe-incorrect" => Ok(Applicability::MaybeIncorrect),
-            "has-placeholders" => Ok(Applicability::HasPlaceholders),
-            "unspecified" => Ok(Applicability::Unspecified),
-            _ => Err(()),
-        }
-    }
-}
-
-impl quote::ToTokens for Applicability {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Applicability::MachineApplicable => {
-                quote! { rustc_errors::Applicability::MachineApplicable }
-            }
-            Applicability::MaybeIncorrect => {
-                quote! { rustc_errors::Applicability::MaybeIncorrect }
-            }
-            Applicability::HasPlaceholders => {
-                quote! { rustc_errors::Applicability::HasPlaceholders }
-            }
-            Applicability::Unspecified => {
-                quote! { rustc_errors::Applicability::Unspecified }
-            }
-        });
-    }
-}
-
 /// Which kind of suggestion is being created?
 #[derive(Clone, Copy)]
 enum SubdiagnosticSuggestionKind {
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 6791a9e35b8..1f36af0a20b 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -3,6 +3,7 @@ use proc_macro::Span;
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote};
 use std::collections::BTreeSet;
+use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Meta, Type, Visibility};
 use synstructure::BindingInfo;
 
@@ -222,3 +223,45 @@ pub(crate) trait HasFieldMap {
         }
     }
 }
+
+/// `Applicability` of a suggestion - mirrors `rustc_errors::Applicability` - and used to represent
+/// the user's selection of applicability if specified in an attribute.
+pub(crate) enum Applicability {
+    MachineApplicable,
+    MaybeIncorrect,
+    HasPlaceholders,
+    Unspecified,
+}
+
+impl FromStr for Applicability {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "machine-applicable" => Ok(Applicability::MachineApplicable),
+            "maybe-incorrect" => Ok(Applicability::MaybeIncorrect),
+            "has-placeholders" => Ok(Applicability::HasPlaceholders),
+            "unspecified" => Ok(Applicability::Unspecified),
+            _ => Err(()),
+        }
+    }
+}
+
+impl quote::ToTokens for Applicability {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend(match self {
+            Applicability::MachineApplicable => {
+                quote! { rustc_errors::Applicability::MachineApplicable }
+            }
+            Applicability::MaybeIncorrect => {
+                quote! { rustc_errors::Applicability::MaybeIncorrect }
+            }
+            Applicability::HasPlaceholders => {
+                quote! { rustc_errors::Applicability::HasPlaceholders }
+            }
+            Applicability::Unspecified => {
+                quote! { rustc_errors::Applicability::Unspecified }
+            }
+        });
+    }
+}