diff --git a/src/AST/Property.cs b/src/AST/Property.cs index bad67004..3654ab94 100644 --- a/src/AST/Property.cs +++ b/src/AST/Property.cs @@ -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; + } } } \ No newline at end of file diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 028fcd59..a6a8ca9a 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -259,8 +259,6 @@ namespace CppSharp.Generators.CLI GenerateClassConstructors(@class, nativeType); - GenerateClassFields(@class); - GenerateClassProperties(@class); GenerateClassEvents(@class); @@ -271,6 +269,13 @@ namespace CppSharp.Generators.CLI GenerateClassVariables(@class); + if (@class.Fields.Any()) + { + NewLine(); + WriteLine("private:"); + GenerateClassFields(@class); + } + WriteLine("};"); } @@ -390,41 +395,43 @@ namespace CppSharp.Generators.CLI public void GenerateClassFields(Class @class) { - if (!@class.IsValueType) - return; - // 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) { - Class baseClass; - if (!@base.Type.IsTagDecl(out baseClass)) + if (!@base.IsClass) continue; + 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)) continue; - - GenerateDeclarationCommon(field); - if (@class.IsUnion) - WriteLine("[System::Runtime::InteropServices::FieldOffset({0})]", - field.Offset); - WriteLine("{0} {1};", field.Type, SafeIdentifier(field.Name)); + 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)); + } + public void GenerateClassEvents(Class @class) { foreach (var @event in @class.Events) @@ -560,10 +567,28 @@ namespace CppSharp.Generators.CLI 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(); - 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); GenerateProperty(prop); diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index c2b44b73..89d17feb 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -196,7 +196,15 @@ namespace CppSharp.Generators.CLI 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) @@ -530,7 +538,15 @@ namespace CppSharp.Generators.CLI 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) @@ -589,7 +605,7 @@ namespace CppSharp.Generators.CLI Context.SupportBefore.WriteLine("auto {0} = ::{1}();", marshalVar, @class.QualifiedOriginalName); - MarshalValueClassFields(@class, marshalVar); + MarshalValueClassProperties(@class, marshalVar); Context.Return.Write(marshalVar); @@ -601,7 +617,7 @@ namespace CppSharp.Generators.CLI ArgumentPrefix.Write("&"); } - public void MarshalValueClassFields(Class @class, string marshalVar) + public void MarshalValueClassProperties(Class @class, string marshalVar) { foreach (var @base in @class.Bases) { @@ -609,22 +625,22 @@ namespace CppSharp.Generators.CLI continue; 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; - 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, - field.Name); + property.Name); var marshalCtx = new MarshalContext(Context.Driver) { @@ -634,7 +650,7 @@ namespace CppSharp.Generators.CLI }; var marshal = new CLIMarshalManagedToNativePrinter(marshalCtx); - field.Visit(marshal); + property.Visit(marshal); Context.ParameterIndex = marshalCtx.ParameterIndex; @@ -643,7 +659,7 @@ namespace CppSharp.Generators.CLI 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(); @@ -654,7 +670,7 @@ namespace CppSharp.Generators.CLI } Context.SupportBefore.WriteLine("{0}.{1} = {2};", marshalVar, - field.OriginalName, marshal.Context.Return); + property.Field.OriginalName, marshal.Context.Return); if (isRef) Context.SupportBefore.PopIndent(); @@ -671,6 +687,17 @@ namespace CppSharp.Generators.CLI 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) { throw new NotImplementedException(); diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index a1cb9fa1..cc613699 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -165,8 +165,7 @@ namespace CppSharp.Generators.CLI } } - foreach (var property in @class.Properties) - GenerateProperty(property); + GenerateClassProperties(@class, @class); foreach (var @event in @class.Events) { @@ -192,6 +191,21 @@ namespace CppSharp.Generators.CLI 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) { var printer = TypePrinter; @@ -236,7 +250,7 @@ namespace CppSharp.Generators.CLI printer.Context = oldCtx; } - private void GenerateProperty(Property property) + private void GenerateProperty(Property property, Class realOwner) { if (property.Ignore) return; @@ -246,21 +260,21 @@ namespace CppSharp.Generators.CLI if (property.Field != null) { if (property.HasGetter) - GeneratePropertyGetter(property.Field, @class, property.Name, + GeneratePropertyGetter(property.Field, realOwner, property.Name, property.Type); if (property.HasSetter) - GeneratePropertySetter(property.Field, @class, property.Name, + GeneratePropertySetter(property.Field, realOwner, property.Name, property.Type); } else { if (property.HasGetter) - GeneratePropertyGetter(property.GetMethod, @class, property.Name, + GeneratePropertyGetter(property.GetMethod, realOwner, property.Name, property.Type); if (property.HasSetter) - GeneratePropertySetter(property.SetMethod, @class, property.Name, + GeneratePropertySetter(property.SetMethod, realOwner, property.Name, property.Type); } PopBlock(); @@ -285,6 +299,13 @@ namespace CppSharp.Generators.CLI } else { + if (@class.IsValueType && decl is Field) + { + WriteLine("{0} = value;", decl.Name); + WriteCloseBraceIndent(); + NewLine(); + return; + } var param = new Parameter { Name = "value", @@ -335,6 +356,13 @@ namespace CppSharp.Generators.CLI } else { + if (@class.IsValueType && decl is Field) + { + WriteLine("return {0};", decl.Name); + WriteCloseBraceIndent(); + NewLine(); + return; + } string variable; if (decl is Variable) variable = string.Format("::{0}::{1}", @@ -526,27 +554,27 @@ namespace CppSharp.Generators.CLI 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}", - nativeVar, field.OriginalName); + nativeVar, property.Field.OriginalName); var ctx = new MarshalContext(Driver) { - ArgName = field.Name, + ArgName = property.Name, ReturnVarName = nativeField, - ReturnType = field.QualifiedType + ReturnType = property.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); - field.Visit(marshal); + property.Visit(marshal); if (!string.IsNullOrWhiteSpace(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, string.Join(", ", names)); - GenerateValueTypeConstructorCallFields(@class); + GenerateValueTypeConstructorCallProperties(@class); } - private void GenerateValueTypeConstructorCallFields(Class @class) + private void GenerateValueTypeConstructorCallProperties(Class @class) { foreach (var @base in @class.Bases) { @@ -676,28 +704,28 @@ namespace CppSharp.Generators.CLI continue; 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) { ReturnVarName = varName, - ReturnType = field.QualifiedType + ReturnType = property.QualifiedType }; var marshal = new CLIMarshalNativeToManagedPrinter(ctx); - field.Visit(marshal); + property.Visit(marshal); if (!string.IsNullOrWhiteSpace(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); - marshal.MarshalValueClassFields(@class, valueMarshalName); + marshal.MarshalValueClassProperties(@class, valueMarshalName); if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) Write(marshal.Context.SupportBefore); diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 3795bdc8..5710797f 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -607,6 +607,20 @@ namespace CppSharp.Generators.CSharp 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) { Context.Return.Write(Context.Parameter.Name); diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 5c441698..7fd0268c 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -363,8 +363,8 @@ namespace CppSharp.Generators.CSharp GenerateClassMarshals(@class); GenerateClassConstructors(@class); - if (@class.IsValueType) - GenerateValueClassFields(@class); + if (@class.IsUnion) + GenerateUnionFields(@class); GenerateClassMethods(@class); GenerateClassVariables(@class); @@ -448,26 +448,28 @@ namespace CppSharp.Generators.CSharp 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; - if (!fieldClass.IsValueType) - return; - GenerateClassField(field); - }); + GenerateClassField(field); + } } 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); - 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); } } @@ -604,39 +606,39 @@ namespace CppSharp.Generators.CSharp WriteLine("struct Internal"); } - private void GenerateStructMarshalingFields(Class @class) + private void GenerateStructMarshalingProperties(Class @class) { foreach (var @base in @class.Bases) { if (!@base.IsClass || @base.Class.Ignore) 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]; - if (ASTUtils.CheckIgnoreField(field)) continue; + var property = @class.Properties[i]; + if (property.Ignore || property.Field == null) continue; var nativeField = string.Format("{0}->{1}", - Generator.GeneratedIdentifier("ptr"), field.OriginalName); + Generator.GeneratedIdentifier("ptr"), property.Field.OriginalName); var ctx = new CSharpMarshalContext(Driver) { Kind = CSharpMarshalKind.NativeField, - ArgName = field.Name, + ArgName = property.Name, ReturnVarName = nativeField, - ReturnType = field.QualifiedType + ReturnType = property.QualifiedType }; var marshal = new CSharpMarshalNativeToManagedPrinter(ctx) { VarSuffix = i }; - field.Visit(marshal); + property.Visit(marshal); if (!string.IsNullOrWhiteSpace(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"); WriteLine("var {0} = new {1}.Internal();", marshalVar, QualifiedIdentifier(@class)); - GenerateStructInternalMarshalingFields(@class, marshalVar); + GenerateStructInternalMarshalingProperties(@class, 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) { @@ -658,44 +660,44 @@ namespace CppSharp.Generators.CSharp continue; 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; - 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) { - 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(); @@ -795,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); @@ -805,7 +807,8 @@ namespace CppSharp.Generators.CSharp if (@class.IsUnion) 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); } @@ -857,7 +860,7 @@ namespace CppSharp.Generators.CSharp var function = decl as Function; if (function.IsPure && Driver.Options.GenerateAbstractImpls) { - Write("; "); + Write(";"); PopBlock(NewLineKind.BeforeNextBlock); return; } @@ -895,8 +898,23 @@ namespace CppSharp.Generators.CSharp } 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(); var field = decl as Field; @@ -950,7 +968,7 @@ namespace CppSharp.Generators.CSharp var function = decl as Function; if (function.IsPure && Driver.Options.GenerateAbstractImpls) { - Write("; "); + Write(";"); PopBlock(NewLineKind.BeforeNextBlock); return; } @@ -975,6 +993,22 @@ namespace CppSharp.Generators.CSharp } 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(); WriteStartBraceIndent(); var field = decl as Field; @@ -1078,9 +1112,28 @@ namespace CppSharp.Generators.CSharp } 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)) { + if (prop.IsBackedByValueClassField()) + { + GenerateClassField(prop.Field, true); + continue; + } + PushBlock(CSharpBlockKind.Property); // 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();", Generator.GeneratedIdentifier("ptr"), "native"); - GenerateStructMarshalingFields(@class); + GenerateStructMarshalingProperties(@class); } WriteCloseBraceIndent(); @@ -1722,7 +1775,7 @@ namespace CppSharp.Generators.CSharp WriteLine("internal void FromInternal(Internal* native)"); WriteStartBraceIndent(); WriteLine("var {0} = {1};", Generator.GeneratedIdentifier("ptr"), "native"); - GenerateStructMarshalingFields(@class); + GenerateStructMarshalingProperties(@class); WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); } diff --git a/src/Generator/Passes/FieldToPropertyPass.cs b/src/Generator/Passes/FieldToPropertyPass.cs index d6b9104d..76113aac 100644 --- a/src/Generator/Passes/FieldToPropertyPass.cs +++ b/src/Generator/Passes/FieldToPropertyPass.cs @@ -1,5 +1,6 @@ using System.Linq; using CppSharp.AST; +using CppSharp.Generators; namespace CppSharp.Passes { @@ -14,15 +15,12 @@ namespace CppSharp.Passes if (@class == null) return false; - if (@class.IsValueType) - return false; - if (ASTUtils.CheckIgnoreField(field)) return false; // Check if we already have a synthetized property. var existingProp = @class.Properties.FirstOrDefault(property => - property.Name == field.Name && + property.Name == field.Name && property.QualifiedType == field.QualifiedType); if (existingProp != null) @@ -42,6 +40,13 @@ namespace CppSharp.Passes 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); Log.Debug("Property created from field: {0}::{1}", @class.Name, diff --git a/src/Generator/Passes/verbs.txt b/src/Generator/Passes/verbs.txt index 9c9ce287..8d7f2f7f 100644 --- a/src/Generator/Passes/verbs.txt +++ b/src/Generator/Passes/verbs.txt @@ -5797,6 +5797,7 @@ prepartaken prepartook prepave prepay +prepend prepenetrate prepersuade preperuse diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 5fed717c..e5a613a0 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -164,5 +164,21 @@ public class BasicTests : GeneratorTestFixture var doubleSum = delegates.A(2) + delegates.B(2); 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)); + } } \ No newline at end of file diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index b0fa57df..f09a6896 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -90,6 +90,7 @@ public: union NestedPublic { int j; float g; + long l; }; Hello ();