diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 3af7012f..e72b874c 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -1271,6 +1271,8 @@ public readonly CXCursor DefaultArg public readonly CXString ObjCPropertySetterName => clang.Cursor_getObjCPropertySetterName(this); + public readonly CXString ObjCRuntimeNameAttrMetadataName => clangsharp.Cursor_getObjCRuntimeNameAttrMetadataName(this); + public readonly int ObjCSelectorIndex => clang.Cursor_getObjCSelectorIndex(this); public readonly long OffsetOfField => clang.Cursor_getOffsetOfField(this); diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index f430268d..667064a2 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -748,6 +748,9 @@ public static partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getNumVBases", ExactSpelling = true)] public static extern int Cursor_getNumVBases(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getObjCRuntimeNameAttrMetadataName", ExactSpelling = true)] + public static extern CXString Cursor_getObjCRuntimeNameAttrMetadataName(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getOpaqueValue", ExactSpelling = true)] public static extern CXCursor Cursor_getOpaqueValue(CXCursor C); diff --git a/sources/ClangSharp/Cursors/Attrs/Attr.cs b/sources/ClangSharp/Cursors/Attrs/Attr.cs index 3d3a79b5..6e76af38 100644 --- a/sources/ClangSharp/Cursors/Attrs/Attr.cs +++ b/sources/ClangSharp/Cursors/Attrs/Attr.cs @@ -473,4 +473,6 @@ private protected Attr(CXCursor handle) : base(handle, handle.Kind) public string KindSpelling => Handle.AttrKindSpelling; public string PrettyPrint() => Handle.PrettyPrintAttribute().ToString(); + + public string ObjCRuntimeNameMetadataName => Handle.ObjCRuntimeNameAttrMetadataName.ToString(); } diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 70389fb9..6f56d31c 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -3682,6 +3682,22 @@ int clangsharp_Cursor_getNumVBases(CXCursor C) { return -1; } +CLANGSHARP_LINKAGE CXString clangsharp_Cursor_getObjCRuntimeNameAttrMetadataName(CXCursor C) +{ + if (clang_isAttribute(C.kind)) { + const Attr* A = getCursorAttr(C); + + StringRef message; + if (const auto *OCRN = dyn_cast(A)) { + message = OCRN->getMetadataName(); + } + + return createDup(message); + } + + return createEmpty(); +} + CXCursor clangsharp_Cursor_getOpaqueValue(CXCursor C) { if (isStmtOrExpr(C.kind)) { const Stmt* S = getCursorStmt(C); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 4e5384b9..ccc770e4 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -657,6 +657,8 @@ CLANGSHARP_LINKAGE int clangsharp_Cursor_getNumTypeParams(CXCursor C); CLANGSHARP_LINKAGE int clangsharp_Cursor_getNumVBases(CXCursor C); +CLANGSHARP_LINKAGE CXString clangsharp_Cursor_getObjCRuntimeNameAttrMetadataName(CXCursor C); + CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getOpaqueValue(CXCursor C); CLANGSHARP_LINKAGE CXType clangsharp_Cursor_getOriginalType(CXCursor C); diff --git a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs index b00947cd..be0d7ffd 100644 --- a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs +++ b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs @@ -10,6 +10,42 @@ namespace ClangSharp.UnitTests; [Platform("macosx")] public sealed class ObjectiveCTest : TranslationUnitTest { + [Test] + public void Attribute_ObjCRuntimeName() + { + AssertNeedNewClangSharp(); + + var inputContents = $$""" +__attribute__((objc_runtime_name("MyRenamedClass"))) +@interface MyClass +@end + +__attribute__((objc_runtime_name("MyRenamedProtocol"))) +@protocol MyProtocol +@end +"""; + using var translationUnit = CreateTranslationUnit(inputContents, "objective-c++"); + + var classes = translationUnit.TranslationUnitDecl.Decls.OfType().ToList(); + + var myClass = classes.SingleOrDefault(v => v.Name == "MyClass")!; + Assert.That(myClass, Is.Not.Null, "MyClass"); + var myClassAttrs = myClass.Attrs; + Assert.That(myClassAttrs.Count, Is.EqualTo(1), "myClassAttrs.Count"); + var runtimeNameAttr = myClassAttrs[0]; + Assert.That(runtimeNameAttr.Kind, Is.EqualTo(CX_AttrKind.CX_AttrKind_ObjCRuntimeName), "myClass Attr Kind"); + Assert.That(runtimeNameAttr.ObjCRuntimeNameMetadataName, Is.EqualTo("MyRenamedClass"), "myClass Attr ObjCRuntimeNameMetadataName"); + + var protocols = translationUnit.TranslationUnitDecl.Decls.OfType().ToList(); + var myProtocol = protocols.SingleOrDefault(v => v.Name == "MyProtocol")!; + Assert.That(myProtocol, Is.Not.Null, "MyProtocol"); + var myProtocolAttrs = myProtocol.Attrs; + Assert.That(myProtocolAttrs.Count, Is.EqualTo(1), "myProtocolAttrs.Count"); + runtimeNameAttr = myProtocolAttrs[0]; + Assert.That(runtimeNameAttr.Kind, Is.EqualTo(CX_AttrKind.CX_AttrKind_ObjCRuntimeName), "myProtocol Attr Kind"); + Assert.That(runtimeNameAttr.ObjCRuntimeNameMetadataName, Is.EqualTo("MyRenamedProtocol"), "myProtocol Attr ObjCRuntimeNameMetadataName"); + } + [Test] public void Type_IsObjCInstanceType() {