Skip to content

Commit b550825

Browse files
Ensure remapping and anonymous record names are correct (#219)
* Catch exceptions and return them as a trailing error diagnostic * Handle null statements * Ensure nested anonymous records get the correct name * Adding tests to cover remapping nested type names * Ensure remapping works for either A::B or A.B
1 parent f5e2b19 commit b550825

11 files changed

Lines changed: 617 additions & 89 deletions

File tree

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl)
348348
}
349349

350350
contextNameParts.Push(EscapeName(contextNamePart));
351-
contextTypeParts.Push(GetRemappedTypeName(anonymousRecordDecl, context: null, anonymousRecordDecl.TypeForDecl, out string nativeTypeName));
351+
contextTypeParts.Push(GetRemappedTypeName(rootRecordDecl, context: null, rootRecordDecl.TypeForDecl, out string nativeTypeName));
352352

353353
if (!rootRecordDecl.IsAnonymousStructOrUnion)
354354
{

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,11 @@ private void VisitMemberExpr(MemberExpr memberExpr)
10071007
StopCSharpCode();
10081008
}
10091009

1010+
private void VisitNullStmt(NullStmt nullStmt)
1011+
{
1012+
// null statements are empty by definition, so nothing to do
1013+
}
1014+
10101015
private void VisitParenExpr(ParenExpr parenExpr)
10111016
{
10121017
var outputBuilder = StartCSharpCode();
@@ -1106,7 +1111,13 @@ private void VisitStmt(Stmt stmt)
11061111

11071112
// case CX_StmtClass.CX_StmtClass_IndirectGotoStmt:
11081113
// case CX_StmtClass.CX_StmtClass_MSDependentExistsStmt:
1109-
// case CX_StmtClass.CX_StmtClass_NullStmt:
1114+
1115+
case CX_StmtClass.CX_StmtClass_NullStmt:
1116+
{
1117+
VisitNullStmt((NullStmt)stmt);
1118+
break;
1119+
}
1120+
11101121
// case CX_StmtClass.CX_StmtClass_OMPAtomicDirective:
11111122
// case CX_StmtClass.CX_StmtClass_OMPBarrierDirective:
11121123
// case CX_StmtClass.CX_StmtClass_OMPCancelDirective:

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -275,42 +275,50 @@ public void GenerateBindings(TranslationUnit translationUnit, string filePath, s
275275
}
276276
}
277277

278-
if (_config.GenerateMacroBindings)
278+
try
279279
{
280-
var translationUnitHandle = translationUnit.Handle;
280+
if (_config.GenerateMacroBindings)
281+
{
282+
var translationUnitHandle = translationUnit.Handle;
281283

282-
var file = translationUnitHandle.GetFile(_filePath);
283-
var fileContents = translationUnitHandle.GetFileContents(file, out var size);
284+
var file = translationUnitHandle.GetFile(_filePath);
285+
var fileContents = translationUnitHandle.GetFileContents(file, out var size);
284286

285287
#if NETCOREAPP
286-
_fileContentsBuilder.Append(Encoding.UTF8.GetString(fileContents));
288+
_fileContentsBuilder.Append(Encoding.UTF8.GetString(fileContents));
287289
#else
288-
_fileContentsBuilder.Append(Encoding.UTF8.GetString(fileContents.ToArray()));
290+
_fileContentsBuilder.Append(Encoding.UTF8.GetString(fileContents.ToArray()));
289291
#endif
290292

291-
foreach (var cursor in translationUnit.TranslationUnitDecl.CursorChildren)
292-
{
293-
if (cursor is PreprocessedEntity preprocessedEntity)
293+
foreach (var cursor in translationUnit.TranslationUnitDecl.CursorChildren)
294294
{
295-
VisitPreprocessedEntity(preprocessedEntity);
295+
if (cursor is PreprocessedEntity preprocessedEntity)
296+
{
297+
VisitPreprocessedEntity(preprocessedEntity);
298+
}
296299
}
297-
}
298300

299-
var unsavedFileContents = _fileContentsBuilder.ToString();
300-
_fileContentsBuilder.Clear();
301+
var unsavedFileContents = _fileContentsBuilder.ToString();
302+
_fileContentsBuilder.Clear();
301303

302-
using var unsavedFile = CXUnsavedFile.Create(_filePath, unsavedFileContents);
303-
var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
304+
using var unsavedFile = CXUnsavedFile.Create(_filePath, unsavedFileContents);
305+
var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
304306

305-
translationFlags = _translationFlags & ~CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;
306-
var handle = CXTranslationUnit.Parse(IndexHandle, _filePath, _clangCommandLineArgs, unsavedFiles, translationFlags);
307+
translationFlags = _translationFlags & ~CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;
308+
var handle = CXTranslationUnit.Parse(IndexHandle, _filePath, _clangCommandLineArgs, unsavedFiles, translationFlags);
307309

308-
using var nestedTranslationUnit = TranslationUnit.GetOrCreate(handle);
309-
Visit(nestedTranslationUnit.TranslationUnitDecl);
310+
using var nestedTranslationUnit = TranslationUnit.GetOrCreate(handle);
311+
Visit(nestedTranslationUnit.TranslationUnitDecl);
312+
}
313+
else
314+
{
315+
Visit(translationUnit.TranslationUnitDecl);
316+
}
310317
}
311-
else
318+
catch (Exception e)
312319
{
313-
Visit(translationUnit.TranslationUnitDecl);
320+
var diagnostic = new Diagnostic(DiagnosticLevel.Error, e.ToString());
321+
_diagnostics.Add(diagnostic);
314322
}
315323
}
316324

@@ -885,7 +893,7 @@ private string GetCursorQualifiedName(NamedDecl namedDecl, bool truncateFunction
885893
while (parts.Count != 0)
886894
{
887895
AppendNamedDecl(part, GetCursorName(part), qualifiedName);
888-
qualifiedName.Append('.');
896+
qualifiedName.Append("::");
889897
part = parts.Pop();
890898
}
891899

@@ -1078,6 +1086,14 @@ private string GetRemappedCursorName(NamedDecl namedDecl)
10781086
return remappedName;
10791087
}
10801088

1089+
name = name.Replace("::", ".");
1090+
remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true);
1091+
1092+
if (remappedName != name)
1093+
{
1094+
return remappedName;
1095+
}
1096+
10811097
name = GetCursorQualifiedName(namedDecl, truncateFunctionParameters: true);
10821098
remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true);
10831099

@@ -1086,6 +1102,14 @@ private string GetRemappedCursorName(NamedDecl namedDecl)
10861102
return remappedName;
10871103
}
10881104

1105+
name = name.Replace("::", ".");
1106+
remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true);
1107+
1108+
if (remappedName != name)
1109+
{
1110+
return remappedName;
1111+
}
1112+
10891113
name = GetCursorName(namedDecl);
10901114
remappedName = GetRemappedName(name, namedDecl, tryRemapOperatorName: true);
10911115

@@ -1188,11 +1212,34 @@ private string GetRemappedTypeName(Cursor cursor, Cursor context, Type type, out
11881212
name = "_";
11891213
name += GetRemappedCursorName(matchingField);
11901214
}
1191-
else if (parentRecordDecl.AnonymousRecords.Count > 1)
1215+
else
11921216
{
1193-
var index = parentRecordDecl.AnonymousRecords.IndexOf(cursor) + 1;
1194-
name += index.ToString();
1195-
}
1217+
var index = 0;
1218+
1219+
if (parentRecordDecl.AnonymousRecords.Count > 1)
1220+
{
1221+
index = parentRecordDecl.AnonymousRecords.IndexOf(cursor) + 1;
1222+
}
1223+
1224+
while ((parentRecordDecl.IsAnonymousStructOrUnion) && (parentRecordDecl.IsUnion == recordType.Decl.IsUnion))
1225+
{
1226+
index += 1;
1227+
1228+
if (parentRecordDecl.Parent is RecordDecl parentRecordDeclParent)
1229+
{
1230+
if (parentRecordDeclParent.AnonymousRecords.Count > 0)
1231+
{
1232+
index += parentRecordDeclParent.AnonymousRecords.Count - 1;
1233+
}
1234+
parentRecordDecl = parentRecordDeclParent;
1235+
}
1236+
}
1237+
1238+
if (index != 0)
1239+
{
1240+
name += index.ToString();
1241+
}
1242+
}
11961243
}
11971244

11981245
name += $"_e__{(recordDecl.IsUnion ? "Union" : "Struct")}";
@@ -2193,7 +2240,7 @@ bool IsExcludedByName(Cursor cursor, out bool isExcludedByConflictingDefinition)
21932240
}
21942241
}
21952242

2196-
if (_config.ExcludedNames.Contains(qualifiedName))
2243+
if (_config.ExcludedNames.Contains(qualifiedName) || _config.ExcludedNames.Contains(qualifiedName.Replace("::", ".")))
21972244
{
21982245
if (_config.LogExclusions)
21992246
{

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/EnumDeclarationTest.cs

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,26 +122,74 @@ public enum MyEnum : {expectedManagedType}
122122

123123
public override Task RemapTest()
124124
{
125-
var inputContents = @"typedef enum _MyEnum : int
125+
var inputContents = @"typedef enum _MyEnum1 : int
126126
{
127-
MyEnum_Value1,
128-
MyEnum_Value2,
129-
MyEnum_Value3,
130-
} MyEnum;
127+
MyEnum1_Value1,
128+
MyEnum1_Value2,
129+
MyEnum1_Value3,
130+
} MyEnum1;
131+
132+
namespace Namespace1
133+
{
134+
namespace Namespace2
135+
{
136+
typedef enum _MyEnum2 : int
137+
{
138+
MyEnum2_Value1,
139+
MyEnum2_Value2,
140+
MyEnum2_Value3,
141+
} MyEnum2;
142+
143+
typedef enum _MyEnum3 : int
144+
{
145+
MyEnum3_Value1,
146+
MyEnum3_Value2,
147+
MyEnum3_Value3,
148+
} MyEnum3;
149+
150+
typedef enum _MyEnum4 : int
151+
{
152+
MyEnum4_Value1,
153+
MyEnum4_Value2,
154+
MyEnum4_Value3,
155+
} MyEnum4;
156+
}
157+
}
131158
";
132159

133-
var expectedOutputContents = $@"namespace ClangSharp.Test
134-
{{
135-
public enum MyEnum
136-
{{
137-
MyEnum_Value1,
138-
MyEnum_Value2,
139-
MyEnum_Value3,
140-
}}
141-
}}
160+
var expectedOutputContents = @"namespace ClangSharp.Test
161+
{
162+
public enum MyEnum1
163+
{
164+
MyEnum1_Value1,
165+
MyEnum1_Value2,
166+
MyEnum1_Value3,
167+
}
168+
169+
public enum MyEnum2
170+
{
171+
MyEnum2_Value1,
172+
MyEnum2_Value2,
173+
MyEnum2_Value3,
174+
}
175+
176+
public enum MyEnum3
177+
{
178+
MyEnum3_Value1,
179+
MyEnum3_Value2,
180+
MyEnum3_Value3,
181+
}
182+
183+
public enum MyEnum4
184+
{
185+
MyEnum4_Value1,
186+
MyEnum4_Value2,
187+
MyEnum4_Value3,
188+
}
189+
}
142190
";
143191

144-
var remappedNames = new Dictionary<string, string> { ["_MyEnum"] = "MyEnum" };
192+
var remappedNames = new Dictionary<string, string> { ["_MyEnum1"] = "MyEnum1", ["Namespace1.Namespace2._MyEnum2"] = "MyEnum2", ["_MyEnum3"] = "MyEnum3", ["Namespace1::Namespace2::_MyEnum4"] = "MyEnum4" };
145193
return ValidateGeneratedCSharpCompatibleUnixBindingsAsync(inputContents, expectedOutputContents, remappedNames: remappedNames);
146194
}
147195

tests/ClangSharp.PInvokeGenerator.UnitTests/CSharpCompatibleUnix/StructDeclarationTest.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,21 @@ struct MyStruct
822822
{nativeType} value;
823823
}} w;
824824
825+
struct
826+
{{
827+
{nativeType} value1;
828+
829+
struct
830+
{{
831+
{nativeType} value;
832+
}};
833+
}};
834+
835+
union
836+
{{
837+
{nativeType} value2;
838+
}};
839+
825840
MyUnion u;
826841
{nativeType} buffer1[4];
827842
MyUnion buffer2[4];
@@ -871,6 +886,39 @@ public ref _Anonymous_e__Struct._w_e__Struct w
871886
}}
872887
}}
873888
889+
public ref {expectedManagedType} value1
890+
{{
891+
get
892+
{{
893+
fixed (_Anonymous_e__Struct._Anonymous1_e__Struct* pField = &Anonymous.Anonymous1)
894+
{{
895+
return ref pField->value1;
896+
}}
897+
}}
898+
}}
899+
900+
public ref {expectedManagedType} value
901+
{{
902+
get
903+
{{
904+
fixed (_Anonymous_e__Struct._Anonymous1_e__Struct._Anonymous_e__Struct* pField = &Anonymous.Anonymous1.Anonymous)
905+
{{
906+
return ref pField->value;
907+
}}
908+
}}
909+
}}
910+
911+
public ref {expectedManagedType} value2
912+
{{
913+
get
914+
{{
915+
fixed (_Anonymous_e__Struct._Anonymous2_e__Union* pField = &Anonymous.Anonymous2)
916+
{{
917+
return ref pField->value2;
918+
}}
919+
}}
920+
}}
921+
874922
public ref MyUnion u
875923
{{
876924
get
@@ -911,6 +959,12 @@ public unsafe partial struct _Anonymous_e__Struct
911959
[NativeTypeName(""struct (anonymous struct at ClangUnsavedFile.h:14:9)"")]
912960
public _w_e__Struct w;
913961
962+
[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:19:9)"")]
963+
public _Anonymous1_e__Struct Anonymous1;
964+
965+
[NativeTypeName(""MyStruct::(anonymous union at ClangUnsavedFile.h:29:9)"")]
966+
public _Anonymous2_e__Union Anonymous2;
967+
914968
public MyUnion u;
915969
916970
[NativeTypeName(""{nativeType} [4]"")]
@@ -924,6 +978,26 @@ public partial struct _w_e__Struct
924978
public {expectedManagedType} value;
925979
}}
926980
981+
public partial struct _Anonymous1_e__Struct
982+
{{
983+
public {expectedManagedType} value1;
984+
985+
[NativeTypeName(""MyStruct::(anonymous struct at ClangUnsavedFile.h:23:13)"")]
986+
public _Anonymous_e__Struct Anonymous;
987+
988+
public partial struct _Anonymous_e__Struct
989+
{{
990+
public {expectedManagedType} value;
991+
}}
992+
}}
993+
994+
[StructLayout(LayoutKind.Explicit)]
995+
public partial struct _Anonymous2_e__Union
996+
{{
997+
[FieldOffset(0)]
998+
public {expectedManagedType} value2;
999+
}}
1000+
9271001
public partial struct _buffer2_e__FixedBuffer
9281002
{{
9291003
public MyUnion e0;

0 commit comments

Comments
 (0)