diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index 1623b529..6b933999 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -1145,6 +1145,8 @@ public readonly CXCursor DefaultArg public readonly bool IsThisDeclarationADefinition => clangsharp.Cursor_getIsThisDeclarationADefinition(this) != 0; + public readonly bool IsPropertyAccessor => clangsharp.Cursor_getIsPropertyAccessor(this) != 0; + public readonly bool IsThrownVariableInScope => clangsharp.Cursor_getIsThrownVariableInScope(this) != 0; public readonly bool IsTranslationUnit => clang.isTranslationUnit(Kind) != 0; diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index 540329f0..f3a933b4 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -588,6 +588,10 @@ public static partial class @clangsharp [return: NativeTypeName("unsigned int")] public static extern uint Cursor_getIsThisDeclarationADefinition(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getIsPropertyAccessor", ExactSpelling = true)] + [return: NativeTypeName("unsigned int")] + public static extern uint Cursor_getIsPropertyAccessor(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getIsThrownVariableInScope", ExactSpelling = true)] [return: NativeTypeName("unsigned int")] public static extern uint Cursor_getIsThrownVariableInScope(CXCursor C); diff --git a/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs b/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs index 4bc028f7..e074cc15 100644 --- a/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/ObjCMethodDecl.cs @@ -53,4 +53,6 @@ internal ObjCMethodDecl(CXCursor handle) : base(handle, handle.Kind, CX_DeclKind public ImplicitParamDecl SelfDecl => _selfDecl.Value; public Type SendResultType => _sendResultType.Value; + + public bool IsPropertyAccessor => Handle.IsPropertyAccessor; } diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 1e4b1627..ea074bb8 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -2716,6 +2716,17 @@ unsigned clangsharp_Cursor_getIsThisDeclarationADefinition(CXCursor C) { return 0; } +unsigned clangsharp_Cursor_getIsPropertyAccessor(CXCursor C) { + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); + + if (const ObjCMethodDecl* OCMD = dyn_cast(D)) { + return OCMD->isPropertyAccessor(); + } + } + + return 0; +} unsigned clangsharp_Cursor_getIsThrownVariableInScope(CXCursor C) { if (isStmtOrExpr(C.kind)) { const Stmt* S = getCursorStmt(C); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index 3b152c39..90db7c1f 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -559,6 +559,8 @@ CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsTemplated(CXCursor C); CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsThisDeclarationADefinition(CXCursor C); +CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsPropertyAccessor(CXCursor C); + CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsThrownVariableInScope(CXCursor C); CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getIsTransparent(CXCursor C); diff --git a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs index ed0fe42d..246b99bb 100644 --- a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs +++ b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs @@ -1,5 +1,6 @@ // Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See License.md in the repository root for more information. +using System; using System.Linq; using ClangSharp.Interop; using NUnit.Framework; @@ -10,9 +11,10 @@ namespace ClangSharp.UnitTests; public sealed class ObjectiveCTest : TranslationUnitTest { [Test] - [Ignore("TODO: this needs a new version of libClangSharp published.")] public void Category_TypeParamList() { + AssertNeedNewClangSharp(); + var inputContents = $@" @interface MyClass @end @@ -29,6 +31,43 @@ @interface MyClass (MyCategory) } } + [Test] + public void Method_IsPropertyAccessor() + { + 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.IsPropertyAccessor, Is.True, "methodP1.IsPropertyAccessor"); + + var methodSetP1 = myClass.Methods.SingleOrDefault(v => v.Name == "setP1:")!; + Assert.That(methodSetP1, Is.Not.Null, "methodSetP1"); + Assert.That(methodSetP1.IsPropertyAccessor, Is.True, "methodSetP1.IsPropertyAccessor"); + + var methodInstanceMethod = myClass.Methods.SingleOrDefault(v => v.Name == "instanceMethod")!; + Assert.That(methodInstanceMethod, Is.Not.Null, "methodInstanceMethod"); + Assert.That(methodInstanceMethod.IsPropertyAccessor, Is.False, "methodInstanceMethod.IsPropertyAccessor"); + + var methodStaticMethod = myClass.Methods.SingleOrDefault(v => v.Name == "staticMethod")!; + Assert.That(methodStaticMethod, Is.Not.Null, "methodStaticMethod"); + Assert.That(methodStaticMethod.IsPropertyAccessor, Is.False, "methodStaticMethod.IsPropertyAccessor"); + } + [Test] public void PointerTypes() { @@ -57,4 +96,15 @@ @interface MyClass var pointee2Type = pointeeType.PointeeType; Assert.That(pointee2Type.Kind, Is.EqualTo(CXTypeKind.CXType_ObjCInterface), "pointee2Type.Kind"); } + + private static void AssertNeedNewClangSharp() + { + var forceRun = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("FORCE_RUN")); + + if (forceRun) + { + return; + } + Assert.Ignore("TODO: this needs a new version of libClangSharp published."); + } }