From a1ef1e7a88a7c4853209d8b83f8e843ea18bf178 Mon Sep 17 00:00:00 2001 From: Trubnikov Sergey Date: Wed, 23 Nov 2022 09:17:54 +0000 Subject: [PATCH] reafactor: Better error reporting --- --- a/crates/evm-coder/procedural/src/abi_derive.rs +++ b/crates/evm-coder/procedural/src/abi_derive.rs @@ -2,129 +2,151 @@ pub(crate) fn impl_abi_macro(ast: &syn::DeriveInput) -> syn::Result { let name = &ast.ident; + match &ast.data { + syn::Data::Struct(ds) => expand_struct(ds, ast), + syn::Data::Enum(de) => expand_enum(de, ast), + syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")), + } +} - match &ast.data { - syn::Data::Struct(ds) => { - let docs = extract_docs(&ast.attrs)?; - let (is_named_fields, field_names, field_types, field_docs, params_count) = - match ds.fields { - syn::Fields::Named(ref fields) => Ok(( - true, - fields.named.iter().enumerate().map(map_field_to_name), - fields.named.iter().map(map_field_to_type), - fields.named.iter().map(map_field_to_doc), - fields.named.len(), - )), - syn::Fields::Unnamed(ref fields) => Ok(( - false, - fields.unnamed.iter().enumerate().map(map_field_to_name), - fields.unnamed.iter().map(map_field_to_type), - fields.unnamed.iter().map(map_field_to_doc), - fields.unnamed.len(), - )), - syn::Fields::Unit => { - Err(syn::Error::new(name.span(), "Unit structs not supported")) - } - }?; +fn expand_struct( + ds: &syn::DataStruct, + ast: &syn::DeriveInput, +) -> syn::Result { + let name = &ast.ident; + let docs = extract_docs(&ast.attrs)?; + let (is_named_fields, field_names, field_types, field_docs, params_count) = match ds.fields { + syn::Fields::Named(ref fields) => Ok(( + true, + fields.named.iter().enumerate().map(map_field_to_name), + fields.named.iter().map(map_field_to_type), + fields.named.iter().map(map_field_to_doc), + fields.named.len(), + )), + syn::Fields::Unnamed(ref fields) => Ok(( + false, + fields.unnamed.iter().enumerate().map(map_field_to_name), + fields.unnamed.iter().map(map_field_to_type), + fields.unnamed.iter().map(map_field_to_doc), + fields.unnamed.len(), + )), + syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")), + }?; + + if params_count == 0 { + return Err(syn::Error::new(name.span(), "Empty structs not supported")); + }; + + let tuple_type = tuple_type(field_types.clone()); + let tuple_ref_type = tuple_ref_type(field_types.clone()); + let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone()); + let tuple_names = tuple_names(is_named_fields, field_names.clone()); + let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone()); + + let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name); + let abi_type = impl_abi_type(name, tuple_type.clone()); + let abi_read = impl_abi_read(name, tuple_type, tuple_names, struct_from_tuple); + let abi_write = impl_abi_write(name, is_named_fields, tuple_ref_type, tuple_data); + let solidity_type = impl_solidity_type(name, field_types.clone(), params_count); + let solidity_type_name = impl_solidity_type_name(name, field_types.clone(), params_count); + let solidity_struct_collect = + impl_solidity_struct_collect(name, field_names, field_types, field_docs, &docs)?; - if params_count == 0 { - return Err(syn::Error::new(name.span(), "Empty structs not supported")); - }; + Ok(quote! { + #can_be_plcaed_in_vec + #abi_type + #abi_read + #abi_write + #solidity_type + #solidity_type_name + #solidity_struct_collect + }) +} - let tuple_type = tuple_type(field_types.clone()); - let tuple_ref_type = tuple_ref_type(field_types.clone()); - let tuple_data = tuple_data_as_ref(is_named_fields, field_names.clone()); - let tuple_names = tuple_names(is_named_fields, field_names.clone()); - let struct_from_tuple = struct_from_tuple(name, is_named_fields, field_names.clone()); +fn expand_enum( + de: &syn::DataEnum, + ast: &syn::DeriveInput, +) -> syn::Result { + let name = &ast.ident; + check_repr_u8(name, &ast.attrs)?; + check_option_validity(de)?; - let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name); - let abi_type = impl_abi_type(name, tuple_type.clone()); - let abi_read = impl_abi_read(name, tuple_type, tuple_names, struct_from_tuple); - let abi_write = impl_abi_write(name, is_named_fields, tuple_ref_type, tuple_data); - let solidity_type = impl_solidity_type(name, field_types.clone(), params_count); - let solidity_type_name = - impl_solidity_type_name(name, field_types.clone(), params_count); - let solidity_struct_collect = - impl_solidity_struct_collect(name, field_names, field_types, field_docs, &docs)?; + dbg!(&de); - Ok(quote! { - #can_be_plcaed_in_vec - #abi_type - #abi_read - #abi_write - #solidity_type - #solidity_type_name - #solidity_struct_collect - }) - } - syn::Data::Enum(de) => { - check_repr_u8(name, &ast.attrs)?; + Ok(quote!()) +} - dbg!(&de); - for f in de.variants.iter().filter_map(|v| { - if !v.fields.is_empty() { - Some(Err(syn::Error::new( - v.ident.span(), - "Enumeration parameters should not have fields", - ))) - } else if v.discriminant.is_some() { - Some(Err(syn::Error::new( - v.ident.span(), - "Enumeration options should not have an explicit specified value", - ))) - } else { - None - } - }) { - f?; - } - Ok(quote!()) +fn check_option_validity(de: &syn::DataEnum) -> syn::Result<()> { + for error in de.variants.iter().filter_map(|v| { + if !v.fields.is_empty() { + Some(Err(syn::Error::new( + v.ident.span(), + "Enumeration parameters should not have fields", + ))) + } else if v.discriminant.is_some() { + Some(Err(syn::Error::new( + v.ident.span(), + "Enumeration options should not have an explicit specified value", + ))) + } else { + None } - syn::Data::Union(_) => Err(syn::Error::new(name.span(), "Unions not supported")), + }) { + return error; } + + Ok(()) } fn check_repr_u8(name: &syn::Ident, attrs: &Vec) -> syn::Result<()> { - let repr_u8 = attrs - .iter() - .filter_map(|attr| { - if let Some(ps) = attr.path.segments.first() { - if ps.ident == "repr" { - let meta = match attr.parse_meta() { - Ok(meta) => meta, - Err(e) => return Some(Err(e)), - }; - let is_repr_u8 = match meta { - syn::Meta::List(p) => { - p.nested - .iter() - .filter(|nm| match nm { - syn::NestedMeta::Meta(m) => match m { - syn::Meta::Path(p) => { - p.segments.iter().filter(|ps| ps.ident == "u8").count() - == 1 + let mut has_repr = false; + for error in attrs.iter().filter_map(|attr| { + if let Some(ps) = attr.path.segments.first() { + if ps.ident == "repr" { + has_repr = true; + let meta = match attr.parse_meta() { + Ok(meta) => meta, + Err(e) => return Some(Err(e)), + }; + match meta { + syn::Meta::List(p) => { + for error in p.nested.iter().filter_map(|nm| match nm { + syn::NestedMeta::Meta(m) => match m { + syn::Meta::Path(p) => { + for i in p.segments.iter().filter_map(|ps| { + if ps.ident != "u8" { + Some(Err(syn::Error::new( + ps.ident.span(), + "Enum is not \"repr(u8)\"", + ))) + } else { + None } - _ => false, - }, - _ => false, - }) - .count() == 1 + }) { + return Some(i); + } + None + } + _ => None, + }, + _ => None, + }) { + return Some(error); } - _ => false, - }; - - if is_repr_u8 { - return Some(Ok(())); - }; - } + None::> + } + _ => None, + }; } - None::> - }) - .collect::>>()?; + } + None + }) { + return error; + } - if repr_u8.len() != 1 { + if !has_repr { return Err(syn::Error::new(name.span(), "Enum is not \"repr(u8)\"")); - }; + } Ok(()) } --- a/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr +++ b/crates/evm-coder/tests/build_failed/abi_derive_enum_generation.stderr @@ -5,10 +5,10 @@ | ^^^^^^^ error: Enum is not "repr(u8)" - --> tests/build_failed/abi_derive_enum_generation.rs:12:6 + --> tests/build_failed/abi_derive_enum_generation.rs:11:8 | -12 | enum NonReprU8 { - | ^^^^^^^^^ +11 | #[repr(u32)] + | ^^^ error: Enumeration parameters should not have fields --> tests/build_failed/abi_derive_enum_generation.rs:21:2 -- gitstuff