Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sources/ClangSharp.Interop/Extensions/CXCursor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1921,6 +1921,10 @@ public readonly int GetPlatformAvailability(out bool alwaysDeprecated, out CXStr

public readonly CXCursor GetTypeParam(uint index) => clangsharp.Cursor_getTypeParam(this, index);

public readonly bool TypeParamHasExplicitBound => clangsharp.Cursor_getTypeParamHasExplicitBound(this) != 0;

public readonly ObjCTypeParamVariance TypeParamVariance => (ObjCTypeParamVariance)clangsharp.Cursor_getTypeParamVariance(this);

public readonly CXCursor GetVBase(uint index) => clangsharp.Cursor_getVBase(this, index);

public override readonly string ToString() => Spelling.ToString();
Expand Down
15 changes: 15 additions & 0 deletions sources/ClangSharp.Interop/clang/ObjCTypeParamVariance.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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.

// Ported from https://github.com/llvm/llvm-project/tree/llvmorg-21.1.8/clang/include/clang-c
// 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.

using System;

namespace ClangSharp.Interop;

public enum ObjCTypeParamVariance
{
Invariant,
Covariant,
Contravariant,
}
8 changes: 8 additions & 0 deletions sources/ClangSharp.Interop/clangsharp/clangsharp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,14 @@ public static partial class @clangsharp
[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getUsedContext", ExactSpelling = true)]
public static extern CXCursor Cursor_getUsedContext(CXCursor C);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getTypeParamHasExplicitBound", ExactSpelling = true)]
[return: NativeTypeName("unsigned int")]
public static extern uint Cursor_getTypeParamHasExplicitBound(CXCursor C);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getTypeParamVariance", ExactSpelling = true)]
[return: NativeTypeName("unsigned int")]
public static extern uint Cursor_getTypeParamVariance(CXCursor C);

[DllImport("libClangSharp", CallingConvention = CallingConvention.Cdecl, EntryPoint = "clangsharp_Cursor_getVBase", ExactSpelling = true)]
public static extern CXCursor Cursor_getVBase(CXCursor C, [NativeTypeName("unsigned int")] uint i);

Expand Down
4 changes: 4 additions & 0 deletions sources/ClangSharp/Cursors/Decls/ObjCTypeParamDecl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ internal ObjCTypeParamDecl(CXCursor handle) : base(handle, CXCursor_TemplateType
}

public uint Index => unchecked((uint)Handle.TemplateTypeParmIndex);

public bool HasExplicitBound => Handle.TypeParamHasExplicitBound;

public ObjCTypeParamVariance Variance => Handle.TypeParamVariance;
}
26 changes: 26 additions & 0 deletions sources/libClangSharp/ClangSharp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4918,6 +4918,32 @@ CXCursor clangsharp_Cursor_getUsedContext(CXCursor C) {
return clang_getNullCursor();
}

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getTypeParamHasExplicitBound(CXCursor C)
{
if (isDeclOrTU(C.kind)) {
const Decl* D = getCursorDecl(C);

if (const ObjCTypeParamDecl* OCTPD = dyn_cast<ObjCTypeParamDecl>(D)) {
return OCTPD->hasExplicitBound();
}
}

return 0;
}

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getTypeParamVariance(CXCursor C)
{
if (isDeclOrTU(C.kind)) {
const Decl* D = getCursorDecl(C);

if (const ObjCTypeParamDecl* OCTPD = dyn_cast<ObjCTypeParamDecl>(D)) {
return (unsigned int) OCTPD->getVariance();
}
}

return 0 /* ObjCTypeParamVariance::Invariant */;
}

CXCursor clangsharp_Cursor_getVBase(CXCursor C, unsigned i) {
if (isDeclOrTU(C.kind)) {
const Decl* D = getCursorDecl(C);
Expand Down
4 changes: 4 additions & 0 deletions sources/libClangSharp/ClangSharp.h
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getUninstantiatedDefaultArg(CXCurs

CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getUsedContext(CXCursor C);

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getTypeParamHasExplicitBound(CXCursor C);

CLANGSHARP_LINKAGE unsigned clangsharp_Cursor_getTypeParamVariance(CXCursor C);

CLANGSHARP_LINKAGE CXCursor clangsharp_Cursor_getVBase(CXCursor C, unsigned i);

CLANGSHARP_LINKAGE int64_t clangsharp_Cursor_getDtorVtblIdx(CXCursor C, CX_DestructorType dtor);
Expand Down
38 changes: 38 additions & 0 deletions tests/ClangSharp.UnitTests/ObjectiveCTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ @interface NSObject
@interface MyClass<T, Y> (MyCategory)
@end

@interface MyVariantClass<__contravariant T, __covariant U, V> : NSObject
@end

@interface MyBoundedClass<T : NSObject*> : NSObject
@end

""";
using var translationUnit = CreateTranslationUnit(inputContents, "objective-c++");

Expand All @@ -222,7 +228,11 @@ @interface MyClass<T, Y> (MyCategory)
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[0].HasExplicitBound, Is.EqualTo(false), "myClassTypeParams[0].HasExplicitBound");
Assert.That(myClassTypeParams[0].Variance, Is.EqualTo(ObjCTypeParamVariance.Invariant), "myClassTypeParams[0].Variance");
Assert.That(myClassTypeParams[1].Name, Is.EqualTo("B"), "myClassTypeParams[1].Name");
Assert.That(myClassTypeParams[1].HasExplicitBound, Is.EqualTo(false), "myClassTypeParams[1].HasExplicitBound");
Assert.That(myClassTypeParams[1].Variance, Is.EqualTo(ObjCTypeParamVariance.Invariant), "myClassTypeParams[1].Variance");

var categories = translationUnit.TranslationUnitDecl.Decls.OfType<ObjCCategoryDecl>().ToList();
var myCategory = categories.SingleOrDefault(v => v.Name == "MyCategory")!;
Expand All @@ -231,7 +241,35 @@ @interface MyClass<T, Y> (MyCategory)
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[0].HasExplicitBound, Is.EqualTo(false), "myCategoryTypeParams[0].HasExplicitBound");
Assert.That(myCategoryTypeParams[0].Variance, Is.EqualTo(ObjCTypeParamVariance.Invariant), "myCategoryTypeParams[0].Variance");
Assert.That(myCategoryTypeParams[1].Name, Is.EqualTo("Y"), "myCategoryTypeParams[1].Name");
Assert.That(myCategoryTypeParams[1].HasExplicitBound, Is.EqualTo(false), "myCategoryTypeParams[1].HasExplicitBound");
Assert.That(myCategoryTypeParams[1].Variance, Is.EqualTo(ObjCTypeParamVariance.Invariant), "myCategoryTypeParams[1].Variance");

var myVariantClass = classes.SingleOrDefault(v => v.Name == "MyVariantClass")!;
Assert.That(myVariantClass, Is.Not.Null, "MyVariantClass");
Assert.That(myVariantClass.TypeParamList, Is.Not.Null, "myVariantClass TypeParamList");
var myVariantClassTypeParams = myVariantClass.TypeParamList.ToList();
Assert.That(myVariantClassTypeParams.Count, Is.EqualTo(3), "myVariantClassTypeParams.Count");
Assert.That(myVariantClassTypeParams[0].Name, Is.EqualTo("T"), "myVariantClassTypeParams[0].Name");
Assert.That(myVariantClassTypeParams[1].Name, Is.EqualTo("U"), "myVariantClassTypeParams[1].Name");
Assert.That(myVariantClassTypeParams[2].Name, Is.EqualTo("V"), "myVariantClassTypeParams[2].Name");
Assert.That(myVariantClassTypeParams[0].HasExplicitBound, Is.EqualTo(false), "myVariantClassTypeParams[0].HasExplicitBound");
Assert.That(myVariantClassTypeParams[1].HasExplicitBound, Is.EqualTo(false), "myVariantClassTypeParams[1].HasExplicitBound");
Assert.That(myVariantClassTypeParams[2].HasExplicitBound, Is.EqualTo(false), "myBoundedClassTypeParams[2].HasExplicitBound");
Assert.That(myVariantClassTypeParams[0].Variance, Is.EqualTo(ObjCTypeParamVariance.Contravariant), "myVariantClassTypeParams[0].Variance");
Assert.That(myVariantClassTypeParams[1].Variance, Is.EqualTo(ObjCTypeParamVariance.Covariant), "myVariantClassTypeParams[1].Variance");
Assert.That(myVariantClassTypeParams[2].Variance, Is.EqualTo(ObjCTypeParamVariance.Invariant), "myVariantClassTypeParams[2].Variance");

var myBoundedClass = classes.SingleOrDefault(v => v.Name == "MyBoundedClass")!;
Assert.That(myBoundedClass, Is.Not.Null, "MyBoundedClass");
Assert.That(myBoundedClass.TypeParamList, Is.Not.Null, "myBoundedClass TypeParamList");
var myBoundedClassTypeParams = myBoundedClass.TypeParamList.ToList();
Assert.That(myBoundedClassTypeParams.Count, Is.EqualTo(1), "myBoundedClassTypeParams.Count");
Assert.That(myBoundedClassTypeParams[0].Name, Is.EqualTo("T"), "myBoundedClassTypeParams[0].Name");
Assert.That(myBoundedClassTypeParams[0].HasExplicitBound, Is.EqualTo(true), "myBoundedClassTypeParams[0].HasExplicitBound");
Assert.That(myBoundedClassTypeParams[0].Variance, Is.EqualTo(ObjCTypeParamVariance.Invariant), "myBoundedClassTypeParams[0].Variance");
}

[Test]
Expand Down