Browse Source

Added better wrapping for static classes.

pull/188/merge
triton 12 years ago
parent
commit
0a102d8fbc
  1. 3
      src/AST/Class.cs
  2. 1
      src/Generator/Driver.cs
  3. 14
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  4. 26
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  5. 65
      src/Generator/Passes/CheckStaticClass.cs
  6. 6
      tests/Basic/Basic.Tests.cs
  7. 8
      tests/Basic/Basic.h

3
src/AST/Class.cs

@ -114,6 +114,9 @@ namespace CppSharp.AST
// True if the class has a non trivial destructor. // True if the class has a non trivial destructor.
public bool HasNonTrivialDestructor; public bool HasNonTrivialDestructor;
// True if the class represents a static class.
public bool IsStatic;
public Class() public Class()
{ {
Bases = new List<BaseClassSpecifier>(); Bases = new List<BaseClassSpecifier>();

1
src/Generator/Driver.cs

@ -256,6 +256,7 @@ namespace CppSharp
library.SetupPasses(this); library.SetupPasses(this);
TranslationUnitPasses.AddPass(new FindSymbolsPass()); TranslationUnitPasses.AddPass(new FindSymbolsPass());
TranslationUnitPasses.AddPass(new CheckStaticClass());
TranslationUnitPasses.AddPass(new MoveOperatorToClassPass()); TranslationUnitPasses.AddPass(new MoveOperatorToClassPass());
TranslationUnitPasses.AddPass(new MoveFunctionToClassPass()); TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions()); TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());

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

@ -360,6 +360,9 @@ namespace CppSharp.Generators.CLI
public void GenerateClassConstructors(Class @class, string nativeType) public void GenerateClassConstructors(Class @class, string nativeType)
{ {
if (@class.IsStatic)
return;
PushIndent(); PushIndent();
// Output a default constructor that takes the native pointer. // Output a default constructor that takes the native pointer.
@ -566,10 +569,13 @@ namespace CppSharp.Generators.CLI
return true; return true;
} }
if (CSharpTextTemplate.HasRefBase(@class)) if (!@class.IsStatic)
Write(" : {0}", QualifiedIdentifier(@class.Bases[0].Class)); {
else if (@class.IsRefType) if (CSharpTextTemplate.HasRefBase(@class))
Write(" : ICppInstance"); Write(" : {0}", QualifiedIdentifier(@class.Bases[0].Class));
else if (@class.IsRefType)
Write(" : ICppInstance");
}
NewLine(); NewLine();
WriteLine("{"); WriteLine("{");

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

@ -135,15 +135,7 @@ namespace CppSharp.Generators.CLI
GenerateDeclContext(@class); GenerateDeclContext(@class);
// Output a default constructor that takes the native pointer. GenerateClassConstructors(@class);
GenerateClassConstructor(@class, isIntPtr: false);
GenerateClassConstructor(@class, isIntPtr: true);
if (@class.IsRefType)
{
GenerateClassDestructor(@class);
GenerateClassFinalizer(@class);
}
foreach (var method in @class.Methods) foreach (var method in @class.Methods)
{ {
@ -199,6 +191,22 @@ namespace CppSharp.Generators.CLI
PopBlock(); PopBlock();
} }
private void GenerateClassConstructors(Class @class)
{
if (@class.IsStatic)
return;
// Output a default constructor that takes the native pointer.
GenerateClassConstructor(@class, isIntPtr: false);
GenerateClassConstructor(@class, isIntPtr: true);
if (@class.IsRefType)
{
GenerateClassDestructor(@class);
GenerateClassFinalizer(@class);
}
}
private void GenerateClassProperties(Class @class, Class realOwner) private void GenerateClassProperties(Class @class, Class realOwner)
{ {
if (@class.IsValueType) if (@class.IsValueType)

65
src/Generator/Passes/CheckStaticClass.cs

@ -0,0 +1,65 @@
using System.Linq;
using CppSharp.AST;
namespace CppSharp.Passes
{
/// <summary>
/// Checks for classes that should be bound as static classes.
/// </summary>
public class CheckStaticClass : TranslationUnitPass
{
static bool ReturnsClassInstance(Function function)
{
var returnType = function.ReturnType.Type.Desugar();
TagType tag;
if (!returnType.IsPointerTo(out tag))
return false;
var @class = (Class) function.Namespace;
var decl = tag.Declaration;
if (decl is Class)
return false;
return @class.QualifiedOriginalName == decl.QualifiedOriginalName;
}
public override bool VisitClassDecl(Class @class)
{
if (!VisitDeclaration(@class))
return false;
// If the class has any non-private constructors then it cannot
// be bound as a static class and we bail out early.
if (@class.Constructors.Any(m =>
!(m.IsCopyConstructor || m.IsMoveConstructor)
&& m.Access != AccessSpecifier.Private))
return false;
// Check for any non-static fields or methods, in which case we
// assume the class is not meant to be static.
// Note: Static fields are represented as variables in the AST.
if (@class.Fields.Any() ||
@class.Methods.Any(m => m.Kind == CXXMethodKind.Normal
&& !m.IsStatic))
return false;
// Check for any static function that return a pointer to the class.
// If one exists, we assume it's a factory function and the class is
// not meant to be static. It's a simple heuristic but it should be
// good enough for the time being.
if (@class.Functions.Any(ReturnsClassInstance))
return false;
// TODO: We should take C++ friends into account here, they might allow
// a class to be instantiated even it if's not possible to instantiate
// it using just its regular members.
// If all the above constraints hold, then we assume the class can be
// static.
@class.IsStatic = true;
return true;
}
}
}

6
tests/Basic/Basic.Tests.cs

@ -181,5 +181,11 @@ public class BasicTests : GeneratorTestFixture
bar2.pointerToStruct.A = 15; bar2.pointerToStruct.A = 15;
Assert.That(bar2.pointerToStruct.A, Is.EqualTo(15)); Assert.That(bar2.pointerToStruct.A, Is.EqualTo(15));
} }
[Test]
public void TestStaticClasses()
{
Assert.That(TestStaticClass.Add(1, 2), Is.EqualTo(3));
}
} }

8
tests/Basic/Basic.h

@ -253,3 +253,11 @@ struct DLL_API TestFinalizers
{ {
}; };
// Tests static classes
struct DLL_API TestStaticClass
{
static int Add(int a, int b) { return a + b; }
private:
TestStaticClass();
};
Loading…
Cancel
Save