Skip to content

feat: expose Core.SimplifyNameToQualifiedName (Python parity, sret)#37

Merged
tinysec merged 1 commit into
masterfrom
feat/simplify-name-to-qualified-name
Jul 8, 2026
Merged

feat: expose Core.SimplifyNameToQualifiedName (Python parity, sret)#37
tinysec merged 1 commit into
masterfrom
feat/simplify-name-to-qualified-name

Conversation

@tinysec

@tinysec tinysec commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Closes HIGH-severity missing-capi gap #24. BNRustSimplifyStrToFQN (returns BNQualifiedName by value) was declared but never exposed — two TODO notes warned the struct-return (sret) ABI made the binding "non-trivial" and redirected callers to the string-only RustSimplifyStrToStr. Python's demangle.simplify_name_to_qualified_name (demangle.py:253) had no managed equivalent.

The sret concern was unfounded

BNQualifiedName is blittable (two IntPtr + a ulong, [StructLayout(Sequential)]), so the P/Invoke marshaller handles the struct-return ABI directly — the same proven pattern as BNTypeBuilderGetStructureName. No manual sret / IntPtr retBuf workaround needed.

API

Overload Mirrors
Core.SimplifyNameToQualifiedName(string, bool simplify = true) simplify_name_to_qualified_name(str, simplify) (demangle.py:253)
Core.SimplifyNameToQualifiedName(QualifiedName) simplify_name_to_qualified_name(QualifiedName) — forces simplify=true (demangle.py:267)

Both wrap via QualifiedName.TakeNative (reads components eagerly, then frees the native array) and return null when the simplifier yields no components (matching Python's if len(result) == 0: return None).

E2E tests (harness repo)

SimplifyNameToQualifiedNameTests (6 tests), each asserting components + join + rendered string match Python exactly:

  • SimplifiesTemplatedCppName — the Python doc example → std::basic_string<wchar>.
  • TokenizesWithoutSimplifyingsimplify=false keeps default args.
  • TokenizesPlainScopedNamea::b::c unaffected by the flag.
  • SingleComponentNameRoundTrips — one-element list.
  • EmptyInputReturnsNullNone parity.
  • QualifiedNameOverloadForcesSimplification.

Full harness regression 64/64.

Closes HIGH missing-capi gap #24. The binding declared the
BNRustSimplifyStrToFQN P/Invoke (which returns a BNQualifiedName by value)
but declined to expose it: two TODO notes warned the struct-return (sret)
ABI made the binding "non-trivial" and redirected callers to the
string-only RustSimplifyStrToStr, so Python's
demangle.simplify_name_to_qualified_name (demangle.py:253) had no managed
equivalent.

The sret concern was unfounded: BNQualifiedName is blittable (two IntPtrs
plus a ulong), so the P/Invoke marshaller handles the struct-return ABI
directly -- the same pattern as BNTypeBuilderGetStructureName. Verified
end-to-end: a templated C++ name collapses identically to Python.

Add Core.SimplifyNameToQualifiedName with a string overload (simplify
flag, defaults true) and a QualifiedName overload (Python forces
simplify=true for qualified-name input). Both wrap via
QualifiedName.TakeNative (reads components eagerly, then frees the native
array) and return null when the simplifier yields no components. Removes
the two stale TODO notes.
@tinysec tinysec merged commit 6143064 into master Jul 8, 2026
1 check passed
@tinysec tinysec deleted the feat/simplify-name-to-qualified-name branch July 8, 2026 17:14
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.

1 participant