Browse Source

Merge pull request #225 from azeno/master

Const pointer and indexer fixes
pull/227/merge
João Matos 11 years ago
parent
commit
90dd38e42c
  1. 52
      src/AST/TypeExtensions.cs
  2. 12
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  3. 14
      src/Generator/Generators/CLI/CLIMarshal.cs
  4. 24
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  5. 20
      src/Generator/Generators/CLI/CLITypePrinter.cs
  6. 4
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  7. 23
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  8. 2
      src/Generator/Passes/CheckIgnoredDecls.cs
  9. 16
      src/Generator/Passes/CheckOperatorsOverloads.cs
  10. 11
      src/Generator/Types/Types.cs
  11. 20
      tests/Basic/Basic.Tests.cs
  12. 5
      tests/Basic/Basic.cpp
  13. 23
      tests/Basic/Basic.h

52
src/AST/TypeExtensions.cs

@ -94,21 +94,14 @@ @@ -94,21 +94,14 @@
public static bool IsPointerTo<T>(this Type t, out T type) where T : Type
{
var ptr = t as PointerType;
if (ptr == null)
var pointee = t.GetPointee();
type = pointee as T;
if (type == null)
{
var functionPointer = t as MemberPointerType;
if (functionPointer != null)
{
type = functionPointer.Pointee as T;
return type != null;
var attributedType = pointee as AttributedType;
if (attributedType != null)
type = attributedType.Modified.Type as T;
}
type = null;
return false;
}
type = ptr.Pointee as T;
return type != null;
}
@ -155,5 +148,38 @@ @@ -155,5 +148,38 @@
return t;
}
/// <summary>
/// If t is a pointer type the type pointed to by t will be returned.
/// Otherwise null.
/// </summary>
public static Type GetPointee(this Type t)
{
var ptr = t as PointerType;
if (ptr != null)
return ptr.Pointee;
var memberPtr = t as MemberPointerType;
if (memberPtr != null)
return memberPtr.Pointee;
return null;
}
/// <summary>
/// If t is a pointer type the type pointed to by t will be returned
/// after fully dereferencing it. Otherwise null.
/// For example int** -> int.
/// </summary>
public static Type GetFinalPointee(this Type t)
{
var finalPointee = t.GetPointee();
var pointee = finalPointee;
while (pointee != null)
{
pointee = pointee.GetPointee();
if (pointee != null)
finalPointee = pointee;
}
return finalPointee;
}
}
}

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

@ -616,15 +616,18 @@ namespace CppSharp.Generators.CLI @@ -616,15 +616,18 @@ namespace CppSharp.Generators.CLI
public void GenerateIndexer(Property property)
{
var type = property.QualifiedType.Visit(TypePrinter);
var getter = property.GetMethod;
var indexParameter = getter.Parameters[0];
var indexParameterType = indexParameter.QualifiedType.Visit(TypePrinter);
WriteLine("property {0} default[int]", type);
WriteLine("property {0} default[{1}]", type, indexParameterType);
WriteStartBraceIndent();
if (property.HasGetter)
WriteLine("{0} get(int index);", type);
WriteLine("{0} get({1} {2});", type, indexParameterType, indexParameter.Name);
if (property.HasSetter)
WriteLine("void set(int index, {0});", type);
WriteLine("void set({1} {2}, {0} value);", type, indexParameterType, indexParameter.Name);
WriteCloseBraceIndent();
}
@ -637,6 +640,9 @@ namespace CppSharp.Generators.CLI @@ -637,6 +640,9 @@ namespace CppSharp.Generators.CLI
PushBlock(CLIBlockKind.Property, property);
var type = property.QualifiedType.Visit(TypePrinter);
if (property.IsStatic)
Write("static ");
if (property.IsIndexer)
{
GenerateIndexer(property);

14
src/Generator/Generators/CLI/CLIMarshal.cs

@ -91,11 +91,15 @@ namespace CppSharp.Generators.CLI @@ -91,11 +91,15 @@ namespace CppSharp.Generators.CLI
if (pointee.IsPrimitiveType(out primitive))
{
var returnVarName = Context.ReturnVarName;
if (quals.IsConst != Context.ReturnType.Qualifiers.IsConst)
returnVarName = string.Format("const_cast<{0}>({1})",
Context.ReturnType, Context.ReturnVarName);
if (pointer.Pointee is TypedefType)
Context.Return.Write("reinterpret_cast<{0}>({1})", pointer,
Context.ReturnVarName);
returnVarName);
else
Context.Return.Write(Context.ReturnVarName);
Context.Return.Write(returnVarName);
return true;
}
@ -438,8 +442,8 @@ namespace CppSharp.Generators.CLI @@ -438,8 +442,8 @@ namespace CppSharp.Generators.CLI
return pointee.Visit(this, quals);
}
PrimitiveType primitive;
if (pointee.IsPrimitiveType(out primitive))
var finalPointee = pointer.GetFinalPointee();
if (finalPointee.IsPrimitiveType())
{
var cppTypePrinter = new CppTypePrinter(Context.Driver.TypeDatabase);
var cppTypeName = pointer.Visit(cppTypePrinter, quals);
@ -506,7 +510,7 @@ namespace CppSharp.Generators.CLI @@ -506,7 +510,7 @@ namespace CppSharp.Generators.CLI
}
PrimitiveType primitive;
if (decl.Type.Desugar().IsPrimitiveType(out primitive))
if (decl.Type.IsPrimitiveType(out primitive))
{
Context.Return.Write("(::{0})", typedef.Declaration.QualifiedOriginalName);
}

24
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -330,28 +330,29 @@ namespace CppSharp.Generators.CLI @@ -330,28 +330,29 @@ namespace CppSharp.Generators.CLI
property.Type);
if (property.HasSetter)
if (property.IsIndexer)
GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type, property.GetMethod.Parameters[0]);
else
GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type);
}
PopBlock();
}
private void GeneratePropertySetter<T>(T decl, Class @class, string name, Type type)
private void GeneratePropertySetter<T>(T decl, Class @class, string name, Type type, Parameter indexParameter = null)
where T : Declaration, ITypedDecl
{
if (decl == null)
return;
var method = decl as Method;
var isIndexer = method != null &&
method.OperatorKind == CXXOperatorKind.Subscript;
var args = new List<string>();
var isIndexer = indexParameter != null;
if (isIndexer)
args.Add("int index");
args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name));
var function = decl as Function;
var argName = function != null ? function.Parameters[0].Name : "value";
var argName = function != null && !isIndexer ? function.Parameters[0].Name : "value";
args.Add(string.Format("{0} {1}", type, argName));
WriteLine("void {0}::{1}::set({2})", QualifiedIdentifier(@class),
@ -397,7 +398,7 @@ namespace CppSharp.Generators.CLI @@ -397,7 +398,7 @@ namespace CppSharp.Generators.CLI
@class.QualifiedOriginalName, decl.OriginalName);
if (isIndexer)
variable += "(index)";
variable += string.Format("({0})", indexParameter.Name);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
@ -421,7 +422,10 @@ namespace CppSharp.Generators.CLI @@ -421,7 +422,10 @@ namespace CppSharp.Generators.CLI
var args = new List<string>();
if (isIndexer)
args.Add("int index");
{
var indexParameter = method.Parameters[0];
args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name));
}
WriteLine("{0} {1}::{2}::get({3})", type, QualifiedIdentifier(@class),
name, string.Join(", ", args));
@ -966,7 +970,7 @@ namespace CppSharp.Generators.CLI @@ -966,7 +970,7 @@ namespace CppSharp.Generators.CLI
if (Driver.Options.MarshalCharAsManagedChar)
{
foreach (var param in method.Parameters.Where(
p => p.Type.Desugar().IsPrimitiveType(PrimitiveType.Int8)))
p => p.Type.IsPrimitiveType(PrimitiveType.Int8)))
{
WriteLine("if ({0} < System::Char::MinValue || {0} > System::SByte::MaxValue)", param.Name);
WriteLineIndent(

20
src/Generator/Generators/CLI/CLITypePrinter.cs

@ -142,14 +142,22 @@ namespace CppSharp.Generators.CLI @@ -142,14 +142,22 @@ namespace CppSharp.Generators.CLI
return "System::String^";
}
PrimitiveType primitive;
if (pointee.IsPrimitiveType(out primitive))
{
// From http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx
// Any of the following types may be a pointer type:
// * sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
// * Any enum type.
// * Any pointer type.
// * Any user-defined struct type that contains fields of unmanaged types only.
var finalPointee = pointer.GetFinalPointee();
if (finalPointee.IsPrimitiveType())
{
// Skip one indirection if passed by reference
var param = Context.Parameter;
if (param != null && (param.IsOut || param.IsInOut))
return VisitPrimitiveType(primitive);
if (param != null && (param.IsOut || param.IsInOut)
&& pointee == finalPointee)
return pointee.Visit(this, quals);
return VisitPrimitiveType(primitive, quals) + "*";
return pointee.Visit(this, quals) + "*";
}
Enumeration @enum;

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

@ -2105,7 +2105,7 @@ namespace CppSharp.Generators.CSharp @@ -2105,7 +2105,7 @@ namespace CppSharp.Generators.CSharp
if (Driver.Options.MarshalCharAsManagedChar)
{
foreach (var param in method.Parameters.Where(
p => p.Type.Desugar().IsPrimitiveType(PrimitiveType.Int8)))
p => p.Type.IsPrimitiveType(PrimitiveType.Int8)))
{
WriteLine("if ({0} < char.MinValue || {0} > sbyte.MaxValue)", param.Name);
WriteLineIndent(
@ -2690,7 +2690,7 @@ namespace CppSharp.Generators.CSharp @@ -2690,7 +2690,7 @@ namespace CppSharp.Generators.CSharp
WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled);
if (function.ReturnType.Type.Desugar().IsPrimitiveType(PrimitiveType.Bool))
if (function.ReturnType.Type.IsPrimitiveType(PrimitiveType.Bool))
WriteLine("[return: MarshalAsAttribute(UnmanagedType.I1)]");
var @params = new List<string>();

23
src/Generator/Generators/CSharp/CSharpTypePrinter.cs

@ -208,18 +208,27 @@ namespace CppSharp.Generators.CSharp @@ -208,18 +208,27 @@ namespace CppSharp.Generators.CSharp
if (IsConstCharString(pointer))
return isManagedContext ? "string" : "global::System.IntPtr";
PrimitiveType primitive;
var desugared = pointee.Desugar();
if (desugared.IsPrimitiveType(out primitive))
{
if (isManagedContext && Context.Parameter != null &&
(Context.Parameter.IsOut || Context.Parameter.IsInOut))
return VisitPrimitiveType(primitive, quals);
// From http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx
// Any of the following types may be a pointer type:
// * sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
// * Any enum type.
// * Any pointer type.
// * Any user-defined struct type that contains fields of unmanaged types only.
var finalPointee = pointer.GetFinalPointee();
if (finalPointee.IsPrimitiveType())
{
// Skip one indirection if passed by reference
var param = Context.Parameter;
if (isManagedContext && param != null && (param.IsOut || param.IsInOut)
&& pointee == finalPointee)
return pointee.Visit(this, quals);
if (ContextKind == CSharpTypePrinterContextKind.GenericDelegate)
return "global::System.IntPtr";
return VisitPrimitiveType(primitive, quals) + "*";
return pointee.Visit(this, quals) + "*";
}
Enumeration @enum;

2
src/Generator/Passes/CheckIgnoredDecls.cs

@ -342,7 +342,7 @@ namespace CppSharp.Passes @@ -342,7 +342,7 @@ namespace CppSharp.Passes
var arrayType = type as ArrayType;
PrimitiveType primitive;
if (arrayType != null && arrayType.SizeType == ArrayType.ArraySize.Constant &&
!arrayType.Type.Desugar().IsPrimitiveType(out primitive) &&
!arrayType.Type.IsPrimitiveType(out primitive) &&
!arrayType.Type.Desugar().IsPointerToPrimitiveType())
{
msg = "unsupported";

16
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -100,14 +100,18 @@ namespace CppSharp.Passes @@ -100,14 +100,18 @@ namespace CppSharp.Passes
if (!@operator.ReturnType.Qualifiers.IsConst && @operator.ReturnType.Type.IsAddress())
property.SetMethod = @operator;
// C++/CLI uses "default" as the indexer property name.
if (Driver.Options.IsCLIGenerator)
{
// If we've a setter use the pointee as the type of the property.
var pointerType = property.Type as PointerType;
if (pointerType != null && property.HasSetter)
{
property.QualifiedType = new QualifiedType(pointerType.Pointee, property.QualifiedType.Qualifiers);
property.GetMethod.ReturnType = property.QualifiedType;
}
// C++/CLI uses "default" as the indexer property name.
property.Name = "default";
property.GetMethod.Parameters[0].Name = "index";
if (property.SetMethod != null)
property.SetMethod.Parameters[0].Name = "index";
}
property.Parameters.AddRange(@operator.Parameters);

11
src/Generator/Types/Types.cs

@ -128,6 +128,17 @@ namespace CppSharp @@ -128,6 +128,17 @@ namespace CppSharp
Ignore();
return base.VisitTemplateSpecializationType(template, quals);
}
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
// We don't know how to marshal non-static member functions
if (function.CallingConvention == CallingConvention.ThisCall)
{
Ignore();
return false;
}
return base.VisitFunctionType(function, quals);
}
}
}

20
tests/Basic/Basic.Tests.cs

@ -23,6 +23,16 @@ public class BasicTests : GeneratorTestFixture @@ -23,6 +23,16 @@ public class BasicTests : GeneratorTestFixture
Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11));
Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11));
Assert.That(hello.AddFooRef(foo), Is.EqualTo(11));
unsafe
{
var pointer = foo.SomePointer;
var pointerPointer = foo.SomePointerPointer;
for (int i = 0; i < 4; i++)
{
Assert.AreEqual(i, pointer[i]);
Assert.AreEqual(i, (*pointerPointer)[i]);
}
}
var bar = new Bar { A = 4, B = 7 };
Assert.That(hello.AddBar(bar), Is.EqualTo(11));
@ -168,6 +178,13 @@ public class BasicTests : GeneratorTestFixture @@ -168,6 +178,13 @@ public class BasicTests : GeneratorTestFixture
Assert.AreEqual(8, doubleSum);
}
[Test]
public void TestAttributedDelegate()
{
var result = basic.AttributedDelegate(2);
Assert.AreEqual(4, result);
}
[Test]
public void TestUnion()
{
@ -224,6 +241,9 @@ public class BasicTests : GeneratorTestFixture @@ -224,6 +241,9 @@ public class BasicTests : GeneratorTestFixture
{
var someStruct = new SomeStruct();
Assert.That(someStruct[0], Is.EqualTo(1));
Assert.That(someStruct["foo"], Is.EqualTo(1));
someStruct[0] = 2;
Assert.That(someStruct[0], Is.EqualTo(2));
}
[Test]

5
tests/Basic/Basic.cpp

@ -2,6 +2,11 @@ @@ -2,6 +2,11 @@
Foo::Foo()
{
auto p = new int[4];
for (int i = 0; i < 4; i++)
p[i] = i;
SomePointer = p;
SomePointerPointer = &SomePointer;
}
const char* Foo::GetANSI()

23
tests/Basic/Basic.h

@ -18,7 +18,11 @@ public: @@ -18,7 +18,11 @@ public:
// 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
@ -243,14 +247,26 @@ typedef int (*DelegateInGlobalNamespace)(int); @@ -243,14 +247,26 @@ typedef int (*DelegateInGlobalNamespace)(int);
struct DLL_API TestDelegates
{
typedef int (*DelegateInClass)(int);
typedef int(TestDelegates::*MemberDelegate)(int);
TestDelegates() : A(Double), B(Double) {}
TestDelegates() : A(Double), B(Double) { C = &TestDelegates::Triple; }
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;
};
// 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
@ -307,8 +323,9 @@ typedef unsigned long foo_t; @@ -307,8 +323,9 @@ typedef unsigned long foo_t;
typedef struct DLL_API SomeStruct
{
SomeStruct() : p(1) {}
const foo_t& operator[](int i) const { return p; }
foo_t operator[](int i) { return p; }
foo_t& operator[](int i) { return p; }
// CSharp backend can't deal with a setter here
foo_t operator[](const char* name) { return p; }
foo_t p;
}
SomeStruct;

Loading…
Cancel
Save