Browse Source

Merge pull request #81 from ddobrev/master

Consider indirect args and value type - pointer type pairs when generating properties
pull/103/head
João Matos 12 years ago
parent
commit
20c06646f4
  1. 33
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  2. 13
      src/Generator/Passes/CheckOperatorsOverloads.cs
  3. 30
      src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs
  4. 2
      src/Generator/Passes/MultipleInheritancePass.cs
  5. 31
      src/Generator/Passes/ParamTypeToInterfacePass.cs
  6. 2
      src/Generator/Passes/verbs.txt
  7. 9
      tests/CSharpTemp/CSharpTemp.Tests.cs
  8. 39
      tests/CSharpTemp/CSharpTemp.cpp
  9. 1
      tests/CSharpTemp/CSharpTemp.cs
  10. 17
      tests/CSharpTemp/CSharpTemp.h

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

@ -536,7 +536,7 @@ namespace CppSharp.Generators.CSharp
TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
var retParam = new Parameter { QualifiedType = function.ReturnType }; var retParam = new Parameter { QualifiedType = function.OriginalReturnType };
retType = retParam.CSharpType(TypePrinter); retType = retParam.CSharpType(TypePrinter);
var method = function as Method; var method = function as Method;
@ -1245,11 +1245,21 @@ namespace CppSharp.Generators.CSharp
NewLine(); NewLine();
} }
private void GenerateVTableClassSetupCall(Class @class) private void GenerateVTableClassSetupCall(Class @class, bool addPointerGuard = false)
{ {
var entries = GetVTableMethodEntries(@class); var entries = GetVTableMethodEntries(@class);
if (Options.GenerateVirtualTables && @class.IsDynamic && entries.Count != 0) if (Options.GenerateVirtualTables && @class.IsDynamic && entries.Count != 0)
{
// called from internal ctors which may have been passed an IntPtr.Zero
if (addPointerGuard)
{
WriteLine("if ({0} != global::System.IntPtr.Zero)", Helpers.InstanceIdentifier);
PushIndent();
}
WriteLine("SetupVTables({0});", Generator.GeneratedIdentifier("Instance")); WriteLine("SetupVTables({0});", Generator.GeneratedIdentifier("Instance"));
if (addPointerGuard)
PopIndent();
}
} }
private void GenerateVTableManagedCall(Method method) private void GenerateVTableManagedCall(Method method)
@ -1285,8 +1295,7 @@ namespace CppSharp.Generators.CSharp
marshals.Add(marshal.Context.Return); marshals.Add(marshal.Context.Return);
} }
var hasReturn = !method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void) var hasReturn = !method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void);
&& !method.HasIndirectReturnTypeParameter;
if (hasReturn) if (hasReturn)
Write("var _ret = "); Write("var _ret = ");
@ -1300,8 +1309,6 @@ namespace CppSharp.Generators.CSharp
InvokeProperty(method, marshals); InvokeProperty(method, marshals);
} }
// TODO: Handle hidden structure return types.
if (hasReturn) if (hasReturn)
{ {
var param = new Parameter var param = new Parameter
@ -1319,7 +1326,7 @@ namespace CppSharp.Generators.CSharp
}; };
var marshal = new CSharpMarshalManagedToNativePrinter(ctx); var marshal = new CSharpMarshalManagedToNativePrinter(ctx);
method.ReturnType.Visit(marshal); method.OriginalReturnType.Visit(marshal);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore); Write(marshal.Context.SupportBefore);
@ -1350,7 +1357,7 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.VTableDelegate); PushBlock(CSharpBlockKind.VTableDelegate);
WriteLine("[SuppressUnmanagedCodeSecurity]"); WriteLine("[SuppressUnmanagedCodeSecurity]");
WriteLine("[UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.{0})]", WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]",
Helpers.ToCSharpCallConv(method.CallingConvention)); Helpers.ToCSharpCallConv(method.CallingConvention));
CSharpTypePrinterResult retType; CSharpTypePrinterResult retType;
@ -1423,7 +1430,7 @@ namespace CppSharp.Generators.CSharp
delegateName = delegateInstance + "Delegate"; delegateName = delegateInstance + "Delegate";
delegateRaise = delegateInstance + "RaiseInstance"; delegateRaise = delegateInstance + "RaiseInstance";
WriteLine("[UnmanagedFunctionPointerAttribute(System.Runtime.InteropServices.CallingConvention.Cdecl)]"); WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.Cdecl)]");
WriteLine("delegate void {0}({1});", delegateName, args); WriteLine("delegate void {0}({1});", delegateName, args);
WriteLine("{0} {1};", delegateName, delegateRaise); WriteLine("{0} {1};", delegateName, delegateRaise);
NewLine(); NewLine();
@ -1616,7 +1623,7 @@ namespace CppSharp.Generators.CSharp
if (ShouldGenerateClassNativeField(@class)) if (ShouldGenerateClassNativeField(@class))
{ {
WriteLine("{0} = native;", Helpers.InstanceIdentifier); WriteLine("{0} = native;", Helpers.InstanceIdentifier);
GenerateVTableClassSetupCall(@class); GenerateVTableClassSetupCall(@class, true);
} }
} }
else else
@ -1695,7 +1702,7 @@ namespace CppSharp.Generators.CSharp
public void GenerateMethod(Method method, Class @class) public void GenerateMethod(Method method, Class @class)
{ {
PushBlock(CSharpBlockKind.Method); PushBlock(CSharpBlockKind.Method, method);
GenerateDeclarationCommon(method); GenerateDeclarationCommon(method);
if (method.ExplicitInterfaceImpl == null) if (method.ExplicitInterfaceImpl == null)
@ -2188,7 +2195,7 @@ 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(System.Runtime.InteropServices.CallingConvention.{0})]", WriteLine("[UnmanagedFunctionPointerAttribute(global::System.Runtime.InteropServices.CallingConvention.{0})]",
Helpers.ToCSharpCallConv(functionType.CallingConvention)); Helpers.ToCSharpCallConv(functionType.CallingConvention));
TypePrinter.PushContext(CSharpTypePrinterContextKind.Native); TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
WriteLine("{0}unsafe {1};", WriteLine("{0}unsafe {1};",
@ -2317,7 +2324,7 @@ namespace CppSharp.Generators.CSharp
Write("[DllImport(\"{0}\", ", libName); Write("[DllImport(\"{0}\", ", libName);
var callConv = Helpers.ToCSharpCallConv(function.CallingConvention); var callConv = Helpers.ToCSharpCallConv(function.CallingConvention);
WriteLine("CallingConvention = System.Runtime.InteropServices.CallingConvention.{0},", WriteLine("CallingConvention = global::System.Runtime.InteropServices.CallingConvention.{0},",
callConv); callConv);
WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled); WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled);

13
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -169,11 +169,8 @@ namespace CppSharp.Passes
case CXXOperatorKind.Minus: case CXXOperatorKind.Minus:
case CXXOperatorKind.Exclaim: case CXXOperatorKind.Exclaim:
case CXXOperatorKind.Tilde: case CXXOperatorKind.Tilde:
case CXXOperatorKind.PlusPlus:
case CXXOperatorKind.MinusMinus:
// These binary operators can be overloaded // These binary operators can be overloaded
case CXXOperatorKind.Star:
case CXXOperatorKind.Slash: case CXXOperatorKind.Slash:
case CXXOperatorKind.Percent: case CXXOperatorKind.Percent:
case CXXOperatorKind.Amp: case CXXOperatorKind.Amp:
@ -193,12 +190,22 @@ namespace CppSharp.Passes
case CXXOperatorKind.Conversion: case CXXOperatorKind.Conversion:
return true; return true;
// Only prefix operators can be overloaded
case CXXOperatorKind.PlusPlus:
case CXXOperatorKind.MinusMinus:
return @operator.Parameters.Count == 0;
// Bitwise shift operators can only be overloaded if the second parameter is int
case CXXOperatorKind.LessLess: case CXXOperatorKind.LessLess:
case CXXOperatorKind.GreaterGreater: case CXXOperatorKind.GreaterGreater:
PrimitiveType primitiveType; PrimitiveType primitiveType;
return @operator.Parameters.Last().Type.IsPrimitiveType(out primitiveType) && return @operator.Parameters.Last().Type.IsPrimitiveType(out primitiveType) &&
primitiveType == PrimitiveType.Int32; primitiveType == PrimitiveType.Int32;
// No parameters means the dereference operator - cannot be overloaded
case CXXOperatorKind.Star:
return @operator.Parameters.Count > 0;
// Assignment operators cannot be overloaded // Assignment operators cannot be overloaded
case CXXOperatorKind.PlusEqual: case CXXOperatorKind.PlusEqual:
case CXXOperatorKind.MinusEqual: case CXXOperatorKind.MinusEqual:

30
src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs

@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using CppSharp.AST; using CppSharp.AST;
using Type = CppSharp.AST.Type;
namespace CppSharp.Passes namespace CppSharp.Passes
{ {
@ -94,7 +95,8 @@ namespace CppSharp.Passes
{ {
string name = GetPropertyName(getter.Name); string name = GetPropertyName(getter.Name);
if (string.Compare(name, afterSet, StringComparison.OrdinalIgnoreCase) == 0 && if (string.Compare(name, afterSet, StringComparison.OrdinalIgnoreCase) == 0 &&
getter.ReturnType == setter.Parameters[0].QualifiedType && GetUnderlyingType(getter.OriginalReturnType).Equals(
GetUnderlyingType(setter.Parameters[0].QualifiedType)) &&
!type.Methods.Any( !type.Methods.Any(
m => m =>
m != getter && m != getter &&
@ -132,6 +134,18 @@ namespace CppSharp.Passes
} }
} }
private static Type GetUnderlyingType(QualifiedType type)
{
TagType tagType = type.Type as TagType;
if (tagType != null)
return type.Type;
// TODO: we should normally check pointer types for const;
// however, there's some bug, probably in the parser, that returns IsConst = false for "const Type& arg"
// so skip the check for the time being
PointerType pointerType = type.Type as PointerType;
return pointerType != null ? pointerType.Pointee : type.Type;
}
private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null) private static void GenerateProperty(DeclarationContext context, Method getter, Method setter = null)
{ {
Class type = (Class) context; Class type = (Class) context;
@ -142,13 +156,14 @@ namespace CppSharp.Passes
Property property = new Property(); Property property = new Property();
property.Name = GetPropertyName(getter.Name); property.Name = GetPropertyName(getter.Name);
property.Namespace = type; property.Namespace = type;
property.QualifiedType = getter.ReturnType; property.QualifiedType = getter.OriginalReturnType;
if (getter.IsOverride || (setter != null && setter.IsOverride)) if (getter.IsOverride || (setter != null && setter.IsOverride))
{ {
Property baseVirtualProperty = type.GetRootBaseProperty(property); Property baseVirtualProperty = type.GetRootBaseProperty(property);
if (baseVirtualProperty.SetMethod == null) if (baseVirtualProperty.SetMethod == null)
setter = null; setter = null;
foreach (Method method in type.Methods.Where(m => m.Name == property.Name && m.Parameters.Count > 0)) foreach (Method method in type.Methods.Where(m => m.Name == property.Name &&
m.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType)))
method.Name = "get" + method.Name; method.Name = "get" + method.Name;
} }
property.GetMethod = getter; property.GetMethod = getter;
@ -204,7 +219,7 @@ namespace CppSharp.Passes
private void DistributeMethod(Method method) private void DistributeMethod(Method method)
{ {
if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 && if (GetFirstWord(method.Name) == "set" && method.Name.Length > 3 &&
method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void))
{ {
if (method.Parameters.Count == 1) if (method.Parameters.Count == 1)
setters.Add(method); setters.Add(method);
@ -215,15 +230,16 @@ namespace CppSharp.Passes
{ {
if (IsGetter(method)) if (IsGetter(method))
getters.Add(method); getters.Add(method);
if (method.Parameters.Count == 0) if (method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType))
nonSetters.Add(method); nonSetters.Add(method);
} }
} }
private bool IsGetter(Method method) private bool IsGetter(Method method)
{ {
if (method.ReturnType.Type.IsPrimitiveType(PrimitiveType.Void) || if (method.IsDestructor ||
method.Parameters.Count > 0 || method.IsDestructor) (method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void)) ||
method.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType))
return false; return false;
var result = GetFirstWord(method.Name); var result = GetFirstWord(method.Name);
return (result.Length < method.Name.Length && return (result.Length < method.Name.Length &&

2
src/Generator/Passes/MultipleInheritancePass.cs

@ -68,7 +68,7 @@ namespace CppSharp.Passes
@interface.Methods.AddRange( @interface.Methods.AddRange(
from m in @base.Methods from m in @base.Methods
where !m.IsConstructor && !m.IsDestructor && !m.IsStatic && !m.Ignore where !m.IsConstructor && !m.IsDestructor && !m.IsStatic && !m.Ignore && !m.IsOperator
select new Method(m) { Namespace = @interface }); select new Method(m) { Namespace = @interface });
@interface.Properties.AddRange( @interface.Properties.AddRange(

31
src/Generator/Passes/ParamTypeToInterfacePass.cs

@ -1,4 +1,5 @@
using CppSharp.AST; using System.Linq;
using CppSharp.AST;
namespace CppSharp.Passes namespace CppSharp.Passes
{ {
@ -6,24 +7,26 @@ namespace CppSharp.Passes
{ {
public override bool VisitFunctionDecl(Function function) public override bool VisitFunctionDecl(Function function)
{ {
if (function.HasIndirectReturnTypeParameter) if (!function.IsOperator)
{ {
var parameter = function.Parameters.Find(p => p.Kind == ParameterKind.IndirectReturnType); if (function.HasIndirectReturnTypeParameter)
parameter.QualifiedType = GetInterfaceType(parameter.QualifiedType); {
} var parameter = function.Parameters.Find(p => p.Kind == ParameterKind.IndirectReturnType);
else parameter.QualifiedType = GetInterfaceType(parameter.QualifiedType);
{ }
function.ReturnType = GetInterfaceType(function.ReturnType); else
{
function.ReturnType = GetInterfaceType(function.ReturnType);
}
foreach (Parameter parameter in function.Parameters.Where(
p => p.Kind != ParameterKind.IndirectReturnType))
{
parameter.QualifiedType = GetInterfaceType(parameter.QualifiedType);
}
} }
return base.VisitFunctionDecl(function); return base.VisitFunctionDecl(function);
} }
public override bool VisitParameterDecl(Parameter parameter)
{
parameter.QualifiedType = GetInterfaceType(parameter.QualifiedType);
return base.VisitParameterDecl(parameter);
}
private static QualifiedType GetInterfaceType(QualifiedType type) private static QualifiedType GetInterfaceType(QualifiedType type)
{ {
var tagType = type.Type as TagType; var tagType = type.Type as TagType;

2
src/Generator/Passes/verbs.txt

@ -6583,6 +6583,7 @@ regerminate
regild regild
regionalize regionalize
regird regird
register
registrate registrate
regive regive
regiven regiven
@ -7209,6 +7210,7 @@ rettore
rettorn rettorn
retune retune
returf returf
return
retwine retwine
retwist retwist
retype retype

9
tests/CSharpTemp/CSharpTemp.Tests.cs

@ -1,5 +1,4 @@
using System; using System.Reflection;
using System.Reflection;
using CSharpTemp; using CSharpTemp;
using NUnit.Framework; using NUnit.Framework;
using Foo = CSharpTemp.Foo; using Foo = CSharpTemp.Foo;
@ -8,7 +7,7 @@ using Foo = CSharpTemp.Foo;
public class CSharpTempTests public class CSharpTempTests
{ {
[Test] [Test]
public unsafe void TestIndexer() public void TestIndexer()
{ {
var foo = new Foo(); var foo = new Foo();
@ -74,5 +73,9 @@ public class CSharpTempTests
Assert.That(p.value, Is.EqualTo(30)); Assert.That(p.value, Is.EqualTo(30));
p.prop = 50; p.prop = 50;
Assert.That(p.prop, Is.EqualTo(150)); Assert.That(p.prop, Is.EqualTo(150));
ComplexType complexType = new ComplexType();
p.complexType = complexType;
Assert.That(p.complexType.check(), Is.EqualTo(5));
} }
} }

39
tests/CSharpTemp/CSharpTemp.cpp

@ -46,6 +46,30 @@ Foo& Bar::operator[](int i)
return m_foo; return m_foo;
} }
Bar Bar::operator *()
{
return *this;
}
const Bar& Bar::operator *(int m)
{
index *= m;
return *this;
}
const Bar& Bar::operator ++()
{
++index;
return *this;
}
Bar Bar::operator ++(int i)
{
Bar bar = *this;
index++;
return bar;
}
Baz::Nested::operator int() const Baz::Nested::operator int() const
{ {
return 300; return 300;
@ -95,3 +119,18 @@ long P::prop()
{ {
return m_property + 100; return m_property + 100;
} }
int ComplexType::check()
{
return 5;
}
ComplexType P::complexType()
{
return m_complexType;
}
void P::setComplexType(const ComplexType& value)
{
m_complexType = value;
}

1
tests/CSharpTemp/CSharpTemp.cs

@ -14,6 +14,7 @@ namespace CppSharp.Tests
{ {
driver.Options.GenerateInterfacesForMultipleInheritance = true; driver.Options.GenerateInterfacesForMultipleInheritance = true;
driver.Options.GenerateProperties = true; driver.Options.GenerateProperties = true;
driver.Options.GenerateVirtualTables = true;
} }
public static void Main(string[] args) public static void Main(string[] args)

17
tests/CSharpTemp/CSharpTemp.h

@ -31,8 +31,13 @@ public:
int method(); int method();
const Foo& operator[](int i) const; const Foo& operator[](int i) const;
Foo& operator[](int i); Foo& operator[](int i);
Bar operator*();
const Bar& operator*(int m);
const Bar& operator++();
Bar operator++(int i);
private: private:
int index;
Foo m_foo; Foo m_foo;
}; };
@ -86,9 +91,21 @@ public:
virtual long prop(); virtual long prop();
}; };
class DLL_API ComplexType
{
public:
int check();
};
class DLL_API P : Proprietor class DLL_API P : Proprietor
{ {
public: public:
virtual void setValue(int value); virtual void setValue(int value);
virtual long prop(); virtual long prop();
ComplexType complexType();
void setComplexType(const ComplexType& value);
private:
ComplexType m_complexType;
}; };

Loading…
Cancel
Save