Skip to content

Commit 6b74445

Browse files
ddobrevtritao
authored andcommitted
Flatten anonymous types to avoid empty names
This improves our generated API as we no longer need "_0"-like names and also prevents conflicts between an anonymous type and a property of this type. Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent 64773a5 commit 6b74445

File tree

6 files changed

+121
-5
lines changed

6 files changed

+121
-5
lines changed

src/Generator/Driver.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ public void SetupPasses(ILibrary library)
247247
Generator.SetupPasses();
248248

249249
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass());
250+
TranslationUnitPasses.AddPass(new FlattenAnonymousTypesToFields());
250251
TranslationUnitPasses.AddPass(new FieldToPropertyPass());
251252
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
252253
TranslationUnitPasses.AddPass(new CheckFlagEnumsPass());

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -925,12 +925,12 @@ private void GenerateFieldSetter(Field field, Class @class, QualifiedType fieldT
925925
}
926926
else
927927
{
928-
var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name;
929-
var identifier = name;
928+
var name = ((Class) field.Namespace).Layout.Fields.First(
929+
f => f.FieldPtr == field.OriginalPtr).Name;
930930
if (@class.IsValueType)
931-
returnVar = $"{Helpers.InstanceField}.{identifier}";
931+
returnVar = $"{Helpers.InstanceField}.{name}";
932932
else
933-
returnVar = $"(({TypePrinter.PrintNative(@class)}*){Helpers.InstanceIdentifier})->{identifier}";
933+
returnVar = $"(({TypePrinter.PrintNative(@class)}*){Helpers.InstanceIdentifier})->{name}";
934934
}
935935

936936
var param = new Parameter
@@ -1210,7 +1210,8 @@ private static Property GetActualProperty(Property property, Class c)
12101210

12111211
private void GenerateFieldGetter(Field field, Class @class, QualifiedType returnType)
12121212
{
1213-
var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name;
1213+
var name = ((Class) field.Namespace).Layout.Fields.First(
1214+
f => f.FieldPtr == field.OriginalPtr).Name;
12141215
string returnVar;
12151216
var arrayType = field.Type.Desugar() as ArrayType;
12161217
if (@class.IsValueType)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using CppSharp.AST;
2+
using CppSharp.AST.Extensions;
3+
4+
namespace CppSharp.Passes
5+
{
6+
/// <summary>
7+
/// Replaces anonymous types with their contained fields
8+
/// in class layouts and properties in order to avoid generating
9+
/// these very same anonymous types which is useless and
10+
/// also forces unappealing names.
11+
/// </summary>
12+
public class FlattenAnonymousTypesToFields : TranslationUnitPass
13+
{
14+
public FlattenAnonymousTypesToFields()
15+
{
16+
VisitOptions.VisitClassBases = false;
17+
VisitOptions.VisitClassFields = false;
18+
VisitOptions.VisitClassMethods = false;
19+
VisitOptions.VisitClassProperties = false;
20+
VisitOptions.VisitEventParameters = false;
21+
VisitOptions.VisitFunctionParameters = false;
22+
VisitOptions.VisitFunctionReturnType = false;
23+
VisitOptions.VisitNamespaceEnums = false;
24+
VisitOptions.VisitNamespaceTemplates = false;
25+
VisitOptions.VisitNamespaceTypedefs = false;
26+
VisitOptions.VisitNamespaceVariables = false;
27+
VisitOptions.VisitPropertyAccessors = false;
28+
VisitOptions.VisitTemplateArguments = false;
29+
}
30+
31+
public override bool VisitClassDecl(Class @class)
32+
{
33+
if (!base.VisitClassDecl(@class) || @class.Ignore || @class.IsDependent)
34+
return false;
35+
36+
for (int i = @class.Fields.Count - 1; i >= 0; i--)
37+
{
38+
Field field = @class.Fields[i];
39+
Class fieldType;
40+
if (!string.IsNullOrEmpty(field.OriginalName) ||
41+
!field.Type.Desugar().TryGetClass(out fieldType) ||
42+
!string.IsNullOrEmpty(fieldType.OriginalName))
43+
continue;
44+
45+
ReplaceField(@class, i, fieldType);
46+
ReplaceLayoutField(@class, field, fieldType);
47+
fieldType.Fields.Clear();
48+
fieldType.ExplicitlyIgnore();
49+
}
50+
51+
return true;
52+
}
53+
54+
private static void ReplaceField(Class @class, int i, Class fieldType)
55+
{
56+
@class.Fields.RemoveAt(i);
57+
58+
for (int j = 0; j < fieldType.Fields.Count; j++)
59+
{
60+
Field nestedField = fieldType.Fields[j];
61+
nestedField.Namespace = @class;
62+
@class.Fields.Insert(i + j, nestedField);
63+
}
64+
}
65+
66+
private static void ReplaceLayoutField(Class @class, Field field, Class fieldType)
67+
{
68+
LayoutField layoutField = @class.Layout.Fields.Find(
69+
f => f.FieldPtr == field.OriginalPtr);
70+
int layoutIndex = @class.Layout.Fields.IndexOf(layoutField);
71+
@class.Layout.Fields.RemoveAt(layoutIndex);
72+
73+
for (int j = 0; j < fieldType.Layout.Fields.Count; j++)
74+
{
75+
LayoutField nestedlayoutField = fieldType.Layout.Fields[j];
76+
nestedlayoutField.Offset += layoutField.Offset;
77+
@class.Layout.Fields.Insert(layoutIndex + j, nestedlayoutField);
78+
}
79+
}
80+
}
81+
}

tests/Common/Common.Tests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,22 @@ public void TestUnion()
354354
Assert.That(nestedPublic.G, Is.Not.EqualTo(0));
355355
}
356356

357+
[Test]
358+
public void TestNestedAnonymousTypes()
359+
{
360+
using (TestNestedTypes testNestedTypes = new TestNestedTypes())
361+
{
362+
testNestedTypes.ToVerifyCorrectLayoutBefore = 5;
363+
Assert.That(testNestedTypes.ToVerifyCorrectLayoutBefore, Is.EqualTo(5));
364+
testNestedTypes.I = 10;
365+
Assert.That(testNestedTypes.I, Is.EqualTo(10));
366+
testNestedTypes.C = 'D';
367+
Assert.That(testNestedTypes.C, Is.EqualTo('D'));
368+
testNestedTypes.ToVerifyCorrectLayoutAfter = 15;
369+
Assert.That(testNestedTypes.ToVerifyCorrectLayoutAfter, Is.EqualTo(15));
370+
}
371+
}
372+
357373
[Test]
358374
public void TestPropertyChains()
359375
{

tests/Common/Common.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,14 @@ void va_listFunction(va_list v)
412412
{
413413
}
414414

415+
TestNestedTypes::TestNestedTypes()
416+
{
417+
}
418+
419+
TestNestedTypes::~TestNestedTypes()
420+
{
421+
}
422+
415423
void TestDelegates::MarshalUnattributedDelegate(DelegateInGlobalNamespace del)
416424
{
417425
}

tests/Common/Common.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,8 @@ DLL_API void va_listFunction(va_list v);
827827
struct DLL_API TestNestedTypes
828828
{
829829
public:
830+
TestNestedTypes();
831+
~TestNestedTypes();
830832
union as_types
831833
{
832834
int as_int;
@@ -835,6 +837,13 @@ struct DLL_API TestNestedTypes
835837
unsigned char blue, green, red, alpha;
836838
} as_uchar;
837839
};
840+
int toVerifyCorrectLayoutBefore;
841+
union
842+
{
843+
int i;
844+
char c;
845+
};
846+
int toVerifyCorrectLayoutAfter;
838847
};
839848

840849
class DLL_API HasStdString

0 commit comments

Comments
 (0)