diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.Naming.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.Naming.cs index 361f6366..6b6a8bc1 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.Naming.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.Naming.cs @@ -146,6 +146,16 @@ private void ResolveAnonymousCursorName(NamedDecl namedDecl, ReadOnlySpan private static string GetNamespaceQualifiedNativeTypeName(Type type, string nativeTypeName) { + // clang 22 can spell a global-scope name with a redundant leading `::` (e.g. `::boolean`) + // when the unqualified name is shadowed in an enclosing namespace. Drop the global-scope + // qualifier so the NativeTypeName stays consistent with every other unqualified spelling. + var globalScopeOffset = SkipLeadingTypeQualifiers(nativeTypeName); + + if (nativeTypeName.AsSpan(globalScopeOffset).StartsWith("::", StringComparison.Ordinal)) + { + nativeTypeName = nativeTypeName.Remove(globalScopeOffset, 2); + } + // Peel pointer/reference/array layers so a stripped namespace is restored even for // `Ns::Point *` and similar, where clang only ever drops the leading `Namespace::`. @@ -195,6 +205,36 @@ private static string GetNamespaceQualifiedNativeTypeName(Type type, string nati // qualifier belongs on the type name, after any leading run of these. private static readonly string[] s_leadingTypeQualifiers = ["const ", "volatile ", "struct ", "class ", "union ", "enum ", "__unaligned "]; + // Advances past any leading run of cv-qualifiers, elaborated tag keywords, or `__unaligned` to + // the offset where the type's nested-name-specifier begins. + private static int SkipLeadingTypeQualifiers(string nativeTypeName) + { + var offset = 0; + + while (true) + { + var rest = nativeTypeName.AsSpan(offset); + var matched = false; + + foreach (var prefix in s_leadingTypeQualifiers) + { + if (rest.StartsWith(prefix, StringComparison.Ordinal)) + { + offset += prefix.Length; + matched = true; + break; + } + } + + if (!matched) + { + break; + } + } + + return offset; + } + private static string GetNamespaceQualifiedNativeTypeName(Decl decl, string nativeTypeName) { // clang 22's type printer omits the enclosing C++ namespace from a reference when a @@ -220,28 +260,7 @@ private static string GetNamespaceQualifiedNativeTypeName(Decl decl, string nati // The qualifier belongs on the type name, after any leading cv-qualifiers, elaborated tag // keywords, or `__unaligned`, so e.g. a `const struct` pointer stays `const struct Ns::Point *` // rather than the malformed `Ns::const struct Point *`. - var offset = 0; - - while (true) - { - var rest = nativeTypeName.AsSpan(offset); - var matched = false; - - foreach (var prefix in s_leadingTypeQualifiers) - { - if (rest.StartsWith(prefix, StringComparison.Ordinal)) - { - offset += prefix.Length; - matched = true; - break; - } - } - - if (!matched) - { - break; - } - } + var offset = SkipLeadingTypeQualifiers(nativeTypeName); // The source spelling may already carry a trailing run of the namespace (a minimally // qualified reference, e.g. `Windows::Foundation::IPropertyValue` written inside diff --git a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs index d2c71488..fa9dc7a3 100644 --- a/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs +++ b/sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs @@ -1526,6 +1526,15 @@ private void VisitImplicitCastExpr(ImplicitCastExpr implicitCastExpr) } else { + // A constant-array field decayed to a pointer projects to an `[InlineArray]` + // value type, which has no implicit pointer conversion, so take its address to + // bind it to a pointer. A compatible-mode fixed buffer decays on its own, and + // array locals (managed arrays) or string literals must not be addressed here. + if (!Config.GenerateCompatibleCode && (subExpr is MemberExpr) && (subExpr.Type.CanonicalType is ConstantArrayType) && (implicitCastExpr.Type.CanonicalType is PointerType)) + { + outputBuilder.Write('&'); + } + VisitStmt(subExpr); } break; diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Compatible.Unix.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Compatible.Unix.cs new file mode 100644 index 00000000..9c40df1c --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Compatible.Unix.cs @@ -0,0 +1,21 @@ +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public unsafe partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public fixed byte Data[16]; + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "_Z15MyOtherFunctionPv", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Compatible.Windows.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Compatible.Windows.cs new file mode 100644 index 00000000..2b2853e0 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Compatible.Windows.cs @@ -0,0 +1,21 @@ +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public unsafe partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public fixed byte Data[16]; + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?MyOtherFunction@@YAXPEAX@Z", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Default.Unix.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Default.Unix.cs new file mode 100644 index 00000000..d6e31c8b --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Default.Unix.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public _Data_e__FixedBuffer Data; + + [InlineArray(16)] + public partial struct _Data_e__FixedBuffer + { + public byte e0; + } + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "_Z15MyOtherFunctionPv", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(&pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Default.Windows.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Default.Windows.cs new file mode 100644 index 00000000..5b5f6d5f --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Default.Windows.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public _Data_e__FixedBuffer Data; + + [InlineArray(16)] + public partial struct _Data_e__FixedBuffer + { + public byte e0; + } + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?MyOtherFunction@@YAXPEAX@Z", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(&pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Latest.Unix.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Latest.Unix.cs new file mode 100644 index 00000000..d6e31c8b --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Latest.Unix.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public _Data_e__FixedBuffer Data; + + [InlineArray(16)] + public partial struct _Data_e__FixedBuffer + { + public byte e0; + } + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "_Z15MyOtherFunctionPv", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(&pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Latest.Windows.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Latest.Windows.cs new file mode 100644 index 00000000..5b5f6d5f --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Latest.Windows.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public _Data_e__FixedBuffer Data; + + [InlineArray(16)] + public partial struct _Data_e__FixedBuffer + { + public byte e0; + } + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?MyOtherFunction@@YAXPEAX@Z", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(&pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Preview.Unix.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Preview.Unix.cs new file mode 100644 index 00000000..d6e31c8b --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Preview.Unix.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public _Data_e__FixedBuffer Data; + + [InlineArray(16)] + public partial struct _Data_e__FixedBuffer + { + public byte e0; + } + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "_Z15MyOtherFunctionPv", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(&pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Preview.Windows.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Preview.Windows.cs new file mode 100644 index 00000000..5b5f6d5f --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.CSharp.Preview.Windows.cs @@ -0,0 +1,28 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ClangSharp.Test +{ + public partial struct MyStruct + { + [NativeTypeName("unsigned char[16]")] + public _Data_e__FixedBuffer Data; + + [InlineArray(16)] + public partial struct _Data_e__FixedBuffer + { + public byte e0; + } + } + + public static unsafe partial class Methods + { + [DllImport("ClangSharpPInvokeGenerator", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?MyOtherFunction@@YAXPEAX@Z", ExactSpelling = true)] + public static extern void MyOtherFunction(void* pData); + + public static void MyFunction([NativeTypeName("struct MyStruct *")] MyStruct* pStruct) + { + MyOtherFunction(&pStruct->Data); + } + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Compatible.Unix.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Compatible.Unix.xml new file mode 100644 index 00000000..8cd5dace --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Compatible.Unix.xml @@ -0,0 +1,25 @@ + + + + + + byte + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Compatible.Windows.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Compatible.Windows.xml new file mode 100644 index 00000000..15dc30e5 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Compatible.Windows.xml @@ -0,0 +1,25 @@ + + + + + + byte + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Default.Unix.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Default.Unix.xml new file mode 100644 index 00000000..296fd096 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Default.Unix.xml @@ -0,0 +1,31 @@ + + + + + + byte + + + InlineArray(16) + + byte + + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(&pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Default.Windows.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Default.Windows.xml new file mode 100644 index 00000000..37511c1b --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Default.Windows.xml @@ -0,0 +1,31 @@ + + + + + + byte + + + InlineArray(16) + + byte + + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(&pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Latest.Unix.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Latest.Unix.xml new file mode 100644 index 00000000..296fd096 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Latest.Unix.xml @@ -0,0 +1,31 @@ + + + + + + byte + + + InlineArray(16) + + byte + + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(&pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Latest.Windows.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Latest.Windows.xml new file mode 100644 index 00000000..37511c1b --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Latest.Windows.xml @@ -0,0 +1,31 @@ + + + + + + byte + + + InlineArray(16) + + byte + + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(&pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Preview.Unix.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Preview.Unix.xml new file mode 100644 index 00000000..296fd096 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Preview.Unix.xml @@ -0,0 +1,31 @@ + + + + + + byte + + + InlineArray(16) + + byte + + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(&pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Preview.Windows.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Preview.Windows.xml new file mode 100644 index 00000000..37511c1b --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/FunctionDeclarationBodyImport/ArrayFieldToPointerArgumentTest.Xml.Preview.Windows.xml @@ -0,0 +1,31 @@ + + + + + + byte + + + InlineArray(16) + + byte + + + + + + void + + void* + + + + void + + MyStruct* + + MyOtherFunction(&pStruct->Data); + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/NamespaceNativeTypeName/GlobalScopeQualifierIsStrippedTest.CSharp.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/NamespaceNativeTypeName/GlobalScopeQualifierIsStrippedTest.CSharp.cs new file mode 100644 index 00000000..e93ebd86 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/NamespaceNativeTypeName/GlobalScopeQualifierIsStrippedTest.CSharp.cs @@ -0,0 +1,13 @@ +namespace ClangSharp.Test +{ + public partial struct @boolean + { + public int x; + } + + public unsafe partial struct Holder + { + [NativeTypeName("boolean *")] + public byte* globalPtr; + } +} diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/NamespaceNativeTypeName/GlobalScopeQualifierIsStrippedTest.Xml.xml b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/NamespaceNativeTypeName/GlobalScopeQualifierIsStrippedTest.Xml.xml new file mode 100644 index 00000000..990c7e29 --- /dev/null +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/Baselines/NamespaceNativeTypeName/GlobalScopeQualifierIsStrippedTest.Xml.xml @@ -0,0 +1,15 @@ + + + + + + int + + + + + byte* + + + + diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/FunctionDeclarationBodyImportTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/FunctionDeclarationBodyImportTest.cs index 46881ef6..857ca648 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/FunctionDeclarationBodyImportTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/FunctionDeclarationBodyImportTest.cs @@ -44,6 +44,28 @@ public Task ArraySubscriptTest() return ValidateAsync(nameof(ArraySubscriptTest), inputContents); } + // A constant-array field projects to an `[InlineArray]` value type, which has no implicit + // pointer conversion, so a decay to a pointer argument must take its address (`&pStruct->Data`). + // A compatible-mode fixed buffer decays to a pointer on its own, so it stays unaddressed. + [Test] + public Task ArrayFieldToPointerArgumentTest() + { + var inputContents = @"void MyOtherFunction(void* pData); + +struct MyStruct +{ + unsigned char Data[16]; +}; + +void MyFunction(struct MyStruct* pStruct) +{ + MyOtherFunction(pStruct->Data); +} +"; + + return ValidateAsync(nameof(ArrayFieldToPointerArgumentTest), inputContents); + } + [Test] public Task BasicTest() { diff --git a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/NamespaceNativeTypeNameTest.cs b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/NamespaceNativeTypeNameTest.cs index 1fe1220f..0bf201d8 100644 --- a/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/NamespaceNativeTypeNameTest.cs +++ b/tests/ClangSharp.PInvokeGenerator.UnitTests/Baseline/NamespaceNativeTypeNameTest.cs @@ -100,4 +100,30 @@ struct Interop return ValidateAsync(nameof(PartiallyQualifiedNamespaceIsNotDuplicatedTest), inputContents); } + + // clang 22 can spell a global-scope reference with a redundant leading `::` (e.g. `::boolean`) + // when the unqualified name is shadowed by a type in the enclosing namespace. The generator + // drops that global-scope qualifier so the `NativeTypeName` stays consistent with every other + // unqualified spelling rather than churning to `::boolean`. + [Test] + public Task GlobalScopeQualifierIsStrippedTest() + { + var inputContents = @"typedef unsigned char boolean; + +namespace Ns +{ + struct boolean + { + int x; + }; + + struct Holder + { + ::boolean* globalPtr; + }; +} +"; + + return ValidateAsync(nameof(GlobalScopeQualifierIsStrippedTest), inputContents); + } }