From cc3cc40fc498733b57e2402e48bb3ae8e4d88172 Mon Sep 17 00:00:00 2001 From: Elias Holzer Date: Sun, 4 May 2014 20:26:11 +0200 Subject: [PATCH] When generating delegates attributed types need to be taken into account or proper calling convention won't get picked up. --- .../Generators/CLI/CLIHeadersTemplate.cs | 17 +- .../Generators/CSharp/CSharpTextTemplate.cs | 15 +- tests/Basic/Basic.Tests.cs | 11 +- tests/Basic/Basic.h | 731 +++++++++--------- tests/Tests.h | 4 + 5 files changed, 396 insertions(+), 382 deletions(-) diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 30e9bbcf..9239a453 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -716,13 +716,18 @@ namespace CppSharp.Generators.CLI var insideClass = typedef.Namespace is Class; - var callingConvention = function.CallingConvention.ToInteropCallConv(); - if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) + var attributedType = typedef.Type.GetPointee() as AttributedType; + if (attributedType != null) { - WriteLine("[{0}({1}::{2})] ", - "System::Runtime::InteropServices::UnmanagedFunctionPointer", - "System::Runtime::InteropServices::CallingConvention", - callingConvention); + var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType; + var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv(); + if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) + { + WriteLine("[{0}({1}::{2})] ", + "System::Runtime::InteropServices::UnmanagedFunctionPointer", + "System::Runtime::InteropServices::CallingConvention", + callingConvention); + } } WriteLine("{0}{1};", diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 02443502..0a7ea727 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -2542,9 +2542,18 @@ namespace CppSharp.Generators.CSharp } else if (typedef.Type.IsPointerTo(out functionType)) { - PushBlock(CSharpBlockKind.Typedef); - WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]", - functionType.CallingConvention.ToInteropCallConv()); + PushBlock(CSharpBlockKind.Typedef); + var attributedType = typedef.Type.GetPointee() as AttributedType; + if (attributedType != null) + { + var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType; + var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv(); + if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) + { + WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]", + callingConvention); + } + } TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); WriteLine("{0}unsafe {1};", Helpers.GetAccess(typedef.Access), diff --git a/tests/Basic/Basic.Tests.cs b/tests/Basic/Basic.Tests.cs index 3249f343..38965139 100644 --- a/tests/Basic/Basic.Tests.cs +++ b/tests/Basic/Basic.Tests.cs @@ -176,13 +176,12 @@ public class BasicTests : GeneratorTestFixture var delegates = new TestDelegates(); var doubleSum = delegates.A(2) + delegates.B(2); Assert.AreEqual(8, doubleSum); - } + + var stdcall = delegates.StdCall(i => i); + Assert.AreEqual(1, stdcall); - [Test] - public void TestAttributedDelegate() - { - var result = basic.AttributedDelegate(2); - Assert.AreEqual(4, result); + var cdecl = delegates.CDecl(i => i); + Assert.AreEqual(1, cdecl); } [Test] diff --git a/tests/Basic/Basic.h b/tests/Basic/Basic.h index 92c5dd2f..3a60dcfd 100644 --- a/tests/Basic/Basic.h +++ b/tests/Basic/Basic.h @@ -1,324 +1,321 @@ -#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 Base -{ - // methods within Base can use template to access members of Derived - Derived* create() { return new Derived(); } -}; - -class Derived : public Base -{ -}; - -// 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 Base +{ + // methods within Base can use template to access members of Derived + Derived* create() { return new Derived(); } +}; + +class Derived : public Base +{ +}; + +// 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 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 fieldOfIgnoredType; -}; - -template -class DependentTypeWithNestedIndependent -{ - union - { - int i; - long l; - }; -}; - -class DLL_API TestCopyConstructorRef -{ -public: - TestCopyConstructorRef(); - TestCopyConstructorRef(const TestCopyConstructorRef& other); - int A; - float B; -}; - +// Tests delegates +typedef int (*DelegateInGlobalNamespace)(int); +typedef int (STDCALL *DelegateStdCall)(int); +typedef int (CDECL *DelegateCDecl)(int n); + +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; } + + int StdCall(DelegateStdCall del) { return del(1); } + int CDecl(DelegateCDecl del) { return del(1); } + + 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 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 fieldOfIgnoredType; +}; + +template +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 +324,13 @@ TestCopyConstructorRef::TestCopyConstructorRef(const TestCopyConstructorRef& oth { A = other.A; B = other.B; -} - -template -struct EmptyNamedNestedEnum -{ - enum { Value = 10 }; -}; +} + +template +struct EmptyNamedNestedEnum +{ + enum { Value = 10 }; +}; typedef unsigned long foo_t; typedef struct DLL_API SomeStruct @@ -362,30 +359,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,35 +415,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; -}; +}; + +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/Tests.h b/tests/Tests.h index 28a11b7e..f9d7e4cf 100644 --- a/tests/Tests.h +++ b/tests/Tests.h @@ -2,8 +2,12 @@ #if defined(_MSC_VER) #define DLL_API __declspec(dllexport) +#define STDCALL __stdcall +#define CDECL __cdecl #else #define DLL_API __attribute__ ((visibility ("default"))) +#define STDCALL __attribute__((stdcall)) +#define CDECL __attribute__((stdcall)) #endif #define CS_OUT \ No newline at end of file