Browse Source

Extended the ObjectOverridesPass to generate ToString methods if the insertion operator (<<) is overloaded.

pull/250/head
Elias Holzer 11 years ago
parent
commit
06218ec48a
  1. 4
      src/Generator/Generators/CLI/CLIGenerator.cs
  2. 7
      src/Generator/Options.cs
  3. 115
      src/Generator/Passes/ObjectOverridesPass.cs
  4. 9
      tests/CLITemp/CLITemp.Tests.cs
  5. 1
      tests/CLITemp/CLITemp.cs
  6. 23
      tests/CLITemp/CLITemp.h

4
src/Generator/Generators/CLI/CLIGenerator.cs

@ -32,6 +32,10 @@ namespace CppSharp.Generators.CLI @@ -32,6 +32,10 @@ namespace CppSharp.Generators.CLI
public override bool SetupPasses()
{
// Note: The ToString override will only work if this pass runs
// after the MoveOperatorToCallPass.
if (Driver.Options.GenerateObjectOverrides)
Driver.TranslationUnitPasses.AddPass(new ObjectOverridesPass());
return true;
}
}

7
src/Generator/Options.cs

@ -127,6 +127,13 @@ namespace CppSharp @@ -127,6 +127,13 @@ namespace CppSharp
/// </summary>
public bool GenerateConversionOperators;
/// <summary>
/// If set to true the CLI generator will use ObjectOverridesPass to create
/// Equals, GetHashCode and (if the insertion operator << is overloaded) ToString
/// methods.
/// </summary>
public bool GenerateObjectOverrides;
//List of include directories that are used but not generated
public List<string> NoGenIncludeDirs;

115
src/Generator/Passes/ObjectOverridesPass.cs

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Generators.CLI;
@ -7,10 +8,17 @@ using CppSharp.Passes; @@ -7,10 +8,17 @@ using CppSharp.Passes;
namespace CppSharp
{
// This pass adds Equals and GetHashCode methods to classes.
// It will also add a ToString method if the insertion operator (<<)
// of the class is overloaded.
// Note that the OperatorToClassPass needs to run first in order for
// this to work.
public class ObjectOverridesPass : TranslationUnitPass
{
private bool needsStreamInclude;
private void OnUnitGenerated(GeneratorOutput output)
{
needsStreamInclude = false;
foreach (var template in output.Templates)
{
foreach (var block in template.FindBlocks(CLIBlockKind.MethodBody))
@ -18,6 +26,20 @@ namespace CppSharp @@ -18,6 +26,20 @@ namespace CppSharp
var method = block.Declaration as Method;
VisitMethod(method, block);
}
if (needsStreamInclude)
{
var sourcesTemplate = template as CLISourcesTemplate;
if (sourcesTemplate != null)
{
foreach (var block in sourcesTemplate.FindBlocks(CLIBlockKind.Includes))
{
block.WriteLine("#include <sstream>");
block.WriteLine("");
break;
}
break;
}
}
}
}
@ -33,6 +55,9 @@ namespace CppSharp @@ -33,6 +55,9 @@ namespace CppSharp
if (method.Name == "Equals" && method.Parameters.Count == 1)
GenerateEquals(@class, block, method);
if (method.Name == "ToString" && method.Parameters.Count == 0)
GenerateToString(@class, block, method);
}
void GenerateGetHashCode(Block block)
@ -54,6 +79,14 @@ namespace CppSharp @@ -54,6 +79,14 @@ namespace CppSharp
block.Write("return __Instance == obj->__Instance;");
}
void GenerateToString(Class @class, Block block, Method method)
{
needsStreamInclude = true;
block.WriteLine("std::ostringstream os;");
block.WriteLine("os << *NativePtr;");
block.Write("return clix::marshalString<clix::E_UTF8>(os.str());");
}
private bool isHooked;
public override bool VisitClassDecl(Class @class)
{
@ -67,6 +100,33 @@ namespace CppSharp @@ -67,6 +100,33 @@ namespace CppSharp
if (!VisitDeclaration(@class))
return false;
foreach (var method in @class.Methods)
{
if (!IsInsertionOperator(method))
continue;
// Create the ToString method
var stringType = GetType("std::string");
if (stringType == null)
stringType = new CILType(typeof(string));
var toStringMethod = new Method()
{
Name = "ToString",
Namespace = @class,
ReturnType = new QualifiedType(stringType),
IsSynthetized = true,
IsOverride = true,
IsProxy = true
};
@class.Methods.Add(toStringMethod);
Driver.Diagnostics.Debug("Function converted to ToString: {0}::{1}",
@class.Name, method.Name);
break;
}
if (@class.IsValueType)
return false;
@ -86,8 +146,8 @@ namespace CppSharp @@ -86,8 +146,8 @@ namespace CppSharp
IsOverride = true,
IsProxy = true
};
@class.Methods.Add(methodEquals);
@class.Methods.Add(methodEquals);
var methodHashCode = new Method
{
Name = "GetHashCode",
@ -101,5 +161,56 @@ namespace CppSharp @@ -101,5 +161,56 @@ namespace CppSharp
@class.Methods.Add(methodHashCode);
return true;
}
private Dictionary<string, AST.Type> typeCache;
protected AST.Type GetType(string typeName)
{
if (typeCache == null)
typeCache = new Dictionary<string, AST.Type>();
AST.Type result;
if (!typeCache.TryGetValue(typeName, out result))
{
var typeDef = Driver.ASTContext.FindTypedef(typeName)
.FirstOrDefault();
if (typeDef != null)
result = new TypedefType() { Declaration = typeDef };
typeCache.Add(typeName, result);
}
return result;
}
private bool IsInsertionOperator(Method method)
{
// Do some basic check
if (!method.IsOperator)
return false;
if (method.OperatorKind != CXXOperatorKind.LessLess)
return false;
if (method.Parameters.Count != 2)
return false;
// Check that first parameter is a std::ostream&
var fstType = method.Parameters[0].Type as PointerType;
if (fstType == null)
return false;
var oStreamType = GetType("std::ostream");
if (oStreamType == null)
return false;
if (!oStreamType.Equals(fstType.Pointee))
return false;
// Check that second parameter is a const CLASS&
var sndType = method.Parameters[1].Type as PointerType;
if (sndType == null)
return false;
if (!sndType.QualifiedPointee.Qualifiers.IsConst)
return false;
var @class = method.Namespace as Class;
var classType = new TagType(@class);
if (!classType.Equals(sndType.Pointee))
return false;
return true;
}
}
}

9
tests/CLITemp/CLITemp.Tests.cs

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
using CppSharp.Utils;
using NUnit.Framework;
using CLITemp;
using System;
public class CLITests : GeneratorTestFixture
{
@ -11,4 +12,12 @@ public class CLITests : GeneratorTestFixture @@ -11,4 +12,12 @@ public class CLITests : GeneratorTestFixture
var sum = new Types().AttributedSum(3, 4);
Assert.That(sum, Is.EqualTo(7));
}
[Test]
public void TestToStringOverride()
{
var date = new Date(24, 12, 1924);
var s = date.ToString();
Assert.AreEqual("24/12/1924", s);
}
}

1
tests/CLITemp/CLITemp.cs

@ -14,6 +14,7 @@ namespace CppSharp.Tests @@ -14,6 +14,7 @@ namespace CppSharp.Tests
public override void Setup(Driver driver)
{
driver.Options.GenerateFinalizers = true;
driver.Options.GenerateObjectOverrides = true;
base.Setup(driver);
}

23
tests/CLITemp/CLITemp.h

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
#include "../Tests.h"
#include <ostream>
// Tests for C++ types
struct DLL_API Types
{
@ -23,4 +25,23 @@ class DLL_API TestProtectedDestructors @@ -23,4 +25,23 @@ class DLL_API TestProtectedDestructors
~TestProtectedDestructors();
};
TestProtectedDestructors::~TestProtectedDestructors() {}
TestProtectedDestructors::~TestProtectedDestructors() {}
// Tests the insertion operator (<<) to ToString method pass
class DLL_API Date
{
public:
Date(int m, int d, int y)
{
mo = m; da = d; yr = y;
}
// Not picked up by parser yet
//friend std::ostream& operator<<(std::ostream& os, const Date& dt);
int mo, da, yr;
};
std::ostream& operator<<(std::ostream& os, const Date& dt)
{
os << dt.mo << '/' << dt.da << '/' << dt.yr;
return os;
}

Loading…
Cancel
Save