Skip to content

Commit

Permalink
Fixed anonymous types with field array
Browse files Browse the repository at this point in the history
  • Loading branch information
xoofx committed May 19, 2024
1 parent 1fbed1e commit b00cdbf
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
39 changes: 39 additions & 0 deletions src/CppAst.Tests/TestStructs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,45 @@ struct HelloWorld
);
}

[Test]
public void TestAnonymousUnionWithField2()
{
ParseAssert(@"
struct HelloWorld
{
int a;
union {
int c;
int d;
} e[4];
};
",
compilation =>
{
Assert.False(compilation.HasErrors);

Assert.AreEqual(1, compilation.Classes.Count);

{
var cppStruct = compilation.Classes[0];

// Only one union
Assert.AreEqual(1, cppStruct.Classes.Count);

// Only 2 fields
Assert.AreEqual(2, cppStruct.Fields.Count);

// Check the union
Assert.AreEqual("e", cppStruct.Fields[1].Name);
Assert.IsInstanceOf<CppArrayType>(cppStruct.Fields[1].Type);
var cppArrayType = ((CppArrayType)cppStruct.Fields[1].Type);
Assert.IsInstanceOf<CppClass>(cppArrayType.ElementType);
var cppUnion = ((CppClass)cppArrayType.ElementType);
Assert.AreEqual(CppClassKind.Union, cppUnion.ClassKind);
Assert.AreEqual(2, cppUnion.Fields.Count);
}
}
);
}
}
}
22 changes: 21 additions & 1 deletion src/CppAst/CppModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,25 @@ public static CppSourceLocation GetSourceLocation(CXSourceLocation start)
return new CppSourceLocation(fileNameStr, (int)offset, (int)line, (int)column);
}

private static bool IsAnonymousTypeUsed(CppType type, CppType anonymousType)
{
return IsAnonymousTypeUsed(type, anonymousType, new HashSet<CppType>());
}

private static bool IsAnonymousTypeUsed(CppType type, CppType anonymousType, HashSet<CppType> visited)
{
if (!visited.Add(type)) return false;

if (ReferenceEquals(type, anonymousType)) return true;

if (type is CppTypeWithElementType typeWithElementType)
{
return IsAnonymousTypeUsed(typeWithElementType.ElementType, anonymousType);
}

return false;
}

private CppField VisitFieldOrVariable(CppContainerContext containerContext, CXCursor cursor, void* data)
{
var fieldName = CXUtil.GetCursorSpelling(cursor);
Expand All @@ -849,10 +868,11 @@ private CppField VisitFieldOrVariable(CppContainerContext containerContext, CXCu
CppField cppField;
// This happen in the type is anonymous, we create implicitly a field for it, but if type is the same
// we should reuse the anonymous field we created just before
if (previousField != null && previousField.IsAnonymous && ReferenceEquals(previousField.Type, type))
if (previousField != null && previousField.IsAnonymous && IsAnonymousTypeUsed(type, previousField.Type))
{
cppField = previousField;
cppField.Name = fieldName;
cppField.Type = type;
cppField.Offset = cursor.OffsetOfField / 8;
}
else
Expand Down

0 comments on commit b00cdbf

Please sign in to comment.