|
|
|
@ -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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|