Skip to content

Commit ac8b1a7

Browse files
Merge pull request #281 from tannergooding/main
Greatly improve the understanding of the `log-potential-typedef-remappings` feature
2 parents d894cac + e208c72 commit ac8b1a7

4 files changed

Lines changed: 207 additions & 40 deletions

File tree

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitDecl.cs

Lines changed: 33 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ private void VisitDecl(Decl decl)
2121
{
2222
if (IsExcluded(decl))
2323
{
24+
if (decl.Kind == CX_DeclKind.CX_DeclKind_Typedef)
25+
{
26+
VisitTypedefDecl((TypedefDecl)decl, onlyHandleRemappings: true);
27+
}
2428
return;
2529
}
2630

@@ -133,7 +137,7 @@ private void VisitDecl(Decl decl)
133137

134138
case CX_DeclKind.CX_DeclKind_Typedef:
135139
{
136-
VisitTypedefDecl((TypedefDecl)decl);
140+
VisitTypedefDecl((TypedefDecl)decl, onlyHandleRemappings: false);
137141
break;
138142
}
139143

@@ -268,7 +272,7 @@ private void VisitEnumConstantDecl(EnumConstantDecl enumConstantDecl)
268272
var kind = isAnonymousEnum ? ValueKind.Primitive : ValueKind.Enumerator;
269273
var flags = ValueFlags.Constant;
270274

271-
if (enumConstantDecl.InitExpr is not null)
275+
if ((enumConstantDecl.InitExpr is not null) || isAnonymousEnum)
272276
{
273277
flags |= ValueFlags.Initializer;
274278
}
@@ -2411,13 +2415,13 @@ private void VisitTypeAliasDecl(TypeAliasDecl typeAliasDecl)
24112415
// Nothing to generate for type alias declarations
24122416
}
24132417

2414-
private void VisitTypedefDecl(TypedefDecl typedefDecl)
2418+
private void VisitTypedefDecl(TypedefDecl typedefDecl, bool onlyHandleRemappings)
24152419
{
2416-
ForUnderlyingType(typedefDecl, typedefDecl.UnderlyingType);
2420+
ForUnderlyingType(typedefDecl, typedefDecl.UnderlyingType, onlyHandleRemappings);
24172421

2418-
void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionProtoType, Type parentType)
2422+
void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionProtoType, Type parentType, bool onlyHandleRemappings)
24192423
{
2420-
if (!_config.ExcludeFnptrCodegen)
2424+
if (!_config.ExcludeFnptrCodegen || onlyHandleRemappings)
24212425
{
24222426
return;
24232427
}
@@ -2457,43 +2461,43 @@ void ForFunctionProtoType(TypedefDecl typedefDecl, FunctionProtoType functionPro
24572461
StopUsingOutputBuilder();
24582462
}
24592463

2460-
void ForPointeeType(TypedefDecl typedefDecl, Type parentType, Type pointeeType)
2464+
void ForPointeeType(TypedefDecl typedefDecl, Type parentType, Type pointeeType, bool onlyHandleRemappings)
24612465
{
24622466
if (pointeeType is AttributedType attributedType)
24632467
{
2464-
ForPointeeType(typedefDecl, attributedType, attributedType.ModifiedType);
2468+
ForPointeeType(typedefDecl, attributedType, attributedType.ModifiedType, onlyHandleRemappings);
24652469
}
24662470
else if (pointeeType is ElaboratedType elaboratedType)
24672471
{
2468-
ForPointeeType(typedefDecl, elaboratedType, elaboratedType.NamedType);
2472+
ForPointeeType(typedefDecl, elaboratedType, elaboratedType.NamedType, onlyHandleRemappings);
24692473
}
24702474
else if (pointeeType is FunctionProtoType functionProtoType)
24712475
{
2472-
ForFunctionProtoType(typedefDecl, functionProtoType, parentType);
2476+
ForFunctionProtoType(typedefDecl, functionProtoType, parentType, onlyHandleRemappings);
24732477
}
24742478
else if (pointeeType is PointerType pointerType)
24752479
{
2476-
ForPointeeType(typedefDecl, pointerType, pointerType.PointeeType);
2480+
ForPointeeType(typedefDecl, pointerType, pointerType.PointeeType, onlyHandleRemappings);
24772481
}
24782482
else if (pointeeType is TypedefType typedefType)
24792483
{
2480-
ForPointeeType(typedefDecl, typedefType, typedefType.Decl.UnderlyingType);
2484+
ForPointeeType(typedefDecl, typedefType, typedefType.Decl.UnderlyingType, onlyHandleRemappings);
24812485
}
24822486
else if (pointeeType is not ConstantArrayType and not BuiltinType and not TagType and not TemplateTypeParmType)
24832487
{
24842488
AddDiagnostic(DiagnosticLevel.Error, $"Unsupported pointee type: '{pointeeType.TypeClassSpelling}'. Generating bindings may be incomplete.", typedefDecl);
24852489
}
24862490
}
24872491

2488-
void ForUnderlyingType(TypedefDecl typedefDecl, Type underlyingType)
2492+
void ForUnderlyingType(TypedefDecl typedefDecl, Type underlyingType, bool onlyHandleRemappings)
24892493
{
24902494
if (underlyingType is ArrayType arrayType)
24912495
{
24922496
// Nothing to do for array types
24932497
}
24942498
else if (underlyingType is AttributedType attributedType)
24952499
{
2496-
ForUnderlyingType(typedefDecl, attributedType.ModifiedType);
2500+
ForUnderlyingType(typedefDecl, attributedType.ModifiedType, onlyHandleRemappings);
24972501
}
24982502
else if (underlyingType is BuiltinType builtinType)
24992503
{
@@ -2505,46 +2509,41 @@ void ForUnderlyingType(TypedefDecl typedefDecl, Type underlyingType)
25052509
}
25062510
else if (underlyingType is ElaboratedType elaboratedType)
25072511
{
2508-
ForUnderlyingType(typedefDecl, elaboratedType.NamedType);
2512+
ForUnderlyingType(typedefDecl, elaboratedType.NamedType, onlyHandleRemappings);
25092513
}
25102514
else if (underlyingType is FunctionProtoType functionProtoType)
25112515
{
2512-
ForFunctionProtoType(typedefDecl, functionProtoType, parentType: null);
2516+
ForFunctionProtoType(typedefDecl, functionProtoType, parentType: null, onlyHandleRemappings);
25132517
}
25142518
else if (underlyingType is PointerType pointerType)
25152519
{
2516-
ForPointeeType(typedefDecl, parentType: null, pointerType.PointeeType);
2520+
ForPointeeType(typedefDecl, parentType: null, pointerType.PointeeType, onlyHandleRemappings);
25172521
}
25182522
else if (underlyingType is ReferenceType referenceType)
25192523
{
2520-
ForPointeeType(typedefDecl, parentType: null, referenceType.PointeeType);
2524+
ForPointeeType(typedefDecl, parentType: null, referenceType.PointeeType, onlyHandleRemappings);
25212525
}
25222526
else if (underlyingType is TagType underlyingTagType)
25232527
{
2524-
// See if there's a potential typedef remapping we want to log
2525-
if (_config.LogPotentialTypedefRemappings)
2526-
{
2527-
var typedefName = typedefDecl.UnderlyingDecl.Name;
2528-
var possibleNamesToRemap = new string[] {"_" + typedefName, "_tag" + typedefName, "tag" + typedefName, typedefName + "_tag" };
2529-
var underlyingName = underlyingTagType.AsString;
2528+
var underlyingName = GetCursorName(underlyingTagType.AsTagDecl);
2529+
var typedefName = GetCursorName(typedefDecl);
25302530

2531-
foreach (var possibleNameToRemap in possibleNamesToRemap)
2531+
if (underlyingName != typedefName)
2532+
{
2533+
if (!_validNameRemappings.TryGetValue(underlyingName, out var remappings))
25322534
{
2533-
if (!_config.RemappedNames.ContainsKey(possibleNameToRemap) && !_config.RemappedNames.ContainsKey(possibleNameToRemap + "*"))
2534-
{
2535-
if (possibleNameToRemap == underlyingName)
2536-
{
2537-
AddDiagnostic(DiagnosticLevel.Info, $"Potential remap: {possibleNameToRemap}={typedefName}");
2538-
}
2539-
}
2535+
remappings = new HashSet<string>();
2536+
_validNameRemappings[underlyingName] = remappings;
25402537
}
2538+
2539+
_ = remappings.Add(typedefName);
25412540
}
25422541
}
25432542
else if (underlyingType is TemplateSpecializationType templateSpecializationType)
25442543
{
25452544
if (templateSpecializationType.IsTypeAlias)
25462545
{
2547-
ForUnderlyingType(typedefDecl, templateSpecializationType.AliasedType);
2546+
ForUnderlyingType(typedefDecl, templateSpecializationType.AliasedType, onlyHandleRemappings);
25482547
}
25492548
else
25502549
{
@@ -2557,7 +2556,7 @@ void ForUnderlyingType(TypedefDecl typedefDecl, Type underlyingType)
25572556
}
25582557
else if (underlyingType is TypedefType typedefType)
25592558
{
2560-
ForUnderlyingType(typedefDecl, typedefType.Decl.UnderlyingType);
2559+
ForUnderlyingType(typedefDecl, typedefType.Decl.UnderlyingType, onlyHandleRemappings);
25612560
}
25622561
else
25632562
{

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.VisitStmt.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2440,7 +2440,7 @@ private void VisitOffsetOfExpr(OffsetOfExpr offsetOfExpr)
24402440
outputBuilder.Write("Marshal.OffsetOf<");
24412441
outputBuilder.Write(GetRemappedTypeName(offsetOfExpr, context: null, offsetOfExpr.TypeSourceInfoType, out var _, skipUsing: false));
24422442
outputBuilder.Write(">(\"");
2443-
Visit(offsetOfExpr.Referenced);
2443+
Visit(offsetOfExpr.Referenced ?? offsetOfExpr.CursorChildren[1]);
24442444
outputBuilder.Write("\")");
24452445

24462446
StopCSharpCode();

sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs

Lines changed: 149 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public sealed partial class PInvokeGenerator : IDisposable
3737
private readonly Dictionary<NamedDecl, string> _cursorNames;
3838
private readonly Dictionary<(NamedDecl namedDecl, bool truncateForFunctionParameters), string> _cursorQualifiedNames;
3939
private readonly Dictionary<(Cursor cursor, Cursor context, Type type), (string typeName, string nativeTypeName)> _typeNames;
40+
private readonly Dictionary<string, HashSet<string>> _validNameRemappings;
41+
private readonly HashSet<string> _usedRemappings;
4042

4143
private string _filePath;
4244
private string[] _clangCommandLineArgs;
@@ -90,6 +92,14 @@ public PInvokeGenerator(PInvokeGeneratorConfiguration config, Func<string, Strea
9092
_cursorNames = new Dictionary<NamedDecl, string>();
9193
_cursorQualifiedNames = new Dictionary<(NamedDecl, bool), string>();
9294
_typeNames = new Dictionary<(Cursor, Cursor, Type), (string, string)>();
95+
_validNameRemappings = new Dictionary<string, HashSet<string>>() {
96+
["intptr_t"] = new HashSet<string>() { "IntPtr", "nint" },
97+
["ptrdiff_t"] = new HashSet<string>() { "IntPtr", "nint" },
98+
["size_t"] = new HashSet<string>() { "UIntPtr", "nuint" },
99+
["uintptr_t"] = new HashSet<string>() { "UIntPtr", "nuint" },
100+
["_GUID"] = new HashSet<string>() { "Guid" },
101+
};
102+
_usedRemappings = new HashSet<string>();
93103
}
94104

95105
~PInvokeGenerator()
@@ -121,7 +131,7 @@ public void Close()
121131
{
122132
var iidName = foundUuid.Key;
123133

124-
if (_generatedUuids.Contains(iidName))
134+
if (_generatedUuids.Contains(iidName) || _config.ExcludedNames.Contains(iidName))
125135
{
126136
continue;
127137
}
@@ -355,6 +365,121 @@ public void GenerateBindings(TranslationUnit translationUnit, string filePath, s
355365
{
356366
Visit(translationUnit.TranslationUnitDecl);
357367
}
368+
369+
if (_config.LogPotentialTypedefRemappings)
370+
{
371+
foreach (var kvp in _validNameRemappings)
372+
{
373+
var name = kvp.Key;
374+
var remappings = kvp.Value;
375+
376+
if (!_config.RemappedNames.TryGetValue(name, out var remappedName))
377+
{
378+
AddDiagnostic(DiagnosticLevel.Info, $"Potential missing remapping '{name}'. {GetFoundRemappingString(name, remappings)}");
379+
}
380+
else if (!remappings.Contains(remappedName) && (name != remappedName) && !_config.ForceRemappedNames.Contains(name))
381+
{
382+
AddDiagnostic(DiagnosticLevel.Info, $"Potential invalid remapping '{name}={remappedName}'. {GetFoundRemappingString(name, remappings)}");
383+
}
384+
}
385+
386+
foreach (var name in _usedRemappings)
387+
{
388+
var remappedName = _config.RemappedNames[name];
389+
390+
if (!_validNameRemappings.ContainsKey(name) && (name != remappedName) && !_config.ForceRemappedNames.Contains(name))
391+
{
392+
AddDiagnostic(DiagnosticLevel.Info, $"Potential invalid remapping '{name}={remappedName}'. No remappings were found.");
393+
}
394+
}
395+
396+
static string GetFoundRemappingString(string name, HashSet<string> remappings)
397+
{
398+
var recommendedRemapping = "";
399+
400+
if (remappings.Count == 1)
401+
{
402+
recommendedRemapping = remappings.Single();
403+
}
404+
405+
if ((recommendedRemapping == "") && name.StartsWith("_"))
406+
{
407+
var remapping = name[1..];
408+
409+
if (remappings.Contains(remapping))
410+
{
411+
recommendedRemapping = remapping;
412+
}
413+
}
414+
415+
if ((recommendedRemapping == "") && name.StartsWith("tag"))
416+
{
417+
var remapping = name[3..];
418+
419+
if (remappings.Contains(remapping))
420+
{
421+
recommendedRemapping = remapping;
422+
}
423+
}
424+
425+
if ((recommendedRemapping == "") && name.EndsWith("_"))
426+
{
427+
var remapping = name[0..^1];
428+
429+
if (remappings.Contains(remapping))
430+
{
431+
recommendedRemapping = remapping;
432+
}
433+
}
434+
435+
if ((recommendedRemapping == "") && name.EndsWith("tag"))
436+
{
437+
var remapping = name[0..^3];
438+
439+
if (remappings.Contains(remapping))
440+
{
441+
recommendedRemapping = remapping;
442+
}
443+
}
444+
445+
if (recommendedRemapping == "")
446+
{
447+
var remapping = name.ToUpperInvariant();
448+
449+
if (remappings.Contains(remapping))
450+
{
451+
recommendedRemapping = remapping;
452+
}
453+
}
454+
455+
var result = "";
456+
var remainingRemappings = (IEnumerable<string>)remappings;
457+
var remainingString = "Found";
458+
459+
if (recommendedRemapping != "")
460+
{
461+
result += $"Recommended remapping: '{name}={recommendedRemapping}'.";
462+
463+
if (remappings.Count == 1)
464+
{
465+
remainingRemappings = Array.Empty<string>();
466+
}
467+
else
468+
{
469+
result += ' ';
470+
remainingRemappings = remappings.Except(new string[] { recommendedRemapping });
471+
remainingString = "Other";
472+
}
473+
}
474+
475+
if (remainingRemappings.Any())
476+
{
477+
result += $"{remainingString} typedefs: {string.Join("; ", remainingRemappings)}";
478+
}
479+
480+
return result;
481+
}
482+
}
358483
}
359484
catch (Exception e)
360485
{
@@ -1336,20 +1461,29 @@ private string GetRemappedName(string name, Cursor cursor, bool tryRemapOperator
13361461
if (_config.RemappedNames.TryGetValue(name, out var remappedName))
13371462
{
13381463
wasRemapped = true;
1464+
_ = _usedRemappings.Add(name);
13391465
return AddUsingDirectiveIfNeeded(_outputBuilder, remappedName, skipUsing);
13401466
}
13411467

1342-
if (name.StartsWith("const ") && _config.RemappedNames.TryGetValue(name[6..], out remappedName))
1468+
if (name.StartsWith("const "))
13431469
{
1344-
wasRemapped = true;
1345-
return AddUsingDirectiveIfNeeded(_outputBuilder, remappedName, skipUsing);
1470+
var tmpName = name[6..];
1471+
1472+
if (_config.RemappedNames.TryGetValue(tmpName, out remappedName))
1473+
{
1474+
1475+
wasRemapped = true;
1476+
_ = _usedRemappings.Add(tmpName);
1477+
return AddUsingDirectiveIfNeeded(_outputBuilder, remappedName, skipUsing);
1478+
}
13461479
}
13471480

13481481
remappedName = name;
13491482

13501483
if ((cursor is FunctionDecl functionDecl) && tryRemapOperatorName && TryRemapOperatorName(ref remappedName, functionDecl))
13511484
{
13521485
wasRemapped = true;
1486+
// We don't track remapped operators in _usedRemappings
13531487
return AddUsingDirectiveIfNeeded(_outputBuilder, remappedName, skipUsing);
13541488
}
13551489

@@ -2607,6 +2741,17 @@ bool IsExcludedByName(Cursor cursor, out bool isExcludedByConflictingDefinition)
26072741
{
26082742
return false;
26092743
}
2744+
2745+
if (qualifiedName.Contains("ClangSharpMacro_"))
2746+
{
2747+
qualifiedName = qualifiedName.Replace("ClangSharpMacro_", "");
2748+
}
2749+
2750+
if (name.Contains("ClangSharpMacro_"))
2751+
{
2752+
name = name.Replace("ClangSharpMacro_", "");
2753+
}
2754+
26102755
if (cursor is RecordDecl recordDecl)
26112756
{
26122757
if (_config.ExcludeEmptyRecords && IsEmptyRecord(recordDecl))

0 commit comments

Comments
 (0)