Demangle Function

There isn't any stable API to the demangler, but the demangler code is mostly separable from the rest of the codebase, so you could try building it yourself and bundling it with your program.

@Joe_Groff
I do see the following api in SwiftDemangle.h
Is there no way to call it in legit way, it seems like part of Swift? (again my appologizes for lack of knowledge in the structure of the swift lib)

I'd use something like this:

func demangle(_ mangledName: String) -> String {
    typealias DemangleProc = @convention(c) (_ name: UnsafePointer<UInt8>?, _ length: Int, _ buffer: UnsafeMutablePointer<UInt8>?, _ bufferSize: UnsafeMutablePointer<Int>?, _ flags: UInt32) -> UnsafeMutablePointer<Int8>?
    
    let lib = dlopen(nil, RTLD_NOW)!
    let symbol = dlsym(lib, "swift_demangle")!
    let demangleProc = unsafeBitCast(symbol, to: DemangleProc.self)
    let string = demangleProc(mangledName, mangledName.count, nil, nil, 0)!
    let result = String(cString: string)
    string.deallocate()
    return result
}

Error handling removed for simplicity, in real code it should probably be guard check instead of force unwrap.

Note that the header you mentioned uses slightly different API. I'm not too familiar with demangle API(s) to know if there's any difference or if one is a wrapper on top of another, or which one is better to use.

1 Like

yes I saw it here : here
looks very hacky. especially when I need to sheep that code inside SDK.
I was thinking to use that source code: CwlDemangle/CwlDemangle.swift at master · mattgallagher/CwlDemangle · GitHub

If you consider dlsym & co too hacky consider putting this in the bridging header:

unsigned char* swift_demangle(const unsigned char* name, long length, unsigned char* buffer, long* bufferSize, int flags);

Then you can call it from Swift normally:

func demangle(_ mangledName: String) -> String {
    let string = swift_demangle(mangledName, mangledName.count, nil, nil, 0)!
    let result = String(cString: string)
    string.deallocate()
    return result
}

Could we name space this function into some type? I imagine we'd eventually have other related functions like mangle, and perhaps a Swifty wrapper around dlopen.

For those without "Objective-C fobia":

// SwiftMangling.h

#import <Foundation/Foundation.h>

@interface SwiftMangling: NSObject
+ (NSString*)demangle:(NSString*)mangled;
@end

// SwiftMangling.m

#import "SwiftMangling.h"

unsigned char* swift_demangle(const unsigned char* name, long length, unsigned char* buffer, long* bufferSize, int flags);

@implementation SwiftMangling
+ (NSString*)demangle:(NSString*)mangled {
    unsigned char* str = [mangled cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char* string = swift_demangle(str, strlen(str), nil, nil, 0);
    NSString* result = [NSString stringWithCString:string encoding:NSASCIIStringEncoding];
    free(string);
    return result;
}
@end

// Bridging header:

#import "SwiftMangling.h"

// usage from swift:

let s = SwiftMangling.demangle("$sSi")
print(s) // Optional("Swift.Int")
1 Like

@tera thanks.
I noticed that mangling happens only when u call NSStringFromClass on generic swift classes (e.g swiftui). but when u call type(of: ) in swift there is no mangling .
_TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View_ in Objc
will be
UIHostingController<_ViewList_View> in Swift
What the purpose of mangling and why Objc should behave differently?(I have read Mangling.rst)
So maybe in that case it would be much simpler to call type(of: ) and pass it back to Objc as a string?

swift_demangle isn't intended to be public API; I don't know how stringently the App Store checks for it but I wouldn't risk it for Apple platforms. Building your own copy of the demangler library will give you safer access to the entire underlying demangling implementation, as well as some insulation from upstream changes we make to the implementation.

1 Like

@Joe_Groff Thanks a lot.
I agree that why I think swift_demangle would not be that appropriate.
Could u please answer my previous question (as I think I lack some knowledge)

I noticed that mangling happens only when u call NSStringFromClass on generic swift classes (e.g swiftui). but when u call type(of: ) in swift there is no mangling .
_TtGC7SwiftUI19UIHostingControllerVS_14_ViewList_View_ in Objc
will be
UIHostingController<_ViewList_View> in Swift
What the purpose of mangling and why Objc should behave differently?(I have read Mangling.rst)
So maybe in that case it would be much simpler to call type(of: ) and pass it back to Objc as a String

The Objective-C runtime needs a unique, stable runtime name for every class, and the Swift type mangling provides that uniqueness and stability guarantee. By contrast, when you print a type value, the printing is intended to be for human consumption, and might leave out information (such as module qualification) that makes the output hard to read but which would be necessary to make the printing fully unambiguous. Fully qualified type names in Swift code are also a lot larger than mangled names and more complicated to parse, so in places where the type name is an implementation detail, we favor using the mangling, which is more compact.

1 Like

If that's for debugging / logging and it works for you – why not.