Skip to content

Commit 29c8038

Browse files
committed
Fix root container detection
1 parent dff0cb8 commit 29c8038

File tree

1 file changed

+123
-88
lines changed

1 file changed

+123
-88
lines changed

src/CppAst/CppModelBuilder.cs

Lines changed: 123 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ namespace CppAst
1717
/// </summary>
1818
internal unsafe class CppModelBuilder
1919
{
20-
private readonly CppContainerContext _rootContainerContext;
20+
private readonly CppContainerContext _userRootContainerContext;
21+
private readonly CppContainerContext _systemRootContainerContext;
22+
private CppContainerContext _rootContainerContext;
2123
private readonly Dictionary<string, CppContainerContext> _containers;
2224
private readonly Dictionary<string, CppType> _typedefs;
2325
private CppClass _currentClassBeingVisited;
@@ -27,7 +29,14 @@ public CppModelBuilder()
2729
_containers = new Dictionary<string, CppContainerContext>();
2830
RootCompilation = new CppCompilation();
2931
_typedefs = new Dictionary<string, CppType>();
30-
_rootContainerContext = new CppContainerContext(RootCompilation);
32+
_userRootContainerContext = new CppContainerContext(RootCompilation)
33+
{
34+
NameContext = "user"
35+
};
36+
_systemRootContainerContext = new CppContainerContext(RootCompilation.System)
37+
{
38+
NameContext = "system"
39+
};
3140
}
3241

3342
public bool AutoSquashTypedef { get; set; }
@@ -42,15 +51,6 @@ public CppModelBuilder()
4251

4352
public CXChildVisitResult VisitTranslationUnit(CXCursor cursor, CXCursor parent, void* data)
4453
{
45-
_rootContainerContext.Container = RootCompilation;
46-
47-
48-
if (cursor.Location.IsInSystemHeader)
49-
{
50-
if (!ParseSystemIncludes) return CXChildVisitResult.CXChildVisit_Continue;
51-
52-
_rootContainerContext.Container = RootCompilation.System;
53-
}
5454
return VisitMember(cursor, parent, data);
5555
}
5656

@@ -98,7 +98,7 @@ private bool TryGetDeclarationContainer(CXCursor cursor, void* data, out string
9898
typeAsCString = CXUtil.GetCursorDisplayName(cursor);
9999
}
100100
// Try to workaround anonymous types
101-
typeKey = $"{typeAsCString}{(cursor.IsAnonymous ? "/" + cursor.Hash : string.Empty)}";
101+
typeKey = $"{_rootContainerContext.NameContext}/{typeAsCString}{(cursor.IsAnonymous ? "/" + cursor.Hash : string.Empty)}";
102102
return _containers.TryGetValue(typeKey, out containerContext);
103103
}
104104

@@ -116,6 +116,11 @@ private CppContainerContext GetDeclarationContainer(CXCursor cursor, void* data)
116116

117117
private CppContainerContext GetOrCreateDeclarationContainer(CXCursor cursor, void* data)
118118
{
119+
while (cursor.Kind == CXCursorKind.CXCursor_LinkageSpec)
120+
{
121+
cursor = cursor.SemanticParent;
122+
}
123+
119124
if (TryGetDeclarationContainer(cursor, data, out string typeKey, out var containerContext))
120125
{
121126
return containerContext;
@@ -383,30 +388,54 @@ private CppClass VisitClassDecl(CXCursor cursor, void* data)
383388
private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* data)
384389
{
385390
CppElement element = null;
391+
392+
// Only set the root container when we know the location
393+
// Otherwise assume that it hasn't changed
394+
// We expect it to be always set
395+
if (cursor.Location != CXSourceLocation.Null)
396+
{
397+
if (cursor.Location.IsInSystemHeader)
398+
{
399+
if (!ParseSystemIncludes) return CXChildVisitResult.CXChildVisit_Continue;
400+
401+
_rootContainerContext = _systemRootContainerContext;
402+
}
403+
else
404+
{
405+
_rootContainerContext = _userRootContainerContext;
406+
}
407+
}
408+
409+
if (_rootContainerContext is null)
410+
{
411+
RootCompilation.Diagnostics.Error($"Unexpected error with cursor location. Cannot determine Root Compilation context.");
412+
return CXChildVisitResult.CXChildVisit_Continue;
413+
}
414+
386415
switch (cursor.Kind)
387416
{
388417
case CXCursorKind.CXCursor_FieldDecl:
389418
case CXCursorKind.CXCursor_VarDecl:
390-
{
391-
var containerContext = GetOrCreateDeclarationContainer(parent, data);
392-
element = VisitFieldOrVariable(containerContext, cursor, data);
393-
break;
394-
}
419+
{
420+
var containerContext = GetOrCreateDeclarationContainer(parent, data);
421+
element = VisitFieldOrVariable(containerContext, cursor, data);
422+
break;
423+
}
395424

396425
case CXCursorKind.CXCursor_EnumConstantDecl:
397-
{
398-
var containerContext = GetOrCreateDeclarationContainer(parent, data);
399-
var cppEnum = (CppEnum)containerContext.Container;
400-
var enumItem = new CppEnumItem(CXUtil.GetCursorSpelling(cursor), cursor.EnumConstantDeclValue);
401-
ParseAttributes(cursor, enumItem, true);
426+
{
427+
var containerContext = GetOrCreateDeclarationContainer(parent, data);
428+
var cppEnum = (CppEnum)containerContext.Container;
429+
var enumItem = new CppEnumItem(CXUtil.GetCursorSpelling(cursor), cursor.EnumConstantDeclValue);
430+
ParseAttributes(cursor, enumItem, true);
402431

403-
VisitInitValue(cursor, data, out var enumItemExpression, out var enumValue);
404-
enumItem.ValueExpression = enumItemExpression;
432+
VisitInitValue(cursor, data, out var enumItemExpression, out var enumValue);
433+
enumItem.ValueExpression = enumItemExpression;
405434

406-
cppEnum.Items.Add(enumItem);
407-
element = enumItem;
408-
break;
409-
}
435+
cppEnum.Items.Add(enumItem);
436+
element = enumItem;
437+
break;
438+
}
410439

411440
case CXCursorKind.CXCursor_Namespace:
412441
element = VisitNamespace(cursor, data);
@@ -419,47 +448,48 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d
419448
case CXCursorKind.CXCursor_ObjCInterfaceDecl:
420449
case CXCursorKind.CXCursor_ObjCProtocolDecl:
421450
case CXCursorKind.CXCursor_ObjCCategoryDecl:
451+
{
452+
bool isAnonymous = cursor.IsAnonymous;
453+
var cppClass = VisitClassDecl(cursor, data);
454+
var containerContext = GetOrCreateDeclarationContainer(parent, data);
455+
// Empty struct/class/union declaration are considered as fields
456+
if (isAnonymous)
422457
{
423-
bool isAnonymous = cursor.IsAnonymous;
424-
var cppClass = VisitClassDecl(cursor, data);
425-
var containerContext = GetOrCreateDeclarationContainer(parent, data);
426-
// Empty struct/class/union declaration are considered as fields
427-
if (isAnonymous)
458+
cppClass.Name = string.Empty;
459+
Debug.Assert(string.IsNullOrEmpty(cppClass.Name));
460+
461+
// We try to recover the offset from the previous field
462+
// Might not be always correct (with alignment rules),
463+
// but not sure how to recover the offset without recalculating the entire offsets
464+
var offset = 0;
465+
var cppClassContainer = containerContext.Container as CppClass;
466+
if (cppClassContainer is object && cppClassContainer.Fields.Count > 0)
428467
{
429-
cppClass.Name = string.Empty;
430-
Debug.Assert(string.IsNullOrEmpty(cppClass.Name));
431-
432-
// We try to recover the offset from the previous field
433-
// Might not be always correct (with alignment rules),
434-
// but not sure how to recover the offset without recalculating the entire offsets
435-
var offset = 0;
436-
var cppClassContainer = containerContext.Container as CppClass;
437-
if (cppClassContainer is object && cppClassContainer.Fields.Count > 0)
438-
{
439-
var lastField = cppClassContainer.Fields[cppClassContainer.Fields.Count - 1];
440-
offset = (int)lastField.Offset + lastField.Type.SizeOf;
441-
}
442-
443-
// Create an anonymous field for the type
444-
var cppField = new CppField(cppClass, string.Empty)
445-
{
446-
Visibility = containerContext.CurrentVisibility,
447-
StorageQualifier = GetStorageQualifier(cursor),
448-
IsAnonymous = true,
449-
Offset = offset,
450-
};
451-
ParseAttributes(cursor, cppField, true);
452-
containerContext.DeclarationContainer.Fields.Add(cppField);
453-
element = cppField;
468+
var lastField = cppClassContainer.Fields[cppClassContainer.Fields.Count - 1];
469+
offset = (int)lastField.Offset + lastField.Type.SizeOf;
454470
}
455-
else
471+
472+
// Create an anonymous field for the type
473+
var cppField = new CppField(cppClass, string.Empty)
456474
{
457-
cppClass.Visibility = containerContext.CurrentVisibility;
458-
element = cppClass;
459-
}
460-
break;
475+
Visibility = containerContext.CurrentVisibility,
476+
StorageQualifier = GetStorageQualifier(cursor),
477+
IsAnonymous = true,
478+
Offset = offset,
479+
};
480+
ParseAttributes(cursor, cppField, true);
481+
containerContext.DeclarationContainer.Fields.Add(cppField);
482+
element = cppField;
483+
}
484+
else
485+
{
486+
cppClass.Visibility = containerContext.CurrentVisibility;
487+
element = cppClass;
461488
}
462489

490+
break;
491+
}
492+
463493
case CXCursorKind.CXCursor_EnumDecl:
464494
element = VisitEnumDecl(cursor, data);
465495
break;
@@ -495,7 +525,7 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d
495525
break;
496526
case CXCursorKind.CXCursor_UnexposedDecl:
497527
return CXChildVisitResult.CXChildVisit_Recurse;
498-
528+
499529
case CXCursorKind.CXCursor_ObjCClassRef:
500530
case CXCursorKind.CXCursor_ObjCProtocolRef:
501531
{
@@ -513,6 +543,7 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d
513543
cppClass.ObjCImplementedProtocols.Add(referencedType);
514544
}
515545
}
546+
516547
break;
517548
}
518549
case CXCursorKind.CXCursor_TypeRef:
@@ -523,43 +554,40 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d
523554
var type = GetCppType(cursor.Referenced, cursor.Type, cursor, data);
524555
genericType.GenericArguments.Add(type);
525556
}
557+
526558
break;
527-
528-
559+
560+
529561
case CXCursorKind.CXCursor_CXXBaseSpecifier:
562+
{
563+
var cppClass = (CppClass)GetOrCreateDeclarationContainer(parent, data).Container;
564+
var baseType = GetCppType(cursor.Type.Declaration, cursor.Type, cursor, data);
565+
var cppBaseType = new CppBaseType(baseType)
530566
{
531-
var cppClass = (CppClass)GetOrCreateDeclarationContainer(parent, data).Container;
532-
var baseType = GetCppType(cursor.Type.Declaration, cursor.Type, cursor, data);
533-
var cppBaseType = new CppBaseType(baseType)
534-
{
535-
Visibility = GetVisibility(cursor.CXXAccessSpecifier),
536-
IsVirtual = cursor.IsVirtualBase
537-
};
538-
cppClass.BaseTypes.Add(cppBaseType);
539-
break;
540-
}
567+
Visibility = GetVisibility(cursor.CXXAccessSpecifier),
568+
IsVirtual = cursor.IsVirtualBase
569+
};
570+
cppClass.BaseTypes.Add(cppBaseType);
571+
break;
572+
}
541573

542574
case CXCursorKind.CXCursor_CXXAccessSpecifier:
543-
{
544-
var containerContext = GetOrCreateDeclarationContainer(parent, data);
545-
containerContext.CurrentVisibility = GetVisibility(cursor.CXXAccessSpecifier);
546-
}
575+
{
576+
var containerContext = GetOrCreateDeclarationContainer(parent, data);
577+
containerContext.CurrentVisibility = GetVisibility(cursor.CXXAccessSpecifier);
578+
}
547579

548580
break;
549581

550582
case CXCursorKind.CXCursor_MacroDefinition:
551583
element = ParseMacro(cursor);
552584
break;
553-
585+
554586
case CXCursorKind.CXCursor_MacroExpansion:
555587
case CXCursorKind.CXCursor_InclusionDirective:
556-
case CXCursorKind.CXCursor_FirstRef:
588+
case CXCursorKind.CXCursor_FirstRef:
557589
case CXCursorKind.CXCursor_ObjCIvarDecl:
558590
case CXCursorKind.CXCursor_TemplateTypeParameter:
559-
if (cursor.IsAttribute)
560-
{
561-
System.Diagnostics.Debugger.Break();
562-
}
563591
break;
564592

565593
case CXCursorKind.CXCursor_LinkageSpec:
@@ -572,19 +600,21 @@ private CXChildVisitResult VisitMember(CXCursor cursor, CXCursor parent, void* d
572600
element = VisitProperty(containerContext, cursor, data);
573601
break;
574602
}
575-
603+
576604
default:
577605
if (!cursor.IsAttribute)
578606
{
579607
WarningUnhandled(cursor, parent);
580608
}
609+
581610
break;
582611
}
583612

584613
if (element != null)
585614
{
586615
bool isForwardDeclaration = (element is CppClass || element is CppEnum) && !cursor.IsDefinition;
587-
if (!isForwardDeclaration) {
616+
if (!isForwardDeclaration)
617+
{
588618
AssignSourceSpan(cursor, element);
589619
}
590620
}
@@ -2271,6 +2301,11 @@ public CppContainerContext(ICppContainer container)
22712301

22722302
public CppVisibility CurrentVisibility;
22732303

2304+
/// <summary>
2305+
/// Either "system" (include) or user.
2306+
/// </summary>
2307+
public string? NameContext { get; init; }
2308+
22742309
public bool IsChildrenVisited;
22752310
}
22762311
}

0 commit comments

Comments
 (0)