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 {
public virtual CppInstancePtr Cast (ICppObject instance, Type targetType) public virtual CppInstancePtr Cast (ICppObject instance, Type targetType)
{ {
var instanceType = instance.GetType ();
var found = false; var found = false;
int offset = 0; var offset = 0;
foreach (var baseClass in base_classes) { if (WrapperType.Equals (targetType)) {
if (baseClass.WrapperType.Equals (targetType)) { // check for downcast (base type -> this type)
found = true;
break; 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) 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. // 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 // 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 {
public partial class CSharpClass : Base { 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); var returnType = GetCSharpType (method.ReturnType);
if (method.IsVirtual) if (!isNonPrimaryOverride && method.IsVirtual)
WriteLine ("[OverrideNative (\"{0}\")]", method.Name); WriteLine ("[OverrideNative (\"{0}\")]", method.Name);
Write (CurrentIndent + "public "); Write (CurrentIndent + (@protected? "protected " : "public "));
if (method.IsConstructor) { if (method.IsConstructor) {
Write (method.FormattedName); Write (method.FormattedName);
} else { } else {
if (method.IsStatic) Write ("static "); 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 (returnType);
Write (" "); Write (" ");
Write (method.FormattedName); Write (isNonPrimaryOverride && layoutClass != null? layoutClass : method.FormattedName);
} }
Write (" ("); Write (" (");
WriteParameters (method.Parameters, true, false); WriteParameters (method.Parameters, true, false);
Write (")\n"); Write (")\n");
if (method.IsConstructor) if (method.IsConstructor && layoutClass != null)
WriteLine (layoutClass); WriteLine (layoutClass);
else else
WriteLine ("{"); WriteLine ("{");
@ -152,8 +153,8 @@ private bool IsByVal (CppType t)
var wrapper = Class.Name; var wrapper = Class.Name;
var iface = "I" + Class.Name; var iface = "I" + Class.Name;
var layout = "_" + Class.Name; var layout = "_" + Class.Name;
var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\tLayoutClass ();"; var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\t__cxxi_LayoutClass ();";
var initBases = (Class.BaseClasses.Count > 1 ? "\tInitBases ();\n\t\t}" : "}"); var initBases = (Class.BaseClasses.Count > 1 ? "\t__cxxi_InitBases ();\n\t\t}" : "}");
#line default #line default
@ -627,7 +628,7 @@ private bool IsByVal (CppType t)
PushIndent ("\t\t"); PushIndent ("\t\t");
foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) { foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) {
WriteMethodHeader (method, layoutClass); WriteMethodHeader (method, layoutClass, false, false);
if (method.IsConstructor) if (method.IsConstructor)
Write ("Native = "); Write ("Native = ");
@ -753,7 +754,7 @@ private bool IsByVal (CppType t)
#line hidden #line hidden
#line 185 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" #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 default
#line hidden #line hidden
@ -802,180 +803,377 @@ foreach (var npBase in Class.BaseClasses.Skip (1)) {
#line hidden #line hidden
#line 198 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" #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 default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name ));
#line default #line default
#line hidden #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(":\n\t\tpublic "); this.Write("\n\t\tprivate class ");
#line default #line default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name ));
#line default #line default
#line hidden #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(" "); this.Write(" ");
#line default #line default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name ));
#line default #line default
#line hidden #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(" { get; protected set; }\n\t\tpublic static implicit operator "); this.Write(" { get { return __cxxi_");
#line default #line default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name ));
#line default #line default
#line hidden #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("("); this.Write("(");
#line default #line default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( wrapper ));
#line default #line default
#line hidden #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."); this.Write(" subClass)\n\t\t{\n\t\t\treturn subClass.");
#line default #line default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name ));
#line default #line default
#line hidden #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(";\n\t\t}\n\n"); 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 default
#line hidden #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"); PushIndent ("\t\t");
foreach (var method in npBase.Methods) { foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) {
// 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 || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id)))
if (!method.GenWrapperMethod || method.IsConstructor || method.IsStatic ||
(method.IsVirtual && Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id))))
continue; 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); WriteParameters (method.Parameters, false, false);
PopIndent (); PopIndent ();
Write (");\n{0}}}\n\n", CurrentIndent); Write (");\n{0}}}\n\n", CurrentIndent);
} }
ClearIndent (); ClearIndent ();
WriteLine ("#endregion");
} }
if (Class.BaseClasses.Count > 1) { if (Class.BaseClasses.Count > 1) {
#line default #line default
#line hidden #line hidden
#line 224 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt" #line 267 "/Users/alex/OpenSource/cppinterop/src/generator/Templates/CSharp/CSharpClass.tt"
this.Write("\t\tprivate void InitBases ()\n\t\t{\n"); this.Write("\t\tprivate void __cxxi_InitBases ()\n\t\t{\n");
#line default #line default
#line hidden #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)) { foreach (var npBase in Class.BaseClasses.Skip (1)) {
#line default #line default
#line hidden #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("\t\t\t"); this.Write("\t\t\t__cxxi_");
#line default #line default
#line hidden #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 )); this.Write(this.ToStringHelper.ToStringWithCulture( npBase.Name ));
#line default #line default
#line hidden #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 "); this.Write(" = new ");
#line default #line default
#line hidden #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 )); 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(" (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 default #line default
#line hidden #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(")));\n"); this.Write(" (this);\n");
#line default #line default
#line hidden #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 default
#line hidden #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"); this.Write("\t\t}\n");
#line default #line default
#line hidden #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 default
#line hidden #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"); this.Write("\t}\n}\n\n");
#line default #line default

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

@ -8,8 +8,8 @@
var wrapper = Class.Name; var wrapper = Class.Name;
var iface = "I" + Class.Name; var iface = "I" + Class.Name;
var layout = "_" + Class.Name; var layout = "_" + Class.Name;
var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\tLayoutClass ();"; var layoutClass = (hasBase? "\t: base (impl.TypeInfo)\n\t\t{" : "{") + "\n\t\t\t__cxxi_LayoutClass ();";
var initBases = (Class.BaseClasses.Count > 1 ? "\tInitBases ();\n\t\t}" : "}"); var initBases = (Class.BaseClasses.Count > 1 ? "\t__cxxi_InitBases ();\n\t\t}" : "}");
#> #>
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Managed wrapper for <#= Class.Name #> // Managed wrapper for <#= Class.Name #>
@ -106,7 +106,7 @@ namespace <#= Generator.Namespace #> {
<# PushIndent ("\t\t"); <# PushIndent ("\t\t");
foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) { foreach (var method in Class.Methods.Where (m => m.GenWrapperMethod)) {
WriteMethodHeader (method, layoutClass); WriteMethodHeader (method, layoutClass, false, false);
if (method.IsConstructor) if (method.IsConstructor)
Write ("Native = "); Write ("Native = ");
@ -185,7 +185,7 @@ namespace <#= Generator.Namespace #> {
Native.Dispose (); Native.Dispose ();
} }
private void LayoutClass () private void __cxxi_LayoutClass ()
{ {
<# foreach (var npBase in Class.BaseClasses.Skip (1)) { #> <# foreach (var npBase in Class.BaseClasses.Skip (1)) { #>
new <#= npBase.Name #> (impl.TypeInfo); new <#= npBase.Name #> (impl.TypeInfo);
@ -195,36 +195,79 @@ namespace <#= Generator.Namespace #> {
<# /* Make this wrapper castable to non-primary bases */ <# /* Make this wrapper castable to non-primary bases */
foreach (var npBase in Class.BaseClasses.Skip (1)) { #> 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) public static implicit operator <#= npBase.Name #>(<#= wrapper #> subClass)
{ {
return subClass.<#= npBase.Name #>; 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"); <# PushIndent ("\t\t");
foreach (var method in npBase.Methods) { foreach (var method in npBase.Methods.Where (m => m.IsVirtual)) {
// 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 || Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id)))
if (!method.GenWrapperMethod || method.IsConstructor || method.IsStatic ||
(method.IsVirtual && Class.Methods.Any (m => m.Node.CheckValue ("overrides", method.Node.Id))))
continue; 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); WriteParameters (method.Parameters, false, false);
PopIndent (); PopIndent ();
Write (");\n{0}}}\n\n", CurrentIndent); Write (");\n{0}}}\n\n", CurrentIndent);
} }
ClearIndent (); ClearIndent ();
WriteLine ("#endregion");
} }
if (Class.BaseClasses.Count > 1) { #> if (Class.BaseClasses.Count > 1) { #>
private void InitBases () private void __cxxi_InitBases ()
{ {
<# foreach (var npBase in Class.BaseClasses.Skip (1)) { #> <# 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); var returnType = GetCSharpType (method.ReturnType);
if (method.IsVirtual) if (!isNonPrimaryOverride && method.IsVirtual)
WriteLine ("[OverrideNative (\"{0}\")]", method.Name); WriteLine ("[OverrideNative (\"{0}\")]", method.Name);
Write (CurrentIndent + "public "); Write (CurrentIndent + (@protected? "protected " : "public "));
if (method.IsConstructor) { if (method.IsConstructor) {
Write (method.FormattedName); Write (method.FormattedName);
} else { } else {
if (method.IsStatic) Write ("static "); 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 (returnType);
Write (" "); Write (" ");
Write (method.FormattedName); Write (isNonPrimaryOverride && layoutClass != null? layoutClass : method.FormattedName);
} }
Write (" ("); Write (" (");
WriteParameters (method.Parameters, true, false); WriteParameters (method.Parameters, true, false);
Write (")\n"); Write (")\n");
if (method.IsConstructor) if (method.IsConstructor && layoutClass != null)
WriteLine (layoutClass); WriteLine (layoutClass);
else else
WriteLine ("{"); WriteLine ("{");

12
tests/InheritanceTests.cs

@ -45,7 +45,7 @@ namespace Tests {
Assert.AreEqual (9, cls.Number, "#3"); Assert.AreEqual (9, cls.Number, "#3");
Assert.AreEqual (3, ((MultiplierClass)cls).Number, "#4"); Assert.AreEqual (3, ((MultiplierClass)cls).Number, "#4");
cls.Multiply (10); cls.MultiplierClass.Multiply (10);
Assert.AreEqual (9, cls.Number, "#5"); Assert.AreEqual (9, cls.Number, "#5");
Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#6"); Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#6");
} }
@ -61,7 +61,7 @@ namespace Tests {
Assert.AreEqual (9, cls.Number, "#3"); Assert.AreEqual (9, cls.Number, "#3");
Assert.AreEqual (9, ((MultiplierClassWithVirtualBase)cls).Number, "#4"); Assert.AreEqual (9, ((MultiplierClassWithVirtualBase)cls).Number, "#4");
cls.Multiply (6); cls.MultiplierClassWithVirtualBase.Multiply (6);
Assert.AreEqual (30, cls.Number, "#5"); Assert.AreEqual (30, cls.Number, "#5");
Assert.AreEqual (30, ((MultiplierClassWithVirtualBase)cls).Number, "#6"); Assert.AreEqual (30, ((MultiplierClassWithVirtualBase)cls).Number, "#6");
} }
@ -113,9 +113,9 @@ namespace Tests {
} }
// override virtual member inherited from non-primary base // 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 () public void TestManagedOverride2 ()
{ {
var cls = new ManagedOverride2 (); var cls = new ManagedOverride2 ();
cls.Multiply (7); cls.MultiplierClass.Multiply (7);
Assert.AreEqual (5, cls.Number, "#1"); Assert.AreEqual (5, cls.Number, "#1");
Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#2"); Assert.AreEqual (30, ((MultiplierClass)cls).Number, "#2");
cls.CallMultiply (2); cls.CallMultiply (2);
@ -152,7 +152,7 @@ namespace Tests {
Assert.AreEqual (-30, cls.NegativeNumber, "#6"); Assert.AreEqual (-30, cls.NegativeNumber, "#6");
// cast to non-primary subclass // cast to non-primary subclass
Assert.IsNotNull (cls as ManagedOverride2, "#7"); Assert.IsNotNull (((ClassWithNonVirtualBases)cls) as ManagedOverride2, "#7");
} }
} }

Loading…
Cancel
Save