Skip to content

Commit 24a70e5

Browse files
Merge pull request #667 from rolfbjarne/objcpropertydecl-getpropertyattributes
Add ObjCPropertyDecl.GetPropertyAttributes().
2 parents 85eebc8 + 06a860d commit 24a70e5

File tree

7 files changed

+193
-0
lines changed

7 files changed

+193
-0
lines changed

sources/ClangSharp.Interop/Extensions/CXCursor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,6 +1878,8 @@ public readonly bool GetIsExternalSymbol(out CXString language, out CXString def
18781878

18791879
public readonly CXObjCPropertyAttrKind GetObjCPropertyAttributes(uint reserved) => (CXObjCPropertyAttrKind)clang.Cursor_getObjCPropertyAttributes(this, reserved);
18801880

1881+
public readonly ObjCPropertyAttributeKind GetPropertyAttributes() => (ObjCPropertyAttributeKind)clangsharp.Cursor_getPropertyAttributes(this);
1882+
18811883
public readonly CXCursor GetOverloadedDecl(uint index) => clang.getOverloadedDecl(this, index);
18821884

18831885
public readonly int GetPlatformAvailability(out bool alwaysDeprecated, out CXString deprecatedMessage, out bool alwaysUnavailable, out CXString unavailableMessage, Span<CXPlatformAvailability> availability)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// 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.
2+
3+
// Ported from https://github.com/llvm/llvm-project/tree/llvmorg-21.1.8/clang/include/clang-c
4+
// Original source is Copyright (c) the LLVM Project and Contributors. Licensed under the Apache License v2.0 with LLVM Exceptions. See NOTICE.txt in the project root for license information.
5+
6+
using System;
7+
8+
namespace ClangSharp.Interop;
9+
10+
[Flags]
11+
public enum ObjCPropertyAttributeKind
12+
{
13+
NoAttr = 0x00,
14+
ReadOnly = 0x01,
15+
Getter = 0x02,
16+
Assign = 0x04,
17+
ReadWrite = 0x08,
18+
Retain = 0x10,
19+
Copy = 0x20,
20+
NonAtomic = 0x40,
21+
Setter = 0x80,
22+
Atomic = 0x100,
23+
Weak = 0x200,
24+
Strong = 0x400,
25+
UnsafeUnretained = 0x800,
26+
Nullability = 0x1000,
27+
NullResettable = 0x2000,
28+
Class = 0x4000,
29+
Direct = 0x8000,
30+
}

sources/ClangSharp.Interop/clangsharp/clangsharp.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,10 @@ public static partial class @clangsharp
779779
[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getPrimaryTemplate", ExactSpelling = true)]
780780
public static extern CXCursor Cursor_getPrimaryTemplate(CXCursor C);
781781

782+
[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getPropertyAttributes", ExactSpelling = true)]
783+
[return: NativeTypeName("unsigned int")]
784+
public static extern uint Cursor_getPropertyAttributes(CXCursor C);
785+
782786
[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getProtocol", ExactSpelling = true)]
783787
public static extern CXCursor Cursor_getProtocol(CXCursor C, [NativeTypeName("unsigned int")] uint i);
784788

sources/ClangSharp/Cursors/Decls/ObjCPropertyDecl.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,20 @@ internal ObjCPropertyDecl(CXCursor handle) : base(handle, CXCursor_ObjCPropertyD
2727

2828
public bool IsInstanceProperty => !IsClassProperty;
2929

30+
#pragma warning disable CA1721
31+
// CA1721: The property name 'PropertyAttributes' is confusing given the existence of method 'GetPropertyAttributes'.
32+
// Handle.GetObjCPropertyAttributes() calls Cursor_getObjCPropertyAttributes, which confusingly is implemented using
33+
// 'getPropertyAttributeAsWritten()' (and not 'getPropertyAttributes()'): https://github.com/llvm/llvm-project/blob/1cea4a0841dacefa49241538a55fbf4f34462633/clang/tools/libclang/CIndex.cpp#L9159-L9165
34+
// We have to keep our 'PropertyAttributes' property for backwards compatibility, so introduce
35+
// a new method, GetPropertyAttributes(), that gets the final property attributes, and not just the as written variety.
36+
37+
/// <summary>This calls ObjCPropertyDecl->getPropertyAttributesAsWritten()</summary>
3038
public CXObjCPropertyAttrKind PropertyAttributes => Handle.GetObjCPropertyAttributes(0);
3139

40+
/// <summary>This calls ObjCPropertyDecl->getPropertyAttributes()</summary>
41+
public ObjCPropertyAttributeKind GetPropertyAttributes () => Handle.GetPropertyAttributes();
42+
#pragma warning restore CA1721
43+
3244
public ObjCIvarDecl PropertyIvarDecl => _propertyIvarDecl.Value;
3345

3446
public ObjCMethodDecl SetterMethodDecl => _setterMethodDecl.Value;

sources/libClangSharp/ClangSharp.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3815,6 +3815,19 @@ CXCursor clangsharp_Cursor_getPrimaryTemplate(CXCursor C) {
38153815
return clang_getNullCursor();
38163816
}
38173817

3818+
CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getPropertyAttributes(CXCursor C)
3819+
{
3820+
if (isDeclOrTU(C.kind)) {
3821+
const Decl* D = getCursorDecl(C);
3822+
3823+
if (const ObjCPropertyDecl* OCPD = dyn_cast<ObjCPropertyDecl>(D)) {
3824+
return OCPD->getPropertyAttributes();
3825+
}
3826+
}
3827+
3828+
return 0 /* ObjCPropertyAttribute::Kind::kind_noattr */;
3829+
}
3830+
38183831
CXCursor clangsharp_Cursor_getProtocol(CXCursor C, unsigned i) {
38193832
if (isDeclOrTU(C.kind)) {
38203833
const Decl* D = getCursorDecl(C);

sources/libClangSharp/ClangSharp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,8 @@ CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getPreviousDecl(CXCursor C);
677677

678678
CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getPrimaryTemplate(CXCursor C);
679679

680+
CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getPropertyAttributes(CXCursor C);
681+
680682
CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getProtocol(CXCursor C, unsigned i);
681683

682684
CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getRedeclContext(CXCursor C);

tests/ClangSharp.UnitTests/ObjectiveCTest.cs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,4 +356,134 @@ @interface MyClass
356356
Assert.That(methodStaticMethodAttrs.Count, Is.EqualTo(1), "methodStaticMethodAttrs.Count");
357357
Assert.That(methodStaticMethodAttrs[0].PrettyPrint(), Is.EqualTo("__attribute__((availability(ios, introduced=13.0)))"), "methodStaticMethod.Attr.PrettyPrint");
358358
}
359+
360+
[Test]
361+
public void Property_PropertyAttributes()
362+
{
363+
AssertNeedNewClangSharp();
364+
365+
var inputContents = $$"""
366+
@class NSObject;
367+
368+
@interface MyClass
369+
@property NSObject* P_none;
370+
371+
@property (readonly) NSObject* P_readonly;
372+
@property (getter=getGetter) NSObject* P_getter;
373+
@property (assign) NSObject* P_assign;
374+
@property (readwrite) NSObject* P_readwrite;
375+
@property (retain) NSObject* P_retain;
376+
@property (copy) NSObject* P_copy;
377+
@property (nonatomic) NSObject* P_nonatomic;
378+
@property (setter=setSetter:) NSObject* P_setter;
379+
@property (atomic) NSObject* P_atomic;
380+
@property (weak) NSObject* P_weak;
381+
@property (strong) NSObject* P_strong;
382+
@property (unsafe_unretained) NSObject* P_unsafe_unretained;
383+
@property (nonnull) NSObject* P_nonnull;
384+
@property (null_unspecified) NSObject* P_null_unspecified;
385+
@property (null_resettable) NSObject* P_null_resettable;
386+
@property (class) NSObject* P_class;
387+
@property (direct) NSObject* P_direct;
388+
389+
// multiple
390+
@property (retain,readonly,class) NSObject* P_retain_readonly_class;
391+
@end
392+
""";
393+
394+
using var translationUnit = CreateTranslationUnit(inputContents, "objective-c++");
395+
396+
var classes = translationUnit.TranslationUnitDecl.Decls.OfType<ObjCInterfaceDecl>().ToList();
397+
Assert.That(classes.Count, Is.GreaterThanOrEqualTo(1), $"At least one class");
398+
var myClass = classes.SingleOrDefault(v => v.Name == "MyClass")!;
399+
Assert.That(myClass, Is.Not.Null, "MyClass");
400+
401+
var properties = myClass.Properties.ToList();
402+
403+
var take = new Func<string, ObjCPropertyDecl>((string propertyName) => {
404+
var idx = properties.FindIndex(v => v.Name == propertyName);
405+
Assert.That(idx, Is.GreaterThanOrEqualTo(0), $"property {propertyName} not found, properties remaining: {string.Join(", ", properties.Select(p => p.Name))}");
406+
var rv = properties[idx];
407+
properties.RemoveAt(idx);
408+
return rv;
409+
});
410+
411+
var property_none = take("P_none");
412+
Assert.That(property_none.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_noattr), "property_none PropertyAttributes");
413+
Assert.That(property_none.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_none GetPropertyAttributes()");
414+
415+
var property_readonly = take("P_readonly");
416+
Assert.That(property_readonly.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_readonly), "property_readonly PropertyAttributes");
417+
Assert.That(property_readonly.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.ReadOnly | ObjCPropertyAttributeKind.Atomic), "property_readonly GetPropertyAttributes()");
418+
419+
var property_getter = take("P_getter");
420+
Assert.That(property_getter.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_getter), "property_getter PropertyAttributes");
421+
Assert.That(property_getter.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Getter | ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_getter GetPropertyAttributes()");
422+
423+
var property_assign = take("P_assign");
424+
Assert.That(property_assign.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_assign), "property_assign PropertyAttributes");
425+
Assert.That(property_assign.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_assign GetPropertyAttributes()");
426+
427+
var property_readwrite = take("P_readwrite");
428+
Assert.That(property_readwrite.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_readwrite), "property_readwrite PropertyAttributes");
429+
Assert.That(property_readwrite.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_readwrite GetPropertyAttributes()");
430+
431+
var property_retain = take("P_retain");
432+
Assert.That(property_retain.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_retain), "property_retain PropertyAttributes");
433+
Assert.That(property_retain.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Retain | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic), "property_retain GetPropertyAttributes()");
434+
435+
var property_copy = take("P_copy");
436+
Assert.That(property_copy.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_copy), "property_copy PropertyAttributes");
437+
Assert.That(property_copy.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Copy | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic), "property_copy GetPropertyAttributes()");
438+
439+
var property_nonatomic = take("P_nonatomic");
440+
Assert.That(property_nonatomic.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_nonatomic), "property_nonatomic PropertyAttributes");
441+
Assert.That(property_nonatomic.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.NonAtomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_nonatomic GetPropertyAttributes()");
442+
443+
var property_setter = take("P_setter");
444+
Assert.That(property_setter.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_setter), "property_setter PropertyAttributes");
445+
Assert.That(property_setter.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Setter | ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_setter GetPropertyAttributes()");
446+
447+
var property_atomic = take("P_atomic");
448+
Assert.That(property_atomic.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_atomic), "property_atomic PropertyAttributes");
449+
Assert.That(property_atomic.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_atomic GetPropertyAttributes()");
450+
451+
var property_weak = take("P_weak");
452+
Assert.That(property_weak.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_weak), "property_weak PropertyAttributes");
453+
Assert.That(property_weak.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Weak | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic), "property_weak GetPropertyAttributes()");
454+
455+
var property_strong = take("P_strong");
456+
Assert.That(property_strong.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_strong), "property_strong PropertyAttributes");
457+
Assert.That(property_strong.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Strong | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic), "property_strong GetPropertyAttributes()");
458+
459+
var property_unsafe_unretained = take("P_unsafe_unretained");
460+
Assert.That(property_unsafe_unretained.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_unsafe_unretained), "property_unsafe_unretained PropertyAttributes");
461+
Assert.That(property_unsafe_unretained.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_unsafe_unretained GetPropertyAttributes()");
462+
463+
var property_null_resettable = take("P_null_resettable");
464+
Assert.That(property_null_resettable.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_noattr), "property_null_resettable PropertyAttributes");
465+
Assert.That(property_null_resettable.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained | ObjCPropertyAttributeKind.Nullability | ObjCPropertyAttributeKind.NullResettable), "property_null_resettable GetPropertyAttributes()");
466+
467+
var property_class = take("P_class");
468+
Assert.That(property_class.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_class), "property_class PropertyAttributes");
469+
Assert.That(property_class.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Class | ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_class GetPropertyAttributes()");
470+
471+
var property_direct = take("P_direct");
472+
Assert.That(property_direct.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_noattr), "property_direct PropertyAttributes");
473+
Assert.That(property_direct.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Direct | ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained), "property_direct GetPropertyAttributes()");
474+
475+
var property_nonnull = take("P_nonnull");
476+
Assert.That(property_nonnull.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_noattr), "property_nonnull PropertyAttributes");
477+
Assert.That(property_nonnull.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained | ObjCPropertyAttributeKind.Nullability), "property_nonnull GetPropertyAttributes()");
478+
479+
var property_unspecified = take("P_null_unspecified");
480+
Assert.That(property_unspecified.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_noattr), "property_unspecified PropertyAttributes");
481+
Assert.That(property_unspecified.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Assign | ObjCPropertyAttributeKind.ReadWrite | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.UnsafeUnretained | ObjCPropertyAttributeKind.Nullability), "property_unspecified GetPropertyAttributes()");
482+
483+
var property_retain_readonly_class = take("P_retain_readonly_class");
484+
Assert.That(property_retain_readonly_class.PropertyAttributes, Is.EqualTo(CXObjCPropertyAttrKind.CXObjCPropertyAttr_retain | CXObjCPropertyAttrKind.CXObjCPropertyAttr_readonly | CXObjCPropertyAttrKind.CXObjCPropertyAttr_class), "property_retain_readonly_class PropertyAttributes");
485+
Assert.That(property_retain_readonly_class.GetPropertyAttributes(), Is.EqualTo(ObjCPropertyAttributeKind.Retain | ObjCPropertyAttributeKind.ReadOnly | ObjCPropertyAttributeKind.Atomic | ObjCPropertyAttributeKind.Class), "property_retain_readonly_class GetPropertyAttributes()");
486+
487+
Assert.That(properties, Is.Empty, "All properties processed");
488+
}
359489
}

0 commit comments

Comments
 (0)