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
Original file line number Diff line number Diff line change
Expand Up @@ -1545,7 +1545,14 @@ private void VisitRecordDecl(RecordDecl recordDecl)

if (_config.GenerateExplicitVtbls)
{
_outputBuilder.WriteRegularField("Vtbl*", "lpVtbl");
if (_config.GenerateMarkerInterfaces && !_config.GenerateCompatibleCode)
{
_outputBuilder.WriteRegularField($"Vtbl<{nativeName}>*", "lpVtbl");
}
else
{
_outputBuilder.WriteRegularField("Vtbl*", "lpVtbl");
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public abstract class CXXMethodDeclarationTest : PInvokeGeneratorTest
[Test]
public Task NewKeywordVirtualWithExplicitVtblTest() => NewKeywordVirtualWithExplicitVtblTestImpl();

[Test]
public Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTest() => NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl();

[Test]
public Task OperatorTest() => OperatorTestImpl();

Expand Down Expand Up @@ -118,6 +121,8 @@ public static int buf_close(void* pcontext)

protected abstract Task NewKeywordVirtualWithExplicitVtblTestImpl();

protected abstract Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl();

protected abstract Task OperatorTestImpl();

protected abstract Task OperatorCallTestImpl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,91 @@ public partial struct Vtbl
return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
}

protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
{
var inputContents = @"struct MyStruct
{
virtual int GetType(int obj) = 0;
virtual int GetType() = 0;
virtual int GetType(int objA, int objB) = 0;
};";

var nativeCallConv = "";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
{
nativeCallConv = " __attribute__((thiscall))";
}

var expectedOutputContents = $@"using System;
using System.Runtime.InteropServices;

namespace ClangSharp.Test
{{
public unsafe partial struct MyStruct : MyStruct.Interface
{{
public Vtbl* lpVtbl;

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetType(MyStruct* pThis, int objA, int objB);

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetType1(MyStruct* pThis);

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetType2(MyStruct* pThis, int obj);

public int GetType(int objA, int objB)
{{
fixed (MyStruct* pThis = &this)
{{
return Marshal.GetDelegateForFunctionPointer<_GetType>(lpVtbl->GetType)(pThis, objA, objB);
}}
}}

public new int GetType()
{{
fixed (MyStruct* pThis = &this)
{{
return Marshal.GetDelegateForFunctionPointer<_GetType1>(lpVtbl->GetType1)(pThis);
}}
}}

public int GetType(int obj)
{{
fixed (MyStruct* pThis = &this)
{{
return Marshal.GetDelegateForFunctionPointer<_GetType2>(lpVtbl->GetType2)(pThis, obj);
}}
}}

public interface Interface
{{
int GetType(int objA, int objB);

int GetType();

int GetType(int obj);
}}

public partial struct Vtbl
{{
[NativeTypeName(""int (int, int){nativeCallConv}"")]
public new IntPtr GetType;

[NativeTypeName(""int (){nativeCallConv}"")]
public IntPtr GetType1;

[NativeTypeName(""int (int){nativeCallConv}"")]
public IntPtr GetType2;
}}
}}
}}
";

return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
}

protected override Task OperatorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,91 @@ public partial struct Vtbl
return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
}

protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
{
var inputContents = @"struct MyStruct
{
virtual int GetType(int obj) = 0;
virtual int GetType() = 0;
virtual int GetType(int objA, int objB) = 0;
};";

var nativeCallConv = "";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
{
nativeCallConv = " __attribute__((thiscall))";
}

var expectedOutputContents = $@"using System;
using System.Runtime.InteropServices;

namespace ClangSharp.Test
{{
public unsafe partial struct MyStruct : MyStruct.Interface
{{
public Vtbl* lpVtbl;

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetType(MyStruct* pThis, int objA, int objB);

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetType1(MyStruct* pThis);

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int _GetType2(MyStruct* pThis, int obj);

public int GetType(int objA, int objB)
{{
fixed (MyStruct* pThis = &this)
{{
return Marshal.GetDelegateForFunctionPointer<_GetType>(lpVtbl->GetType)(pThis, objA, objB);
}}
}}

public new int GetType()
{{
fixed (MyStruct* pThis = &this)
{{
return Marshal.GetDelegateForFunctionPointer<_GetType1>(lpVtbl->GetType1)(pThis);
}}
}}

public int GetType(int obj)
{{
fixed (MyStruct* pThis = &this)
{{
return Marshal.GetDelegateForFunctionPointer<_GetType2>(lpVtbl->GetType2)(pThis, obj);
}}
}}

public interface Interface
{{
int GetType(int objA, int objB);

int GetType();

int GetType(int obj);
}}

public partial struct Vtbl
{{
[NativeTypeName(""int (int, int){nativeCallConv}"")]
public new IntPtr GetType;

[NativeTypeName(""int (){nativeCallConv}"")]
public IntPtr GetType1;

[NativeTypeName(""int (int){nativeCallConv}"")]
public IntPtr GetType2;
}}
}}
}}
";

return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
}

protected override Task OperatorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,73 @@ public partial struct Vtbl
return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
}

protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
{
var inputContents = @"struct MyStruct
{
virtual int GetType(int obj) = 0;
virtual int GetType() = 0;
virtual int GetType(int objA, int objB) = 0;
};";

var nativeCallConv = "";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
{
nativeCallConv = " __attribute__((thiscall))";
}

var expectedOutputContents = $@"using System.Runtime.CompilerServices;

namespace ClangSharp.Test
{{
public unsafe partial struct MyStruct : MyStruct.Interface
{{
public Vtbl<MyStruct>* lpVtbl;

public int GetType(int objA, int objB)
{{
return lpVtbl->GetType((MyStruct*)Unsafe.AsPointer(ref this), objA, objB);
}}

public new int GetType()
{{
return lpVtbl->GetType1((MyStruct*)Unsafe.AsPointer(ref this));
}}

public int GetType(int obj)
{{
return lpVtbl->GetType2((MyStruct*)Unsafe.AsPointer(ref this), obj);
}}

public interface Interface
{{
int GetType(int objA, int objB);

int GetType();

int GetType(int obj);
}}

public partial struct Vtbl<TSelf>
where TSelf : unmanaged, Interface
{{
[NativeTypeName(""int (int, int){nativeCallConv}"")]
public new delegate* unmanaged[Thiscall]<TSelf*, int, int, int> GetType;

[NativeTypeName(""int (){nativeCallConv}"")]
public delegate* unmanaged[Thiscall]<TSelf*, int> GetType1;

[NativeTypeName(""int (int){nativeCallConv}"")]
public delegate* unmanaged[Thiscall]<TSelf*, int, int> GetType2;
}}
}}
}}
";

return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
}

protected override Task OperatorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,73 @@ public partial struct Vtbl
return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
}

protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
{
var inputContents = @"struct MyStruct
{
virtual int GetType(int obj) = 0;
virtual int GetType() = 0;
virtual int GetType(int objA, int objB) = 0;
};";

var nativeCallConv = "";

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
{
nativeCallConv = " __attribute__((thiscall))";
}

var expectedOutputContents = $@"using System.Runtime.CompilerServices;

namespace ClangSharp.Test
{{
public unsafe partial struct MyStruct : MyStruct.Interface
{{
public Vtbl<MyStruct>* lpVtbl;

public int GetType(int objA, int objB)
{{
return lpVtbl->GetType((MyStruct*)Unsafe.AsPointer(ref this), objA, objB);
}}

public new int GetType()
{{
return lpVtbl->GetType1((MyStruct*)Unsafe.AsPointer(ref this));
}}

public int GetType(int obj)
{{
return lpVtbl->GetType2((MyStruct*)Unsafe.AsPointer(ref this), obj);
}}

public interface Interface
{{
int GetType(int objA, int objB);

int GetType();

int GetType(int obj);
}}

public partial struct Vtbl<TSelf>
where TSelf : unmanaged, Interface
{{
[NativeTypeName(""int (int, int){nativeCallConv}"")]
public new delegate* unmanaged[Thiscall]<TSelf*, int, int, int> GetType;

[NativeTypeName(""int (){nativeCallConv}"")]
public delegate* unmanaged[Thiscall]<TSelf*, int> GetType1;

[NativeTypeName(""int (int){nativeCallConv}"")]
public delegate* unmanaged[Thiscall]<TSelf*, int, int> GetType2;
}}
}}
}}
";

return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
}

protected override Task OperatorTestImpl()
{
var inputContents = @"struct MyStruct
Expand Down
Loading