diff --git a/sources/ClangSharp.Interop/Extensions/CXCursor.cs b/sources/ClangSharp.Interop/Extensions/CXCursor.cs index f889bdc3..5e09d240 100644 --- a/sources/ClangSharp.Interop/Extensions/CXCursor.cs +++ b/sources/ClangSharp.Interop/Extensions/CXCursor.cs @@ -1257,6 +1257,8 @@ public readonly CXCursor DefaultArg public readonly int NumTemplateParameterLists => clangsharp.Cursor_getNumTemplateParameterLists(this); + public readonly int NumTypeParams => clangsharp.Cursor_getNumTypeParams(this); + public readonly int NumVBases => clangsharp.Cursor_getNumVBases(this); public readonly CXObjCDeclQualifierKind ObjCDeclQualifiers => (CXObjCDeclQualifierKind)clang.Cursor_getObjCDeclQualifiers(this); @@ -1911,6 +1913,8 @@ public readonly int GetPlatformAvailability(out bool alwaysDeprecated, out CXStr public readonly long GetTemplateArgumentValue(uint i) => clang.Cursor_getTemplateArgumentValue(this, i); + public readonly CXCursor GetTypeParam(uint index) => clangsharp.Cursor_getTypeParam(this, index); + public readonly CXCursor GetVBase(uint index) => clangsharp.Cursor_getVBase(this, index); public override readonly string ToString() => Spelling.ToString(); diff --git a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs index cb0ea241..9b1a1029 100644 --- a/sources/ClangSharp.Interop/clangsharp/clangsharp.cs +++ b/sources/ClangSharp.Interop/clangsharp/clangsharp.cs @@ -738,6 +738,9 @@ public static partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getNumTemplateParameterLists", ExactSpelling = true)] public static extern int Cursor_getNumTemplateParameterLists(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getNumTypeParams", ExactSpelling = true)] + public static extern int Cursor_getNumTypeParams(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getNumVBases", ExactSpelling = true)] public static extern int Cursor_getNumVBases(CXCursor C); @@ -869,6 +872,9 @@ public static partial class @clangsharp [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getTypeOperand", ExactSpelling = true)] public static extern CXType Cursor_getTypeOperand(CXCursor C); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getTypeParam", ExactSpelling = true)] + public static extern CXCursor Cursor_getTypeParam(CXCursor C, [NativeTypeName("unsigned int")] uint i); + [DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getUnaryExprOrTypeTraitKind", ExactSpelling = true)] public static extern CX_UnaryExprOrTypeTrait Cursor_getUnaryExprOrTypeTraitKind(CXCursor C); diff --git a/sources/ClangSharp/Cursors/Decls/ObjCCategoryDecl.cs b/sources/ClangSharp/Cursors/Decls/ObjCCategoryDecl.cs index a9564496..44cd5d2a 100644 --- a/sources/ClangSharp/Cursors/Decls/ObjCCategoryDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/ObjCCategoryDecl.cs @@ -26,7 +26,7 @@ internal ObjCCategoryDecl(CXCursor handle) : base(handle, CXCursor_ObjCCategoryD _nextClassCategory = new ValueLazy(() => TranslationUnit.GetOrCreate(Handle.GetSubDecl(2))); _nextClassCategoryRaw = new ValueLazy(() => TranslationUnit.GetOrCreate(Handle.GetSubDecl(3))); _protocols = LazyList.Create(Handle.NumProtocols, (i) => TranslationUnit.GetOrCreate(Handle.GetProtocol(unchecked((uint)i)))); - _typeParamList = LazyList.Create(Handle.NumArguments, (i) => TranslationUnit.GetOrCreate(Handle.GetArgument(unchecked((uint)i)))); + _typeParamList = LazyList.Create(Handle.NumTypeParams, (i) => TranslationUnit.GetOrCreate(Handle.GetTypeParam(unchecked((uint)i)))); } public ObjCInterfaceDecl ClassInterface => _classInterface.Value; diff --git a/sources/ClangSharp/Cursors/Decls/ObjCInterfaceDecl.cs b/sources/ClangSharp/Cursors/Decls/ObjCInterfaceDecl.cs index 452ba9a7..60c11de6 100644 --- a/sources/ClangSharp/Cursors/Decls/ObjCInterfaceDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/ObjCInterfaceDecl.cs @@ -47,7 +47,7 @@ internal ObjCInterfaceDecl(CXCursor handle) : base(handle, CXCursor_ObjCInterfac _superClass = new ValueLazy(() => TranslationUnit.GetOrCreate(Handle.GetSubDecl(2))); _superClassType = new ValueLazy(() => TranslationUnit.GetOrCreate(Handle.TypeOperand)); _typeForDecl = new ValueLazy(() => TranslationUnit.GetOrCreate(Handle.ThisType)); - _typeParamList = LazyList.Create(Handle.NumArguments, (i) => TranslationUnit.GetOrCreate(Handle.GetArgument(unchecked((uint)i)))); + _typeParamList = LazyList.Create(Handle.NumTypeParams, (i) => TranslationUnit.GetOrCreate(Handle.GetTypeParam(unchecked((uint)i)))); _visibleCategories = new ValueLazy>(() => [.. CategoryList.Where((category) => category.IsUnconditionallyVisible)]); _visibleExtensions = new ValueLazy>(() => [.. CategoryList.Where((category) => category.IsClassExtension && category.IsUnconditionallyVisible)]); } diff --git a/sources/ClangSharp/Cursors/Decls/ObjCTypeParamDecl.cs b/sources/ClangSharp/Cursors/Decls/ObjCTypeParamDecl.cs index 916760e9..a0a6b0ac 100644 --- a/sources/ClangSharp/Cursors/Decls/ObjCTypeParamDecl.cs +++ b/sources/ClangSharp/Cursors/Decls/ObjCTypeParamDecl.cs @@ -8,7 +8,7 @@ namespace ClangSharp; public sealed class ObjCTypeParamDecl : TypedefNameDecl { - internal ObjCTypeParamDecl(CXCursor handle) : base(handle, CXCursor_UnexposedDecl, CX_DeclKind_ObjCTypeParam) + internal ObjCTypeParamDecl(CXCursor handle) : base(handle, CXCursor_TemplateTypeParameter, CX_DeclKind_ObjCTypeParam) { } diff --git a/sources/libClangSharp/ClangSharp.cpp b/sources/libClangSharp/ClangSharp.cpp index 1338c0e1..1dd06726 100644 --- a/sources/libClangSharp/ClangSharp.cpp +++ b/sources/libClangSharp/ClangSharp.cpp @@ -3626,6 +3626,29 @@ int clangsharp_Cursor_getNumTemplateParameterLists(CXCursor C) { return -1; } +int clangsharp_Cursor_getNumTypeParams(CXCursor C) +{ + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); + + if (const ObjCCategoryDecl* OCCD = dyn_cast(D)) { + ObjCTypeParamList* typeParamList = OCCD->getTypeParamList(); + if (typeParamList) + return typeParamList->size(); + return 0; + } + + if (const ObjCInterfaceDecl* OCID = dyn_cast(D)) { + ObjCTypeParamList* typeParamList = OCID->getTypeParamList(); + if (typeParamList) + return typeParamList->size(); + return 0; + } + } + + return 0; +} + int clangsharp_Cursor_getNumVBases(CXCursor C) { if (isDeclOrTU(C.kind)) { const Decl* D = getCursorDecl(C); @@ -4743,6 +4766,42 @@ CXType clangsharp_Cursor_getTypeOperand(CXCursor C) { return MakeCXType(QualType(), getCursorTU(C)); } +CXCursor clangsharp_Cursor_getTypeParam(CXCursor C, unsigned i) { + if (isDeclOrTU(C.kind)) { + const Decl* D = getCursorDecl(C); + + if (const ObjCCategoryDecl* OCCD = dyn_cast(D)) { + ObjCTypeParamList* typeParamList = OCCD->getTypeParamList(); + + unsigned int n = 0; + if (i < typeParamList->size()) { + for (auto d : *typeParamList) { + if (n == i) { + return MakeCXCursor(d, getCursorTU(C)); + } + n++; + } + } + } + + if (const ObjCInterfaceDecl* OCID = dyn_cast(D)) { + ObjCTypeParamList* typeParamList = OCID->getTypeParamList(); + + unsigned int n = 0; + if (i < typeParamList->size()) { + for (auto d : *typeParamList) { + if (n == i) { + return MakeCXCursor(d, getCursorTU(C)); + } + n++; + } + } + } + } + + return clang_getNullCursor(); +} + CX_UnaryExprOrTypeTrait clangsharp_Cursor_getUnaryExprOrTypeTraitKind(CXCursor C) { if (isStmtOrExpr(C.kind)) { const Stmt* S = getCursorStmt(C); diff --git a/sources/libClangSharp/ClangSharp.h b/sources/libClangSharp/ClangSharp.h index c8a609c7..5b550922 100644 --- a/sources/libClangSharp/ClangSharp.h +++ b/sources/libClangSharp/ClangSharp.h @@ -651,6 +651,8 @@ CLANGSHARP_LINKAGE int clangsharp_Cursor_getNumTemplateParameters(CXCursor C, un CLANGSHARP_LINKAGE int clangsharp_Cursor_getNumTemplateParameterLists(CXCursor C); +CLANGSHARP_LINKAGE int clangsharp_Cursor_getNumTypeParams(CXCursor C); + CLANGSHARP_LINKAGE int clangsharp_Cursor_getNumVBases(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getOpaqueValue(CXCursor C); @@ -737,6 +739,8 @@ CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getTypedefNameForAnonDecl(CXCursor CLANGSHARP_LINKAGE CXType clangsharp_Cursor_getTypeOperand(CXCursor C); +CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getTypeParam(CXCursor C, unsigned i); + CLANGSHARP_LINKAGE CX_UnaryExprOrTypeTrait clangsharp_Cursor_getUnaryExprOrTypeTraitKind(CXCursor C); CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getUnderlyingDecl(CXCursor C); diff --git a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs index 7588ba0c..bb2b980a 100644 --- a/tests/ClangSharp.UnitTests/ObjectiveCTest.cs +++ b/tests/ClangSharp.UnitTests/ObjectiveCTest.cs @@ -13,6 +13,8 @@ public sealed class ObjectiveCTest : TranslationUnitTest [Test] public void Method_Selector() { + AssertNeedNewClangSharp(); + var inputContents = $@" @interface MyClass @property int P1; @@ -48,6 +50,8 @@ @interface MyClass [Test] public void Category_TypeParamList() { + AssertNeedNewClangSharp(); + var inputContents = $@" @interface MyClass @end @@ -67,6 +71,8 @@ @interface MyClass (MyCategory) [Test] public void Method_IsPropertyAccessor() { + AssertNeedNewClangSharp(); + var inputContents = $@" @interface MyClass @property int P1; @@ -99,9 +105,49 @@ @interface MyClass Assert.That(methodStaticMethod.IsPropertyAccessor, Is.False, "methodStaticMethod.IsPropertyAccessor"); } + [Test] + public void TypeParams() + { + AssertNeedNewClangSharp(); + + var inputContents = $$""" +@interface NSObject +@end + +@interface MyClass : NSObject +@end + +@interface MyClass (MyCategory) +@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"); + Assert.That(myClass.TypeParamList, Is.Not.Null, "myClass TypeParamList"); + var myClassTypeParams = myClass.TypeParamList.ToList(); + Assert.That(myClassTypeParams.Count, Is.EqualTo(2), "myClassTypeParams.Count"); + Assert.That(myClassTypeParams[0].Name, Is.EqualTo("A"), "myClassTypeParams[0].Name"); + Assert.That(myClassTypeParams[1].Name, Is.EqualTo("B"), "myClassTypeParams[1].Name"); + + var categories = translationUnit.TranslationUnitDecl.Decls.OfType().ToList(); + var myCategory = categories.SingleOrDefault(v => v.Name == "MyCategory")!; + Assert.That(myCategory, Is.Not.Null, "MyCategory"); + Assert.That(myCategory.TypeParamList, Is.Not.Null, "myCategory TypeParamList"); + var myCategoryTypeParams = myCategory.TypeParamList.ToList(); + Assert.That(myCategoryTypeParams.Count, Is.EqualTo(2), "myCategoryTypeParams.Count"); + Assert.That(myCategoryTypeParams[0].Name, Is.EqualTo("T"), "myCategoryTypeParams[0].Name"); + Assert.That(myCategoryTypeParams[1].Name, Is.EqualTo("Y"), "myCategoryTypeParams[1].Name"); + } + [Test] public void PointerTypes() { + AssertNeedNewClangSharp(); + var inputContents = """ @interface MyClass -(void)instanceMethod:(MyClass **)ptrToPtrToMyClass; @@ -131,6 +177,8 @@ @interface MyClass [Test] public void BlockTypes() { + AssertNeedNewClangSharp(); + var inputContents = $$""" @interface MyClass -(MyClass *(^)(id))instanceMethod1;