diff --git a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs index 2bc06e95..272afc87 100644 --- a/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/CSharp/CSharpOutputBuilder.VisitDecl.cs @@ -578,8 +578,11 @@ public void BeginParameter(in ParameterDesc info) _customAttrIsForParameter = false; Write(info.Type); - Write(' '); - Write(info.Name); + if (info.Name.Length > 0) + { + Write(' '); + Write(info.Name); + } } } diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs index 0dfe68fb..41acae42 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs @@ -573,7 +573,9 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) _outputBuilder.BeginFunctionInnerPrototype(in desc); - if (isVirtual || (isCxxMethodDecl && !hasBody && cxxMethodDecl.IsInstance)) + bool needsThis = isVirtual || (isCxxMethodDecl && !hasBody && cxxMethodDecl.IsInstance); + + if (needsThis) { Debug.Assert(cxxRecordDecl != null); @@ -612,6 +614,21 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) Visit(functionDecl.Parameters); + if (functionDecl.IsVariadic) + { + if (needsThis || functionDecl.Parameters.Any()) + { + _outputBuilder.WriteParameterSeparator(); + } + var parameterDesc = new ParameterDesc + { + Name = "", + Type = "__arglist" + }; + _outputBuilder.BeginParameter(in parameterDesc); + _outputBuilder.EndParameter(in parameterDesc); + } + _outputBuilder.EndFunctionInnerPrototype(in desc); if (hasBody && !isVirtual) @@ -650,6 +667,15 @@ private void VisitFunctionDecl(FunctionDecl functionDecl) } } + if (functionDecl.IsVariadic) + { + if (parameters.Count != 0) + { + outputBuilder.Write(", "); + } + outputBuilder.Write("__arglist"); + } + outputBuilder.Write(')'); outputBuilder.NeedsSemicolon = true; diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs index 841fb96f..65b25409 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs @@ -1922,6 +1922,14 @@ private Type[] GetBitfieldCount(RecordDecl recordDecl) private CallingConvention GetCallingConvention(Cursor cursor, Cursor context, Type type) { + if (cursor is FunctionDecl functionDecl) + { + if (functionDecl.IsVariadic) + { + return CallingConvention.Cdecl; + } + } + if (cursor is NamedDecl namedDecl) { if (TryGetRemappedValue(namedDecl, _config.WithCallConvs, out var callConv, matchStar: true)) diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/FunctionDeclarationDllImportTest.cs index b8c4d79f..b97dce36 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Base/FunctionDeclarationDllImportTest.cs @@ -73,6 +73,9 @@ public abstract class FunctionDeclarationDllImportTest : PInvokeGeneratorTest [Test] public Task SourceLocationTest() => SourceLocationTestImpl(); + [Test] + public Task VarargsTest() => VarargsTestImpl(); + protected abstract Task BasicTestImpl(); protected abstract Task ArrayParameterTestImpl(); @@ -106,5 +109,7 @@ public abstract class FunctionDeclarationDllImportTest : PInvokeGeneratorTest protected abstract Task WithSetLastErrorStarTestImpl(); protected abstract Task SourceLocationTestImpl(); + + protected abstract Task VarargsTestImpl(); } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/FunctionDeclarationDllImportTest.cs index c2e111f6..d5b902be 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/FunctionDeclarationDllImportTest.cs @@ -396,5 +396,7 @@ public static partial class Methods return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() => Task.CompletedTask; } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs index 5c20714a..5991bd3c 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs @@ -395,5 +395,24 @@ public static partial class Methods return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() + { + const string InputContents = @"extern ""C"" void MyFunction(int value, ...);"; + + const string ExpectedOutputContents = @"using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public static partial class Methods + { + [DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void MyFunction(int value, __arglist); + } +} +"; + + return ValidateGeneratedCSharpCompatibleWindowsBindingsAsync(InputContents, ExpectedOutputContents); + } } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/FunctionDeclarationDllImportTest.cs index a239d6f4..759d4372 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestUnix/FunctionDeclarationDllImportTest.cs @@ -394,5 +394,7 @@ public static partial class Methods return ValidateGeneratedCSharpLatestUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() => Task.CompletedTask; } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs index ed593417..8ef3e790 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs @@ -394,5 +394,24 @@ public static partial class Methods return ValidateGeneratedCSharpLatestWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() + { + const string InputContents = @"extern ""C"" void MyFunction(int value, ...);"; + + const string ExpectedOutputContents = @"using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public static partial class Methods + { + [DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern void MyFunction(int value, __arglist); + } +} +"; + + return ValidateGeneratedCSharpLatestWindowsBindingsAsync(InputContents, ExpectedOutputContents); + } } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/FunctionDeclarationDllImportTest.cs index e641ba57..5ac4372f 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleUnix/FunctionDeclarationDllImportTest.cs @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl() return ValidateGeneratedXmlCompatibleUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() => Task.CompletedTask; } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/FunctionDeclarationDllImportTest.cs index 1ee4d431..895d9547 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlCompatibleWindows/FunctionDeclarationDllImportTest.cs @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl() return ValidateGeneratedXmlCompatibleWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() => Task.CompletedTask; } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/FunctionDeclarationDllImportTest.cs index b7e8bf4f..2fa6dc87 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestUnix/FunctionDeclarationDllImportTest.cs @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl() return ValidateGeneratedXmlLatestUnixBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() => Task.CompletedTask; } } diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/FunctionDeclarationDllImportTest.cs index c0b20b18..80d170d5 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/XmlLatestWindows/FunctionDeclarationDllImportTest.cs @@ -447,5 +447,7 @@ protected override Task SourceLocationTestImpl() return ValidateGeneratedXmlLatestWindowsBindingsAsync(InputContents, ExpectedOutputContents, PInvokeGeneratorConfigurationOptions.GenerateSourceLocationAttribute); } + + protected override Task VarargsTestImpl() => Task.CompletedTask; } }