Skip to content

Commit 73cc020

Browse files
Scope generated fn code mod by contract type name (#1556)
### What Change the name of the generated code module that contains the generated functions for calling the contract, so that the name includes the contract type's name. ### Why Prevents naming conflicts between functions with the same name across different contract implementations. This is particularly helpful in tests and examples where a developer may legitimately define two contracts, that are intended to be used independently, but exist in the same namespace. Today those contracts will see a compile error if the contracts share the same name, which is much more of a common problem now that constructors exist and have a common name. This problem was reported by @ozgunozerk. ### Trying it out Edit your Cargo.toml to include the patch: ```toml [patch.crates-io.soroban-sdk] git = "https://github.com/stellar/rs-soroban-sdk" branch = "allow-coexisting-contractimpls-with-same-names" ```
1 parent 510d3fe commit 73cc020

11 files changed

Lines changed: 48 additions & 17 deletions

soroban-sdk-macros/src/derive_fn.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::{attribute::pass_through_attr_to_gen_code, map_type::map_type};
1+
use crate::{
2+
attribute::pass_through_attr_to_gen_code, map_type::map_type, syn_ext::ty_to_safe_ident_str,
3+
};
24
use itertools::MultiUnzip;
35
use proc_macro2::TokenStream as TokenStream2;
46
use quote::{format_ident, quote};
@@ -13,6 +15,7 @@ use syn::{
1315
#[allow(clippy::too_many_arguments)]
1416
pub fn derive_pub_fn(
1517
crate_path: &Path,
18+
impl_ty: &Type,
1619
call: &TokenStream2,
1720
ident: &Ident,
1821
attrs: &[Attribute],
@@ -97,8 +100,9 @@ pub fn derive_pub_fn(
97100
.multiunzip();
98101

99102
// Generated code parameters.
103+
let impl_ty_safe_str = ty_to_safe_ident_str(impl_ty);
100104
let wrap_export_name = &format!("{}", ident);
101-
let hidden_mod_ident = format_ident!("__{}", ident);
105+
let hidden_mod_ident = format_ident!("__{}__{}", impl_ty_safe_str, ident);
102106
let deprecated_note = format!(
103107
"use `{}::new(&env, &contract_id).{}` instead",
104108
client_ident, &ident
@@ -154,6 +158,7 @@ pub fn derive_pub_fn(
154158
Ok(quote! {
155159
#[doc(hidden)]
156160
#(#attrs)*
161+
#[allow(non_snake_case)]
157162
pub mod #hidden_mod_ident {
158163
use super::*;
159164

@@ -198,15 +203,15 @@ pub fn derive_contract_function_registration_ctor<'a>(
198203
return quote!();
199204
}
200205

206+
let ty_str = ty_to_safe_ident_str(ty);
201207
let (idents, wrap_idents): (Vec<_>, Vec<_>) = methods
202208
.map(|m| {
203209
let ident = format!("{}", m.sig.ident);
204-
let wrap_ident = format_ident!("__{}", m.sig.ident);
210+
let wrap_ident = format_ident!("__{}__{}", ty_str, ident);
205211
(ident, wrap_ident)
206212
})
207213
.multiunzip();
208214

209-
let ty_str = quote!(#ty).to_string().replace(' ', "").replace(':', "_");
210215
let trait_str = quote!(#trait_ident).to_string();
211216
let methods_hash = format!("{:x}", Sha256::digest(idents.join(",").as_bytes()));
212217
let ctor_ident = format_ident!("__{ty_str}_{trait_str}_{methods_hash}_ctor");

soroban-sdk-macros/src/derive_spec_fn.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use syn::{
1212
};
1313

1414
use crate::attribute::pass_through_attr_to_gen_code;
15+
use crate::syn_ext::ty_to_safe_ident_str;
1516
use crate::{doc::docs_from_attrs, map_type::map_type, DEFAULT_XDR_RW_LIMITS};
1617

1718
#[allow(clippy::too_many_arguments)]
@@ -173,14 +174,21 @@ pub fn derive_fn_spec(
173174
.filter(|attr| pass_through_attr_to_gen_code(attr))
174175
.collect::<Vec<_>>();
175176

177+
let ty_str = ty_to_safe_ident_str(ty);
178+
let hidden_mod_ident = format_ident!("__{}__{}__spec", ty_str, ident);
176179
let exported = if export {
177180
Some(quote! {
178181
#[doc(hidden)]
179-
#[allow(non_snake_case)]
180-
#[allow(non_upper_case_globals)]
181182
#(#attrs)*
182-
#[cfg_attr(target_family = "wasm", link_section = "contractspecv0")]
183-
pub static #spec_ident: [u8; #spec_xdr_len] = #ty::#spec_fn_ident();
183+
#[allow(non_snake_case)]
184+
pub mod #hidden_mod_ident {
185+
#[doc(hidden)]
186+
#[allow(non_snake_case)]
187+
#[allow(non_upper_case_globals)]
188+
#(#attrs)*
189+
#[cfg_attr(target_family = "wasm", link_section = "contractspecv0")]
190+
pub static #spec_ident: [u8; #spec_xdr_len] = super::#ty::#spec_fn_ident();
191+
}
184192
})
185193
} else {
186194
None

soroban-sdk-macros/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ pub fn contractimpl(metadata: TokenStream, input: TokenStream) -> TokenStream {
247247
let call = quote! { <super::#ty>::#ident };
248248
derive_pub_fn(
249249
crate_path,
250+
&ty,
250251
&call,
251252
ident,
252253
&m.attrs,

soroban-sdk-macros/src/syn_ext.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,7 @@ fn flatten_associated_items_in_impl_fns(imp: &mut ItemImpl) {
268268
}
269269
}
270270
}
271+
272+
pub fn ty_to_safe_ident_str(ty: &Type) -> String {
273+
quote!(#ty).to_string().replace(' ', "").replace(':', "_")
274+
}

soroban-sdk/src/tests/contract_add_i32.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn test_functional() {
2828

2929
#[test]
3030
fn test_spec() {
31-
let entries = ScSpecEntry::from_xdr(__SPEC_XDR_FN_ADD, Limits::none()).unwrap();
31+
let entries = ScSpecEntry::from_xdr(Contract::spec_xdr_add(), Limits::none()).unwrap();
3232
let expect = ScSpecEntry::FunctionV0(ScSpecFunctionV0 {
3333
doc: "".try_into().unwrap(),
3434
name: "add".try_into().unwrap(),

soroban-sdk/src/tests/contract_docs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ mod fn_ {
2525

2626
#[test]
2727
fn test_spec() {
28-
let entry = ScSpecEntry::from_xdr(__SPEC_XDR_FN_ADD, Limits::none()).unwrap();
28+
let entry = ScSpecEntry::from_xdr(Contract::spec_xdr_add(), Limits::none()).unwrap();
2929
let expect = ScSpecEntry::FunctionV0(ScSpecFunctionV0 {
3030
doc: "Add adds\nthings together.".try_into().unwrap(),
3131
name: "add".try_into().unwrap(),

soroban-sdk/src/tests/contract_duration.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ fn test_functional() {
2121

2222
#[test]
2323
fn test_spec() {
24-
let entries = xdr::ScSpecEntry::from_xdr(__SPEC_XDR_FN_EXEC, xdr::Limits::none()).unwrap();
24+
let entries =
25+
xdr::ScSpecEntry::from_xdr(Contract::spec_xdr_exec(), xdr::Limits::none()).unwrap();
2526
let expect = xdr::ScSpecEntry::FunctionV0(xdr::ScSpecFunctionV0 {
2627
doc: "".try_into().unwrap(),
2728
name: "exec".try_into().unwrap(),

soroban-sdk/src/tests/contract_fn.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ impl Contract {
1919
}
2020
}
2121

22+
#[contract]
23+
pub struct Contract2;
24+
25+
#[contractimpl]
26+
impl Contract2 {
27+
pub fn add(_e: &Env, a: i32, b: i32) -> i32 {
28+
a + b
29+
}
30+
}
31+
2232
#[test]
2333
fn test_functional() {
2434
let e = Env::default();
@@ -32,7 +42,7 @@ fn test_functional() {
3242

3343
#[test]
3444
fn test_spec() {
35-
let entries = ScSpecEntry::from_xdr(__SPEC_XDR_FN_ADD, Limits::none()).unwrap();
45+
let entries = ScSpecEntry::from_xdr(Contract::spec_xdr_add(), Limits::none()).unwrap();
3646
let expect = ScSpecEntry::FunctionV0(ScSpecFunctionV0 {
3747
doc: "".try_into().unwrap(),
3848
name: "add".try_into().unwrap(),
@@ -57,7 +67,8 @@ fn test_spec() {
5767

5868
#[test]
5969
fn test_spec_with_unused_arg() {
60-
let entries = ScSpecEntry::from_xdr(__SPEC_XDR_FN_ADD_WITH_UNUSED_ARG, Limits::none()).unwrap();
70+
let entries =
71+
ScSpecEntry::from_xdr(Contract::spec_xdr_add_with_unused_arg(), Limits::none()).unwrap();
6172
let expect = ScSpecEntry::FunctionV0(ScSpecFunctionV0 {
6273
doc: "".try_into().unwrap(),
6374
name: "add_with_unused_arg".try_into().unwrap(),

soroban-sdk/src/tests/contract_timepoint.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ fn test_functional() {
2121

2222
#[test]
2323
fn test_spec() {
24-
let entries = xdr::ScSpecEntry::from_xdr(__SPEC_XDR_FN_EXEC, xdr::Limits::none()).unwrap();
24+
let entries =
25+
xdr::ScSpecEntry::from_xdr(Contract::spec_xdr_exec(), xdr::Limits::none()).unwrap();
2526
let expect = xdr::ScSpecEntry::FunctionV0(xdr::ScSpecFunctionV0 {
2627
doc: "".try_into().unwrap(),
2728
name: "exec".try_into().unwrap(),

soroban-sdk/src/tests/contract_udt_struct.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ fn test_error_on_partial_decode() {
127127

128128
#[test]
129129
fn test_spec() {
130-
let entries = ScSpecEntry::from_xdr(__SPEC_XDR_FN_ADD, Limits::none()).unwrap();
130+
let entries = ScSpecEntry::from_xdr(Contract::spec_xdr_add(), Limits::none()).unwrap();
131131
let expect = ScSpecEntry::FunctionV0(ScSpecFunctionV0 {
132132
doc: "".try_into().unwrap(),
133133
name: "add".try_into().unwrap(),
@@ -170,7 +170,7 @@ fn test_spec() {
170170
#[test]
171171
fn test_spec_with_long_names() {
172172
let entries =
173-
ScSpecEntry::from_xdr(__SPEC_XDR_FN_ADD_UDT_WITH_LONG_NAME, Limits::none()).unwrap();
173+
ScSpecEntry::from_xdr(Contract::spec_xdr_add_udt_with_long_name(), Limits::none()).unwrap();
174174
let expect = ScSpecEntry::FunctionV0(ScSpecFunctionV0 {
175175
doc: "".try_into().unwrap(),
176176
name: "add_udt_with_long_name".try_into().unwrap(),

0 commit comments

Comments
 (0)