Browse Source

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 <dpldobrev@protonmail.com>
pull/1159/merge
Dimitar Dobrev 6 years ago committed by João Matos
parent
commit
6b744458b4
  1. 1
      src/Generator/Driver.cs
  2. 11
      src/Generator/Generators/CSharp/CSharpSources.cs
  3. 81
      src/Generator/Passes/FlattenAnonymousTypesToFields.cs
  4. 16
      tests/Common/Common.Tests.cs
  5. 8
      tests/Common/Common.cpp
  6. 9
      tests/Common/Common.h

1
src/Generator/Driver.cs

@ -247,6 +247,7 @@ namespace CppSharp @@ -247,6 +247,7 @@ namespace CppSharp
Generator.SetupPasses();
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass());
TranslationUnitPasses.AddPass(new FlattenAnonymousTypesToFields());
TranslationUnitPasses.AddPass(new FieldToPropertyPass());
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
TranslationUnitPasses.AddPass(new CheckFlagEnumsPass());

11
src/Generator/Generators/CSharp/CSharpSources.cs

@ -925,12 +925,12 @@ namespace CppSharp.Generators.CSharp @@ -925,12 +925,12 @@ namespace CppSharp.Generators.CSharp
}
else
{
var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name;
var identifier = name;
var name = ((Class) field.Namespace).Layout.Fields.First(
f => f.FieldPtr == field.OriginalPtr).Name;
if (@class.IsValueType)
returnVar = $"{Helpers.InstanceField}.{identifier}";
returnVar = $"{Helpers.InstanceField}.{name}";
else
returnVar = $"(({TypePrinter.PrintNative(@class)}*){Helpers.InstanceIdentifier})->{identifier}";
returnVar = $"(({TypePrinter.PrintNative(@class)}*){Helpers.InstanceIdentifier})->{name}";
}
var param = new Parameter
@ -1210,7 +1210,8 @@ namespace CppSharp.Generators.CSharp @@ -1210,7 +1210,8 @@ namespace CppSharp.Generators.CSharp
private void GenerateFieldGetter(Field field, Class @class, QualifiedType returnType)
{
var name = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr).Name;
var name = ((Class) field.Namespace).Layout.Fields.First(
f => f.FieldPtr == field.OriginalPtr).Name;
string returnVar;
var arrayType = field.Type.Desugar() as ArrayType;
if (@class.IsValueType)

81
src/Generator/Passes/FlattenAnonymousTypesToFields.cs

@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
using CppSharp.AST;
using CppSharp.AST.Extensions;
namespace CppSharp.Passes
{
/// <summary>
/// Replaces anonymous types with their contained fields
/// in class layouts and properties in order to avoid generating
/// these very same anonymous types which is useless and
/// also forces unappealing names.
/// </summary>
public class FlattenAnonymousTypesToFields : TranslationUnitPass
{
public FlattenAnonymousTypesToFields()
{
VisitOptions.VisitClassBases = false;
VisitOptions.VisitClassFields = false;
VisitOptions.VisitClassMethods = false;
VisitOptions.VisitClassProperties = false;
VisitOptions.VisitEventParameters = false;
VisitOptions.VisitFunctionParameters = false;
VisitOptions.VisitFunctionReturnType = false;
VisitOptions.VisitNamespaceEnums = false;
VisitOptions.VisitNamespaceTemplates = false;
VisitOptions.VisitNamespaceTypedefs = false;
VisitOptions.VisitNamespaceVariables = false;
VisitOptions.VisitPropertyAccessors = false;
VisitOptions.VisitTemplateArguments = false;
}
public override bool VisitClassDecl(Class @class)
{
if (!base.VisitClassDecl(@class) || @class.Ignore || @class.IsDependent)
return false;
for (int i = @class.Fields.Count - 1; i >= 0; i--)
{
Field field = @class.Fields[i];
Class fieldType;
if (!string.IsNullOrEmpty(field.OriginalName) ||
!field.Type.Desugar().TryGetClass(out fieldType) ||
!string.IsNullOrEmpty(fieldType.OriginalName))
continue;
ReplaceField(@class, i, fieldType);
ReplaceLayoutField(@class, field, fieldType);
fieldType.Fields.Clear();
fieldType.ExplicitlyIgnore();
}
return true;
}
private static void ReplaceField(Class @class, int i, Class fieldType)
{
@class.Fields.RemoveAt(i);
for (int j = 0; j < fieldType.Fields.Count; j++)
{
Field nestedField = fieldType.Fields[j];
nestedField.Namespace = @class;
@class.Fields.Insert(i + j, nestedField);
}
}
private static void ReplaceLayoutField(Class @class, Field field, Class fieldType)
{
LayoutField layoutField = @class.Layout.Fields.Find(
f => f.FieldPtr == field.OriginalPtr);
int layoutIndex = @class.Layout.Fields.IndexOf(layoutField);
@class.Layout.Fields.RemoveAt(layoutIndex);
for (int j = 0; j < fieldType.Layout.Fields.Count; j++)
{
LayoutField nestedlayoutField = fieldType.Layout.Fields[j];
nestedlayoutField.Offset += layoutField.Offset;
@class.Layout.Fields.Insert(layoutIndex + j, nestedlayoutField);
}
}
}
}

16
tests/Common/Common.Tests.cs

@ -354,6 +354,22 @@ public class CommonTests : GeneratorTestFixture @@ -354,6 +354,22 @@ public class CommonTests : GeneratorTestFixture
Assert.That(nestedPublic.G, Is.Not.EqualTo(0));
}
[Test]
public void TestNestedAnonymousTypes()
{
using (TestNestedTypes testNestedTypes = new TestNestedTypes())
{
testNestedTypes.ToVerifyCorrectLayoutBefore = 5;
Assert.That(testNestedTypes.ToVerifyCorrectLayoutBefore, Is.EqualTo(5));
testNestedTypes.I = 10;
Assert.That(testNestedTypes.I, Is.EqualTo(10));
testNestedTypes.C = 'D';
Assert.That(testNestedTypes.C, Is.EqualTo('D'));
testNestedTypes.ToVerifyCorrectLayoutAfter = 15;
Assert.That(testNestedTypes.ToVerifyCorrectLayoutAfter, Is.EqualTo(15));
}
}
[Test]
public void TestPropertyChains()
{

8
tests/Common/Common.cpp

@ -412,6 +412,14 @@ void va_listFunction(va_list v) @@ -412,6 +412,14 @@ void va_listFunction(va_list v)
{
}
TestNestedTypes::TestNestedTypes()
{
}
TestNestedTypes::~TestNestedTypes()
{
}
void TestDelegates::MarshalUnattributedDelegate(DelegateInGlobalNamespace del)
{
}

9
tests/Common/Common.h

@ -827,6 +827,8 @@ DLL_API void va_listFunction(va_list v); @@ -827,6 +827,8 @@ DLL_API void va_listFunction(va_list v);
struct DLL_API TestNestedTypes
{
public:
TestNestedTypes();
~TestNestedTypes();
union as_types
{
int as_int;
@ -835,6 +837,13 @@ public: @@ -835,6 +837,13 @@ public:
unsigned char blue, green, red, alpha;
} as_uchar;
};
int toVerifyCorrectLayoutBefore;
union
{
int i;
char c;
};
int toVerifyCorrectLayoutAfter;
};
class DLL_API HasStdString

Loading…
Cancel
Save