Browse Source

Delete a custom pass added as standard

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1261/head
Dimitar Dobrev 6 years ago
parent
commit
c62f85bfa8
  1. 9
      src/Generator/Generators/CLI/CLIGenerator.cs
  2. 227
      src/Generator/Passes/ObjectOverridesPass.cs
  3. 8
      tests/CLI/CLI.Tests.cs

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

@ -29,14 +29,7 @@ namespace CppSharp.Generators.CLI
return outputs; return outputs;
} }
public override bool SetupPasses() public override bool SetupPasses() => true;
{
// Note: The ToString override will only work if this pass runs
// after the MoveOperatorToCallPass.
if (Context.Options.GenerateObjectOverrides)
Context.TranslationUnitPasses.AddPass(new ObjectOverridesPass(this));
return true;
}
public static bool ShouldGenerateClassNativeField(Class @class) public static bool ShouldGenerateClassNativeField(Class @class)
{ {

227
src/Generator/Passes/ObjectOverridesPass.cs

@ -1,227 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using CppSharp.AST;
using CppSharp.Generators;
using CppSharp.Generators.CLI;
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 Generator Generator { get; set; }
public ObjectOverridesPass(Generator generator)
{
Generator = generator;
}
private bool needsStreamInclude;
private void OnUnitGenerated(GeneratorOutput output)
{
needsStreamInclude = false;
foreach (var template in output.Outputs)
{
foreach (var block in template.FindBlocks(BlockKind.MethodBody))
{
var method = block.Object as Method;
VisitMethod(method, block);
}
if (needsStreamInclude)
{
var sourcesTemplate = template as CLISources;
if (sourcesTemplate != null)
{
foreach (var block in sourcesTemplate.FindBlocks(BlockKind.Includes))
{
block.WriteLine("#include <sstream>");
block.WriteLine("");
break;
}
break;
}
}
}
}
private void VisitMethod(Method method, Block block)
{
if (!method.IsSynthetized)
return;
var @class = (Class)method.Namespace;
if (method.Name == "GetHashCode" && method.Parameters.Count == 0)
GenerateGetHashCode(block);
if (method.Name == "Equals" && method.Parameters.Count == 1)
GenerateEquals(@class, block, method);
if (method.Name == "ToString" && method.Parameters.Count == 0)
GenerateToString(block);
}
void GenerateGetHashCode(Block block)
{
block.Write("return (int)NativePtr;");
}
void GenerateEquals(Class @class, Block block, Method method)
{
var cliTypePrinter = new CLITypePrinter(Context);
var classCliType = @class.Visit(cliTypePrinter);
block.WriteLine("if (!object) return false;");
block.WriteLine("auto obj = dynamic_cast<{0}>({1});",
classCliType, method.Parameters[0].Name);
block.NewLine();
block.WriteLine("if (!obj) return false;");
block.Write("return __Instance == obj->__Instance;");
}
void GenerateToString(Block block)
{
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)
{
// FIXME: Add a better way to hook the event
if (!isHooked)
{
Generator.OnUnitGenerated += OnUnitGenerated;
isHooked = true;
}
if (!VisitDeclaration(@class))
return false;
// We can't handle value types yet
// The generated code assumes that a NativePtr is available
if (@class.IsValueType)
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),
SynthKind = FunctionSynthKind.ComplementOperator,
IsProxy = true
};
toStringMethod.OverriddenMethods.Add(new Method { Name = "ToString" });
@class.Methods.Add(toStringMethod);
Diagnostics.Debug("Function converted to ToString: {0}::{1}",
@class.Name, method.Name);
break;
}
var methodEqualsParam = new Parameter
{
Name = "object",
QualifiedType = new QualifiedType(new CILType(typeof(Object)))
};
var methodEquals = new Method
{
Name = "Equals",
Namespace = @class,
ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Bool)),
SynthKind = FunctionSynthKind.ComplementOperator,
IsProxy = true
};
methodEqualsParam.Namespace = methodEquals;
methodEquals.Parameters.Add(methodEqualsParam);
methodEquals.OverriddenMethods.Add(new Method { Name = "Equals" });
@class.Methods.Add(methodEquals);
var methodHashCode = new Method
{
Name = "GetHashCode",
Namespace = @class,
ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Int)),
SynthKind = FunctionSynthKind.ComplementOperator,
IsProxy = true
};
methodHashCode.OverriddenMethods.Add(new Method { Name = "GetHashCode" });
@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 = 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;
}
}
}

8
tests/CLI/CLI.Tests.cs

@ -12,14 +12,6 @@ public class CLITests : GeneratorTestFixture
Assert.That(sum, Is.EqualTo(7)); 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);
}
[Test] [Test]
public void TestStdString() public void TestStdString()
{ {

Loading…
Cancel
Save