Skip to content

Commit b27574f

Browse files
Merge pull request #663 from rolfbjarne/special-objc-cxtype
Fix handling ElaboratedType and TypeWithKeyword instances of id/SEL/Class.
2 parents 4459c5f + cab237a commit b27574f

5 files changed

Lines changed: 66 additions & 6 deletions

File tree

sources/ClangSharp/Types/ElaboratedType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public sealed class ElaboratedType : TypeWithKeyword
1212
private readonly ValueLazy<Type> _namedType;
1313
private readonly ValueLazy<TagDecl?> _ownedTagDecl;
1414

15-
internal ElaboratedType(CXType handle) : base(handle, CXType_Elaborated, CX_TypeClass_Elaborated)
15+
internal ElaboratedType(CXType handle) : base(handle, CXType_Elaborated, CX_TypeClass_Elaborated, CXType_ObjCClass, CXType_ObjCId, CXType_ObjCSel)
1616
{
1717
_namedType = new ValueLazy<Type>(() => TranslationUnit.GetOrCreate<Type>(Handle.NamedType));
1818
_ownedTagDecl = new ValueLazy<TagDecl?>(() => !Handle.OwnedTagDecl.IsNull ?TranslationUnit.GetOrCreate<TagDecl>(Handle.OwnedTagDecl) : null);

sources/ClangSharp/Types/Type.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ public unsafe class Type : IEquatable<Type>
1818
private readonly ValueLazy<Type> _pointeeType;
1919
private readonly ValueLazy<TranslationUnit> _translationUnit;
2020

21-
protected Type(CXType handle, CXTypeKind expectedKind, CX_TypeClass expectedTypeClass)
21+
protected Type(CXType handle, CXTypeKind expectedKind, CX_TypeClass expectedTypeClass, params ReadOnlySpan<CXTypeKind> additionalExpectedKinds)
2222
{
23-
if (handle.kind != expectedKind)
23+
#if NET10_0_OR_GREATER
24+
if (handle.kind != expectedKind && !additionalExpectedKinds.Contains(handle.kind))
25+
#else
26+
if (handle.kind != expectedKind && !Contains(additionalExpectedKinds, handle.kind))
27+
#endif
2428
{
2529
throw new ArgumentOutOfRangeException(nameof(handle));
2630
}
@@ -39,6 +43,20 @@ protected Type(CXType handle, CXTypeKind expectedKind, CX_TypeClass expectedType
3943
_translationUnit = new ValueLazy<TranslationUnit>(() => TranslationUnit.GetOrCreate((CXTranslationUnit)Handle.data[1]));
4044
}
4145

46+
#if !NET10_0_OR_GREATER
47+
private static bool Contains(ReadOnlySpan<CXTypeKind> kinds, CXTypeKind find)
48+
{
49+
for (var i = 0; i < kinds.Length; i++)
50+
{
51+
if (kinds[i] == find)
52+
{
53+
return true;
54+
}
55+
}
56+
return false;
57+
}
58+
#endif
59+
4260
public CXXRecordDecl? AsCXXRecordDecl => AsTagDecl as CXXRecordDecl;
4361

4462
public string AsString => _asString.Value;
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
// 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.
22

3+
using System;
34
using ClangSharp.Interop;
45

56
namespace ClangSharp;
67

78
public class TypeWithKeyword : Type
89
{
9-
private protected TypeWithKeyword(CXType handle, CXTypeKind expectedTypeKind, CX_TypeClass expectedTypeClass) : base(handle, expectedTypeKind, expectedTypeClass)
10+
private protected TypeWithKeyword(CXType handle, CXTypeKind expectedTypeKind, CX_TypeClass expectedTypeClass, params ReadOnlySpan<CXTypeKind> additionalExpectedKinds) : base(handle, expectedTypeKind, expectedTypeClass, additionalExpectedKinds)
1011
{
1112
}
1213
}

sources/ClangSharp/Types/TypedefType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public sealed class TypedefType : Type
1111
{
1212
private readonly ValueLazy<TypedefNameDecl> _decl;
1313

14-
internal TypedefType(CXType handle) : base(handle, CXType_Typedef, CX_TypeClass_Typedef)
14+
internal TypedefType(CXType handle) : base(handle, CXType_Typedef, CX_TypeClass_Typedef, CXType_ObjCClass, CXType_ObjCId, CXType_ObjCSel)
1515
{
1616
_decl = new ValueLazy<TypedefNameDecl>(() => TranslationUnit.GetOrCreate<TypedefNameDecl>(Handle.Declaration));
1717
}

tests/ClangSharp.UnitTests/ObjectiveCTest.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,48 @@ @interface MyClass
9696
var pointee2Type = pointeeType.PointeeType;
9797
Assert.That(pointee2Type.Kind, Is.EqualTo(CXTypeKind.CXType_ObjCInterface), "pointee2Type.Kind");
9898
}
99-
99+
100+
[Test]
101+
public void BlockTypes()
102+
{
103+
var inputContents = $$"""
104+
@interface MyClass
105+
-(MyClass *(^)(id))instanceMethod1;
106+
-(MyClass *(^)(SEL))instanceMethod2;
107+
-(MyClass *(^)(Class))instanceMethod3;
108+
@end
109+
""";
110+
using var translationUnit = CreateTranslationUnit(inputContents, "objective-c++");
111+
112+
var classes = translationUnit.TranslationUnitDecl.Decls.OfType<ObjCInterfaceDecl>().ToList();
113+
114+
var myClass = classes.SingleOrDefault(v => v.Name == "MyClass")!;
115+
Assert.That(myClass, Is.Not.Null, "MyClass");
116+
117+
var info = new[] {
118+
(Name: "instanceMethod1", Type: CXTypeKind.CXType_ObjCId),
119+
(Name: "instanceMethod2", Type: CXTypeKind.CXType_ObjCSel),
120+
(Name: "instanceMethod3", Type: CXTypeKind.CXType_ObjCClass),
121+
};
122+
123+
foreach (var i in info)
124+
{
125+
var instanceMethod = myClass.Methods.SingleOrDefault(v => v.Name == i.Name)!;
126+
Assert.That(instanceMethod, Is.Not.Null, "instanceMethod");
127+
var returnType = instanceMethod.ReturnType;
128+
Assert.That(returnType.Kind, Is.EqualTo(CXTypeKind.CXType_BlockPointer), "returnType.Kind");
129+
var pointeeType = returnType.PointeeType;
130+
Assert.That(pointeeType.Kind, Is.EqualTo(CXTypeKind.CXType_FunctionProto), "pointeeType.Kind");
131+
var functionProtoType = (FunctionProtoType)pointeeType;
132+
Assert.That(functionProtoType.ParamTypes.Count, Is.EqualTo(1), "functionProtoType.ParamTypes.Count()");
133+
var paramType = functionProtoType.ParamTypes[0];
134+
Assert.That(paramType.Kind, Is.EqualTo(i.Type), "paramType.Kind");
135+
var elaboratedParamType = (ElaboratedType)paramType;
136+
Assert.That(elaboratedParamType, Is.Not.Null, "elaboratedParamType");
137+
Assert.That(elaboratedParamType.Desugar, Is.Not.Null, "elaboratedParamType.Desugar");
138+
}
139+
}
140+
100141
private static void AssertNeedNewClangSharp()
101142
{
102143
var forceRun = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("FORCE_RUN"));

0 commit comments

Comments
 (0)