From 2929f15acd154cf9bbbf18e800747812e680518c Mon Sep 17 00:00:00 2001 From: Berrysoft Date: Sat, 30 Apr 2022 10:57:48 +0800 Subject: [PATCH 1/2] Add support for varargs. --- .../PInvokeGenerator.VisitDecl.cs | 28 ++++++++++++++++++- .../PInvokeGenerator.cs | 8 ++++++ .../Base/FunctionDeclarationDllImportTest.cs | 5 ++++ .../FunctionDeclarationDllImportTest.cs | 2 ++ .../FunctionDeclarationDllImportTest.cs | 19 +++++++++++++ .../FunctionDeclarationDllImportTest.cs | 2 ++ .../FunctionDeclarationDllImportTest.cs | 19 +++++++++++++ .../FunctionDeclarationDllImportTest.cs | 2 ++ .../FunctionDeclarationDllImportTest.cs | 2 ++ .../FunctionDeclarationDllImportTest.cs | 2 ++ .../FunctionDeclarationDllImportTest.cs | 2 ++ 11 files changed, 90 insertions(+), 1 deletion(-) 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..fcdddff0 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..03dad33d 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; } } From 329e6fc8d60c8d1abd683063e42cc6c2f8e72996 Mon Sep 17 00:00:00 2001 From: Yuyi Wang Date: Wed, 8 Jun 2022 14:30:00 +0800 Subject: [PATCH 2/2] Remove the tailing space. When the param name is empty. Actually the only possible case is when type is __arglist. --- .../CSharp/CSharpOutputBuilder.VisitDecl.cs | 7 +++++-- .../FunctionDeclarationDllImportTest.cs | 2 +- .../FunctionDeclarationDllImportTest.cs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) 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/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs index fcdddff0..5991bd3c 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleWindows/FunctionDeclarationDllImportTest.cs @@ -407,7 +407,7 @@ namespace ClangSharp.Test public static partial class Methods { [DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void MyFunction(int value, __arglist ); + public static extern void MyFunction(int value, __arglist); } } "; diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs index 03dad33d..8ef3e790 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpLatestWindows/FunctionDeclarationDllImportTest.cs @@ -406,7 +406,7 @@ namespace ClangSharp.Test public static partial class Methods { [DllImport(""ClangSharpPInvokeGenerator"", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] - public static extern void MyFunction(int value, __arglist ); + public static extern void MyFunction(int value, __arglist); } } ";