Browse Source

Added experimental destructors/finalizers support.

This has exposed some underlying bugs on some pieces of generated code, so I've put it under an option temporarily.

Fixes #148.
pull/153/merge
triton 12 years ago
parent
commit
0f76dc0090
  1. 54
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  2. 80
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  3. 2
      src/Generator/Generators/CLI/CLITextTemplate.cs
  4. 40
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  5. 7
      src/Generator/Options.cs
  6. 5
      tests/Basic/Basic.h

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

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Generators.CSharp;
using CppSharp.Types; using CppSharp.Types;
namespace CppSharp.Generators.CLI namespace CppSharp.Generators.CLI
@ -252,10 +253,8 @@ namespace CppSharp.Generators.CLI
var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName); var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName);
if (@class.IsRefType) if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class))
{
GenerateClassNativeField(@class, nativeType); GenerateClassNativeField(@class, nativeType);
}
GenerateClassConstructors(@class, nativeType); GenerateClassConstructors(@class, nativeType);
@ -279,23 +278,8 @@ namespace CppSharp.Generators.CLI
WriteLine("};"); WriteLine("};");
} }
internal static bool HasRefBase(Class @class)
{
Class baseClass = null;
if (@class.HasBaseClass)
baseClass = @class.Bases[0].Class;
var hasRefBase = baseClass != null && baseClass.IsRefType
&& !baseClass.Ignore;
return hasRefBase;
}
public void GenerateClassNativeField(Class @class, string nativeType) public void GenerateClassNativeField(Class @class, string nativeType)
{ {
if (HasRefBase(@class)) return;
WriteLineIndent("property {0} NativePtr;", nativeType); WriteLineIndent("property {0} NativePtr;", nativeType);
PushIndent(); PushIndent();
@ -380,19 +364,41 @@ namespace CppSharp.Generators.CLI
foreach (var ctor in @class.Constructors) foreach (var ctor in @class.Constructors)
{ {
if (ctor.IsCopyConstructor || ctor.IsMoveConstructor) if (ASTUtils.CheckIgnoreMethod(ctor))
continue;
// Default constructors are not supported in .NET value types.
if (ctor.Parameters.Count == 0 && @class.IsValueType)
continue; continue;
GenerateMethod(ctor); GenerateMethod(ctor);
} }
if (@class.IsRefType)
{
GenerateClassDestructor(@class);
GenerateClassFinalizer(@class);
}
PopIndent(); PopIndent();
} }
private void GenerateClassDestructor(Class @class)
{
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Destructor);
WriteLine("~{0}();", @class.Name);
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateClassFinalizer(Class @class)
{
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Finalizer);
WriteLine("!{0}();", @class.Name);
PopBlock(NewLineKind.BeforeNextBlock);
}
public void GenerateClassFields(Class @class) public void GenerateClassFields(Class @class)
{ {
// Handle the case of struct (value-type) inheritance by adding the base // Handle the case of struct (value-type) inheritance by adding the base
@ -552,7 +558,7 @@ namespace CppSharp.Generators.CLI
return true; return true;
} }
if (HasRefBase(@class)) if (CSharpTextTemplate.HasRefBase(@class))
Write(" : {0}", QualifiedIdentifier(@class.Bases[0].Class)); Write(" : {0}", QualifiedIdentifier(@class.Bases[0].Class));
else if (@class.IsRefType) else if (@class.IsRefType)
Write(" : ICppInstance"); Write(" : ICppInstance");

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

@ -4,6 +4,7 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Generators.CSharp;
using CppSharp.Types; using CppSharp.Types;
using Type = CppSharp.AST.Type; using Type = CppSharp.AST.Type;
@ -134,6 +135,12 @@ namespace CppSharp.Generators.CLI
GenerateClassConstructor(@class, isIntPtr: false); GenerateClassConstructor(@class, isIntPtr: false);
GenerateClassConstructor(@class, isIntPtr: true); GenerateClassConstructor(@class, isIntPtr: true);
if (@class.IsRefType)
{
GenerateClassDestructor(@class);
GenerateClassFinalizer(@class);
}
foreach (var method in @class.Methods) foreach (var method in @class.Methods)
{ {
if (ASTUtils.CheckIgnoreMethod(method)) if (ASTUtils.CheckIgnoreMethod(method))
@ -142,27 +149,24 @@ namespace CppSharp.Generators.CLI
GenerateMethod(method, @class); GenerateMethod(method, @class);
} }
if (@class.IsRefType) if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class))
{ {
if (!CLIHeadersTemplate.HasRefBase(@class)) PushBlock(CLIBlockKind.Method);
{ WriteLine("System::IntPtr {0}::Instance::get()",
PushBlock(CLIBlockKind.Method); QualifiedIdentifier(@class));
WriteLine("System::IntPtr {0}::Instance::get()", WriteStartBraceIndent();
QualifiedIdentifier(@class)); WriteLine("return System::IntPtr(NativePtr);");
WriteStartBraceIndent(); WriteCloseBraceIndent();
WriteLine("return System::IntPtr(NativePtr);"); PopBlock(NewLineKind.BeforeNextBlock);
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock); PushBlock(CLIBlockKind.Method);
WriteLine("void {0}::Instance::set(System::IntPtr object)",
PushBlock(CLIBlockKind.Method); QualifiedIdentifier(@class));
WriteLine("void {0}::Instance::set(System::IntPtr object)", WriteStartBraceIndent();
QualifiedIdentifier(@class)); var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName);
WriteStartBraceIndent(); WriteLine("NativePtr = ({0})object.ToPointer();", nativeType);
var nativeType = string.Format("::{0}*", @class.QualifiedOriginalName); WriteCloseBraceIndent();
WriteLine("NativePtr = ({0})object.ToPointer();", nativeType); PopBlock(NewLineKind.BeforeNextBlock);
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
} }
GenerateClassProperties(@class, @class); GenerateClassProperties(@class, @class);
@ -206,6 +210,42 @@ namespace CppSharp.Generators.CLI
GenerateProperty(property, realOwner); GenerateProperty(property, realOwner);
} }
private void GenerateClassDestructor(Class @class)
{
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Destructor);
WriteLine("{0}::~{1}()", QualifiedIdentifier(@class), @class.Name);
WriteStartBraceIndent();
if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class))
WriteLine("delete NativePtr;");
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateClassFinalizer(Class @class)
{
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Finalizer);
WriteLine("{0}::!{1}()", QualifiedIdentifier(@class), @class.Name);
WriteStartBraceIndent();
if (CSharpTextTemplate.ShouldGenerateClassNativeField(@class))
WriteLine("delete NativePtr;");
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
}
private void GenerateFunctionTemplate(FunctionTemplate template) private void GenerateFunctionTemplate(FunctionTemplate template)
{ {
var printer = TypePrinter; var printer = TypePrinter;

2
src/Generator/Generators/CLI/CLITextTemplate.cs

@ -43,6 +43,8 @@ namespace CppSharp.Generators.CLI
public const int Typedef = BlockKind.LAST + 14; public const int Typedef = BlockKind.LAST + 14;
public const int Variable = BlockKind.LAST + 15; public const int Variable = BlockKind.LAST + 15;
public const int Template = BlockKind.LAST + 16; public const int Template = BlockKind.LAST + 16;
public static int Destructor = BlockKind.LAST + 17;
public static int Finalizer = BlockKind.LAST + 18;
} }
/// <summary> /// <summary>

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

@ -96,6 +96,7 @@ namespace CppSharp.Generators.CSharp
public const int VTableDelegate = FIRST + 16; public const int VTableDelegate = FIRST + 16;
public const int Region = FIRST + 17; public const int Region = FIRST + 17;
public const int Interface = FIRST + 18; public const int Interface = FIRST + 18;
public const int Finalizer = FIRST + 19;
} }
public class CSharpTextTemplate : Template public class CSharpTextTemplate : Template
@ -703,21 +704,22 @@ namespace CppSharp.Generators.CSharp
WriteCloseBraceIndent(); WriteCloseBraceIndent();
} }
public bool ShouldGenerateClassNativeField(Class @class) public static bool HasRefBase(Class @class)
{ {
if (!@class.IsRefType)
return false;
Class baseClass = null; Class baseClass = null;
if (@class.HasBaseClass) if (@class.HasBaseClass)
baseClass = @class.Bases[0].Class; baseClass = @class.Bases[0].Class;
var hasRefBase = baseClass != null && baseClass.IsRefType && !baseClass.Ignore; var hasRefBase = baseClass != null && baseClass.IsRefType
&& !baseClass.Ignore;
var hasIgnoredBase = baseClass != null && baseClass.Ignore; return hasRefBase;
}
return !@class.HasBase || !hasRefBase || hasIgnoredBase; public static bool ShouldGenerateClassNativeField(Class @class)
{
return @class.IsRefType && (!@class.HasBase || !HasRefBase(@class));
} }
public void GenerateClassProlog(Class @class) public void GenerateClassProlog(Class @class)
@ -1657,7 +1659,25 @@ namespace CppSharp.Generators.CSharp
} }
if (@class.IsRefType) if (@class.IsRefType)
{
GenerateClassFinalizer(@class);
GenerateDisposeMethods(@class); GenerateDisposeMethods(@class);
}
}
private void GenerateClassFinalizer(Class @class)
{
if (!Options.GenerateFinalizers)
return;
PushBlock(CSharpBlockKind.Finalizer);
WriteLine("~{0}()", @class.Name);
WriteStartBraceIndent();
WriteLine("Dispose(false);");
WriteCloseBraceIndent();
PopBlock(NewLineKind.BeforeNextBlock);
} }
private void GenerateDisposeMethods(Class @class) private void GenerateDisposeMethods(Class @class)
@ -1682,12 +1702,12 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.Method); PushBlock(CSharpBlockKind.Method);
if (@class.IsValueType) if (@class.IsValueType)
{ {
this.Write("private "); Write("private ");
} }
else else
{ {
this.Write("protected "); Write("protected ");
this.Write(hasBaseClass ? "override " : "virtual "); Write(hasBaseClass ? "override " : "virtual ");
} }
WriteLine("void Dispose(bool disposing)"); WriteLine("void Dispose(bool disposing)");

7
src/Generator/Options.cs

@ -89,6 +89,13 @@ namespace CppSharp
public bool GenerateInterfacesForMultipleInheritance; public bool GenerateInterfacesForMultipleInheritance;
public bool GenerateProperties; public bool GenerateProperties;
public bool GenerateInternalImports; public bool GenerateInternalImports;
/// <summary>
/// Enable this option to enable generation of finalizers.
/// Works in both CLI and C# backends.
/// </summary>
public bool GenerateFinalizers;
public string IncludePrefix; public string IncludePrefix;
public bool WriteOnlyWhenChanged; public bool WriteOnlyWhenChanged;
public Func<TranslationUnit, string> GenerateName; public Func<TranslationUnit, string> GenerateName;

5
tests/Basic/Basic.h

@ -244,4 +244,9 @@ struct DLL_API TestMemoryLeaks
TestMemoryLeaks(const char* name) {} TestMemoryLeaks(const char* name) {}
}; };
// Tests that finalizers are generated
/* CLI: ~TestFinalizers() */
struct DLL_API TestFinalizers
{
};

Loading…
Cancel
Save