Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve NativeTypeName information to ensure it isn't dropped and doesn't conflict due to path changes #441

Merged
merged 1 commit into from
Apr 9, 2023
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
167 changes: 98 additions & 69 deletions sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2719,103 +2719,102 @@ private string GetRemappedTypeName(Cursor? cursor, Cursor? context, Type type, o
var nameToCheck = nativeTypeName;
var remappedName = GetRemappedName(nameToCheck, cursor, tryRemapOperatorName: false, out var wasRemapped, skipUsing, skipUsingIfNotRemapped: true);

if (wasRemapped)
{
return remappedName;
}

nameToCheck = nameToCheck.Replace("::", ".");
remappedName = GetRemappedName(nameToCheck, cursor, tryRemapOperatorName: false, out wasRemapped, skipUsing, skipUsingIfNotRemapped: true);

if (wasRemapped)
{
return remappedName;
}

nameToCheck = name;
remappedName = GetRemappedName(nameToCheck, cursor, tryRemapOperatorName: false, out wasRemapped, skipUsing);

if (!wasRemapped)
{
if (IsTypeConstantOrIncompleteArray(cursor, type, out var arrayType) && IsType<RecordType>(cursor, arrayType.ElementType))
{
type = arrayType.ElementType;
}
nameToCheck = nameToCheck.Replace("::", ".");
remappedName = GetRemappedName(nameToCheck, cursor, tryRemapOperatorName: false, out wasRemapped, skipUsing, skipUsingIfNotRemapped: true);

if (IsType<RecordType>(cursor, type, out var recordType) && remappedName.StartsWith("__AnonymousRecord_"))
if (!wasRemapped)
{
var recordDecl = recordType.Decl;
remappedName = "_Anonymous";
nameToCheck = name;
remappedName = GetRemappedName(nameToCheck, cursor, tryRemapOperatorName: false, out wasRemapped, skipUsing);

if (recordDecl.Parent is RecordDecl parentRecordDecl)
if (!wasRemapped)
{
var matchingField = parentRecordDecl.Fields.Where((fieldDecl) => fieldDecl.Type.CanonicalType == recordType).FirstOrDefault();

if (matchingField is not null)
if (IsTypeConstantOrIncompleteArray(cursor, type, out var arrayType) && IsType<RecordType>(cursor, arrayType.ElementType))
{
remappedName = "_";
remappedName += GetRemappedCursorName(matchingField);
type = arrayType.ElementType;
}
else
{
var index = 0;

if (parentRecordDecl.AnonymousRecords.Count > 1)
{
index = parentRecordDecl.AnonymousRecords.IndexOf(cursor) + 1;
}
if (IsType<RecordType>(cursor, type, out var recordType) && remappedName.StartsWith("__AnonymousRecord_"))
{
var recordDecl = recordType.Decl;
remappedName = "_Anonymous";

while (parentRecordDecl.IsAnonymousStructOrUnion && (parentRecordDecl.IsUnion == recordType.Decl.IsUnion))
if (recordDecl.Parent is RecordDecl parentRecordDecl)
{
index += 1;
var matchingField = parentRecordDecl.Fields.Where((fieldDecl) => fieldDecl.Type.CanonicalType == recordType).FirstOrDefault();

if (parentRecordDecl.Parent is RecordDecl parentRecordDeclParent)
if (matchingField is not null)
{
if (parentRecordDeclParent.AnonymousRecords.Count > 0)
remappedName = "_";
remappedName += GetRemappedCursorName(matchingField);
}
else
{
var index = 0;

if (parentRecordDecl.AnonymousRecords.Count > 1)
{
index += parentRecordDeclParent.AnonymousRecords.Count - 1;
index = parentRecordDecl.AnonymousRecords.IndexOf(cursor) + 1;
}

while (parentRecordDecl.IsAnonymousStructOrUnion && (parentRecordDecl.IsUnion == recordType.Decl.IsUnion))
{
index += 1;

if (parentRecordDecl.Parent is RecordDecl parentRecordDeclParent)
{
if (parentRecordDeclParent.AnonymousRecords.Count > 0)
{
index += parentRecordDeclParent.AnonymousRecords.Count - 1;
}
parentRecordDecl = parentRecordDeclParent;
}
}

if (index != 0)
{
remappedName += index.ToString();
}
parentRecordDecl = parentRecordDeclParent;
}
}

if (index != 0)
{
remappedName += index.ToString();
}
remappedName += $"_e__{(recordDecl.IsUnion ? "Union" : "Struct")}";
}
}

remappedName += $"_e__{(recordDecl.IsUnion ? "Union" : "Struct")}";
}
else if (IsType<EnumType>(cursor, type, out var enumType) && remappedName.StartsWith("__AnonymousEnum_"))
{
remappedName = GetRemappedTypeName(enumType.Decl, context: null, enumType.Decl.IntegerType, out _, skipUsing);
}
else if (cursor is EnumDecl enumDecl)
{
var enumDeclName = GetRemappedCursorName(enumDecl);
else if (IsType<EnumType>(cursor, type, out var enumType) && remappedName.StartsWith("__AnonymousEnum_"))
{
remappedName = GetRemappedTypeName(enumType.Decl, context: null, enumType.Decl.IntegerType, out _, skipUsing);
}
else if (cursor is EnumDecl enumDecl)
{
// Even though some types have entries with names like *_FORCE_DWORD or *_FORCE_UINT
// MSVC and Clang both still treat this as "signed" values and thus we don't want
// to specially handle it as uint, as that can break ABI handling on some platforms.

if (enumDecl.Enumerators.Any((enumConstantDecl) => IsForceDwordOrForceUInt(enumDeclName, enumConstantDecl)))
{
remappedName = "uint";
WithType(enumDecl, ref remappedName, ref nativeTypeName);
}
}

WithType(enumDecl, ref remappedName, ref nativeTypeName);
}
}

if (IsNativeTypeNameEquivalent(nativeTypeName, remappedName))
if (string.IsNullOrWhiteSpace(nativeTypeName))
{
nativeTypeName = string.Empty;
// When we have an empty native type name, it means the original
// name is the same as the native type name and no adjustments
// were made. In order to ensure things are correctly preserved
// we need to ensure its propagated back here so the below comparison
// works and we don't end up comparing "empty" vs "remapped"
nativeTypeName = name;
}
return remappedName;

bool IsForceDwordOrForceUInt(string enumDeclName, EnumConstantDecl enumConstantDecl)
if (IsNativeTypeNameEquivalent(nativeTypeName, remappedName))
{
var enumConstantDeclName = GetRemappedCursorName(enumConstantDecl);
return (enumConstantDeclName == $"{enumDeclName}_FORCE_DWORD") || (enumConstantDeclName == $"{enumDeclName}_FORCE_UINT");
// Empty the native type name if its equivalent to the new name
nativeTypeName = string.Empty;
}

return remappedName;
}

private static string GetSourceRangeContents(CXTranslationUnit translationUnit, CXSourceRange sourceRange)
Expand Down Expand Up @@ -2904,13 +2903,38 @@ private string GetTargetTypeName(Cursor cursor, out string nativeTypeName)
}

private string GetTypeName(Cursor? cursor, Cursor? context, Type type, bool ignoreTransparentStructsWhereRequired, out string nativeTypeName)
=> GetTypeName(cursor, context, type, type, ignoreTransparentStructsWhereRequired, out nativeTypeName);
{
if (_typeNames.TryGetValue((cursor, context, type), out var result))
{
nativeTypeName = result.nativeTypeName;
return result.typeName;
}
else if (IsType<TagType>(cursor, type, out var tagType) && tagType.Decl.Handle.IsAnonymous)
{
// In order to avoid minor path differences, casing, and other deltas across different
// invocations of the tool, we want to use the "built" anonymous name so we get a more
// minimal but still accurate set of information embedded in the output.

result.typeName = GetAnonymousName(tagType.Decl, tagType.KindSpelling);
result.nativeTypeName = result.typeName;

_typeNames[(cursor, context, type)] = result;

nativeTypeName = result.nativeTypeName;
return result.typeName;
}
else
{
return GetTypeName(cursor, context, type, type, ignoreTransparentStructsWhereRequired, out nativeTypeName);
}
}

private string GetTypeName(Cursor? cursor, Cursor? context, Type rootType, Type type, bool ignoreTransparentStructsWhereRequired, out string nativeTypeName)
{
if (!_typeNames.TryGetValue((cursor, context, type), out var result))
{
result.typeName = type.AsString.NormalizePath()
.Replace("unnamed enum at", "anonymous enum at")
.Replace("unnamed struct at", "anonymous struct at")
.Replace("unnamed union at", "anonymous union at");

Expand Down Expand Up @@ -3113,7 +3137,12 @@ private string GetTypeName(Cursor? cursor, Cursor? context, Type rootType, Type
{
if (tagType.Decl.Handle.IsAnonymous)
{
// In order to avoid minor path differences, casing, and other deltas across different
// invocations of the tool, we want to use the "built" anonymous name so we get a more
// minimal but still accurate set of information embedded in the output.

result.typeName = GetAnonymousName(tagType.Decl, tagType.KindSpelling);
result.nativeTypeName = result.typeName;
}
else if (tagType.Handle.IsConstQualified)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ namespace ClangSharp.Test
public partial struct MyUnion
{
[FieldOffset(0)]
[NativeTypeName(""MyUnion::(anonymous struct at ClangUnsavedFile.h:3:5)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L3_C5"")]
public _Anonymous_e__Struct Anonymous;

public ref int a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ public unsafe partial struct MyStruct

public {expectedManagedType} y;

[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:{line}:{column})"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L{line}_C{column}"")]
public _Anonymous_e__Struct Anonymous;

public ref {expectedManagedType} z
Expand Down Expand Up @@ -1009,13 +1009,13 @@ public unsafe partial struct _Anonymous_e__Struct
{{
public {expectedManagedType} z;

[NativeTypeName(""struct (anonymous struct at ClangUnsavedFile.h:14:9)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L14_C9"")]
public _w_e__Struct w;

[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:19:9)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L19_C9"")]
public _Anonymous1_e__Struct Anonymous1;

[NativeTypeName(""MyStruct::(anonymous union at ClangUnsavedFile.h:29:9)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L29_C9"")]
public _Anonymous2_e__Union Anonymous2;

public MyUnion u;
Expand All @@ -1035,7 +1035,7 @@ public partial struct _Anonymous1_e__Struct
{{
public {expectedManagedType} value1;

[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:23:13)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L23_C13"")]
public _Anonymous_e__Struct Anonymous;

public partial struct _Anonymous_e__Struct
Expand Down Expand Up @@ -1106,7 +1106,7 @@ public partial struct MyStruct

public int y;

[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:6:5)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L6_C5"")]
public _Anonymous_e__Struct Anonymous;

public ref int z
Expand Down Expand Up @@ -1161,7 +1161,7 @@ public partial struct _Anonymous_e__Struct
{
public int z;

[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:10:9)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L10_C9"")]
public _Anonymous_e__Struct Anonymous;

public partial struct _Anonymous_e__Struct
Expand Down Expand Up @@ -1498,7 +1498,7 @@ public partial struct MyStruct

public double b;

[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:7:5)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C5"")]
public _Anonymous_e__Struct Anonymous;

public ref double a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ public unsafe partial struct MyUnion
public {expectedManagedType} b;

[FieldOffset(0)]
[NativeTypeName(""MyUnion::(anonymous union at ClangUnsavedFile.h:{line}:{column})"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L{line}_C{column}"")]
public _Anonymous_e__Union Anonymous;

public ref {expectedManagedType} a
Expand Down Expand Up @@ -902,7 +902,7 @@ public partial struct MyUnion
public int y;

[FieldOffset(0)]
[NativeTypeName(""MyUnion::(anonymous union at ClangUnsavedFile.h:6:5)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L6_C5"")]
public _Anonymous_e__Union Anonymous;

public ref int z
Expand Down Expand Up @@ -960,7 +960,7 @@ public partial struct _Anonymous_e__Union
public int z;

[FieldOffset(0)]
[NativeTypeName(""MyUnion::(anonymous union at ClangUnsavedFile.h:10:9)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L10_C9"")]
public _Anonymous_e__Union Anonymous;

[StructLayout(LayoutKind.Explicit)]
Expand Down Expand Up @@ -1297,7 +1297,7 @@ public partial struct MyUnion
public double b;

[FieldOffset(0)]
[NativeTypeName(""MyUnion::(anonymous union at ClangUnsavedFile.h:7:5)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L7_C5"")]
public _Anonymous_e__Union Anonymous;

public ref double a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ namespace ClangSharp.Test
public partial struct MyUnion
{
[FieldOffset(0)]
[NativeTypeName(""MyUnion::(anonymous struct at ClangUnsavedFile.h:3:5)"")]
[NativeTypeName(""__AnonymousRecord_ClangUnsavedFile_L3_C5"")]
public _Anonymous_e__Struct Anonymous;

public ref int a
Expand Down
Loading