Browse Source

Initial support for downcasting wrappers from non-primary base to subclass

pull/1/head
Alex Corrado 14 years ago
parent
commit
f994b3f338
  1. 36
      src/Mono.Cxxi/CppTypeInfo.cs
  2. 322
      src/generator/Templates/CSharp/CSharpClass.cs
  3. 86
      src/generator/Templates/CSharp/CSharpClass.tt
  4. 12
      tests/InheritanceTests.cs

36
src/Mono.Cxxi/CppTypeInfo.cs

@ -146,20 +146,42 @@ namespace Mono.Cxxi { @@ -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

322
src/generator/Templates/CSharp/CSharpClass.cs

@ -19,32 +19,33 @@ namespace Templates { @@ -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) @@ -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) @@ -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) @@ -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)) { @@ -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

86
src/generator/Templates/CSharp/CSharpClass.tt

@ -8,8 +8,8 @@ @@ -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 #> { @@ -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 #> { @@ -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 #> { @@ -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) { #> @@ -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 ("{");

12
tests/InheritanceTests.cs

@ -45,7 +45,7 @@ namespace Tests { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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");
}
}

Loading…
Cancel
Save