Browse Source

Wrapped properties of non-primitive value types as fields.

Signed-off-by: Dimitar Dobrev <dpldobrev@yahoo.com>
pull/151/head
Dimitar Dobrev 12 years ago
parent
commit
9686187eb1
  1. 13
      src/AST/Property.cs
  2. 41
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  3. 10
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  4. 36
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  5. 7
      src/Generator/Passes/FieldToPropertyPass.cs
  6. 7
      tests/Basic/Basic.Tests.cs

13
src/AST/Property.cs

@ -104,5 +104,18 @@ namespace CppSharp.AST @@ -104,5 +104,18 @@ namespace CppSharp.AST
{
return visitor.VisitProperty(this);
}
public bool IsBackedByValueClassField()
{
if (Field == null)
return false;
Type type;
Field.Type.IsPointerTo(out type);
type = type ?? Field.Type;
Class decl;
return type.IsTagDecl(out decl) && decl.IsValueType;
}
}
}

41
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -396,7 +396,7 @@ namespace CppSharp.Generators.CLI @@ -396,7 +396,7 @@ namespace CppSharp.Generators.CLI
public void GenerateClassFields(Class @class)
{
// Handle the case of struct (value-type) inheritance by adding the base
// fields to the managed value subtypes.
// properties to the managed value subtypes.
foreach (var @base in @class.Bases)
{
if (!@base.IsClass)
@ -404,28 +404,33 @@ namespace CppSharp.Generators.CLI @@ -404,28 +404,33 @@ namespace CppSharp.Generators.CLI
Class baseClass = @base.Class;
if (!baseClass.IsValueType || baseClass.Ignore)
{
Log.EmitMessage("Ignored base class of value type '{0}'",
baseClass.Name);
continue;
}
GenerateClassFields(baseClass);
}
PushIndent();
foreach (var field in @class.Fields)
// check for value types because some of the ignored fields may back properties;
// not the case for ref types because the NativePtr pattern is used there
foreach (var field in @class.Fields.Where(f => !f.Ignore || @class.IsValueType))
{
if (ASTUtils.CheckIgnoreField(field) && !@class.IsValueType) continue;
var property = @class.Properties.FirstOrDefault(p => p.Field == field);
if (property != null && !property.IsBackedByValueClassField())
{
GenerateField(@class, field);
}
}
PopIndent();
}
private void GenerateField(Class @class, Field field)
{
GenerateDeclarationCommon(field);
if (@class.IsUnion)
WriteLine("[System::Runtime::InteropServices::FieldOffset({0})]",
field.Offset);
WriteLine("{0} {1};", field.Type, SafeIdentifier(field.Name));
}
PopIndent();
}
public void GenerateClassEvents(Class @class)
{
@ -560,10 +565,10 @@ namespace CppSharp.Generators.CLI @@ -560,10 +565,10 @@ namespace CppSharp.Generators.CLI
return false;
}
public void GenerateClassProperties(Class @class, bool onlyFieldProperties = false)
public void GenerateClassProperties(Class @class)
{
// Handle the case of struct (value-type) inheritance by adding the base
// fields to the managed value subtypes.
// properties to the managed value subtypes.
foreach (var @base in @class.Bases)
{
if (!@base.IsClass)
@ -571,19 +576,19 @@ namespace CppSharp.Generators.CLI @@ -571,19 +576,19 @@ namespace CppSharp.Generators.CLI
Class baseClass = @base.Class;
if (!baseClass.IsValueType || baseClass.Ignore)
{
Log.EmitMessage("Ignored base class of value type '{0}'",
baseClass.Name);
continue;
}
GenerateClassProperties(baseClass, true);
GenerateClassProperties(baseClass);
}
PushIndent();
foreach (var prop in @class.Properties)
foreach (var prop in @class.Properties.Where(prop => !prop.Ignore))
{
if (prop.Ignore || (onlyFieldProperties && prop.Field == null)) continue;
if (prop.IsBackedByValueClassField())
{
GenerateField(@class, prop.Field);
continue;
}
GenerateDeclarationCommon(prop);
GenerateProperty(prop);

10
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -191,19 +191,18 @@ namespace CppSharp.Generators.CLI @@ -191,19 +191,18 @@ namespace CppSharp.Generators.CLI
PopBlock();
}
private void GenerateClassProperties(Class @class, Class realOwner,
bool onlyFieldProperties = false)
private void GenerateClassProperties(Class @class, Class realOwner)
{
if (@class.IsValueType)
{
foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore))
{
GenerateClassProperties(@base.Class, realOwner, true);
GenerateClassProperties(@base.Class, realOwner);
}
}
foreach (var property in @class.Properties.Where(
p => !p.Ignore && (!onlyFieldProperties || p.Field != null)))
p => !p.Ignore && !p.IsBackedByValueClassField()))
GenerateProperty(property, realOwner);
}
@ -575,8 +574,7 @@ namespace CppSharp.Generators.CLI @@ -575,8 +574,7 @@ namespace CppSharp.Generators.CLI
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
WriteLine("{0} = {1};",
Generator.GeneratedIdentifier(property.Field.OriginalName), marshal.Context.Return);
WriteLine("{0} = {1};", property.Field.Name, marshal.Context.Return);
}
}

36
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -672,32 +672,32 @@ namespace CppSharp.Generators.CSharp @@ -672,32 +672,32 @@ namespace CppSharp.Generators.CSharp
}
}
private void GenerateStructInternalMarshalingProperty(Property field, string marshalVar)
private void GenerateStructInternalMarshalingProperty(Property property, string marshalVar)
{
var marshalCtx = new CSharpMarshalContext(Driver)
{
ArgName = field.Name,
ArgName = property.Name,
};
var marshal = new CSharpMarshalManagedToNativePrinter(marshalCtx);
field.Visit(marshal);
property.Visit(marshal);
Type type;
Class @class;
var isRef = field.Type.IsPointerTo(out type) &&
var isRef = property.Type.IsPointerTo(out type) &&
!(type.IsTagDecl(out @class) && @class.IsValueType) &&
!type.IsPrimitiveType();
if (isRef)
{
WriteLine("if ({0} != null)", field.Name);
WriteLine("if ({0} != null)", property.Name);
WriteStartBraceIndent();
}
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
WriteLine(marshal.Context.SupportBefore);
WriteLine("{0}.{1} = {2};", marshalVar, field.OriginalName, marshal.Context.Return);
WriteLine("{0}.{1} = {2};", marshalVar, property.OriginalName, marshal.Context.Return);
if (isRef)
WriteCloseBraceIndent();
@ -797,7 +797,7 @@ namespace CppSharp.Generators.CSharp @@ -797,7 +797,7 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateClassField(Field field)
private void GenerateClassField(Field field, bool @public = false)
{
PushBlock(CSharpBlockKind.Field);
@ -807,7 +807,8 @@ namespace CppSharp.Generators.CSharp @@ -807,7 +807,8 @@ namespace CppSharp.Generators.CSharp
if (@class.IsUnion)
WriteLine("[FieldOffset({0})]", field.Offset);
WriteLine("private {0} {1};", field.Type, SafeIdentifier(field.Name));
WriteLine("{0} {1} {2};", @public ? "public" : "private",
field.Type, SafeIdentifier(field.Name));
PopBlock(NewLineKind.BeforeNextBlock);
}
@ -913,6 +914,7 @@ namespace CppSharp.Generators.CSharp @@ -913,6 +914,7 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
WriteStartBraceIndent();
var field = decl as Field;
@ -1006,6 +1008,7 @@ namespace CppSharp.Generators.CSharp @@ -1006,6 +1008,7 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
NewLine();
WriteStartBraceIndent();
var field = decl as Field;
@ -1108,24 +1111,29 @@ namespace CppSharp.Generators.CSharp @@ -1108,24 +1111,29 @@ namespace CppSharp.Generators.CSharp
}
}
private void GenerateClassProperties(Class @class, bool onlyFieldProperties = false)
private void GenerateClassProperties(Class @class)
{
if (@class.IsValueType)
{
foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore))
{
GenerateClassProperties(@base.Class, true);
GenerateClassProperties(@base.Class);
}
}
GenerateProperties(@class, onlyFieldProperties);
GenerateProperties(@class);
}
private void GenerateProperties(Class @class, bool onlyFieldProperties = false)
private void GenerateProperties(Class @class)
{
foreach (var prop in @class.Properties.Where(
p => !p.Ignore && (!onlyFieldProperties || p.Field != null)))
foreach (var prop in @class.Properties.Where(p => !p.Ignore))
{
if (prop.IsBackedByValueClassField())
{
GenerateClassField(prop.Field, true);
continue;
}
PushBlock(CSharpBlockKind.Property);
// If this is an indexer that returns an address use the real type

7
src/Generator/Passes/FieldToPropertyPass.cs

@ -39,8 +39,13 @@ namespace CppSharp.Passes @@ -39,8 +39,13 @@ namespace CppSharp.Passes
Access = field.Access,
Field = field
};
// do not rename value-class fields because they would be
// generated as fields later on even though they are wrapped by properties;
// that is, in turn, because it's cleaner to write
// the struct marshalling logic just for properties
if (!prop.IsBackedByValueClassField())
field.Name = Generator.GeneratedIdentifier(field.Name);
@class.Properties.Add(prop);
@class.Properties.Add(prop);

7
tests/Basic/Basic.Tests.cs

@ -173,5 +173,12 @@ public class BasicTests : GeneratorTestFixture @@ -173,5 +173,12 @@ public class BasicTests : GeneratorTestFixture
Assert.That(nestedPublic.l, Is.EqualTo(5));
Assert.That(nestedPublic.g, Is.Not.EqualTo(0));
}
public void TestPropertyChains()
{
var bar2 = new Bar2();
bar2.pointerToStruct.A = 15;
Assert.That(bar2.pointerToStruct.A, Is.EqualTo(15));
}
}
Loading…
Cancel
Save