Browse Source

Merge pull request #151 from ddobrev/field_props

Field properties
pull/152/head
João Matos 12 years ago
parent
commit
4f084a09bf
  1. 13
      src/AST/Property.cs
  2. 69
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  3. 53
      src/Generator/Generators/CLI/CLIMarshal.cs
  4. 76
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  5. 14
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  6. 137
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  7. 13
      src/Generator/Passes/FieldToPropertyPass.cs
  8. 1
      src/Generator/Passes/verbs.txt
  9. 16
      tests/Basic/Basic.Tests.cs
  10. 1
      tests/Basic/Basic.h

13
src/AST/Property.cs

@ -104,5 +104,18 @@ namespace CppSharp.AST
{ {
return visitor.VisitProperty(this); 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;
}
} }
} }

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

@ -259,8 +259,6 @@ namespace CppSharp.Generators.CLI
GenerateClassConstructors(@class, nativeType); GenerateClassConstructors(@class, nativeType);
GenerateClassFields(@class);
GenerateClassProperties(@class); GenerateClassProperties(@class);
GenerateClassEvents(@class); GenerateClassEvents(@class);
@ -271,6 +269,13 @@ namespace CppSharp.Generators.CLI
GenerateClassVariables(@class); GenerateClassVariables(@class);
if (@class.Fields.Any())
{
NewLine();
WriteLine("private:");
GenerateClassFields(@class);
}
WriteLine("};"); WriteLine("};");
} }
@ -390,41 +395,43 @@ namespace CppSharp.Generators.CLI
public void GenerateClassFields(Class @class) public void GenerateClassFields(Class @class)
{ {
if (!@class.IsValueType)
return;
// Handle the case of struct (value-type) inheritance by adding the base // 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) foreach (var @base in @class.Bases)
{ {
Class baseClass; if (!@base.IsClass)
if (!@base.Type.IsTagDecl(out baseClass))
continue; continue;
Class baseClass = @base.Class;
if (!baseClass.IsValueType || baseClass.Ignore) if (!baseClass.IsValueType || baseClass.Ignore)
{
Log.EmitMessage("Ignored base class of value type '{0}'",
baseClass.Name);
continue; continue;
}
GenerateClassFields(baseClass); GenerateClassFields(baseClass);
} }
PushIndent(); 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)) continue; var property = @class.Properties.FirstOrDefault(p => p.Field == field);
if (property != null && !property.IsBackedByValueClassField())
GenerateDeclarationCommon(field); {
if (@class.IsUnion) GenerateField(@class, field);
WriteLine("[System::Runtime::InteropServices::FieldOffset({0})]", }
field.Offset);
WriteLine("{0} {1};", field.Type, SafeIdentifier(field.Name));
} }
PopIndent(); 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));
}
public void GenerateClassEvents(Class @class) public void GenerateClassEvents(Class @class)
{ {
foreach (var @event in @class.Events) foreach (var @event in @class.Events)
@ -560,10 +567,28 @@ namespace CppSharp.Generators.CLI
public void GenerateClassProperties(Class @class) public void GenerateClassProperties(Class @class)
{ {
// Handle the case of struct (value-type) inheritance by adding the base
// properties to the managed value subtypes.
foreach (var @base in @class.Bases)
{
if (!@base.IsClass)
continue;
Class baseClass = @base.Class;
if (!baseClass.IsValueType || baseClass.Ignore)
continue;
GenerateClassProperties(baseClass);
}
PushIndent(); PushIndent();
foreach (var prop in @class.Properties) foreach (var prop in @class.Properties.Where(prop => !prop.Ignore))
{ {
if (prop.Ignore) continue; if (prop.IsBackedByValueClassField())
{
GenerateField(@class, prop.Field);
continue;
}
GenerateDeclarationCommon(prop); GenerateDeclarationCommon(prop);
GenerateProperty(prop); GenerateProperty(prop);

53
src/Generator/Generators/CLI/CLIMarshal.cs

@ -196,7 +196,15 @@ namespace CppSharp.Generators.CLI
public override bool VisitDeclaration(Declaration decl) public override bool VisitDeclaration(Declaration decl)
{ {
throw new NotImplementedException(); TypeMap typeMap;
if (Context.Driver.TypeDatabase.FindTypeMap(decl, out typeMap))
{
typeMap.Declaration = decl;
typeMap.CLIMarshalToManaged(Context);
return false;
}
return true;
} }
public override bool VisitClassDecl(Class @class) public override bool VisitClassDecl(Class @class)
@ -530,7 +538,15 @@ namespace CppSharp.Generators.CLI
public override bool VisitDeclaration(Declaration decl) public override bool VisitDeclaration(Declaration decl)
{ {
throw new NotImplementedException(); TypeMap typeMap;
if (Context.Driver.TypeDatabase.FindTypeMap(decl, out typeMap))
{
typeMap.Declaration = decl;
typeMap.CLIMarshalToNative(Context);
return false;
}
return true;
} }
public override bool VisitClassDecl(Class @class) public override bool VisitClassDecl(Class @class)
@ -589,7 +605,7 @@ namespace CppSharp.Generators.CLI
Context.SupportBefore.WriteLine("auto {0} = ::{1}();", marshalVar, Context.SupportBefore.WriteLine("auto {0} = ::{1}();", marshalVar,
@class.QualifiedOriginalName); @class.QualifiedOriginalName);
MarshalValueClassFields(@class, marshalVar); MarshalValueClassProperties(@class, marshalVar);
Context.Return.Write(marshalVar); Context.Return.Write(marshalVar);
@ -601,7 +617,7 @@ namespace CppSharp.Generators.CLI
ArgumentPrefix.Write("&"); ArgumentPrefix.Write("&");
} }
public void MarshalValueClassFields(Class @class, string marshalVar) public void MarshalValueClassProperties(Class @class, string marshalVar)
{ {
foreach (var @base in @class.Bases) foreach (var @base in @class.Bases)
{ {
@ -609,22 +625,22 @@ namespace CppSharp.Generators.CLI
continue; continue;
var baseClass = @base.Class; var baseClass = @base.Class;
MarshalValueClassFields(baseClass, marshalVar); MarshalValueClassProperties(baseClass, marshalVar);
} }
foreach (var field in @class.Fields) foreach (var property in @class.Properties)
{ {
if(field.Ignore) if (property.Ignore || property.Field == null)
continue; continue;
MarshalValueClassField(field, marshalVar); MarshalValueClassProperty(property, marshalVar);
} }
} }
private void MarshalValueClassField(Field field, string marshalVar) private void MarshalValueClassProperty(Property property, string marshalVar)
{ {
var fieldRef = string.Format("{0}.{1}", Context.Parameter.Name, var fieldRef = string.Format("{0}.{1}", Context.Parameter.Name,
field.Name); property.Name);
var marshalCtx = new MarshalContext(Context.Driver) var marshalCtx = new MarshalContext(Context.Driver)
{ {
@ -634,7 +650,7 @@ namespace CppSharp.Generators.CLI
}; };
var marshal = new CLIMarshalManagedToNativePrinter(marshalCtx); var marshal = new CLIMarshalManagedToNativePrinter(marshalCtx);
field.Visit(marshal); property.Visit(marshal);
Context.ParameterIndex = marshalCtx.ParameterIndex; Context.ParameterIndex = marshalCtx.ParameterIndex;
@ -643,7 +659,7 @@ namespace CppSharp.Generators.CLI
Type type; Type type;
Class @class; Class @class;
var isRef = field.Type.IsPointerTo(out type) && var isRef = property.Type.IsPointerTo(out type) &&
!(type.IsTagDecl(out @class) && @class.IsValueType) && !(type.IsTagDecl(out @class) && @class.IsValueType) &&
!type.IsPrimitiveType(); !type.IsPrimitiveType();
@ -654,7 +670,7 @@ namespace CppSharp.Generators.CLI
} }
Context.SupportBefore.WriteLine("{0}.{1} = {2};", marshalVar, Context.SupportBefore.WriteLine("{0}.{1} = {2};", marshalVar,
field.OriginalName, marshal.Context.Return); property.Field.OriginalName, marshal.Context.Return);
if (isRef) if (isRef)
Context.SupportBefore.PopIndent(); Context.SupportBefore.PopIndent();
@ -671,6 +687,17 @@ namespace CppSharp.Generators.CLI
return field.Type.Visit(this); return field.Type.Visit(this);
} }
public override bool VisitProperty(Property property)
{
Context.Parameter = new Parameter
{
Name = Context.ArgName,
QualifiedType = property.QualifiedType
};
return base.VisitProperty(property);
}
public override bool VisitFunctionDecl(Function function) public override bool VisitFunctionDecl(Function function)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

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

@ -165,8 +165,7 @@ namespace CppSharp.Generators.CLI
} }
} }
foreach (var property in @class.Properties) GenerateClassProperties(@class, @class);
GenerateProperty(property);
foreach (var @event in @class.Events) foreach (var @event in @class.Events)
{ {
@ -192,6 +191,21 @@ namespace CppSharp.Generators.CLI
PopBlock(); PopBlock();
} }
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);
}
}
foreach (var property in @class.Properties.Where(
p => !p.Ignore && !p.IsBackedByValueClassField()))
GenerateProperty(property, realOwner);
}
private void GenerateFunctionTemplate(FunctionTemplate template) private void GenerateFunctionTemplate(FunctionTemplate template)
{ {
var printer = TypePrinter; var printer = TypePrinter;
@ -236,7 +250,7 @@ namespace CppSharp.Generators.CLI
printer.Context = oldCtx; printer.Context = oldCtx;
} }
private void GenerateProperty(Property property) private void GenerateProperty(Property property, Class realOwner)
{ {
if (property.Ignore) return; if (property.Ignore) return;
@ -246,21 +260,21 @@ namespace CppSharp.Generators.CLI
if (property.Field != null) if (property.Field != null)
{ {
if (property.HasGetter) if (property.HasGetter)
GeneratePropertyGetter(property.Field, @class, property.Name, GeneratePropertyGetter(property.Field, realOwner, property.Name,
property.Type); property.Type);
if (property.HasSetter) if (property.HasSetter)
GeneratePropertySetter(property.Field, @class, property.Name, GeneratePropertySetter(property.Field, realOwner, property.Name,
property.Type); property.Type);
} }
else else
{ {
if (property.HasGetter) if (property.HasGetter)
GeneratePropertyGetter(property.GetMethod, @class, property.Name, GeneratePropertyGetter(property.GetMethod, realOwner, property.Name,
property.Type); property.Type);
if (property.HasSetter) if (property.HasSetter)
GeneratePropertySetter(property.SetMethod, @class, property.Name, GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type); property.Type);
} }
PopBlock(); PopBlock();
@ -285,6 +299,13 @@ namespace CppSharp.Generators.CLI
} }
else else
{ {
if (@class.IsValueType && decl is Field)
{
WriteLine("{0} = value;", decl.Name);
WriteCloseBraceIndent();
NewLine();
return;
}
var param = new Parameter var param = new Parameter
{ {
Name = "value", Name = "value",
@ -335,6 +356,13 @@ namespace CppSharp.Generators.CLI
} }
else else
{ {
if (@class.IsValueType && decl is Field)
{
WriteLine("return {0};", decl.Name);
WriteCloseBraceIndent();
NewLine();
return;
}
string variable; string variable;
if (decl is Variable) if (decl is Variable)
variable = string.Format("::{0}::{1}", variable = string.Format("::{0}::{1}",
@ -526,27 +554,27 @@ namespace CppSharp.Generators.CLI
GenerateStructMarshaling(baseClass, nativeVar); GenerateStructMarshaling(baseClass, nativeVar);
} }
foreach (var field in @class.Fields) foreach (var property in @class.Properties)
{ {
if (ASTUtils.CheckIgnoreField(field)) continue; if (property.Ignore || property.Field == null) continue;
var nativeField = string.Format("{0}{1}", var nativeField = string.Format("{0}{1}",
nativeVar, field.OriginalName); nativeVar, property.Field.OriginalName);
var ctx = new MarshalContext(Driver) var ctx = new MarshalContext(Driver)
{ {
ArgName = field.Name, ArgName = property.Name,
ReturnVarName = nativeField, ReturnVarName = nativeField,
ReturnType = field.QualifiedType ReturnType = property.QualifiedType
}; };
var marshal = new CLIMarshalNativeToManagedPrinter(ctx); var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
field.Visit(marshal); property.Visit(marshal);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore); Write(marshal.Context.SupportBefore);
WriteLine("{0} = {1};", field.Name, marshal.Context.Return); WriteLine("{0} = {1};", property.Field.Name, marshal.Context.Return);
} }
} }
@ -665,10 +693,10 @@ namespace CppSharp.Generators.CLI
WriteLine("::{0} _native({1});", @class.QualifiedOriginalName, WriteLine("::{0} _native({1});", @class.QualifiedOriginalName,
string.Join(", ", names)); string.Join(", ", names));
GenerateValueTypeConstructorCallFields(@class); GenerateValueTypeConstructorCallProperties(@class);
} }
private void GenerateValueTypeConstructorCallFields(Class @class) private void GenerateValueTypeConstructorCallProperties(Class @class)
{ {
foreach (var @base in @class.Bases) foreach (var @base in @class.Bases)
{ {
@ -676,28 +704,28 @@ namespace CppSharp.Generators.CLI
continue; continue;
var baseClass = @base.Class; var baseClass = @base.Class;
GenerateValueTypeConstructorCallFields(baseClass); GenerateValueTypeConstructorCallProperties(baseClass);
} }
foreach (var field in @class.Fields) foreach (var property in @class.Properties)
{ {
if (ASTUtils.CheckIgnoreField(field)) continue; if (property.Ignore || property.Field == null) continue;
var varName = string.Format("_native.{0}", field.OriginalName); var varName = string.Format("_native.{0}", property.Field.OriginalName);
var ctx = new MarshalContext(Driver) var ctx = new MarshalContext(Driver)
{ {
ReturnVarName = varName, ReturnVarName = varName,
ReturnType = field.QualifiedType ReturnType = property.QualifiedType
}; };
var marshal = new CLIMarshalNativeToManagedPrinter(ctx); var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
field.Visit(marshal); property.Visit(marshal);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore); Write(marshal.Context.SupportBefore);
WriteLine("this->{0} = {1};", field.Name, marshal.Context.Return); WriteLine("this->{0} = {1};", property.Name, marshal.Context.Return);
} }
} }
@ -749,7 +777,7 @@ namespace CppSharp.Generators.CLI
}; };
var marshal = new CLIMarshalManagedToNativePrinter(ctx); var marshal = new CLIMarshalManagedToNativePrinter(ctx);
marshal.MarshalValueClassFields(@class, valueMarshalName); marshal.MarshalValueClassProperties(@class, valueMarshalName);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore); Write(marshal.Context.SupportBefore);

14
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -607,6 +607,20 @@ namespace CppSharp.Generators.CSharp
return field.Type.Visit(this, field.QualifiedType.Qualifiers); return field.Type.Visit(this, field.QualifiedType.Qualifiers);
} }
public override bool VisitProperty(Property property)
{
if (!VisitDeclaration(property))
return false;
Context.Parameter = new Parameter
{
Name = Context.ArgName,
QualifiedType = property.QualifiedType
};
return base.VisitProperty(property);
}
public override bool VisitEnumDecl(Enumeration @enum) public override bool VisitEnumDecl(Enumeration @enum)
{ {
Context.Return.Write(Context.Parameter.Name); Context.Return.Write(Context.Parameter.Name);

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

@ -363,8 +363,8 @@ namespace CppSharp.Generators.CSharp
GenerateClassMarshals(@class); GenerateClassMarshals(@class);
GenerateClassConstructors(@class); GenerateClassConstructors(@class);
if (@class.IsValueType) if (@class.IsUnion)
GenerateValueClassFields(@class); GenerateUnionFields(@class);
GenerateClassMethods(@class); GenerateClassMethods(@class);
GenerateClassVariables(@class); GenerateClassVariables(@class);
@ -448,26 +448,28 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }
private void GenerateValueClassFields(Class @class) private void GenerateUnionFields(Class @class)
{ {
GenerateClassFields(@class, field => foreach (var field in @class.Fields)
{ {
var fieldClass = (Class) field.Namespace; GenerateClassField(field);
if (!fieldClass.IsValueType) }
return;
GenerateClassField(field);
});
} }
public void GenerateClassInternalsFields(Class @class) public void GenerateClassInternalsFields(Class @class)
{ {
if (@class.IsValueType)
{
foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore))
{
GenerateClassInternalsFields(@base.Class);
}
}
GenerateClassFields(@class, GenerateClassInternalsField); GenerateClassFields(@class, GenerateClassInternalsField);
foreach (var prop in @class.Properties) foreach (var prop in @class.Properties.Where(p => !p.Ignore && p.Field != null))
{ {
if (prop.Ignore || prop.Field == null)
continue;
GenerateClassInternalsField(prop.Field); GenerateClassInternalsField(prop.Field);
} }
} }
@ -604,39 +606,39 @@ namespace CppSharp.Generators.CSharp
WriteLine("struct Internal"); WriteLine("struct Internal");
} }
private void GenerateStructMarshalingFields(Class @class) private void GenerateStructMarshalingProperties(Class @class)
{ {
foreach (var @base in @class.Bases) foreach (var @base in @class.Bases)
{ {
if (!@base.IsClass || @base.Class.Ignore) if (!@base.IsClass || @base.Class.Ignore)
continue; continue;
GenerateStructMarshalingFields(@base.Class); GenerateStructMarshalingProperties(@base.Class);
} }
for (int i = 0; i < @class.Fields.Count; i++) for (int i = 0; i < @class.Properties.Count; i++)
{ {
var field = @class.Fields[i]; var property = @class.Properties[i];
if (ASTUtils.CheckIgnoreField(field)) continue; if (property.Ignore || property.Field == null) continue;
var nativeField = string.Format("{0}->{1}", var nativeField = string.Format("{0}->{1}",
Generator.GeneratedIdentifier("ptr"), field.OriginalName); Generator.GeneratedIdentifier("ptr"), property.Field.OriginalName);
var ctx = new CSharpMarshalContext(Driver) var ctx = new CSharpMarshalContext(Driver)
{ {
Kind = CSharpMarshalKind.NativeField, Kind = CSharpMarshalKind.NativeField,
ArgName = field.Name, ArgName = property.Name,
ReturnVarName = nativeField, ReturnVarName = nativeField,
ReturnType = field.QualifiedType ReturnType = property.QualifiedType
}; };
var marshal = new CSharpMarshalNativeToManagedPrinter(ctx) { VarSuffix = i }; var marshal = new CSharpMarshalNativeToManagedPrinter(ctx) { VarSuffix = i };
field.Visit(marshal); property.Visit(marshal);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore); Write(marshal.Context.SupportBefore);
WriteLine("{0} = {1};", field.Name, marshal.Context.Return); WriteLine("{0} = {1};", property.Name, marshal.Context.Return);
} }
} }
@ -645,12 +647,12 @@ namespace CppSharp.Generators.CSharp
var marshalVar = Generator.GeneratedIdentifier("native"); var marshalVar = Generator.GeneratedIdentifier("native");
WriteLine("var {0} = new {1}.Internal();", marshalVar, QualifiedIdentifier(@class)); WriteLine("var {0} = new {1}.Internal();", marshalVar, QualifiedIdentifier(@class));
GenerateStructInternalMarshalingFields(@class, marshalVar); GenerateStructInternalMarshalingProperties(@class, marshalVar);
WriteLine("return {0};", marshalVar); WriteLine("return {0};", marshalVar);
} }
private void GenerateStructInternalMarshalingFields(Class @class, string marshalVar) private void GenerateStructInternalMarshalingProperties(Class @class, string marshalVar)
{ {
foreach (var @base in @class.Bases) foreach (var @base in @class.Bases)
{ {
@ -658,44 +660,44 @@ namespace CppSharp.Generators.CSharp
continue; continue;
var baseClass = @base.Class; var baseClass = @base.Class;
GenerateStructInternalMarshalingFields(baseClass, marshalVar); GenerateStructInternalMarshalingProperties(baseClass, marshalVar);
} }
foreach (var field in @class.Fields) foreach (var property in @class.Properties)
{ {
if (field.Ignore) if (property.Ignore || property.Field == null)
continue; continue;
GenerateStructInternalMarshalingField(field, marshalVar); GenerateStructInternalMarshalingProperty(property, marshalVar);
} }
} }
private void GenerateStructInternalMarshalingField(Field field, string marshalVar) private void GenerateStructInternalMarshalingProperty(Property property, string marshalVar)
{ {
var marshalCtx = new CSharpMarshalContext(Driver) var marshalCtx = new CSharpMarshalContext(Driver)
{ {
ArgName = field.Name, ArgName = property.Name,
}; };
var marshal = new CSharpMarshalManagedToNativePrinter(marshalCtx); var marshal = new CSharpMarshalManagedToNativePrinter(marshalCtx);
field.Visit(marshal); property.Visit(marshal);
Type type; Type type;
Class @class; Class @class;
var isRef = field.Type.IsPointerTo(out type) && var isRef = property.Type.IsPointerTo(out type) &&
!(type.IsTagDecl(out @class) && @class.IsValueType) && !(type.IsTagDecl(out @class) && @class.IsValueType) &&
!type.IsPrimitiveType(); !type.IsPrimitiveType();
if (isRef) if (isRef)
{ {
WriteLine("if ({0} != null)", field.Name); WriteLine("if ({0} != null)", property.Name);
WriteStartBraceIndent(); WriteStartBraceIndent();
} }
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
WriteLine(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) if (isRef)
WriteCloseBraceIndent(); WriteCloseBraceIndent();
@ -795,7 +797,7 @@ namespace CppSharp.Generators.CSharp
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }
private void GenerateClassField(Field field) private void GenerateClassField(Field field, bool @public = false)
{ {
PushBlock(CSharpBlockKind.Field); PushBlock(CSharpBlockKind.Field);
@ -805,7 +807,8 @@ namespace CppSharp.Generators.CSharp
if (@class.IsUnion) if (@class.IsUnion)
WriteLine("[FieldOffset({0})]", field.Offset); WriteLine("[FieldOffset({0})]", field.Offset);
WriteLine("public {0} {1};", field.Type, SafeIdentifier(field.Name)); WriteLine("{0} {1} {2};", @public ? "public" : "private",
field.Type, SafeIdentifier(field.Name));
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }
@ -857,7 +860,7 @@ namespace CppSharp.Generators.CSharp
var function = decl as Function; var function = decl as Function;
if (function.IsPure && Driver.Options.GenerateAbstractImpls) if (function.IsPure && Driver.Options.GenerateAbstractImpls)
{ {
Write("; "); Write(";");
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
return; return;
} }
@ -895,8 +898,23 @@ namespace CppSharp.Generators.CSharp
} }
WriteCloseBraceIndent(); WriteCloseBraceIndent();
} }
else if (decl is Field) else
{ {
if (@class.IsValueType)
{
if (@class.IsUnion)
{
WriteStartBraceIndent();
WriteLine("{0} = value;", decl.Name);
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
WriteLine(";");
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
WriteStartBraceIndent(); WriteStartBraceIndent();
var field = decl as Field; var field = decl as Field;
@ -950,7 +968,7 @@ namespace CppSharp.Generators.CSharp
var function = decl as Function; var function = decl as Function;
if (function.IsPure && Driver.Options.GenerateAbstractImpls) if (function.IsPure && Driver.Options.GenerateAbstractImpls)
{ {
Write("; "); Write(";");
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
return; return;
} }
@ -975,6 +993,22 @@ namespace CppSharp.Generators.CSharp
} }
else if (decl is Field) else if (decl is Field)
{ {
if (@class.IsValueType)
{
if (@class.IsUnion)
{
NewLine();
WriteStartBraceIndent();
WriteLine("return {0};", decl.Name);
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
WriteLine(";");
PopBlock(NewLineKind.BeforeNextBlock);
return;
}
NewLine(); NewLine();
WriteStartBraceIndent(); WriteStartBraceIndent();
var field = decl as Field; var field = decl as Field;
@ -1078,9 +1112,28 @@ namespace CppSharp.Generators.CSharp
} }
private void GenerateClassProperties(Class @class) private void GenerateClassProperties(Class @class)
{
if (@class.IsValueType)
{
foreach (var @base in @class.Bases.Where(b => b.IsClass && !b.Class.Ignore))
{
GenerateClassProperties(@base.Class);
}
}
GenerateProperties(@class);
}
private void GenerateProperties(Class @class)
{ {
foreach (var prop in @class.Properties.Where(p => !p.Ignore)) foreach (var prop in @class.Properties.Where(p => !p.Ignore))
{ {
if (prop.IsBackedByValueClassField())
{
GenerateClassField(prop.Field, true);
continue;
}
PushBlock(CSharpBlockKind.Property); PushBlock(CSharpBlockKind.Property);
// If this is an indexer that returns an address use the real type // If this is an indexer that returns an address use the real type
@ -1703,7 +1756,7 @@ namespace CppSharp.Generators.CSharp
{ {
WriteLine("var {0} = (Internal*){1}.ToPointer();", WriteLine("var {0} = (Internal*){1}.ToPointer();",
Generator.GeneratedIdentifier("ptr"), "native"); Generator.GeneratedIdentifier("ptr"), "native");
GenerateStructMarshalingFields(@class); GenerateStructMarshalingProperties(@class);
} }
WriteCloseBraceIndent(); WriteCloseBraceIndent();
@ -1722,7 +1775,7 @@ namespace CppSharp.Generators.CSharp
WriteLine("internal void FromInternal(Internal* native)"); WriteLine("internal void FromInternal(Internal* native)");
WriteStartBraceIndent(); WriteStartBraceIndent();
WriteLine("var {0} = {1};", Generator.GeneratedIdentifier("ptr"), "native"); WriteLine("var {0} = {1};", Generator.GeneratedIdentifier("ptr"), "native");
GenerateStructMarshalingFields(@class); GenerateStructMarshalingProperties(@class);
WriteCloseBraceIndent(); WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
} }

13
src/Generator/Passes/FieldToPropertyPass.cs

@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Generators;
namespace CppSharp.Passes namespace CppSharp.Passes
{ {
@ -14,15 +15,12 @@ namespace CppSharp.Passes
if (@class == null) if (@class == null)
return false; return false;
if (@class.IsValueType)
return false;
if (ASTUtils.CheckIgnoreField(field)) if (ASTUtils.CheckIgnoreField(field))
return false; return false;
// Check if we already have a synthetized property. // Check if we already have a synthetized property.
var existingProp = @class.Properties.FirstOrDefault(property => var existingProp = @class.Properties.FirstOrDefault(property =>
property.Name == field.Name && property.Name == field.Name &&
property.QualifiedType == field.QualifiedType); property.QualifiedType == field.QualifiedType);
if (existingProp != null) if (existingProp != null)
@ -42,6 +40,13 @@ namespace CppSharp.Passes
Field = field 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);
Log.Debug("Property created from field: {0}::{1}", @class.Name, Log.Debug("Property created from field: {0}::{1}", @class.Name,

1
src/Generator/Passes/verbs.txt

@ -5797,6 +5797,7 @@ prepartaken
prepartook prepartook
prepave prepave
prepay prepay
prepend
prepenetrate prepenetrate
prepersuade prepersuade
preperuse preperuse

16
tests/Basic/Basic.Tests.cs

@ -164,5 +164,21 @@ public class BasicTests : GeneratorTestFixture
var doubleSum = delegates.A(2) + delegates.B(2); var doubleSum = delegates.A(2) + delegates.B(2);
Assert.AreEqual(8, doubleSum); Assert.AreEqual(8, doubleSum);
} }
[Test]
public void TestUnion()
{
Hello.NestedPublic nestedPublic = new Hello.NestedPublic();
nestedPublic.j = 5;
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));
}
} }

1
tests/Basic/Basic.h

@ -90,6 +90,7 @@ public:
union NestedPublic { union NestedPublic {
int j; int j;
float g; float g;
long l;
}; };
Hello (); Hello ();

Loading…
Cancel
Save