Browse Source

When generating delegates attributed types need to be taken into account or proper calling convention won't get picked up.

pull/234/head
Elias Holzer 11 years ago committed by triton
parent
commit
cc3cc40fc4
  1. 17
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  2. 15
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  3. 11
      tests/Basic/Basic.Tests.cs
  4. 731
      tests/Basic/Basic.h
  5. 4
      tests/Tests.h

17
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -716,13 +716,18 @@ namespace CppSharp.Generators.CLI
var insideClass = typedef.Namespace is Class; var insideClass = typedef.Namespace is Class;
var callingConvention = function.CallingConvention.ToInteropCallConv(); var attributedType = typedef.Type.GetPointee() as AttributedType;
if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) if (attributedType != null)
{ {
WriteLine("[{0}({1}::{2})] ", var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType;
"System::Runtime::InteropServices::UnmanagedFunctionPointer", var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv();
"System::Runtime::InteropServices::CallingConvention", if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi)
callingConvention); {
WriteLine("[{0}({1}::{2})] ",
"System::Runtime::InteropServices::UnmanagedFunctionPointer",
"System::Runtime::InteropServices::CallingConvention",
callingConvention);
}
} }
WriteLine("{0}{1};", WriteLine("{0}{1};",

15
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -2542,9 +2542,18 @@ namespace CppSharp.Generators.CSharp
} }
else if (typedef.Type.IsPointerTo(out functionType)) else if (typedef.Type.IsPointerTo(out functionType))
{ {
PushBlock(CSharpBlockKind.Typedef); PushBlock(CSharpBlockKind.Typedef);
WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]", var attributedType = typedef.Type.GetPointee() as AttributedType;
functionType.CallingConvention.ToInteropCallConv()); 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); TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
WriteLine("{0}unsafe {1};", WriteLine("{0}unsafe {1};",
Helpers.GetAccess(typedef.Access), Helpers.GetAccess(typedef.Access),

11
tests/Basic/Basic.Tests.cs

@ -176,13 +176,12 @@ public class BasicTests : GeneratorTestFixture
var delegates = new TestDelegates(); var delegates = new TestDelegates();
var doubleSum = delegates.A(2) + delegates.B(2); var doubleSum = delegates.A(2) + delegates.B(2);
Assert.AreEqual(8, doubleSum); Assert.AreEqual(8, doubleSum);
}
var stdcall = delegates.StdCall(i => i);
Assert.AreEqual(1, stdcall);
[Test] var cdecl = delegates.CDecl(i => i);
public void TestAttributedDelegate() Assert.AreEqual(1, cdecl);
{
var result = basic.AttributedDelegate(2);
Assert.AreEqual(4, result);
} }
[Test] [Test]

731
tests/Basic/Basic.h

@ -1,324 +1,321 @@
#include "../Tests.h" #include "../Tests.h"
class DLL_API Foo class DLL_API Foo
{ {
public: public:
Foo(); Foo();
int A; int A;
float B; float B;
const char* GetANSI(); const char* GetANSI();
// TODO: VC++ does not support char16 // TODO: VC++ does not support char16
// char16 chr16; // char16 chr16;
// Not properly handled yet - ignore // Not properly handled yet - ignore
float nested_array[2][2]; float nested_array[2][2];
// Primitive pointer types // Primitive pointer types
const int* SomePointer; const int* SomePointer;
const int** SomePointerPointer; const int** SomePointerPointer;
}; };
struct DLL_API Bar struct DLL_API Bar
{ {
enum Item enum Item
{ {
Item1, Item1,
Item2 Item2
}; };
Bar(); Bar();
Item RetItem1(); Item RetItem1();
int A; int A;
float B; float B;
Bar* returnPointerToValueType(); Bar* returnPointerToValueType();
}; };
class DLL_API Foo2 : public Foo class DLL_API Foo2 : public Foo
{ {
struct Copy { struct Copy {
Foo A; Foo A;
}* copy; }* copy;
public: public:
Foo2(); Foo2();
int C; int C;
Foo2 operator<<(signed int i); Foo2 operator<<(signed int i);
Foo2 operator<<(signed long l); Foo2 operator<<(signed long l);
Bar valueTypeField; Bar valueTypeField;
char testCharMarshalling(char c); char testCharMarshalling(char c);
}; };
DLL_API Bar::Item operator |(Bar::Item left, Bar::Item right); DLL_API Bar::Item operator |(Bar::Item left, Bar::Item right);
struct DLL_API Bar2 : public Bar struct DLL_API Bar2 : public Bar
{ {
// Conversion operators // Conversion operators
struct DLL_API Nested struct DLL_API Nested
{ {
operator int() const; operator int() const;
}; };
operator int() const; operator int() const;
operator Foo2(); operator Foo2();
Foo2 needFixedInstance() const; Foo2 needFixedInstance() const;
typedef void *Bar2::*FunctionPointerResolvedAsVoidStar; typedef void *Bar2::*FunctionPointerResolvedAsVoidStar;
operator FunctionPointerResolvedAsVoidStar() const { return 0; } operator FunctionPointerResolvedAsVoidStar() const { return 0; }
int C; int C;
Bar* pointerToStruct; Bar* pointerToStruct;
int* pointerToPrimitive; int* pointerToPrimitive;
Foo2* pointerToClass; Foo2* pointerToClass;
Bar valueStruct; Bar valueStruct;
}; };
enum Enum enum Enum
{ {
A = 0, B = 2, C = 5, A = 0, B = 2, C = 5,
//D = 0x80000000, //D = 0x80000000,
E = 0x1, E = 0x1,
F = -9 F = -9
}; };
class DLL_API Hello class DLL_API Hello
{ {
union NestedPrivate { union NestedPrivate {
int i; int i;
float f; float f;
}; };
public: public:
union NestedPublic { union NestedPublic {
int j; int j;
float g; float g;
long l; long l;
}; };
Hello (); Hello ();
Hello(const Hello& hello); Hello(const Hello& hello);
void PrintHello(const char* s); void PrintHello(const char* s);
bool test1(int i, float f); bool test1(int i, float f);
int add(int a, int b); int add(int a, int b);
int AddFoo(Foo); int AddFoo(Foo);
int AddFooRef(Foo&); int AddFooRef(Foo&);
int AddFooPtr(Foo*); int AddFooPtr(Foo*);
int AddFooPtrRef(Foo*&); int AddFooPtrRef(Foo*&);
Foo RetFoo(int a, float b); Foo RetFoo(int a, float b);
int AddFoo2(Foo2); int AddFoo2(Foo2);
int AddBar(Bar); int AddBar(Bar);
int AddBar2(Bar2); int AddBar2(Bar2);
int RetEnum(Enum); int RetEnum(Enum);
Hello* RetNull(); Hello* RetNull();
bool TestPrimitiveOut(CS_OUT float* f); bool TestPrimitiveOut(CS_OUT float* f);
bool TestPrimitiveOutRef(CS_OUT float& f); bool TestPrimitiveOutRef(CS_OUT float& f);
}; };
class DLL_API AbstractFoo class DLL_API AbstractFoo
{ {
public: public:
virtual int pureFunction(int i) = 0; virtual int pureFunction(int i) = 0;
virtual int pureFunction1() = 0; virtual int pureFunction1() = 0;
virtual int pureFunction2() = 0; virtual int pureFunction2() = 0;
}; };
class DLL_API ImplementsAbstractFoo : public AbstractFoo class DLL_API ImplementsAbstractFoo : public AbstractFoo
{ {
public: public:
virtual int pureFunction(int i); virtual int pureFunction(int i);
virtual int pureFunction1(); virtual int pureFunction1();
virtual int pureFunction2(); virtual int pureFunction2();
}; };
class DLL_API ReturnsAbstractFoo class DLL_API ReturnsAbstractFoo
{ {
public: public:
ReturnsAbstractFoo(); ReturnsAbstractFoo();
const AbstractFoo& getFoo(); const AbstractFoo& getFoo();
private: private:
ImplementsAbstractFoo i; ImplementsAbstractFoo i;
}; };
int DLL_API unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)); int DLL_API unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int));
DLL_API Bar indirectReturn(); DLL_API Bar indirectReturn();
// Tests CheckVirtualOverrideReturnCovariance // Tests CheckVirtualOverrideReturnCovariance
struct Exception; struct Exception;
typedef Exception Ex1; typedef Exception Ex1;
struct DerivedException; struct DerivedException;
typedef DerivedException Ex2; typedef DerivedException Ex2;
struct DLL_API Exception struct DLL_API Exception
{ {
virtual Ex1* clone() = 0; virtual Ex1* clone() = 0;
}; };
struct DLL_API DerivedException : public Exception struct DLL_API DerivedException : public Exception
{ {
virtual Ex2* clone() override { return 0; } virtual Ex2* clone() override { return 0; }
}; };
// Tests for ambiguous call to native functions with default parameters // Tests for ambiguous call to native functions with default parameters
struct DLL_API DefaultParameters struct DLL_API DefaultParameters
{ {
void Foo(int a, int b = 0); void Foo(int a, int b = 0);
void Foo(int a); void Foo(int a);
void Bar() const; void Bar() const;
void Bar(); void Bar();
}; };
// The Curiously Recurring Template Pattern (CRTP) // The Curiously Recurring Template Pattern (CRTP)
template<class Derived> template<class Derived>
class Base class Base
{ {
// methods within Base can use template to access members of Derived // methods within Base can use template to access members of Derived
Derived* create() { return new Derived(); } Derived* create() { return new Derived(); }
}; };
class Derived : public Base<Derived> class Derived : public Base<Derived>
{ {
}; };
// Tests the MoveFunctionToClassPass // Tests the MoveFunctionToClassPass
class DLL_API basic class DLL_API basic
{ {
}; };
DLL_API int test(basic& s); DLL_API int test(basic& s);
// Tests the MoveOperatorToClassPass // Tests the MoveOperatorToClassPass
struct DLL_API TestMoveOperatorToClass struct DLL_API TestMoveOperatorToClass
{ {
TestMoveOperatorToClass(); TestMoveOperatorToClass();
int A; int A;
int B; int B;
}; };
TestMoveOperatorToClass::TestMoveOperatorToClass() {} TestMoveOperatorToClass::TestMoveOperatorToClass() {}
DLL_API int operator *(TestMoveOperatorToClass klass, int b) DLL_API int operator *(TestMoveOperatorToClass klass, int b)
{ {
return klass.A * b; return klass.A * b;
} }
DLL_API TestMoveOperatorToClass operator-(const TestMoveOperatorToClass& b) DLL_API TestMoveOperatorToClass operator-(const TestMoveOperatorToClass& b)
{ {
TestMoveOperatorToClass nb; TestMoveOperatorToClass nb;
nb.A = -b.A; nb.A = -b.A;
nb.B = -b.B; nb.B = -b.B;
return nb; return nb;
} }
DLL_API TestMoveOperatorToClass operator+(const TestMoveOperatorToClass& b1, DLL_API TestMoveOperatorToClass operator+(const TestMoveOperatorToClass& b1,
const TestMoveOperatorToClass& b2) const TestMoveOperatorToClass& b2)
{ {
TestMoveOperatorToClass b; TestMoveOperatorToClass b;
b.A = b1.A + b2.A; b.A = b1.A + b2.A;
b.B = b1.B + b2.B; b.B = b1.B + b2.B;
return b; return b;
} }
// Not a valid operator overload for Foo2 in managed code - comparison operators need to return bool. // 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) DLL_API int operator==(const Foo2& a, const Foo2& b)
{ {
return 0; return 0;
} }
// Tests delegates // Tests delegates
typedef int (*DelegateInGlobalNamespace)(int); typedef int (*DelegateInGlobalNamespace)(int);
typedef int (STDCALL *DelegateStdCall)(int);
struct DLL_API TestDelegates typedef int (CDECL *DelegateCDecl)(int n);
{
typedef int (*DelegateInClass)(int); struct DLL_API TestDelegates
typedef int(TestDelegates::*MemberDelegate)(int); {
typedef int (*DelegateInClass)(int);
TestDelegates(); typedef int(TestDelegates::*MemberDelegate)(int);
static int Double(int N) { return N * 2; }
int Triple(int N) { return N * 3; } TestDelegates();
static int Double(int N) { return N * 2; }
DelegateInClass A; int Triple(int N) { return N * 3; }
DelegateInGlobalNamespace B;
// As long as we can't marshal them make sure they're ignored int StdCall(DelegateStdCall del) { return del(1); }
MemberDelegate C; int CDecl(DelegateCDecl del) { return del(1); }
};
DelegateInClass A;
TestDelegates::TestDelegates() : A(Double), B(Double), C(&TestDelegates::Triple) DelegateInGlobalNamespace B;
{ // As long as we can't marshal them make sure they're ignored
} MemberDelegate C;
};
// Tests delegate generation for attributed function types
typedef int(__cdecl *AttributedDelegate)(int n); TestDelegates::TestDelegates() : A(Double), B(Double), C(&TestDelegates::Triple)
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
// Tests memory leaks in constructors {
// C#: Marshal.FreeHGlobal(arg0); TestMemoryLeaks(const char* name) {}
struct DLL_API TestMemoryLeaks };
{
TestMemoryLeaks(const char* name) {} // Tests that finalizers are generated
}; /* CLI: ~TestFinalizers() */
struct DLL_API TestFinalizers
// Tests that finalizers are generated {
/* CLI: ~TestFinalizers() */ };
struct DLL_API TestFinalizers
{ // Tests static classes
}; struct DLL_API TestStaticClass
{
// Tests static classes static int Add(int a, int b);
struct DLL_API TestStaticClass
{ private:
static int Add(int a, int b); TestStaticClass();
};
private:
TestStaticClass(); int TestStaticClass::Add(int a, int b) { return a + b; }
};
int TestStaticClass::Add(int a, int b) { return a + b; } class HasIgnoredField
{
Base<Derived> fieldOfIgnoredType;
class HasIgnoredField };
{
Base<Derived> fieldOfIgnoredType; template <typename T>
}; class DependentTypeWithNestedIndependent
{
template <typename T> union
class DependentTypeWithNestedIndependent {
{ int i;
union long l;
{ };
int i; };
long l;
}; class DLL_API TestCopyConstructorRef
}; {
public:
class DLL_API TestCopyConstructorRef TestCopyConstructorRef();
{ TestCopyConstructorRef(const TestCopyConstructorRef& other);
public: int A;
TestCopyConstructorRef(); float B;
TestCopyConstructorRef(const TestCopyConstructorRef& other); };
int A;
float B;
};
TestCopyConstructorRef::TestCopyConstructorRef() TestCopyConstructorRef::TestCopyConstructorRef()
{ {
} }
@ -327,13 +324,13 @@ TestCopyConstructorRef::TestCopyConstructorRef(const TestCopyConstructorRef& oth
{ {
A = other.A; A = other.A;
B = other.B; B = other.B;
} }
template <class T> template <class T>
struct EmptyNamedNestedEnum struct EmptyNamedNestedEnum
{ {
enum { Value = 10 }; enum { Value = 10 };
}; };
typedef unsigned long foo_t; typedef unsigned long foo_t;
typedef struct DLL_API SomeStruct typedef struct DLL_API SomeStruct
@ -362,30 +359,30 @@ namespace SomeNamespace
virtual void AbstractMethod() = 0; virtual void AbstractMethod() = 0;
}; };
} }
// Test operator overloads // Test operator overloads
class DLL_API ClassWithOverloadedOperators class DLL_API ClassWithOverloadedOperators
{ {
public: public:
ClassWithOverloadedOperators(); ClassWithOverloadedOperators();
operator char(); operator char();
operator int(); operator int();
operator short(); operator short();
}; };
ClassWithOverloadedOperators::ClassWithOverloadedOperators() {} ClassWithOverloadedOperators::ClassWithOverloadedOperators() {}
ClassWithOverloadedOperators::operator char() { return 1; } ClassWithOverloadedOperators::operator char() { return 1; }
ClassWithOverloadedOperators::operator int() { return 2; } ClassWithOverloadedOperators::operator int() { return 2; }
ClassWithOverloadedOperators::operator short() { return 3; } ClassWithOverloadedOperators::operator short() { return 3; }
// Tests global static function generation // Tests global static function generation
DLL_API int Function() DLL_API int Function()
{ {
return 5; return 5;
} }
// Tests properties // Tests properties
struct DLL_API TestProperties struct DLL_API TestProperties
{ {
TestProperties(); TestProperties();
@ -418,35 +415,35 @@ struct DLL_API TestGetterSetterToProperties
{ {
int getWidth(); int getWidth();
int getHeight(); int getHeight();
}; };
int TestGetterSetterToProperties::getWidth() { return 640; } int TestGetterSetterToProperties::getWidth() { return 640; }
int TestGetterSetterToProperties::getHeight() { return 480; } int TestGetterSetterToProperties::getHeight() { return 480; }
// Tests conversion operators of classes // Tests conversion operators of classes
class DLL_API ClassA class DLL_API ClassA
{ {
public: public:
ClassA(int value) { Value = value; } ClassA(int value) { Value = value; }
int Value; int Value;
}; };
class DLL_API ClassB class DLL_API ClassB
{ {
public: public:
// conversion from ClassA (constructor): // conversion from ClassA (constructor):
ClassB(const ClassA& x) { Value = x.Value; } ClassB(const ClassA& x) { Value = x.Value; }
int Value; int Value;
// conversion from ClassA (assignment): // conversion from ClassA (assignment):
//ClassB& operator= (const ClassA& x) { return *this; } //ClassB& operator= (const ClassA& x) { return *this; }
// conversion to ClassA (type-cast operator) // conversion to ClassA (type-cast operator)
//operator ClassA() { return ClassA(); } //operator ClassA() { return ClassA(); }
}; };
class DLL_API ClassC class DLL_API ClassC
{ {
public: public:
// This should NOT lead to a conversion // This should NOT lead to a conversion
ClassC(const ClassA* x) { Value = x->Value; } ClassC(const ClassA* x) { Value = x->Value; }
// This should lead to an explicit conversion // This should lead to an explicit conversion
explicit ClassC(const ClassB& x) { Value = x.Value; } explicit ClassC(const ClassB& x) { Value = x.Value; }
int Value; int Value;
}; };

4
tests/Tests.h

@ -2,8 +2,12 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define DLL_API __declspec(dllexport) #define DLL_API __declspec(dllexport)
#define STDCALL __stdcall
#define CDECL __cdecl
#else #else
#define DLL_API __attribute__ ((visibility ("default"))) #define DLL_API __attribute__ ((visibility ("default")))
#define STDCALL __attribute__((stdcall))
#define CDECL __attribute__((stdcall))
#endif #endif
#define CS_OUT #define CS_OUT
Loading…
Cancel
Save