From 474f82b513a229e9bcb7e98fda557b3fcbfa342f Mon Sep 17 00:00:00 2001
From: Elias Holzer <elias@vvvv.org>
Date: Thu, 17 Apr 2014 02:23:16 +0200
Subject: [PATCH] Added support for explicit conversion operators and added new
 pass which will create implicit and explicit conversion operators out of
 single argument constructors.

Conflicts:
	src/Generator/Passes/CheckAmbiguousFunctions.cs
	src/Generator/Passes/CheckOperatorsOverloads.cs
---
 src/AST/Method.cs                             |   3 +-
 src/Generator/AST/Utils.cs                    |   2 +
 src/Generator/Driver.cs                       |   6 +-
 .../Generators/CLI/CLIHeadersTemplate.cs      |   8 +-
 .../Generators/CLI/CLISourcesTemplate.cs      |   6 +-
 .../Generators/CLI/CLITextTemplate.cs         |   3 +-
 .../Generators/CSharp/CSharpTextTemplate.cs   |  27 +-
 src/Generator/Options.cs                      |   7 +
 .../Passes/CheckAmbiguousFunctions.cs         |   2 +
 .../Passes/CheckOperatorsOverloads.cs         |  59 +-
 .../ConstructorToConversionOperatorPass.cs    |  61 ++
 tests/Basic/Basic.Tests.cs                    |  10 +
 tests/Basic/Basic.cs                          |   3 +-
 tests/Basic/Basic.h                           | 690 +++++++++---------
 tests/CSharpTemp/CSharpTemp.cs                |   5 +-
 15 files changed, 517 insertions(+), 375 deletions(-)
 create mode 100644 src/Generator/Passes/ConstructorToConversionOperatorPass.cs

diff --git a/src/AST/Method.cs b/src/AST/Method.cs
index 77d72b8e..9a0c0817 100644
--- a/src/AST/Method.cs
+++ b/src/AST/Method.cs
@@ -64,7 +64,8 @@ namespace CppSharp.AST
         Call,
         Subscript,
         Conditional,
-        Conversion
+        Conversion,
+        ExplicitConversion
     }
 
     /// <summary>
diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs
index f7e2a90b..afc66e83 100644
--- a/src/Generator/AST/Utils.cs
+++ b/src/Generator/AST/Utils.cs
@@ -200,6 +200,8 @@ namespace CppSharp.AST
 
                 case CXXOperatorKind.Conversion:
                     return "implicit operator";
+                case CXXOperatorKind.ExplicitConversion:
+                    return "explicit operator";
             }
 
             throw new NotSupportedException();
diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs
index b37f67fd..0dca66ab 100644
--- a/src/Generator/Driver.cs
+++ b/src/Generator/Driver.cs
@@ -276,7 +276,11 @@ namespace CppSharp
             TranslationUnitPasses.AddPass(new FindSymbolsPass());
             TranslationUnitPasses.AddPass(new CheckStaticClass());
             TranslationUnitPasses.AddPass(new MoveOperatorToClassPass());
-            TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
+            TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
+
+            if (Options.GenerateConversionOperators)
+                TranslationUnitPasses.AddPass(new ConstructorToConversionOperatorPass());
+
             TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
             TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass());
             TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance());
diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs
index 6818d052..2748bdd3 100644
--- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs
+++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs
@@ -679,10 +679,14 @@ namespace CppSharp.Generators.CLI
                 Operators.IsBuiltinOperator(method.OperatorKind);
 
             if (method.IsStatic || isBuiltinOperator)
-                Write("static ");
+                Write("static ");
+
+            if (method.OperatorKind == CXXOperatorKind.ExplicitConversion)
+                Write("explicit ");
 
             if (method.IsConstructor || method.IsDestructor ||
-                method.OperatorKind == CXXOperatorKind.Conversion)
+                method.OperatorKind == CXXOperatorKind.Conversion ||
+                method.OperatorKind == CXXOperatorKind.ExplicitConversion)
                 Write("{0}(", GetMethodName(method));
             else
                 Write("{0} {1}(", method.ReturnType, method.Name);
diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs
index 6ef5700d..14bb954f 100644
--- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs
+++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs
@@ -691,7 +691,8 @@ namespace CppSharp.Generators.CLI
             PushBlock(CLIBlockKind.Method, method);
 
             if (method.IsConstructor || method.IsDestructor ||
-                method.OperatorKind == CXXOperatorKind.Conversion)
+                method.OperatorKind == CXXOperatorKind.Conversion ||
+                method.OperatorKind == CXXOperatorKind.ExplicitConversion)
                 Write("{0}::{1}(", QualifiedIdentifier(@class), GetMethodName(method));
             else
                 Write("{0} {1}::{2}(", method.ReturnType, QualifiedIdentifier(@class),
@@ -865,7 +866,8 @@ namespace CppSharp.Generators.CLI
                 Write("auto {0}{1} = ",(function.ReturnType.Type.IsReference())? "&": string.Empty,
                     Generator.GeneratedIdentifier("ret"));
 
-            if (function.OperatorKind == CXXOperatorKind.Conversion)
+            if (function.OperatorKind == CXXOperatorKind.Conversion || 
+                function.OperatorKind == CXXOperatorKind.ExplicitConversion)
             {
                 var method = function as Method;
                 var typePrinter = new CppTypePrinter(Driver.TypeDatabase);
diff --git a/src/Generator/Generators/CLI/CLITextTemplate.cs b/src/Generator/Generators/CLI/CLITextTemplate.cs
index 58c2755e..0ae556b8 100644
--- a/src/Generator/Generators/CLI/CLITextTemplate.cs
+++ b/src/Generator/Generators/CLI/CLITextTemplate.cs
@@ -96,7 +96,8 @@ namespace CppSharp.Generators.CLI
 
         public string GetMethodName(Method method)
         {
-            if (method.OperatorKind == CXXOperatorKind.Conversion)
+            if (method.OperatorKind == CXXOperatorKind.Conversion ||
+                method.OperatorKind == CXXOperatorKind.ExplicitConversion)
                 return "operator " + method.ConversionType;
 
             if (method.IsConstructor || method.IsDestructor)
diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs
index 10bb4ce6..ecb3bd9c 100644
--- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs
+++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs
@@ -2033,7 +2033,8 @@ namespace CppSharp.Generators.CSharp
             else if (method.ExplicitInterfaceImpl != null)
                 Write("{0} {1}.{2}(", method.OriginalReturnType,
                     method.ExplicitInterfaceImpl.Name, functionName);
-            else if (method.OperatorKind == CXXOperatorKind.Conversion)
+            else if (method.OperatorKind == CXXOperatorKind.Conversion || 
+                     method.OperatorKind == CXXOperatorKind.ExplicitConversion)
                 Write("{0} {1}(", functionName, method.OriginalReturnType);
             else
                 Write("{0} {1}(", method.OriginalReturnType, functionName);
@@ -2156,11 +2157,25 @@ namespace CppSharp.Generators.CSharp
         private void GenerateOperator(Method method, Class @class)
         {
             if (method.IsSynthetized)
-            {
-                var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind);
-
-                WriteLine("return !({0} {1} {2});", method.Parameters[0].Name,
-                          @operator, method.Parameters[1].Name);
+            {
+                if (method.Kind == CXXMethodKind.Conversion)
+                {
+                    // To avoid ambiguity when having the multiple inheritance pass enabled
+                    var @interface = @class.Namespace.Classes.Find(c => c.OriginalClass == @class);
+                    if (@interface != null)
+                        WriteLine("return new {0}(({2}){1});", method.ConversionType,
+                                  method.Parameters[0].Name, @interface.Name);
+                    else
+                        WriteLine("return new {0}({1});", method.ConversionType,
+                                  method.Parameters[0].Name);
+                }
+                else
+                {
+                    var @operator = Operators.GetOperatorOverloadPair(method.OperatorKind);
+
+                    WriteLine("return !({0} {1} {2});", method.Parameters[0].Name,
+                              @operator, method.Parameters[1].Name);
+                }
                 return;
             }
 
diff --git a/src/Generator/Options.cs b/src/Generator/Options.cs
index 8b0a6433..68dda98d 100644
--- a/src/Generator/Options.cs
+++ b/src/Generator/Options.cs
@@ -111,6 +111,13 @@ namespace CppSharp
         /// try to match for matching properties.
         /// </summary>
         public bool GeneratePropertiesAdvanced;
+
+        /// <summary>
+        /// If set to true the generator will use ConstructorToConversionOperatorPass to
+        /// create implicit and explicit conversion operators out of single argument
+        /// constructors.
+        /// </summary>
+        public bool GenerateConversionOperators;
 
         //List of include directories that are used but not generated
         public List<string> NoGenIncludeDirs;
diff --git a/src/Generator/Passes/CheckAmbiguousFunctions.cs b/src/Generator/Passes/CheckAmbiguousFunctions.cs
index 922dcc3a..f0c67a89 100644
--- a/src/Generator/Passes/CheckAmbiguousFunctions.cs
+++ b/src/Generator/Passes/CheckAmbiguousFunctions.cs
@@ -37,6 +37,8 @@ namespace CppSharp.Passes
             {
                 if (function.OperatorKind == CXXOperatorKind.Conversion)
                     continue;
+                if (function.OperatorKind == CXXOperatorKind.ExplicitConversion)
+                    continue;
 
                 if (overload == function) continue;
 
diff --git a/src/Generator/Passes/CheckOperatorsOverloads.cs b/src/Generator/Passes/CheckOperatorsOverloads.cs
index 31cef683..980671ab 100644
--- a/src/Generator/Passes/CheckOperatorsOverloads.cs
+++ b/src/Generator/Passes/CheckOperatorsOverloads.cs
@@ -170,35 +170,36 @@ namespace CppSharp.Passes
                 index = @class.Methods.IndexOf(second);
                 return op1;
             }
-
-            index = 0;
-            return CXXOperatorKind.None;
-        }
-
-        static bool IsValidOperatorOverload(Method @operator)
-        {
-            // These follow the order described in MSDN (Overloadable Operators).
-
-            switch (@operator.OperatorKind)
-            {
-                // These unary operators can be overloaded
-                case CXXOperatorKind.Plus:
-                case CXXOperatorKind.Minus:
-                case CXXOperatorKind.Exclaim:
-                case CXXOperatorKind.Tilde:
-
-                // These binary operators can be overloaded
-                case CXXOperatorKind.Slash:
-                case CXXOperatorKind.Percent:
-                case CXXOperatorKind.Amp:
-                case CXXOperatorKind.Pipe:
-                case CXXOperatorKind.Caret:
-
-                // The array indexing operator can be overloaded
-                case CXXOperatorKind.Subscript:
-
-                // The conversion operator can be overloaded
-                case CXXOperatorKind.Conversion:
+
+            index = 0;
+            return CXXOperatorKind.None;
+        }
+
+        static bool IsValidOperatorOverload(Method @operator)
+        {
+            // These follow the order described in MSDN (Overloadable Operators).
+
+            switch (@operator.OperatorKind)
+            {
+                // These unary operators can be overloaded
+                case CXXOperatorKind.Plus:
+                case CXXOperatorKind.Minus:
+                case CXXOperatorKind.Exclaim:
+                case CXXOperatorKind.Tilde:
+
+                // These binary operators can be overloaded
+                case CXXOperatorKind.Slash:
+                case CXXOperatorKind.Percent:
+                case CXXOperatorKind.Amp:
+                case CXXOperatorKind.Pipe:
+                case CXXOperatorKind.Caret:
+
+                // The array indexing operator can be overloaded
+                case CXXOperatorKind.Subscript:
+
+                // The conversion operators can be overloaded
+                case CXXOperatorKind.Conversion:
+                case CXXOperatorKind.ExplicitConversion:
                     return true;
 
                 // The comparison operators can be overloaded if their return type is bool
diff --git a/src/Generator/Passes/ConstructorToConversionOperatorPass.cs b/src/Generator/Passes/ConstructorToConversionOperatorPass.cs
new file mode 100644
index 00000000..71b97c8f
--- /dev/null
+++ b/src/Generator/Passes/ConstructorToConversionOperatorPass.cs
@@ -0,0 +1,61 @@
+using System.Linq;
+using CppSharp.AST;
+using CppSharp.AST.Extensions;
+using CppSharp.Generators;
+
+namespace CppSharp.Passes
+{
+    /// <summary>
+    /// This pass will create conversion operators out of single argument
+    /// constructors.
+    /// </summary>
+    public class ConstructorToConversionOperatorPass : TranslationUnitPass
+    {
+        public override bool VisitMethodDecl(Method method)
+        {
+            if (!method.IsConstructor)
+                return false;
+            if (method.IsCopyConstructor)
+                return false;
+            if (method.Parameters.Count != 1)
+                return false;
+            var parameter = method.Parameters[0];
+            var parameterType = parameter.Type as PointerType;
+            if (parameterType == null)
+                return false;
+            if (!parameterType.IsReference)
+                return false;
+            var qualifiedPointee = parameterType.QualifiedPointee;
+            if (!qualifiedPointee.Qualifiers.IsConst)
+                return false;
+            Class castFromClass;
+            if (!qualifiedPointee.Type.IsTagDecl(out castFromClass))
+                return false;
+            var castToClass = method.OriginalNamespace as Class;
+            if (castToClass == null)
+                return false;
+            if (castFromClass == castToClass)
+                return false;
+
+            var operatorKind = CXXOperatorKind.Conversion;
+            if (method.Signature.StartsWith("explicit", System.StringComparison.OrdinalIgnoreCase))
+                operatorKind = CXXOperatorKind.ExplicitConversion;
+
+            var castToType = new TagType(castToClass);
+            var qualifiedCastToType = new QualifiedType(castToType);
+            var conversionOperator = new Method()
+            {
+                Name = Operators.GetOperatorIdentifier(operatorKind),
+                Namespace = castFromClass,
+                Kind = CXXMethodKind.Conversion,
+                IsSynthetized = true,
+                ConversionType = qualifiedCastToType,
+                ReturnType = qualifiedCastToType
+            };
+            conversionOperator.OperatorKind = operatorKind;
+
+            castFromClass.Methods.Add(conversionOperator);
+            return true;
+        }
+    }
+}
diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs
index fe3a5d69..3249f343 100644
--- a/tests/Basic/Basic.Tests.cs
+++ b/tests/Basic/Basic.Tests.cs
@@ -292,6 +292,16 @@ public class BasicTests : GeneratorTestFixture
         var @class = new TestGetterSetterToProperties();
         Assert.That(@class.Width, Is.EqualTo(640));
         Assert.That(@class.Height, Is.EqualTo(480));
+    }
+
+    [Test]
+    public unsafe void TestSingleArgumentCtorToCastOperator()
+    {
+        var classA = new ClassA(10);
+        ClassB classB = classA;
+        Assert.AreEqual(classA.Value, classB.Value);
+        ClassC classC = (ClassC)classB;
+        Assert.AreEqual(classB.Value, classC.Value);
     }
 }
  
\ No newline at end of file
diff --git a/tests/Basic/Basic.cs b/tests/Basic/Basic.cs
index 93a15552..26813a52 100644
--- a/tests/Basic/Basic.cs
+++ b/tests/Basic/Basic.cs
@@ -20,7 +20,8 @@ namespace CppSharp.Tests
             driver.Options.GenerateVirtualTables = true;
             driver.Options.GenerateCopyConstructors = true;
             driver.Options.MarshalCharAsManagedChar = true;
-            driver.Options.GenerateProperties = true;
+            driver.Options.GenerateProperties = true;
+            driver.Options.GenerateConversionOperators = true;
         }
 
         public override void Preprocess(Driver driver, ASTContext ctx)
diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h
index 4336dca5..92c5dd2f 100644
--- a/tests/Basic/Basic.h
+++ b/tests/Basic/Basic.h
@@ -1,324 +1,324 @@
-#include "../Tests.h"
-
-class DLL_API Foo
-{
-public:
-
-    Foo();
-    int A;
-    float B;
-
-	const char* GetANSI();
-	// TODO: VC++ does not support char16
-	// char16 chr16;
+#include "../Tests.h"
+
+class DLL_API Foo
+{
+public:
+
+    Foo();
+    int A;
+    float B;
+
+	const char* GetANSI();
+	// TODO: VC++ does not support char16
+	// char16 chr16;
 
     // Not properly handled yet - ignore
     float nested_array[2][2];
     // Primitive pointer types
     const int* SomePointer;
     const int** SomePointerPointer;
-};
-
-struct DLL_API Bar
-{
-    enum Item
-    {
-        Item1,
-        Item2
-    };
-
-    Bar();
-    Item RetItem1();
-    int A;
-    float B;
-
-    Bar* returnPointerToValueType();
-};
-
-class DLL_API Foo2 : public Foo
-{
-    struct Copy {
-        Foo A;
-    }* copy;
-
-public:
-
-    Foo2();
-
-    int C;
-
-    Foo2 operator<<(signed int i);
-    Foo2 operator<<(signed long l);
-    Bar valueTypeField;
-    char testCharMarshalling(char c);
-};
-
-DLL_API Bar::Item operator |(Bar::Item left, Bar::Item right);
-
-struct DLL_API Bar2 : public Bar
-{
-    // Conversion operators
-
-    struct DLL_API Nested
-    {
-        operator int() const;
-    };
-
-    operator int() const;
-    operator Foo2();
-    Foo2 needFixedInstance() const;
-
-    typedef void *Bar2::*FunctionPointerResolvedAsVoidStar;
-    operator FunctionPointerResolvedAsVoidStar() const { return 0; }
-
-    int C;
-    Bar* pointerToStruct;
-    int* pointerToPrimitive;
-    Foo2* pointerToClass;
-    Bar valueStruct;
-};
-
-enum Enum
-{
-    A = 0, B = 2, C = 5,
-    //D = 0x80000000,
-    E = 0x1,
-    F = -9
-};
-
-class DLL_API Hello
-{
-    union NestedPrivate {
-        int i;
-        float f;
-    };
-
-public:
-    union NestedPublic {
-        int j;
-        float g;
-        long l;
-    };
-
-    Hello ();
-    Hello(const Hello& hello);
-
-    void PrintHello(const char* s);
-    bool test1(int i, float f);
-    int add(int a, int b);
-
-    int AddFoo(Foo);
-    int AddFooRef(Foo&);
-    int AddFooPtr(Foo*);
-    int AddFooPtrRef(Foo*&);
-    Foo RetFoo(int a, float b);
-
-    int AddFoo2(Foo2);
-
-    int AddBar(Bar);
-    int AddBar2(Bar2);
-
-    int RetEnum(Enum);
-    Hello* RetNull();
-
-    bool TestPrimitiveOut(CS_OUT float* f);
-    bool TestPrimitiveOutRef(CS_OUT float& f);
-};
-
-class DLL_API AbstractFoo
-{
-public:
-    virtual int pureFunction(int i) = 0;
-    virtual int pureFunction1() = 0;
-    virtual int pureFunction2() = 0;
-};
-
-class DLL_API ImplementsAbstractFoo : public AbstractFoo
-{
-public:
-    virtual int pureFunction(int i);
-    virtual int pureFunction1();
-    virtual int pureFunction2();
-};
-
-class DLL_API ReturnsAbstractFoo
-{
-public:
-    ReturnsAbstractFoo();
-    const AbstractFoo& getFoo();
-
-private:
-    ImplementsAbstractFoo i;
-};
-
-int DLL_API unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int));
-
-DLL_API Bar indirectReturn();
-
-// Tests CheckVirtualOverrideReturnCovariance
-struct Exception;
-typedef Exception Ex1;
-
-struct DerivedException;
-typedef DerivedException Ex2;
-
-struct DLL_API Exception
-{
-    virtual Ex1* clone() = 0;
-};
-
-struct DLL_API DerivedException : public Exception
-{
-    virtual Ex2* clone() override { return 0; }
-};
-
-// Tests for ambiguous call to native functions with default parameters
-struct DLL_API DefaultParameters
-{
-    void Foo(int a, int b = 0);
-    void Foo(int a);
-
-    void Bar() const;
-    void Bar();
-};
-
-// The Curiously Recurring Template Pattern (CRTP)
-template<class Derived>
-class Base
-{
-    // methods within Base can use template to access members of Derived
-    Derived* create() { return new Derived(); }
-};
-
-class Derived : public Base<Derived>
-{
-};
-
-// Tests the MoveFunctionToClassPass
-class DLL_API basic
-{
-
-};
-
-DLL_API int test(basic& s);
-
-// Tests the MoveOperatorToClassPass
-struct DLL_API TestMoveOperatorToClass
-{
-    TestMoveOperatorToClass();
-    int A;
-    int B;
-};
-
-TestMoveOperatorToClass::TestMoveOperatorToClass() {}
-
-DLL_API int operator *(TestMoveOperatorToClass klass, int b)
-{
-    return klass.A * b;
-}
-
-DLL_API TestMoveOperatorToClass operator-(const TestMoveOperatorToClass& b)
-{
-    TestMoveOperatorToClass nb;
-    nb.A = -b.A;
-    nb.B = -b.B;
-    return nb;
-}
-
-DLL_API TestMoveOperatorToClass operator+(const TestMoveOperatorToClass& b1,
-                                          const TestMoveOperatorToClass& b2)
-{
-    TestMoveOperatorToClass b;
-    b.A = b1.A + b2.A;
-    b.B = b1.B + b2.B;
-    return b;
-}
-
+};
+
+struct DLL_API Bar
+{
+    enum Item
+    {
+        Item1,
+        Item2
+    };
+
+    Bar();
+    Item RetItem1();
+    int A;
+    float B;
+
+    Bar* returnPointerToValueType();
+};
+
+class DLL_API Foo2 : public Foo
+{
+    struct Copy {
+        Foo A;
+    }* copy;
+
+public:
+
+    Foo2();
+
+    int C;
+
+    Foo2 operator<<(signed int i);
+    Foo2 operator<<(signed long l);
+    Bar valueTypeField;
+    char testCharMarshalling(char c);
+};
+
+DLL_API Bar::Item operator |(Bar::Item left, Bar::Item right);
+
+struct DLL_API Bar2 : public Bar
+{
+    // Conversion operators
+
+    struct DLL_API Nested
+    {
+        operator int() const;
+    };
+
+    operator int() const;
+    operator Foo2();
+    Foo2 needFixedInstance() const;
+
+    typedef void *Bar2::*FunctionPointerResolvedAsVoidStar;
+    operator FunctionPointerResolvedAsVoidStar() const { return 0; }
+
+    int C;
+    Bar* pointerToStruct;
+    int* pointerToPrimitive;
+    Foo2* pointerToClass;
+    Bar valueStruct;
+};
+
+enum Enum
+{
+    A = 0, B = 2, C = 5,
+    //D = 0x80000000,
+    E = 0x1,
+    F = -9
+};
+
+class DLL_API Hello
+{
+    union NestedPrivate {
+        int i;
+        float f;
+    };
+
+public:
+    union NestedPublic {
+        int j;
+        float g;
+        long l;
+    };
+
+    Hello ();
+    Hello(const Hello& hello);
+
+    void PrintHello(const char* s);
+    bool test1(int i, float f);
+    int add(int a, int b);
+
+    int AddFoo(Foo);
+    int AddFooRef(Foo&);
+    int AddFooPtr(Foo*);
+    int AddFooPtrRef(Foo*&);
+    Foo RetFoo(int a, float b);
+
+    int AddFoo2(Foo2);
+
+    int AddBar(Bar);
+    int AddBar2(Bar2);
+
+    int RetEnum(Enum);
+    Hello* RetNull();
+
+    bool TestPrimitiveOut(CS_OUT float* f);
+    bool TestPrimitiveOutRef(CS_OUT float& f);
+};
+
+class DLL_API AbstractFoo
+{
+public:
+    virtual int pureFunction(int i) = 0;
+    virtual int pureFunction1() = 0;
+    virtual int pureFunction2() = 0;
+};
+
+class DLL_API ImplementsAbstractFoo : public AbstractFoo
+{
+public:
+    virtual int pureFunction(int i);
+    virtual int pureFunction1();
+    virtual int pureFunction2();
+};
+
+class DLL_API ReturnsAbstractFoo
+{
+public:
+    ReturnsAbstractFoo();
+    const AbstractFoo& getFoo();
+
+private:
+    ImplementsAbstractFoo i;
+};
+
+int DLL_API unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int));
+
+DLL_API Bar indirectReturn();
+
+// Tests CheckVirtualOverrideReturnCovariance
+struct Exception;
+typedef Exception Ex1;
+
+struct DerivedException;
+typedef DerivedException Ex2;
+
+struct DLL_API Exception
+{
+    virtual Ex1* clone() = 0;
+};
+
+struct DLL_API DerivedException : public Exception
+{
+    virtual Ex2* clone() override { return 0; }
+};
+
+// Tests for ambiguous call to native functions with default parameters
+struct DLL_API DefaultParameters
+{
+    void Foo(int a, int b = 0);
+    void Foo(int a);
+
+    void Bar() const;
+    void Bar();
+};
+
+// The Curiously Recurring Template Pattern (CRTP)
+template<class Derived>
+class Base
+{
+    // methods within Base can use template to access members of Derived
+    Derived* create() { return new Derived(); }
+};
+
+class Derived : public Base<Derived>
+{
+};
+
+// Tests the MoveFunctionToClassPass
+class DLL_API basic
+{
+
+};
+
+DLL_API int test(basic& s);
+
+// Tests the MoveOperatorToClassPass
+struct DLL_API TestMoveOperatorToClass
+{
+    TestMoveOperatorToClass();
+    int A;
+    int B;
+};
+
+TestMoveOperatorToClass::TestMoveOperatorToClass() {}
+
+DLL_API int operator *(TestMoveOperatorToClass klass, int b)
+{
+    return klass.A * b;
+}
+
+DLL_API TestMoveOperatorToClass operator-(const TestMoveOperatorToClass& b)
+{
+    TestMoveOperatorToClass nb;
+    nb.A = -b.A;
+    nb.B = -b.B;
+    return nb;
+}
+
+DLL_API TestMoveOperatorToClass operator+(const TestMoveOperatorToClass& b1,
+                                          const TestMoveOperatorToClass& b2)
+{
+    TestMoveOperatorToClass b;
+    b.A = b1.A + b2.A;
+    b.B = b1.B + b2.B;
+    return b;
+}
+
 // Not a valid operator overload for Foo2 in managed code - comparison operators need to return bool.
 DLL_API int operator==(const Foo2& a, const Foo2& b)
 {
 	return 0;
 }
 
-// Tests delegates
-typedef int (*DelegateInGlobalNamespace)(int);
-
-struct DLL_API TestDelegates
-{
-    typedef int (*DelegateInClass)(int);
-    typedef int(TestDelegates::*MemberDelegate)(int);
-
-    TestDelegates();
-    static int Double(int N) { return N * 2; }
-    int Triple(int N) { return N * 3; }
-
-    DelegateInClass A;
-    DelegateInGlobalNamespace B;
-    // As long as we can't marshal them make sure they're ignored
-    MemberDelegate C;
-};
-
-TestDelegates::TestDelegates() : A(Double), B(Double), C(&TestDelegates::Triple)
-{
-}
-
+// Tests delegates
+typedef int (*DelegateInGlobalNamespace)(int);
+
+struct DLL_API TestDelegates
+{
+    typedef int (*DelegateInClass)(int);
+    typedef int(TestDelegates::*MemberDelegate)(int);
+
+    TestDelegates();
+    static int Double(int N) { return N * 2; }
+    int Triple(int N) { return N * 3; }
+
+    DelegateInClass A;
+    DelegateInGlobalNamespace B;
+    // As long as we can't marshal them make sure they're ignored
+    MemberDelegate C;
+};
+
+TestDelegates::TestDelegates() : A(Double), B(Double), C(&TestDelegates::Triple)
+{
+}
+
 // Tests delegate generation for attributed function types
 typedef int(__cdecl *AttributedDelegate)(int n);
 DLL_API int __cdecl Double(int n) { return n * 2; }
 DLL_API AttributedDelegate GetAttributedDelegate()
 {
     return Double;
-}
-
-// Tests memory leaks in constructors
-//  C#:  Marshal.FreeHGlobal(arg0);
-struct DLL_API TestMemoryLeaks
-{
-    TestMemoryLeaks(const char* name) {}
-};
-
-// Tests that finalizers are generated
-/* CLI: ~TestFinalizers() */
-struct DLL_API TestFinalizers
-{
-};
-
-// Tests static classes
-struct DLL_API TestStaticClass
-{
-    static int Add(int a, int b);
-
-private:
-    TestStaticClass();
-};
-
-int TestStaticClass::Add(int a, int b) { return a + b; }
-
-
-class HasIgnoredField
-{
-    Base<Derived> fieldOfIgnoredType;
-};
-
-template <typename T>
-class DependentTypeWithNestedIndependent
-{
-    union
-    {
-        int i;
-        long l;
-    };
-};
-
-class DLL_API TestCopyConstructorRef
-{
-public:
-    TestCopyConstructorRef();
-    TestCopyConstructorRef(const TestCopyConstructorRef& other);
-    int A;
-    float B;
-};
-
+}
+
+// Tests memory leaks in constructors
+//  C#:  Marshal.FreeHGlobal(arg0);
+struct DLL_API TestMemoryLeaks
+{
+    TestMemoryLeaks(const char* name) {}
+};
+
+// Tests that finalizers are generated
+/* CLI: ~TestFinalizers() */
+struct DLL_API TestFinalizers
+{
+};
+
+// Tests static classes
+struct DLL_API TestStaticClass
+{
+    static int Add(int a, int b);
+
+private:
+    TestStaticClass();
+};
+
+int TestStaticClass::Add(int a, int b) { return a + b; }
+
+
+class HasIgnoredField
+{
+    Base<Derived> fieldOfIgnoredType;
+};
+
+template <typename T>
+class DependentTypeWithNestedIndependent
+{
+    union
+    {
+        int i;
+        long l;
+    };
+};
+
+class DLL_API TestCopyConstructorRef
+{
+public:
+    TestCopyConstructorRef();
+    TestCopyConstructorRef(const TestCopyConstructorRef& other);
+    int A;
+    float B;
+};
+
 TestCopyConstructorRef::TestCopyConstructorRef()
 {
 }
@@ -327,13 +327,13 @@ TestCopyConstructorRef::TestCopyConstructorRef(const TestCopyConstructorRef& oth
 {
     A = other.A;
     B = other.B;
-}
-
-template <class T>
-struct EmptyNamedNestedEnum
-{
-    enum { Value = 10 };
-};
+}
+
+template <class T>
+struct EmptyNamedNestedEnum
+{
+    enum { Value = 10 };
+};
 
 typedef unsigned long foo_t;
 typedef struct DLL_API SomeStruct
@@ -362,30 +362,30 @@ namespace SomeNamespace
 		virtual void AbstractMethod() = 0;
 	};
 }
-
-// Test operator overloads
-class DLL_API ClassWithOverloadedOperators
-{
-public:
-    ClassWithOverloadedOperators();
-
-	operator char();
-	operator int();
-	operator short();
-};
-
-ClassWithOverloadedOperators::ClassWithOverloadedOperators() {}
-ClassWithOverloadedOperators::operator char() { return 1; }
-ClassWithOverloadedOperators::operator int() { return 2; }
-ClassWithOverloadedOperators::operator short() { return 3; }
-
-// Tests global static function generation
+
+// Test operator overloads
+class DLL_API ClassWithOverloadedOperators
+{
+public:
+    ClassWithOverloadedOperators();
+
+	operator char();
+	operator int();
+	operator short();
+};
+
+ClassWithOverloadedOperators::ClassWithOverloadedOperators() {}
+ClassWithOverloadedOperators::operator char() { return 1; }
+ClassWithOverloadedOperators::operator int() { return 2; }
+ClassWithOverloadedOperators::operator short() { return 3; }
+
+// Tests global static function generation
 DLL_API int Function()
 {
     return 5;
 }
 
-// Tests properties
+// Tests properties
 struct DLL_API TestProperties
 {
     TestProperties();
@@ -418,7 +418,35 @@ struct DLL_API TestGetterSetterToProperties
 {
     int getWidth();
     int getHeight();
-};
-
+};
+
 int TestGetterSetterToProperties::getWidth() { return 640; }
 int TestGetterSetterToProperties::getHeight() { return 480; }
+
+// Tests conversion operators of classes
+class DLL_API ClassA 
+{
+public:
+    ClassA(int value) { Value = value; }
+    int Value;
+};
+class DLL_API ClassB
+{
+public:
+    // conversion from ClassA (constructor):
+    ClassB(const ClassA& x) { Value = x.Value; }
+    int Value;
+    // conversion from ClassA (assignment):
+    //ClassB& operator= (const ClassA& x) { return *this; }
+    // conversion to ClassA (type-cast operator)
+    //operator ClassA() { return ClassA(); }
+};
+class DLL_API ClassC
+{
+public:
+    // This should NOT lead to a conversion
+    ClassC(const ClassA* x) { Value = x->Value; }
+    // This should lead to an explicit conversion
+    explicit ClassC(const ClassB& x) { Value = x.Value; }
+    int Value;
+};
diff --git a/tests/CSharpTemp/CSharpTemp.cs b/tests/CSharpTemp/CSharpTemp.cs
index f06f8149..fa47c2be 100644
--- a/tests/CSharpTemp/CSharpTemp.cs
+++ b/tests/CSharpTemp/CSharpTemp.cs
@@ -62,7 +62,10 @@ namespace CppSharp.Tests
             driver.Options.GenerateInterfacesForMultipleInheritance = true;
             driver.Options.GeneratePropertiesAdvanced = true;
             driver.Options.GenerateVirtualTables = true;
-            driver.Options.GenerateCopyConstructors = true;
+            driver.Options.GenerateCopyConstructors = true;
+            // To ensure that calls to constructors in conversion operators
+            // are not ambiguous with multiple inheritance pass enabled.
+            driver.Options.GenerateConversionOperators = true;
             driver.TranslationUnitPasses.AddPass(new TestAttributesPass());
         }