diff --git a/src/Mono.Cxxi/CppTypeInfo.cs b/src/Mono.Cxxi/CppTypeInfo.cs index 51214e63..2a5f19d2 100644 --- a/src/Mono.Cxxi/CppTypeInfo.cs +++ b/src/Mono.Cxxi/CppTypeInfo.cs @@ -146,20 +146,42 @@ namespace Mono.Cxxi { public virtual CppInstancePtr Cast (ICppObject instance, Type targetType) { + var instanceType = instance.GetType (); var found = false; - int offset = 0; + var offset = 0; - foreach (var baseClass in base_classes) { - if (baseClass.WrapperType.Equals (targetType)) { - found = true; - break; + if (WrapperType.Equals (targetType)) { + // check for downcast (base type -> this type) + + foreach (var baseClass in base_classes) { + if (baseClass.WrapperType.Equals (instanceType)) { + found = true; + break; + } + + offset -= baseClass.NativeSize; + } + + + } else if (WrapperType.IsAssignableFrom (instanceType)) { + // check for upcast (this type -> base type) + + foreach (var baseClass in base_classes) { + if (baseClass.WrapperType.Equals (targetType)) { + found = true; + break; + } + + offset += baseClass.NativeSize; } - offset += baseClass.NativeSize; + } else { + throw new ArgumentException ("Either instance type or targetType must be equal to wrapper type."); } if (!found) - throw new InvalidCastException ("Cannot cast an instance of " + instance.GetType () + " to " + targetType); + throw new InvalidCastException ("Cannot cast an instance of " + instanceType + " to " + targetType); + // Construct a new targetType wrapper, passing in our offset this ptr. // FIXME: If the object was alloc'd by managed code, the allocating wrapper (i.e. "instance") will still free the memory when diff --git a/src/generator/Templates/CSharp/CSharpClass.cs b/src/generator/Templates/CSharp/CSharpClass.cs index 1c8f9de5..d1e9c2cc 100644 --- a/src/generator/Templates/CSharp/CSharpClass.cs +++ b/src/generator/Templates/CSharp/CSharpClass.cs @@ -19,32 +19,33 @@ namespace Templates { public partial class CSharpClass : Base { - #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 277 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" -private void WriteMethodHeader (Method method, string layoutClass) +private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected) { var returnType = GetCSharpType (method.ReturnType); - if (method.IsVirtual) + if (!isNonPrimaryOverride && method.IsVirtual) WriteLine ("[OverrideNative (\"{0}\")]", method.Name); - Write (CurrentIndent + "public "); + Write (CurrentIndent + (@protected? "protected " : "public ")); if (method.IsConstructor) { Write (method.FormattedName); } else { if (method.IsStatic) Write ("static "); - if (method.IsVirtual) Write ("virtual "); + if (method.IsVirtual && (!isNonPrimaryOverride || layoutClass != null)) Write ("virtual "); + else if (isNonPrimaryOverride) Write ("override "); // ...? Write (returnType); Write (" "); - Write (method.FormattedName); + Write (isNonPrimaryOverride && layoutClass != null? layoutClass : method.FormattedName); } Write (" ("); WriteParameters (method.Parameters, true, false); Write (")\n"); - if (method.IsConstructor) + if (method.IsConstructor && layoutClass != null) WriteLine (layoutClass); else WriteLine ("{"); @@ -152,8 +153,8 @@ private bool IsByVal (CppType t) var wrapper = Class.Name; var iface = "I" + Class.Name; var layout = "_" + Class.Name; - var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\tLayoutClass ();"; - var initBases = (Class.BaseClasses.Count > 1 ? "\tInitBases ();\n\t\t}" : "}"); + var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\t__cxxi_LayoutClass ();"; + var initBases = (Class.BaseClasses.Count > 1 ? "\t__cxxi_InitBases ();\n\t\t}" : "}"); #line default @@ -627,7 +628,7 @@ private bool IsByVal (CppType t) PushIndent ("\t\t"); foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) { - WriteMethodHeader (method, layoutClass); + WriteMethodHeader (method, layoutClass, false, false); if (method.IsConstructor) Write ("Native = "); @@ -753,7 +754,7 @@ private bool IsByVal (CppType t) #line hidden #line 185 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write("\t\t\tNative.Dispose ();\n\t\t}\n\n\t\tprivate void LayoutClass ()\n\t\t{\n"); + this.Write("\t\t\tNative.Dispose ();\n\t\t}\n\n\t\tprivate void __cxxi_LayoutClass ()\n\t\t{\n"); #line default #line hidden @@ -802,180 +803,377 @@ foreach (var npBase in Class.BaseClasses.Skip (1)) { #line hidden #line 198 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write("\t\t// Non-primary base class implementation for "); + this.Write("\n#region Non-primary base class implementation for "); #line default #line hidden - #line 198 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 199 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 198 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(":\n\t\tpublic "); + #line 199 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("\n\t\tprivate class "); #line default #line hidden - #line 199 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper + "__" + npBase.Name )); + + #line default + #line hidden + + #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" : "); + + #line default + #line hidden + + #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 199 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" {\n\t\t\tpublic "); + + #line default + #line hidden + + #line 201 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); + + #line default + #line hidden + + #line 201 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" instance;\n\t\t\tpublic "); + + #line default + #line hidden + + #line 202 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper + "__" + npBase.Name )); + + #line default + #line hidden + + #line 202 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" ("); + + #line default + #line hidden + + #line 202 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); + + #line default + #line hidden + + #line 202 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" instance)\n\t\t\t\t: base ("); + + #line default + #line hidden + + #line 203 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); + + #line default + #line hidden + + #line 203 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(".impl.TypeInfo.Cast (instance, typeof ("); + + #line default + #line hidden + + #line 203 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + + #line default + #line hidden + + #line 203 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(")))\n\t\t\t{\n\t\t\t\tthis.instance = instance;\n\t\t\t}\n\n"); + + #line default + #line hidden + + #line 208 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + PushIndent ("\t\t\t"); + foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) { + + if (!method.GenWrapperMethod || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id))) + continue; + + /* this is the managed override that has to call the subclass's method */ + WriteMethodHeader (method, null, true, false); + + Write ("instance.{0} (", npBase.Name + "__" + method.FormattedName); + + WriteParameters (method.Parameters, false, false); + PopIndent (); + Write (");\n{0}}}\n\n", CurrentIndent); + + /* this is the method that calls the base implementation that the subclass will use */ + WriteMethodHeader (method, npBase.Name + "__" + method.FormattedName, true, false); + + Write ("base.{0} (", method.FormattedName); + + WriteParameters (method.Parameters, false, false); + PopIndent (); + Write (");\n{0}}}\n\n", CurrentIndent); + } + ClearIndent (); + + #line default + #line hidden + + #line 233 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("\t\t}\n\t\tprivate "); + + #line default + #line hidden + + #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); + + #line default + #line hidden + + #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("__"); + + #line default + #line hidden + + #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + + #line default + #line hidden + + #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" __cxxi_"); + + #line default + #line hidden + + #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + + #line default + #line hidden + + #line 234 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(";\n\t\tpublic "); + + #line default + #line hidden + + #line 235 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + + #line default + #line hidden + + #line 235 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" "); #line default #line hidden - #line 199 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 235 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 199 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(" { get; protected set; }\n\t\tpublic static implicit operator "); + #line 235 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" { get { return __cxxi_"); #line default #line hidden - #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 235 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 235 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("; } }\n\t\tpublic static implicit operator "); + + #line default + #line hidden + + #line 236 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + + #line default + #line hidden + + #line 236 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("("); #line default #line hidden - #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 236 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); #line default #line hidden - #line 200 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 236 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" subClass)\n\t\t{\n\t\t\treturn subClass."); #line default #line hidden - #line 202 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 238 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 202 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(";\n\t\t}\n\n"); + #line 238 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(";\n\t\t}\n\t\tpublic static explicit operator "); + + #line default + #line hidden + + #line 240 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper )); + + #line default + #line hidden + + #line 240 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("("); + + #line default + #line hidden + + #line 240 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + + #line default + #line hidden + + #line 240 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" baseClass)\n\t\t{\n\t\t\tif (baseClass == null) return null;\n\t\t\tvar obj = baseClass as "); #line default #line hidden - #line 205 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 243 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper + "__" + npBase.Name )); + + #line default + #line hidden + + #line 243 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(";\n\t\t\tif (obj == null) throw new InvalidCastException ();\n\t\t\treturn obj.instance;\n\t\t}\n\n"); + + #line default + #line hidden + + #line 248 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + /* Add virtual methods of non-primary bases to this class proper so they can be overridden */ + + #line default + #line hidden + + #line 249 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" PushIndent ("\t\t"); - foreach (var method in npBase.Methods) { - // With the exception of virtual methods that have been overridden, these methods must be called - // thru a cast to the base class that performs a this ptr adjustment - if (!method.GenWrapperMethod || method.IsConstructor || method.IsStatic || - (method.IsVirtual && Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id)))) + foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) { + + if (!method.GenWrapperMethod || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id))) continue; - WriteMethodHeader (method, initBases); + WriteMethodHeader (method, npBase.Name + "__" + method.FormattedName, true, true); - Write ("{0}.{1} (", npBase.Name, method.FormattedName); + Write ("{0}.{1} (", "__cxxi_" + npBase.Name, npBase.Name + "__" + method.FormattedName); WriteParameters (method.Parameters, false, false); PopIndent (); Write (");\n{0}}}\n\n", CurrentIndent); } ClearIndent (); +WriteLine ("#endregion"); } if (Class.BaseClasses.Count > 1) { #line default #line hidden - #line 224 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write("\t\tprivate void InitBases ()\n\t\t{\n"); + #line 267 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("\t\tprivate void __cxxi_InitBases ()\n\t\t{\n"); #line default #line hidden - #line 226 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 269 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" foreach (var npBase in Class.BaseClasses.Skip (1)) { #line default #line hidden - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write("\t\t\t"); + #line 270 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write("\t\t\t__cxxi_"); #line default #line hidden - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 270 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); #line default #line hidden - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 270 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write(" = new "); #line default #line hidden - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); - - #line default - #line hidden - - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(" (impl.TypeInfo.Cast (this, typeof ("); - - #line default - #line hidden - - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name )); + #line 270 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(this.ToStringHelper.ToStringWithCulture( wrapper + "__" + npBase.Name )); #line default #line hidden - #line 227 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" - this.Write(")));\n"); + #line 270 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + this.Write(" (this);\n"); #line default #line hidden - #line 228 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 271 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" } #line default #line hidden - #line 229 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 272 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t\t}\n"); #line default #line hidden - #line 230 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 273 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" } #line default #line hidden - #line 231 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" + #line 274 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" this.Write("\t}\n}\n\n"); #line default diff --git a/src/generator/Templates/CSharp/CSharpClass.tt b/src/generator/Templates/CSharp/CSharpClass.tt index 655bc2fd..ea198882 100644 --- a/src/generator/Templates/CSharp/CSharpClass.tt +++ b/src/generator/Templates/CSharp/CSharpClass.tt @@ -8,8 +8,8 @@ var wrapper = Class.Name; var iface = "I" + Class.Name; var layout = "_" + Class.Name; - var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\tLayoutClass ();"; - var initBases = (Class.BaseClasses.Count > 1 ? "\tInitBases ();\n\t\t}" : "}"); + var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\t__cxxi_LayoutClass ();"; + var initBases = (Class.BaseClasses.Count > 1 ? "\t__cxxi_InitBases ();\n\t\t}" : "}"); #> // ------------------------------------------------------------------------- // Managed wrapper for <#= Class.Name #> @@ -106,7 +106,7 @@ namespace <#= Generator.Namespace #> { <# PushIndent ("\t\t"); foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) { - WriteMethodHeader (method, layoutClass); + WriteMethodHeader (method, layoutClass, false, false); if (method.IsConstructor) Write ("Native = "); @@ -185,7 +185,7 @@ namespace <#= Generator.Namespace #> { Native.Dispose (); } - private void LayoutClass () + private void __cxxi_LayoutClass () { <# foreach (var npBase in Class.BaseClasses.Skip (1)) { #> new <#= npBase.Name #> (impl.TypeInfo); @@ -195,36 +195,79 @@ namespace <#= Generator.Namespace #> { <# /* Make this wrapper castable to non-primary bases */ foreach (var npBase in Class.BaseClasses.Skip (1)) { #> - // Non-primary base class implementation for <#= npBase.Name #>: - public <#= npBase.Name #> <#= npBase.Name #> { get; protected set; } + +#region Non-primary base class implementation for <#= npBase.Name #> + private class <#= wrapper + "__" + npBase.Name #> : <#= npBase.Name #> { + public <#= wrapper #> instance; + public <#= wrapper + "__" + npBase.Name #> (<#= wrapper #> instance) + : base (<#= wrapper #>.impl.TypeInfo.Cast (instance, typeof (<#= npBase.Name #>))) + { + this.instance = instance; + } + +<# PushIndent ("\t\t\t"); + foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) { + + if (!method.GenWrapperMethod || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id))) + continue; + + /* this is the managed override that has to call the subclass's method */ + WriteMethodHeader (method, null, true, false); + + Write ("instance.{0} (", npBase.Name + "__" + method.FormattedName); + + WriteParameters (method.Parameters, false, false); + PopIndent (); + Write (");\n{0}}}\n\n", CurrentIndent); + + /* this is the method that calls the base implementation that the subclass will use */ + WriteMethodHeader (method, npBase.Name + "__" + method.FormattedName, true, false); + + Write ("base.{0} (", method.FormattedName); + + WriteParameters (method.Parameters, false, false); + PopIndent (); + Write (");\n{0}}}\n\n", CurrentIndent); + } + ClearIndent (); #> + } + private <#= wrapper #>__<#= npBase.Name #> __cxxi_<#= npBase.Name #>; + public <#= npBase.Name #> <#= npBase.Name #> { get { return __cxxi_<#= npBase.Name #>; } } public static implicit operator <#= npBase.Name #>(<#= wrapper #> subClass) { return subClass.<#= npBase.Name #>; } + public static explicit operator <#= wrapper #>(<#= npBase.Name #> baseClass) + { + if (baseClass == null) return null; + var obj = baseClass as <#= wrapper + "__" + npBase.Name #>; + if (obj == null) throw new InvalidCastException (); + return obj.instance; + } +<# /* Add virtual methods of non-primary bases to this class proper so they can be overridden */ #> <# PushIndent ("\t\t"); - foreach (var method in npBase.Methods) { - // With the exception of virtual methods that have been overridden, these methods must be called - // thru a cast to the base class that performs a this ptr adjustment - if (!method.GenWrapperMethod || method.IsConstructor || method.IsStatic || - (method.IsVirtual && Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id)))) + foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) { + + if (!method.GenWrapperMethod || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id))) continue; - WriteMethodHeader (method, initBases); + WriteMethodHeader (method, npBase.Name + "__" + method.FormattedName, true, true); - Write ("{0}.{1} (", npBase.Name, method.FormattedName); + Write ("{0}.{1} (", "__cxxi_" + npBase.Name, npBase.Name + "__" + method.FormattedName); WriteParameters (method.Parameters, false, false); PopIndent (); Write (");\n{0}}}\n\n", CurrentIndent); } ClearIndent (); +WriteLine ("#endregion"); } if (Class.BaseClasses.Count > 1) { #> - private void InitBases () + private void __cxxi_InitBases () { <# foreach (var npBase in Class.BaseClasses.Skip (1)) { #> - <#= npBase.Name #> = new <#= npBase.Name #> (impl.TypeInfo.Cast (this, typeof (<#= npBase.Name #>))); + __cxxi_<#= npBase.Name #> = new <#= wrapper + "__" + npBase.Name #> (this); <# } #> } <# } #> @@ -232,30 +275,31 @@ if (Class.BaseClasses.Count > 1) { #> } <#+ -private void WriteMethodHeader (Method method, string layoutClass) +private void WriteMethodHeader (Method method, string layoutClass, bool isNonPrimaryOverride, bool @protected) { var returnType = GetCSharpType (method.ReturnType); - if (method.IsVirtual) + if (!isNonPrimaryOverride && method.IsVirtual) WriteLine ("[OverrideNative (\"{0}\")]", method.Name); - Write (CurrentIndent + "public "); + Write (CurrentIndent + (@protected? "protected " : "public ")); if (method.IsConstructor) { Write (method.FormattedName); } else { if (method.IsStatic) Write ("static "); - if (method.IsVirtual) Write ("virtual "); + if (method.IsVirtual && (!isNonPrimaryOverride || layoutClass != null)) Write ("virtual "); + else if (isNonPrimaryOverride) Write ("override "); // ...? Write (returnType); Write (" "); - Write (method.FormattedName); + Write (isNonPrimaryOverride && layoutClass != null? layoutClass : method.FormattedName); } Write (" ("); WriteParameters (method.Parameters, true, false); Write (")\n"); - if (method.IsConstructor) + if (method.IsConstructor && layoutClass != null) WriteLine (layoutClass); else WriteLine ("{"); diff --git a/tests/InheritanceTests.cs b/tests/InheritanceTests.cs index 238e4d97..a470d61a 100644 --- a/tests/InheritanceTests.cs +++ b/tests/InheritanceTests.cs @@ -45,7 +45,7 @@ namespace Tests { Assert.AreEqual (9, cls.Number, "#3"); Assert.AreEqual (3, ((MultiplierClass)cls).Number, "#4"); - cls.Multiply (10); + cls.MultiplierClass.Multiply (10); Assert.AreEqual (9, cls.Number, "#5"); Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#6"); } @@ -61,7 +61,7 @@ namespace Tests { Assert.AreEqual (9, cls.Number, "#3"); Assert.AreEqual (9, ((MultiplierClassWithVirtualBase)cls).Number, "#4"); - cls.Multiply (6); + cls.MultiplierClassWithVirtualBase.Multiply (6); Assert.AreEqual (30, cls.Number, "#5"); Assert.AreEqual (30, ((MultiplierClassWithVirtualBase)cls).Number, "#6"); } @@ -113,9 +113,9 @@ namespace Tests { } // override virtual member inherited from non-primary base - public override void Multiply (int n) + protected override void MultiplierClass__Multiply (int n) { - base.Multiply (10); + base.MultiplierClass__Multiply (10); } } @@ -123,7 +123,7 @@ namespace Tests { public void TestManagedOverride2 () { var cls = new ManagedOverride2 (); - cls.Multiply (7); + cls.MultiplierClass.Multiply (7); Assert.AreEqual (5, cls.Number, "#1"); Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#2"); cls.CallMultiply (2); @@ -152,7 +152,7 @@ namespace Tests { Assert.AreEqual (-30, cls.NegativeNumber, "#6"); // cast to non-primary subclass - Assert.IsNotNull (cls as ManagedOverride2, "#7"); + Assert.IsNotNull (((ClassWithNonVirtualBases)cls) as ManagedOverride2, "#7"); } }