Skip to content

Normalize raw identifiers (r#) in contract macros#1837

Merged
leighmcculloch merged 6 commits into
mainfrom
support-raw-identifiers
Apr 24, 2026
Merged

Normalize raw identifiers (r#) in contract macros#1837
leighmcculloch merged 6 commits into
mainfrom
support-raw-identifiers

Conversation

@mootz12
Copy link
Copy Markdown
Contributor

@mootz12 mootz12 commented Apr 20, 2026

What

Normalizes raw identifiers (r#) across the Soroban macros so that every name, generated Rust ident, and downstream comparison/sort key uses the unraw'd form of a user's Ident.

For tokens that must refer back to the user's field / variant / fn, the raw Ident is preserved, so it remains valid Rust.

Why

Fixes #1836

Known limitations

None

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR normalizes Rust raw identifiers (r#...) in Soroban SDK macros so that all Soroban-facing names (spec XDR, exported WASM names, client symbols, generated internal idents, and sort keys) use the unraw form, preventing invalid identifiers and runtime failures when contracts use keyword-colliding names.

Changes:

  • Introduces IdentExt::soroban_name() in soroban-sdk-macros and routes Soroban-facing naming through it.
  • Updates multiple derive paths (spec generation, export names, client filtering, internal generated identifiers, and sort keys) to use normalized names while preserving the original Ident where Rust token emission requires it.
  • Adds a new raw-identifier-focused test module and corresponding test snapshot.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
soroban-sdk-macros/src/syn_ext.rs Adds IdentExt::soroban_name() helper for unraw identifier normalization.
soroban-sdk-macros/src/derive_struct.rs Normalizes struct spec/type names and sort keys to use unraw names.
soroban-sdk-macros/src/derive_struct_tuple.rs Normalizes tuple-struct spec/type names and generated spec ident names.
soroban-sdk-macros/src/derive_enum.rs Normalizes enum spec/type names and case names for Soroban-facing output.
soroban-sdk-macros/src/derive_enum_int.rs Normalizes int-enum spec/type names and case names.
soroban-sdk-macros/src/derive_error_enum_int.rs Normalizes error-enum spec/type names and case names.
soroban-sdk-macros/src/derive_event.rs Normalizes event names/params and ensures generated code uses original idents for field access.
soroban-sdk-macros/src/derive_spec_fn.rs Normalizes function/arg names in spec, special-cases __check_auth via unraw comparison, and fixes generated spec identifiers.
soroban-sdk-macros/src/derive_fn.rs Normalizes export names and generated internal identifiers for contract functions.
soroban-sdk-macros/src/derive_client.rs Filters/reserves __* functions based on Soroban-facing name and normalizes try_* method generation.
soroban-sdk/src/tests.rs Registers new raw-identifier test module.
soroban-sdk/src/tests/contract_udt_raw_identifier.rs Adds functional and spec assertions covering raw identifiers across types, events, and functions.
soroban-sdk/test_snapshots/tests/contract_udt_raw_identifier/test_functional.1.json Adds snapshot capturing observable behavior for the new test.

Comment thread soroban-sdk-macros/src/derive_fn.rs
Comment thread soroban-sdk/src/tests/contract_udt_raw_identifier.rs
Comment thread soroban-sdk-macros/src/derive_fn.rs Outdated
Copy link
Copy Markdown
Member

@leighmcculloch leighmcculloch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is focused on functions, and other soroban spec emtities, and introduces the bespoke 'soroban_name', but I think what it is addressing is the more general problem that whenever composing Ident's or getting their string value we should be .unraw(). And that applies to more than just soroban types but Ident usage in general.

So I think we should start calling .unraw() instead of .to_string() everywhere Ident's are used.

Thoughts?

@mootz12
Copy link
Copy Markdown
Contributor Author

mootz12 commented Apr 21, 2026

This change is focused on functions, and other soroban spec emtities, and introduces the bespoke 'soroban_name', but I think what it is addressing is the more general problem that whenever composing Ident's or getting their string value we should be .unraw(). And that applies to more than just soroban types but Ident usage in general.

So I think we should start calling .unraw() instead of .to_string() everywhere Ident's are used.

Thoughts?

Yeah, good call. Updated this to just be a blanket update to Ident usage to ensure we properly use unraw and format_ident! everywhere.

@mootz12 mootz12 requested a review from leighmcculloch April 21, 2026 20:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Normalizes handling of Rust raw identifiers (r#...) across Soroban SDK macros so Soroban-facing names (spec entries, symbols, sort keys) consistently use the unraw’d form, fixing runtime mismatches/panics when contracts use raw idents.

Changes:

  • Update multiple macro generators to compare/sort/export using IdentExt::unraw() while preserving raw idents where needed for valid Rust field/method access.
  • Harden a couple of special-cases (__check_auth, client generation skipping __*) against bypass via raw-identifier spellings.
  • Add a dedicated regression test contract + snapshot covering raw identifiers across contract, events, errors, structs, enums, and traits.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
soroban-sdk/test_snapshots/tests/contract_udt_raw_identifier/test_functional.1.json Adds snapshot output for new raw-identifier regression test.
soroban-sdk/src/tests/contract_udt_raw_identifier.rs New functional + spec-level tests exercising raw identifier normalization end-to-end.
soroban-sdk/src/tests.rs Registers the new raw-identifier test module.
soroban-sdk-macros/src/syn_ext.rs Normalizes trait names via unraw(); adds r# stripping for safe ident strings.
soroban-sdk-macros/src/map_type.rs Avoids stringify+reparse for idents (fixes raw-keyword idents) and uses unraw() for name comparisons.
soroban-sdk-macros/src/lib.rs Normalizes contract type string; adjusts client/args naming construction.
soroban-sdk-macros/src/derive_trait.rs Updates default derived names for Spec/Args/Client in #[contracttrait].
soroban-sdk-macros/src/derive_struct_tuple.rs Ensures tuple-struct spec names / exported statics use unraw’d identifiers.
soroban-sdk-macros/src/derive_struct.rs Sorts struct fields by unraw’d names and emits unraw’d field/spec names.
soroban-sdk-macros/src/derive_spec_fn.rs Uses unraw’d function names for spec entries and special-case checks.
soroban-sdk-macros/src/derive_fn.rs Uses unraw’d function names for exported invocation wrappers and special-case checks.
soroban-sdk-macros/src/derive_event.rs Uses unraw’d event/field names in spec while preserving raw idents for generated Rust field access.
soroban-sdk-macros/src/derive_error_enum_int.rs Emits error-enum case/spec names from unraw’d identifiers.
soroban-sdk-macros/src/derive_enum_int.rs Emits enum case/spec names from unraw’d identifiers.
soroban-sdk-macros/src/derive_enum.rs Emits union/enum case/spec names from unraw’d identifiers.
soroban-sdk-macros/src/derive_contractimpl_trait_macro.rs Uses unraw’d identifiers when generating trait-impl helper macro names/calls.
soroban-sdk-macros/src/derive_contractimpl_trait_default_fns_not_overridden.rs Compares overridden default fns using unraw’d names.
soroban-sdk-macros/src/derive_client.rs Filters/generates client methods using unraw’d function names.
soroban-sdk-macros/src/attribute.rs Matches attribute names using unraw’d identifiers.
Comments suppressed due to low confidence (1)

soroban-sdk-macros/src/syn_ext.rs:162

  • HasFnsItem::name() now normalizes trait idents via unraw(), but the Impl arm still stringifies self_ty directly, which can preserve r# spellings in the returned name. Since item.name() feeds into generated Args/Client docs (and potentially other naming logic), consider stripping raw prefixes here as well to keep naming consistently normalized across Trait vs Impl inputs.
            HasFnsItem::Trait(t) => t.ident.unraw().to_string(),
            HasFnsItem::Impl(i) => {
                let ty = &i.self_ty;
                quote!(#ty).to_string()
            }

Comment thread soroban-sdk-macros/src/lib.rs Outdated
Comment thread soroban-sdk-macros/src/lib.rs Outdated
Comment thread soroban-sdk-macros/src/lib.rs Outdated
Comment thread soroban-sdk-macros/src/derive_trait.rs Outdated
Comment thread soroban-sdk-macros/src/derive_trait.rs Outdated
Comment thread soroban-sdk-macros/src/derive_trait.rs Outdated
Comment thread soroban-sdk-macros/src/derive_trait.rs Outdated
Comment thread soroban-sdk-macros/src/lib.rs Outdated
Comment thread soroban-sdk-macros/src/lib.rs Outdated
@mootz12 mootz12 requested a review from leighmcculloch April 23, 2026 15:29
Comment thread soroban-sdk/src/tests/contract_udt_raw_identifier.rs
@leighmcculloch leighmcculloch added this pull request to the merge queue Apr 24, 2026
Merged via the queue into main with commit 5e36de5 Apr 24, 2026
111 checks passed
@leighmcculloch leighmcculloch deleted the support-raw-identifiers branch April 24, 2026 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Macros do not normalize raw identifiers (r#)

3 participants