aboutsummaryrefslogtreecommitdiff
path: root/macros/src/injectable/macro_args.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-01-30 21:29:21 +0100
committerHampusM <hampus@hampusmat.com>2023-01-30 21:29:21 +0100
commit178267c701c233542078c09fe6b19802f9642dbd (patch)
tree3d3010806f6509c062ca86dbbbe9c3a6cd2fe547 /macros/src/injectable/macro_args.rs
parent17ca46e95af38a914197958bbcc1e759865b6005 (diff)
feat: improve macro error messages
Diffstat (limited to 'macros/src/injectable/macro_args.rs')
-rw-r--r--macros/src/injectable/macro_args.rs135
1 files changed, 97 insertions, 38 deletions
diff --git a/macros/src/injectable/macro_args.rs b/macros/src/injectable/macro_args.rs
index d730e0d..6582cc6 100644
--- a/macros/src/injectable/macro_args.rs
+++ b/macros/src/injectable/macro_args.rs
@@ -1,8 +1,10 @@
+use proc_macro2::Span;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
-use syn::{Token, TypePath};
+use syn::{Ident, Token, TypePath};
use crate::macro_flag::MacroFlag;
+use crate::util::error::diagnostic_error_enum;
use crate::util::iterator_ext::IteratorExt;
pub const INJECTABLE_MACRO_FLAGS: &[&str] =
@@ -14,9 +16,34 @@ pub struct InjectableMacroArgs
pub flags: Punctuated<MacroFlag, Token![,]>,
}
+impl InjectableMacroArgs
+{
+ pub fn check_flags(&self) -> Result<(), InjectableMacroArgsError>
+ {
+ for flag in &self.flags {
+ if !INJECTABLE_MACRO_FLAGS.contains(&flag.flag.to_string().as_str()) {
+ return Err(InjectableMacroArgsError::UnknownFlag {
+ flag_ident: flag.flag.clone(),
+ });
+ }
+ }
+
+ if let Some((dupe_flag_first, dupe_flag_second)) =
+ self.flags.iter().find_duplicate()
+ {
+ return Err(InjectableMacroArgsError::DuplicateFlag {
+ first_flag_ident: dupe_flag_first.flag.clone(),
+ last_flag_span: dupe_flag_second.flag.span(),
+ });
+ }
+
+ Ok(())
+ }
+}
+
impl Parse for InjectableMacroArgs
{
- fn parse(input: ParseStream) -> syn::Result<Self>
+ fn parse(input: ParseStream) -> Result<Self, syn::Error>
{
let input_fork = input.fork();
@@ -50,31 +77,33 @@ impl Parse for InjectableMacroArgs
let flags = Punctuated::<MacroFlag, Token![,]>::parse_terminated(input)?;
- for flag in &flags {
- let flag_str = flag.flag.to_string();
-
- if !INJECTABLE_MACRO_FLAGS.contains(&flag_str.as_str()) {
- return Err(input.error(format!(
- "Unknown flag '{}'. Expected one of [ {} ]",
- flag_str,
- INJECTABLE_MACRO_FLAGS.join(",")
- )));
- }
- }
-
- let flag_names = flags
- .iter()
- .map(|flag| flag.flag.to_string())
- .collect::<Vec<_>>();
-
- if let Some(dupe_flag_name) = flag_names.iter().find_duplicate() {
- return Err(input.error(format!("Duplicate flag '{dupe_flag_name}'")));
- }
-
Ok(Self { interface, flags })
}
}
+diagnostic_error_enum! {
+pub enum InjectableMacroArgsError
+{
+ #[error("Unknown flag '{flag_ident}'"), span = flag_ident.span()]
+ #[
+ help("Expected one of: {}", INJECTABLE_MACRO_FLAGS.join(", ")),
+ span = flag_ident.span()
+ ]
+ UnknownFlag
+ {
+ flag_ident: Ident
+ },
+
+ #[error("Duplicate flag '{first_flag_ident}'"), span = first_flag_ident.span()]
+ #[note("Previously mentioned here"), span = last_flag_span]
+ DuplicateFlag
+ {
+ first_flag_ident: Ident,
+ last_flag_span: Span
+ },
+}
+}
+
#[cfg(test)]
mod tests
{
@@ -188,30 +217,60 @@ mod tests
}
#[test]
- fn cannot_parse_with_invalid_flag()
+ fn can_parse_with_unknown_flag() -> Result<(), Box<dyn Error>>
{
let input_args = quote! {
IFoo, haha = true, async = false
};
- assert!(matches!(parse2::<InjectableMacroArgs>(input_args), Err(_)));
+ assert!(parse2::<InjectableMacroArgs>(input_args).is_ok());
+
+ Ok(())
}
#[test]
- fn cannot_parse_with_duplicate_flag()
+ fn can_parse_with_duplicate_flag()
{
- assert!(matches!(
- parse2::<InjectableMacroArgs>(quote! {
- IFoo, async = false, no_doc_hidden = true, async = false
- }),
- Err(_)
- ));
+ assert!(parse2::<InjectableMacroArgs>(quote! {
+ IFoo, async = false, no_doc_hidden = true, async = false
+ })
+ .is_ok());
+
+ assert!(parse2::<InjectableMacroArgs>(quote! {
+ IFoo, async = true , no_doc_hidden = true, async = false
+ })
+ .is_ok());
+ }
- assert!(matches!(
- parse2::<InjectableMacroArgs>(quote! {
- IFoo, async = true , no_doc_hidden = true, async = false
- }),
- Err(_)
- ));
+ #[test]
+ fn check_flags_fail_with_unknown_flag() -> Result<(), Box<dyn Error>>
+ {
+ let input_args = quote! {
+ IFoo, haha = true, async = false
+ };
+
+ let injectable_macro_args = parse2::<InjectableMacroArgs>(input_args)?;
+
+ assert!(injectable_macro_args.check_flags().is_err());
+
+ Ok(())
+ }
+
+ #[test]
+ fn check_flags_fail_with_duplicate_flag() -> Result<(), Box<dyn Error>>
+ {
+ let macro_args = parse2::<InjectableMacroArgs>(quote! {
+ IFoo, async = false, no_doc_hidden = true, async = false
+ })?;
+
+ assert!(macro_args.check_flags().is_err());
+
+ let macro_args_two = parse2::<InjectableMacroArgs>(quote! {
+ IFoo, async = true , no_doc_hidden = true, async = false
+ })?;
+
+ assert!(macro_args_two.check_flags().is_err());
+
+ Ok(())
}
}