From 1aba43f22894432ff823f861bb7b6f167dcde617 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Tue, 4 Nov 2025 13:11:18 +0100 Subject: [PATCH] Add ObjCMethodDecl.Selector. --- .../ClangSharp.Interop/Extensions/CXCursor.cs | 2 + .../clangsharp/clangsharp.cs | 3 ++ .../Cursors/Decls/ObjCMethodDecl.cs | 2 + sources/libClangSharp/ClangSharp.cpp | 13 +++++++ sources/libClangSharp/ClangSharp.h | 2 + tests/ClangSharp.UnitTests/ObjectiveCTest.cs | 37 +++++++++++++++++++ 6 files changed, 59 insertions(+) diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 6b933999..3a962f2c 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -1321,6 +1321,8 @@ public readonly ReadOnlySpan OverriddenCursors public readonly CXCursor RhsExpr => clangsharp.Cursor_getRhsExpr(this); + public readonly CXString Selector => clangsharp.Cursor_getSelector(this); + public readonly CXCursor SemanticParent => clang.getCursorSemanticParent(this); public readonly bool ShouldCopy => clangsharp.Cursor_getShouldCopy(this) != 0; diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index f3a933b4..e7ce47fa 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -787,6 +787,9 @@ public static partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getRhsExpr", ExactSpelling = true)] public static extern CXCursor Cursor_getRhsExpr(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getSelector", ExactSpelling = true)] + public static extern CXString Cursor_getSelector(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getShouldCopy", ExactSpelling = true)] [return: NativeTypeName("unsigned int")] public static extern uint Cursor_getShouldCopy(CXCursor C); diff --git a/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs b/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs index e074cc15..b6400f2d 100644 --- a/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs @@ -55,4 +55,6 @@ internal ObjCMethodDecl(CXCursor handle) : base(handle, handle.Kind, CX_DeclKind public Type SendResultType => _sendResultType.Value; public bool IsPropertyAccessor => Handle.IsPropertyAccessor; + + public string Selector => Handle.Selector.ToString(); } diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index ea074bb8..6ded87f1 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -710,6 +710,19 @@ CX_CharacterKind clangsharp_Cursor_getCharacterLiteralKind(CXCursor C) { return CX_CLK_Invalid; } +CXString clangsharp_Cursor_getSelector(CXCursor C) { + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); + + if (const ObjCMethodDecl* OCMD = dyn_cast(D)) { + Selector selector = OCMD->getSelector(); + return createDup(selector.getAsString()); + } + } + + return createEmpty(); +} + CX_StringKind clangsharp_Cursor_getStringLiteralKind(CXCursor C) { if (isStmtOrExpr(C.kind)) { const Stmt* S = getCursorStmt(C); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 90db7c1f..259dd7a7 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -683,6 +683,8 @@ CLANGSHARP_LINKAGE CXType clangsharp_Cursor_getReturnType(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getRhsExpr(CXCursor C); +CLANGSHARP_LINKAGE CXString clangsharp_Cursor_getSelector(CXCursor C); + CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getShouldCopy(CXCursor C); CLANGSHARP_LINKAGE CXSourceRange clangsharp_Cursor_getSourceRange(CXCursor C); diff --git a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs index 246b99bb..5299fd8f 100644 --- a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs +++ b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs @@ -10,6 +10,43 @@ namespace ClangSharp.UnitTests; [Platform("macosx")] public sealed class ObjectiveCTest : TranslationUnitTest { + [Test] + public void Method_Selector() + { + AssertNeedNewClangSharp(); + + var inputContents = $@" +@interface MyClass + @property int P1; + -(void) instanceMethod; + +(void) staticMethod; +@end +"; + + using var translationUnit = CreateTranslationUnit(inputContents, "objective-c++"); + + var classes = translationUnit.TranslationUnitDecl.Decls.OfType().ToList(); + Assert.That(classes.Count, Is.GreaterThanOrEqualTo(1), $"At least one class"); + var myClass = classes.SingleOrDefault(v => v.Name == "MyClass")!; + Assert.That(myClass, Is.Not.Null, "MyClass"); + + var methodP1 = myClass.Methods.SingleOrDefault(v => v.Name == "P1")!; + Assert.That(methodP1, Is.Not.Null, "methodP1"); + Assert.That(methodP1.Selector, Is.EqualTo("P1"), "methodP1.Selector"); + + var methodSetP1 = myClass.Methods.SingleOrDefault(v => v.Name == "setP1:")!; + Assert.That(methodSetP1, Is.Not.Null, "methodSetP1"); + Assert.That(methodSetP1.Selector, Is.EqualTo("setP1:"), "methodSetP1.Selector"); + + var methodInstanceMethod = myClass.Methods.SingleOrDefault(v => v.Name == "instanceMethod")!; + Assert.That(methodInstanceMethod, Is.Not.Null, "methodInstanceMethod"); + Assert.That(methodInstanceMethod.Selector, Is.EqualTo("instanceMethod"), "methodInstanceMethod.Selector"); + + var methodStaticMethod = myClass.Methods.SingleOrDefault(v => v.Name == "staticMethod")!; + Assert.That(methodStaticMethod, Is.Not.Null, "methodStaticMethod"); + Assert.That(methodStaticMethod.Selector, Is.EqualTo("staticMethod"), "methodStaticMethod.Selector"); + } + [Test] public void Category_TypeParamList() {