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
63 changes: 41 additions & 22 deletions sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.Naming.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ private void ResolveAnonymousCursorName(NamedDecl namedDecl, ReadOnlySpan<char>

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::`.

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<bindings>
<namespace name="ClangSharp.Test">
<struct name="MyStruct" access="public" unsafe="true">
<field name="Data" access="public">
<type native="unsigned char[16]" count="16" fixed="_Data_e__FixedBuffer">byte</type>
</field>
</struct>
<class name="Methods" access="public" static="true">
<function name="MyOtherFunction" access="public" lib="ClangSharpPInvokeGenerator" convention="Cdecl" entrypoint="_Z15MyOtherFunctionPv" static="true" unsafe="true">
<type>void</type>
<param name="pData">
<type>void*</type>
</param>
</function>
<function name="MyFunction" access="public" static="true" unsafe="true">
<type>void</type>
<param name="pStruct">
<type>MyStruct*</type>
</param>
<code>MyOtherFunction(pStruct-&gt;Data);</code>
</function>
</class>
</namespace>
</bindings>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<bindings>
<namespace name="ClangSharp.Test">
<struct name="MyStruct" access="public" unsafe="true">
<field name="Data" access="public">
<type native="unsigned char[16]" count="16" fixed="_Data_e__FixedBuffer">byte</type>
</field>
</struct>
<class name="Methods" access="public" static="true">
<function name="MyOtherFunction" access="public" lib="ClangSharpPInvokeGenerator" convention="Cdecl" entrypoint="?MyOtherFunction@@YAXPEAX@Z" static="true" unsafe="true">
<type>void</type>
<param name="pData">
<type>void*</type>
</param>
</function>
<function name="MyFunction" access="public" static="true" unsafe="true">
<type>void</type>
<param name="pStruct">
<type>MyStruct*</type>
</param>
<code>MyOtherFunction(pStruct-&gt;Data);</code>
</function>
</class>
</namespace>
</bindings>
Loading
Loading