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()); }