Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prohibit NEAR function generics #980

Merged
merged 12 commits into from
Jan 23, 2023
8 changes: 3 additions & 5 deletions near-sdk-macros/src/core_impl/abi/abi_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ use crate::core_impl::{
};

pub fn generate(i: &ItemImplInfo) -> TokenStream2 {
let public_functions: Vec<&ImplItemMethodInfo> =
i.methods.iter().filter(|m| m.is_public || i.is_trait_impl).collect();
if public_functions.is_empty() {
if i.methods.is_empty() {
// Short-circuit if there are no public functions to export to ABI
return TokenStream2::new();
}

let functions: Vec<TokenStream2> = public_functions.iter().map(|m| m.abi_struct()).collect();
let first_function_name = &public_functions[0].attr_signature_info.ident;
let functions: Vec<TokenStream2> = i.methods.iter().map(|m| m.abi_struct()).collect();
let first_function_name = &i.methods[0].attr_signature_info.ident;
let near_abi_symbol = format_ident!("__near_abi_{}", first_function_name);
quote! {
#[cfg(not(target_arch = "wasm32"))]
Expand Down
6 changes: 3 additions & 3 deletions near-sdk-macros/src/core_impl/code_generator/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ mod tests {
#[warn(unused)]
pub fn method(&self) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = generate_ext_function(&method_info.attr_signature_info);

// Note: only whitelisted non-bindgen attributes are forwarded.
Expand All @@ -267,7 +267,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
pub fn method(&self, k: &String) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = generate_ext_function(&method_info.attr_signature_info);
let expected = quote!(
pub fn method(self, k: &String,) -> near_sdk::Promise {
Expand Down Expand Up @@ -298,7 +298,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
pub fn borsh_test(&mut self, #[serializer(borsh)] a: String) {}
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = generate_ext_function(&method_info.attr_signature_info);
let expected = quote!(
pub fn borsh_test(self, a: String,) -> near_sdk::Promise {
Expand Down
67 changes: 31 additions & 36 deletions near-sdk-macros/src/core_impl/code_generator/item_impl_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ impl ItemImplInfo {
pub fn wrapper_code(&self) -> TokenStream2 {
let mut res = TokenStream2::new();
for method in &self.methods {
if method.is_public || self.is_trait_impl {
res.extend(method.method_wrapper());
}
res.extend(method.method_wrapper());
}
res
}
Expand All @@ -20,10 +18,7 @@ impl ItemImplInfo {
match syn::parse::<Ident>(self.ty.to_token_stream().into()) {
Ok(n) => generate_ext_function_wrappers(
&n,
self.methods
.iter()
.filter(|m| m.is_public || self.is_trait_impl)
.map(|m| &m.attr_signature_info),
self.methods.iter().map(|m| &m.attr_signature_info),
),
Err(e) => syn::Error::new(self.ty.span(), e).to_compile_error(),
}
Expand All @@ -42,7 +37,7 @@ mod tests {
fn trait_implt() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("fn method(&self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, true, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -60,7 +55,7 @@ mod tests {
fn no_args_no_return_no_mut() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("pub fn method(&self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -78,7 +73,7 @@ mod tests {
fn owned_no_args_no_return_no_mut() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("pub fn method(self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -97,7 +92,7 @@ mod tests {
fn mut_owned_no_args_no_return() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("pub fn method(mut self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -115,7 +110,7 @@ mod tests {
fn no_args_no_return_mut() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("pub fn method(&mut self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -137,7 +132,7 @@ mod tests {
fn arg_no_return_no_mut() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("pub fn method(&self, k: u64) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -165,7 +160,7 @@ mod tests {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod =
syn::parse_str("pub fn method(&mut self, k: u64, m: Bar) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -198,7 +193,7 @@ mod tests {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod =
syn::parse_str("pub fn method(&mut self, k: u64, m: Bar) -> Option<u64> { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -234,7 +229,7 @@ mod tests {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod =
syn::parse_str("pub fn method(&self) -> &Option<u64> { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -255,7 +250,7 @@ mod tests {
fn arg_ref() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("pub fn method(&self, k: &u64) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -283,7 +278,7 @@ mod tests {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod =
syn::parse_str("pub fn method(&self, k: &mut u64) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -312,7 +307,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
#[private] pub fn method(&self, #[callback_unwrap] x: &mut u64, y: String, #[callback_unwrap] z: Vec<u8>) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -356,7 +351,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
#[private] pub fn method(&self, #[callback_unwrap] x: &mut u64, #[callback_unwrap] y: String) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -392,7 +387,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
#[private] pub fn method(&self, #[callback_result] x: &mut Result<u64, PromiseError>, #[callback_result] y: Result<String, PromiseError>) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -424,7 +419,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
#[private] pub fn method(&self, #[callback_vec] x: Vec<String>, y: String) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -466,7 +461,7 @@ mod tests {
#[init]
pub fn method(k: &mut u64) -> Self { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -502,7 +497,7 @@ mod tests {
#[init]
pub fn method(k: &mut u64) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
compile_error! { "Init methods must return the contract state" }
Expand All @@ -517,7 +512,7 @@ mod tests {
#[init(ignore_state)]
pub fn method(k: &mut u64) -> Self { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -551,7 +546,7 @@ mod tests {
#[payable]
pub fn method(k: &mut u64) -> Self { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -584,7 +579,7 @@ mod tests {
#[result_serializer(borsh)]
pub fn method(&mut self, #[serializer(borsh)] k: u64, #[serializer(borsh)]m: Bar) -> Option<u64> { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -620,7 +615,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
#[private] pub fn method(&self, #[callback_unwrap] #[serializer(borsh)] x: &mut u64, #[serializer(borsh)] y: String, #[callback_unwrap] #[serializer(json)] z: Vec<u8>) { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -661,7 +656,7 @@ mod tests {
fn no_args_no_return_mut_payable() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("#[payable] pub fn method(&mut self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -680,7 +675,7 @@ mod tests {
fn private_method() {
let impl_type: Type = syn::parse_str("Hello").unwrap();
let mut method: ImplItemMethod = syn::parse_str("#[private] pub fn private_method(&mut self) { }").unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -708,7 +703,7 @@ mod tests {
#[handle_result]
pub fn method(&self) -> Result<u64, &'static str> { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -738,7 +733,7 @@ mod tests {
#[result_serializer(borsh)]
pub fn method(&self) -> Result<u64, &'static str> { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -768,7 +763,7 @@ mod tests {
#[handle_result]
pub fn new() -> Result<Self, &'static str> { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand Down Expand Up @@ -799,7 +794,7 @@ mod tests {
#[handle_result]
pub fn new() -> Result<Self, &'static str> { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
#[cfg(target_arch = "wasm32")]
Expand All @@ -826,7 +821,7 @@ mod tests {
#[handle_result]
pub fn method(&self) -> &'static str { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
compile_error! {
Expand All @@ -842,7 +837,7 @@ mod tests {
let mut method: ImplItemMethod = parse_quote! {
pub fn method(&self) -> Result<u64, &'static str> { }
};
let method_info = ImplItemMethodInfo::new(&mut method, impl_type).unwrap();
let method_info = ImplItemMethodInfo::new(&mut method, false, impl_type).unwrap().unwrap();
let actual = method_info.method_wrapper();
let expected = quote!(
compile_error! {
Expand Down
39 changes: 21 additions & 18 deletions near-sdk-macros/src/core_impl/info_extractor/attr_sig_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::core_impl::utils;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::ToTokens;
use syn::spanned::Spanned;
use syn::{Attribute, Error, FnArg, Ident, Receiver, ReturnType, Signature};
use syn::{Attribute, Error, FnArg, GenericParam, Ident, Receiver, ReturnType, Signature};

/// Information extracted from method attributes and signature.
pub struct AttrSigInfo {
Expand Down Expand Up @@ -40,25 +40,28 @@ impl AttrSigInfo {
original_sig: &mut Signature,
source_type: &TokenStream2,
) -> syn::Result<Self> {
if original_sig.asyncness.is_some() {
return Err(Error::new(
original_sig.span(),
"Contract API is not allowed to be async.",
));
}
if original_sig.abi.is_some() {
return Err(Error::new(
original_sig.span(),
"Contract API is not allowed to have binary interface.",
));
let mut errors = vec![];
for generic in &original_sig.generics.params {
match generic {
GenericParam::Type(type_generic) => {
errors.push(Error::new(
type_generic.span(),
"Contract API is not allowed to have generics.",
));
}
GenericParam::Const(const_generic) => {
// `generic.span()` points to the `const` part of const generics, so we use `ident` explicitly.
itegulov marked this conversation as resolved.
Show resolved Hide resolved
errors.push(Error::new(
const_generic.ident.span(),
"Contract API is not allowed to have generics.",
));
}
_ => {}
}
}
if original_sig.variadic.is_some() {
return Err(Error::new(
original_sig.span(),
"Contract API is not allowed to have variadic arguments.",
));
if let Some(combined_errors) = errors.into_iter().reduce(|mut l, r| (l.combine(r), l).1) {
return Err(combined_errors);
}

let ident = original_sig.ident.clone();
let mut non_bindgen_attrs = vec![];
let mut args = vec![];
Expand Down
Loading