From 6de51082ba132509b700946402e8995aada5938b Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Tue, 21 Jan 2020 02:23:17 +0300 Subject: [PATCH 1/3] Make error messages point to the origin location --- Cargo.toml | 1 + src/generate.rs | 10 +++++++--- src/lib.rs | 15 ++++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3da36c5..20a1c5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,4 @@ proc-macro = true quote = "1" syn = "1" proc-macro2 = { version = "1", default-features = false } +proc-macro-error = "0.4" diff --git a/src/generate.rs b/src/generate.rs index e5da6da..57eb7ac 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -1,6 +1,7 @@ use proc_macro2::TokenStream as TokenStream2; use proc_macro2::{Ident, Span}; -use syn::{self, Field, Lit, Meta, MetaNameValue, Visibility}; +use syn::{self, spanned::Spanned, Field, Lit, Meta, MetaNameValue, Visibility}; +use proc_macro_error::abort; pub struct GenParams { pub attribute_name: &'static str, @@ -38,7 +39,10 @@ pub fn parse_visibility(attr: Option<&Meta>, meta_name: &str) -> Option TokenStre let field_name = field .clone() .ident - .expect("Expected the field to have a name"); + .unwrap_or_else(|| abort!(field.span(), "Expected the field to have a name")); let fn_name = Ident::new( &format!( diff --git a/src/lib.rs b/src/lib.rs index eca7881..3be3cee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,14 +149,16 @@ extern crate proc_macro2; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use syn::{DataStruct, DeriveInput, Meta}; +use proc_macro_error::{proc_macro_error, abort_call_site, ResultExt}; mod generate; use crate::generate::{GenMode, GenParams}; #[proc_macro_derive(Getters, attributes(get, with_prefix))] +#[proc_macro_error] pub fn getters(input: TokenStream) -> TokenStream { // Parse the string representation - let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for getters"); + let ast: DeriveInput = syn::parse(input).expect_or_abort("Couldn't parse for getters"); let params = GenParams { attribute_name: "get", fn_name_prefix: "", @@ -172,9 +174,10 @@ pub fn getters(input: TokenStream) -> TokenStream { } #[proc_macro_derive(CopyGetters, attributes(get_copy, with_prefix))] +#[proc_macro_error] pub fn copy_getters(input: TokenStream) -> TokenStream { // Parse the string representation - let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for getters"); + let ast: DeriveInput = syn::parse(input).expect_or_abort("Couldn't parse for getters"); let params = GenParams { attribute_name: "get_copy", fn_name_prefix: "", @@ -190,9 +193,10 @@ pub fn copy_getters(input: TokenStream) -> TokenStream { } #[proc_macro_derive(MutGetters, attributes(get_mut))] +#[proc_macro_error] pub fn mut_getters(input: TokenStream) -> TokenStream { // Parse the string representation - let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for getters"); + let ast: DeriveInput = syn::parse(input).expect_or_abort("Couldn't parse for getters"); let params = GenParams { attribute_name: "get_mut", fn_name_prefix: "", @@ -207,9 +211,10 @@ pub fn mut_getters(input: TokenStream) -> TokenStream { } #[proc_macro_derive(Setters, attributes(set))] +#[proc_macro_error] pub fn setters(input: TokenStream) -> TokenStream { // Parse the string representation - let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for setters"); + let ast: DeriveInput = syn::parse(input).expect_or_abort("Couldn't parse for setters"); let params = GenParams { attribute_name: "set", fn_name_prefix: "set_", @@ -257,6 +262,6 @@ fn produce(ast: &DeriveInput, mode: &GenMode, params: &GenParams) -> TokenStream } } else { // Nope. This is an Enum. We cannot handle these! - panic!("#[derive(Getters)] is only defined for structs, not for enums!"); + abort_call_site!("#[derive(Getters)] is only defined for structs, not for enums!"); } } From 7b0ee0559954411436896d373f7b5971c2f6ae2d Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Mon, 13 Jan 2020 12:48:03 +0300 Subject: [PATCH 2/3] Do not fail on non-"meta" attributes --- src/generate.rs | 8 ++++---- src/lib.rs | 10 ++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/generate.rs b/src/generate.rs index 57eb7ac..4dad977 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -57,8 +57,8 @@ fn has_prefix_attr(f: &Field) -> bool { let inner = f .attrs .iter() - .filter_map(|v| { - let meta = v.parse_meta().expect("Could not get attribute"); + .filter_map(|v| v.parse_meta().ok()) + .filter_map(|meta| { if ["get", "get_copy"] .iter() .any(|ident| meta.path().is_ident(ident)) @@ -108,8 +108,8 @@ pub fn implement(field: &Field, mode: &GenMode, params: &GenParams) -> TokenStre let attr = field .attrs .iter() - .filter_map(|v| { - let meta = v.parse_meta().expect("attribute"); + .filter_map(|v| v.parse_meta().ok().map(|meta| (v, meta))) + .filter_map(|(v, meta)| { if meta.path().is_ident("doc") { doc.push(v); None diff --git a/src/lib.rs b/src/lib.rs index 3be3cee..f24c2b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -232,14 +232,8 @@ pub fn setters(input: TokenStream) -> TokenStream { fn parse_global_attr(attrs: &[syn::Attribute], attribute_name: &str) -> Option { attrs .iter() - .filter_map(|v| { - let meta = v.parse_meta().expect("attribute"); - if meta.path().is_ident(attribute_name) { - Some(meta) - } else { - None - } - }) + .filter_map(|v| v.parse_meta().ok()) // non "meta" attributes are not our concern + .filter(|meta| meta.path().is_ident(attribute_name)) .last() } From a04a903897864a12d784d143892664e33a4fba71 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Tue, 21 Jan 2020 02:30:14 +0300 Subject: [PATCH 3/3] cargo fmt --all --- src/generate.rs | 22 +++++++--------------- src/lib.rs | 2 +- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/generate.rs b/src/generate.rs index 4dad977..4e73bf2 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -1,7 +1,7 @@ use proc_macro2::TokenStream as TokenStream2; use proc_macro2::{Ident, Span}; -use syn::{self, spanned::Spanned, Field, Lit, Meta, MetaNameValue, Visibility}; use proc_macro_error::abort; +use syn::{self, spanned::Spanned, Field, Lit, Meta, MetaNameValue, Visibility}; pub struct GenParams { pub attribute_name: &'static str, @@ -36,13 +36,10 @@ pub fn parse_visibility(attr: Option<&Meta>, meta_name: &str) -> Option { if path.is_ident(meta_name) { - s.value() - .split(' ') - .find(|v| *v != "with_prefix") - .map(|v| { - syn::parse_str(v) - .unwrap_or_else(|_| abort!(s.span(), "invalid visibility found")) - }) + s.value().split(' ').find(|v| *v != "with_prefix").map(|v| { + syn::parse_str(v) + .unwrap_or_else(|_| abort!(s.span(), "invalid visibility found")) + }) } else { None } @@ -58,15 +55,10 @@ fn has_prefix_attr(f: &Field) -> bool { .attrs .iter() .filter_map(|v| v.parse_meta().ok()) - .filter_map(|meta| { - if ["get", "get_copy"] + .filter(|meta| { + ["get", "get_copy"] .iter() .any(|ident| meta.path().is_ident(ident)) - { - Some(meta) - } else { - None - } }) .last(); match inner { diff --git a/src/lib.rs b/src/lib.rs index f24c2b5..cfba310 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,8 +148,8 @@ extern crate proc_macro2; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; +use proc_macro_error::{abort_call_site, proc_macro_error, ResultExt}; use syn::{DataStruct, DeriveInput, Meta}; -use proc_macro_error::{proc_macro_error, abort_call_site, ResultExt}; mod generate; use crate::generate::{GenMode, GenParams};