Skip to content

Commit ed9de28

Browse files
Merge pull request #363 from SeeminglyScience/SeeminglyScience/issue362
Fix `lpVtbl` field declaration when both `explicit-vtbls` and `generate-marker interfaces` are specified
2 parents 776669a + 28e444e commit ed9de28

File tree

10 files changed

+745
-1
lines changed

10 files changed

+745
-1
lines changed

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1545,7 +1545,14 @@ private void VisitRecordDecl(RecordDecl recordDecl)
15451545

15461546
if (_config.GenerateExplicitVtbls)
15471547
{
1548-
_outputBuilder.WriteRegularField("Vtbl*", "lpVtbl");
1548+
if (_config.GenerateMarkerInterfaces && !_config.GenerateCompatibleCode)
1549+
{
1550+
_outputBuilder.WriteRegularField($"Vtbl<{nativeName}>*", "lpVtbl");
1551+
}
1552+
else
1553+
{
1554+
_outputBuilder.WriteRegularField("Vtbl*", "lpVtbl");
1555+
}
15491556
}
15501557
else
15511558
{

tests/ClangSharp.PInvokeGenerator.UnitTests/Base/CXXMethodDeclarationTest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public abstract class CXXMethodDeclarationTest : PInvokeGeneratorTest
3737
[Test]
3838
public Task NewKeywordVirtualWithExplicitVtblTest() => NewKeywordVirtualWithExplicitVtblTestImpl();
3939

40+
[Test]
41+
public Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTest() => NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl();
42+
4043
[Test]
4144
public Task OperatorTest() => OperatorTestImpl();
4245

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

119122
protected abstract Task NewKeywordVirtualWithExplicitVtblTestImpl();
120123

124+
protected abstract Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl();
125+
121126
protected abstract Task OperatorTestImpl();
122127

123128
protected abstract Task OperatorCallTestImpl();

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/CXXMethodDeclarationTest.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,91 @@ public partial struct Vtbl
539539
return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
540540
}
541541

542+
protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
543+
{
544+
var inputContents = @"struct MyStruct
545+
{
546+
virtual int GetType(int obj) = 0;
547+
virtual int GetType() = 0;
548+
virtual int GetType(int objA, int objB) = 0;
549+
};";
550+
551+
var nativeCallConv = "";
552+
553+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
554+
{
555+
nativeCallConv = " __attribute__((thiscall))";
556+
}
557+
558+
var expectedOutputContents = $@"using System;
559+
using System.Runtime.InteropServices;
560+
561+
namespace ClangSharp.Test
562+
{{
563+
public unsafe partial struct MyStruct : MyStruct.Interface
564+
{{
565+
public Vtbl* lpVtbl;
566+
567+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
568+
public delegate int _GetType(MyStruct* pThis, int objA, int objB);
569+
570+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
571+
public delegate int _GetType1(MyStruct* pThis);
572+
573+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
574+
public delegate int _GetType2(MyStruct* pThis, int obj);
575+
576+
public int GetType(int objA, int objB)
577+
{{
578+
fixed (MyStruct* pThis = &this)
579+
{{
580+
return Marshal.GetDelegateForFunctionPointer<_GetType>(lpVtbl->GetType)(pThis, objA, objB);
581+
}}
582+
}}
583+
584+
public new int GetType()
585+
{{
586+
fixed (MyStruct* pThis = &this)
587+
{{
588+
return Marshal.GetDelegateForFunctionPointer<_GetType1>(lpVtbl->GetType1)(pThis);
589+
}}
590+
}}
591+
592+
public int GetType(int obj)
593+
{{
594+
fixed (MyStruct* pThis = &this)
595+
{{
596+
return Marshal.GetDelegateForFunctionPointer<_GetType2>(lpVtbl->GetType2)(pThis, obj);
597+
}}
598+
}}
599+
600+
public interface Interface
601+
{{
602+
int GetType(int objA, int objB);
603+
604+
int GetType();
605+
606+
int GetType(int obj);
607+
}}
608+
609+
public partial struct Vtbl
610+
{{
611+
[NativeTypeName(""int (int, int){nativeCallConv}"")]
612+
public new IntPtr GetType;
613+
614+
[NativeTypeName(""int (){nativeCallConv}"")]
615+
public IntPtr GetType1;
616+
617+
[NativeTypeName(""int (int){nativeCallConv}"")]
618+
public IntPtr GetType2;
619+
}}
620+
}}
621+
}}
622+
";
623+
624+
return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
625+
}
626+
542627
protected override Task OperatorTestImpl()
543628
{
544629
var inputContents = @"struct MyStruct

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/CXXMethodDeclarationTest.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,91 @@ public partial struct Vtbl
539539
return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
540540
}
541541

542+
protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
543+
{
544+
var inputContents = @"struct MyStruct
545+
{
546+
virtual int GetType(int obj) = 0;
547+
virtual int GetType() = 0;
548+
virtual int GetType(int objA, int objB) = 0;
549+
};";
550+
551+
var nativeCallConv = "";
552+
553+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
554+
{
555+
nativeCallConv = " __attribute__((thiscall))";
556+
}
557+
558+
var expectedOutputContents = $@"using System;
559+
using System.Runtime.InteropServices;
560+
561+
namespace ClangSharp.Test
562+
{{
563+
public unsafe partial struct MyStruct : MyStruct.Interface
564+
{{
565+
public Vtbl* lpVtbl;
566+
567+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
568+
public delegate int _GetType(MyStruct* pThis, int objA, int objB);
569+
570+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
571+
public delegate int _GetType1(MyStruct* pThis);
572+
573+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
574+
public delegate int _GetType2(MyStruct* pThis, int obj);
575+
576+
public int GetType(int objA, int objB)
577+
{{
578+
fixed (MyStruct* pThis = &this)
579+
{{
580+
return Marshal.GetDelegateForFunctionPointer<_GetType>(lpVtbl->GetType)(pThis, objA, objB);
581+
}}
582+
}}
583+
584+
public new int GetType()
585+
{{
586+
fixed (MyStruct* pThis = &this)
587+
{{
588+
return Marshal.GetDelegateForFunctionPointer<_GetType1>(lpVtbl->GetType1)(pThis);
589+
}}
590+
}}
591+
592+
public int GetType(int obj)
593+
{{
594+
fixed (MyStruct* pThis = &this)
595+
{{
596+
return Marshal.GetDelegateForFunctionPointer<_GetType2>(lpVtbl->GetType2)(pThis, obj);
597+
}}
598+
}}
599+
600+
public interface Interface
601+
{{
602+
int GetType(int objA, int objB);
603+
604+
int GetType();
605+
606+
int GetType(int obj);
607+
}}
608+
609+
public partial struct Vtbl
610+
{{
611+
[NativeTypeName(""int (int, int){nativeCallConv}"")]
612+
public new IntPtr GetType;
613+
614+
[NativeTypeName(""int (){nativeCallConv}"")]
615+
public IntPtr GetType1;
616+
617+
[NativeTypeName(""int (int){nativeCallConv}"")]
618+
public IntPtr GetType2;
619+
}}
620+
}}
621+
}}
622+
";
623+
624+
return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
625+
}
626+
542627
protected override Task OperatorTestImpl()
543628
{
544629
var inputContents = @"struct MyStruct

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/CXXMethodDeclarationTest.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,73 @@ public partial struct Vtbl
501501
return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
502502
}
503503

504+
protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
505+
{
506+
var inputContents = @"struct MyStruct
507+
{
508+
virtual int GetType(int obj) = 0;
509+
virtual int GetType() = 0;
510+
virtual int GetType(int objA, int objB) = 0;
511+
};";
512+
513+
var nativeCallConv = "";
514+
515+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
516+
{
517+
nativeCallConv = " __attribute__((thiscall))";
518+
}
519+
520+
var expectedOutputContents = $@"using System.Runtime.CompilerServices;
521+
522+
namespace ClangSharp.Test
523+
{{
524+
public unsafe partial struct MyStruct : MyStruct.Interface
525+
{{
526+
public Vtbl<MyStruct>* lpVtbl;
527+
528+
public int GetType(int objA, int objB)
529+
{{
530+
return lpVtbl->GetType((MyStruct*)Unsafe.AsPointer(ref this), objA, objB);
531+
}}
532+
533+
public new int GetType()
534+
{{
535+
return lpVtbl->GetType1((MyStruct*)Unsafe.AsPointer(ref this));
536+
}}
537+
538+
public int GetType(int obj)
539+
{{
540+
return lpVtbl->GetType2((MyStruct*)Unsafe.AsPointer(ref this), obj);
541+
}}
542+
543+
public interface Interface
544+
{{
545+
int GetType(int objA, int objB);
546+
547+
int GetType();
548+
549+
int GetType(int obj);
550+
}}
551+
552+
public partial struct Vtbl<TSelf>
553+
where TSelf : unmanaged, Interface
554+
{{
555+
[NativeTypeName(""int (int, int){nativeCallConv}"")]
556+
public new delegate* unmanaged[Thiscall]<TSelf*, int, int, int> GetType;
557+
558+
[NativeTypeName(""int (){nativeCallConv}"")]
559+
public delegate* unmanaged[Thiscall]<TSelf*, int> GetType1;
560+
561+
[NativeTypeName(""int (int){nativeCallConv}"")]
562+
public delegate* unmanaged[Thiscall]<TSelf*, int, int> GetType2;
563+
}}
564+
}}
565+
}}
566+
";
567+
568+
return ValidateGeneratedCSharpLatestUnixBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
569+
}
570+
504571
protected override Task OperatorTestImpl()
505572
{
506573
var inputContents = @"struct MyStruct

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/CXXMethodDeclarationTest.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,73 @@ public partial struct Vtbl
501501
return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls);
502502
}
503503

504+
protected override Task NewKeywordVirtualWithExplicitVtblAndMarkerInterfaceTestImpl()
505+
{
506+
var inputContents = @"struct MyStruct
507+
{
508+
virtual int GetType(int obj) = 0;
509+
virtual int GetType() = 0;
510+
virtual int GetType(int objA, int objB) = 0;
511+
};";
512+
513+
var nativeCallConv = "";
514+
515+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !Environment.Is64BitProcess)
516+
{
517+
nativeCallConv = " __attribute__((thiscall))";
518+
}
519+
520+
var expectedOutputContents = $@"using System.Runtime.CompilerServices;
521+
522+
namespace ClangSharp.Test
523+
{{
524+
public unsafe partial struct MyStruct : MyStruct.Interface
525+
{{
526+
public Vtbl<MyStruct>* lpVtbl;
527+
528+
public int GetType(int objA, int objB)
529+
{{
530+
return lpVtbl->GetType((MyStruct*)Unsafe.AsPointer(ref this), objA, objB);
531+
}}
532+
533+
public new int GetType()
534+
{{
535+
return lpVtbl->GetType1((MyStruct*)Unsafe.AsPointer(ref this));
536+
}}
537+
538+
public int GetType(int obj)
539+
{{
540+
return lpVtbl->GetType2((MyStruct*)Unsafe.AsPointer(ref this), obj);
541+
}}
542+
543+
public interface Interface
544+
{{
545+
int GetType(int objA, int objB);
546+
547+
int GetType();
548+
549+
int GetType(int obj);
550+
}}
551+
552+
public partial struct Vtbl<TSelf>
553+
where TSelf : unmanaged, Interface
554+
{{
555+
[NativeTypeName(""int (int, int){nativeCallConv}"")]
556+
public new delegate* unmanaged[Thiscall]<TSelf*, int, int, int> GetType;
557+
558+
[NativeTypeName(""int (){nativeCallConv}"")]
559+
public delegate* unmanaged[Thiscall]<TSelf*, int> GetType1;
560+
561+
[NativeTypeName(""int (int){nativeCallConv}"")]
562+
public delegate* unmanaged[Thiscall]<TSelf*, int, int> GetType2;
563+
}}
564+
}}
565+
}}
566+
";
567+
568+
return ValidateGeneratedCSharpLatestWindowsBindingsAsync(inputContents, expectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateExplicitVtbls | PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
569+
}
570+
504571
protected override Task OperatorTestImpl()
505572
{
506573
var inputContents = @"struct MyStruct

0 commit comments

Comments
 (0)