Browse Source

Improved support for indexed properties.

More types and types with different qualifiers are supported now - in both backends. See test cases for details.
pull/233/head
Elias Holzer 11 years ago
parent
commit
0c260bd223
  1. 30
      src/Generator/Generators/CLI/CLIMarshal.cs
  2. 62
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  3. 66
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  4. 27
      src/Generator/Passes/CheckOperatorsOverloads.cs
  5. 6
      src/Generator/Types/CppTypePrinter.cs
  6. 22
      tests/Basic/Basic.Tests.cs
  7. 15
      tests/Basic/Basic.h

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

@ -93,11 +93,31 @@ namespace CppSharp.Generators.CLI @@ -93,11 +93,31 @@ namespace CppSharp.Generators.CLI
{
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,
returnVarName);
{
var nativeTypePrinter = new CppTypePrinter(Context.Driver.TypeDatabase, false);
var constlessPointer = new PointerType()
{
IsDependent = pointer.IsDependent,
Modifier = pointer.Modifier,
QualifiedPointee = new QualifiedType(Context.ReturnType.Type.GetPointee())
};
var nativeConstlessTypeName = constlessPointer.Visit(nativeTypePrinter, new TypeQualifiers());
returnVarName = string.Format("const_cast<{0}>({1})",
nativeConstlessTypeName, Context.ReturnVarName);
}
if (pointer.Pointee is TypedefType)
{
var desugaredPointer = new PointerType()
{
IsDependent = pointer.IsDependent,
Modifier = pointer.Modifier,
QualifiedPointee = new QualifiedType(pointee)
};
var nativeTypePrinter = new CppTypePrinter(Context.Driver.TypeDatabase);
var nativeTypeName = desugaredPointer.Visit(nativeTypePrinter, quals);
Context.Return.Write("reinterpret_cast<{0}>({1})", nativeTypeName,
returnVarName);
}
else
Context.Return.Write(returnVarName);
return true;

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

@ -372,16 +372,16 @@ namespace CppSharp.Generators.CLI @@ -372,16 +372,16 @@ namespace CppSharp.Generators.CLI
return;
}
var param = new Parameter
{
Name = "value",
QualifiedType = decl.QualifiedType
};
{
Name = "value",
QualifiedType = new QualifiedType(type)
};
var ctx = new MarshalContext(Driver)
{
Parameter = param,
ArgName = param.Name,
};
{
Parameter = param,
ArgName = param.Name,
};
var marshal = new CLIMarshalManagedToNativePrinter(ctx);
param.Visit(marshal);
@ -400,7 +400,10 @@ namespace CppSharp.Generators.CLI @@ -400,7 +400,10 @@ namespace CppSharp.Generators.CLI
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
WriteLine("{0} = {1};", variable, marshal.Context.Return);
if (isIndexer && decl.Type.IsPointer())
WriteLine("*({0}) = {1};", variable, marshal.Context.Return);
else
WriteLine("{0} = {1};", variable, marshal.Context.Return);
}
WriteCloseBraceIndent();
@ -432,7 +435,10 @@ namespace CppSharp.Generators.CLI @@ -432,7 +435,10 @@ namespace CppSharp.Generators.CLI
if (decl is Function)
{
var func = decl as Function;
GenerateFunctionCall(func, @class);
if (isIndexer && func.Type.IsAddress())
GenerateFunctionCall(func, @class, type);
else
GenerateFunctionCall(func, @class);
}
else
{
@ -832,11 +838,13 @@ namespace CppSharp.Generators.CLI @@ -832,11 +838,13 @@ namespace CppSharp.Generators.CLI
WriteCloseBraceIndent();
}
public void GenerateFunctionCall(Function function, Class @class = null)
public void GenerateFunctionCall(Function function, Class @class = null, Type publicRetType = null)
{
CheckArgumentRange(function);
var retType = function.ReturnType;
if (publicRetType == null)
publicRetType = retType.Type;
var needsReturn = !retType.Type.IsPrimitiveType(PrimitiveType.Void);
const string valueMarshalName = "_this0";
@ -861,9 +869,12 @@ namespace CppSharp.Generators.CLI @@ -861,9 +869,12 @@ namespace CppSharp.Generators.CLI
var @params = GenerateFunctionParamsMarshal(function.Parameters, function);
var returnIdentifier = Generator.GeneratedIdentifier("ret");
if (needsReturn)
Write("auto {0}{1} = ",(function.ReturnType.Type.IsReference())? "&": string.Empty,
Generator.GeneratedIdentifier("ret"));
if (retType.Type.IsReference())
Write("auto &{0} = ", returnIdentifier);
else
Write("auto {0} = ", returnIdentifier);
if (function.OperatorKind == CXXOperatorKind.Conversion ||
function.OperatorKind == CXXOperatorKind.ExplicitConversion)
@ -944,24 +955,33 @@ namespace CppSharp.Generators.CLI @@ -944,24 +955,33 @@ namespace CppSharp.Generators.CLI
if (retType.Type.IsPointer() && (isIntPtr || retTypeName.EndsWith("^")))
{
WriteLine("if ({0} == nullptr) return {1};",
Generator.GeneratedIdentifier("ret"),
returnIdentifier,
isIntPtr ? "System::IntPtr()" : "nullptr");
}
var ctx = new MarshalContext(Driver)
{
ArgName = Generator.GeneratedIdentifier("ret"),
ReturnVarName = Generator.GeneratedIdentifier("ret"),
ReturnType = retType
};
{
ArgName = returnIdentifier,
ReturnVarName = returnIdentifier,
ReturnType = retType
};
var marshal = new CLIMarshalNativeToManagedPrinter(ctx);
function.ReturnType.Visit(marshal);
retType.Visit(marshal);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
WriteLine("return {0};", marshal.Context.Return);
// Special case for indexer - needs to dereference if the internal
// function is a pointer type and the property is not.
if (retType.Type.IsPointer() &&
retType.Type.GetPointee().Equals(publicRetType) &&
publicRetType.IsPrimitiveType())
WriteLine("return *({0});", marshal.Context.Return);
else if (retType.Type.IsReference() && publicRetType.IsReference())
WriteLine("return ({0})({1});", publicRetType, marshal.Context.Return);
else
WriteLine("return {0};", marshal.Context.Return);
}
}

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

@ -967,8 +967,8 @@ namespace CppSharp.Generators.CSharp @@ -967,8 +967,8 @@ namespace CppSharp.Generators.CSharp
private void GenerateIndexerSetter(QualifiedType returnType, Function function)
{
Type type;
returnType.Type.IsPointerTo(out type);
Type type;
function.Type.IsPointerTo(out type);
PrimitiveType primitiveType;
string internalFunction = GetFunctionNativeIdentifier(function);
if (type.IsPrimitiveType(out primitiveType))
@ -984,7 +984,7 @@ namespace CppSharp.Generators.CSharp @@ -984,7 +984,7 @@ namespace CppSharp.Generators.CSharp
}
}
private void GeneratePropertyGetter<T>(T decl, Class @class)
private void GeneratePropertyGetter<T>(QualifiedType returnType, T decl, Class @class)
where T : Declaration, ITypedDecl
{
PushBlock(CSharpBlockKind.Method);
@ -1004,19 +1004,9 @@ namespace CppSharp.Generators.CSharp @@ -1004,19 +1004,9 @@ namespace CppSharp.Generators.CSharp
WriteStartBraceIndent();
var method = function as Method;
if (method != null && method.IsOverride && method.IsSynthetized)
{
GenerateVirtualTableFunctionCall(method, @class);
}
else
{
bool isPrimitiveIndexer = function.OperatorKind == CXXOperatorKind.Subscript &&
function.ReturnType.Type.IsPointerToPrimitiveType();
if (isPrimitiveIndexer)
TypePrinter.PushContext(CSharpTypePrinterContextKind.PrimitiveIndexer);
GenerateInternalFunctionCall(function);
if (isPrimitiveIndexer)
TypePrinter.PopContext();
}
GenerateInternalFunctionCall(function, function.Parameters, returnType.Type);
}
else if (decl is Field)
{
@ -1185,12 +1175,6 @@ namespace CppSharp.Generators.CSharp @@ -1185,12 +1175,6 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.Property);
// If this is an indexer that returns an address use the real type
// because there is a setter anyway.
var type = prop.Type;
if (prop.Parameters.Count > 0 && prop.Type.IsPointerToPrimitiveType())
type = ((PointerType) prop.Type).Pointee;
ArrayType arrayType = prop.Type as ArrayType;
if (arrayType != null && arrayType.Type.IsPointerToPrimitiveType() && prop.Field != null)
{
@ -1214,11 +1198,11 @@ namespace CppSharp.Generators.CSharp @@ -1214,11 +1198,11 @@ namespace CppSharp.Generators.CSharp
else if (prop.IsVirtual)
Write("virtual ");
WriteLine("{0} {1}", type, GetPropertyName(prop));
WriteLine("{0} {1}", prop.Type, GetPropertyName(prop));
}
else
{
WriteLine("{0} {1}.{2}", type, prop.ExplicitInterfaceImpl.Name,
WriteLine("{0} {1}.{2}", prop.Type, prop.ExplicitInterfaceImpl.Name,
GetPropertyName(prop));
}
WriteStartBraceIndent();
@ -1226,7 +1210,7 @@ namespace CppSharp.Generators.CSharp @@ -1226,7 +1210,7 @@ namespace CppSharp.Generators.CSharp
if (prop.Field != null)
{
if (prop.HasGetter)
GeneratePropertyGetter(prop.Field, @class);
GeneratePropertyGetter(prop.QualifiedType, prop.Field, @class);
if (prop.HasSetter)
GeneratePropertySetter(prop.Field.QualifiedType, prop.Field,
@ -1234,13 +1218,11 @@ namespace CppSharp.Generators.CSharp @@ -1234,13 +1218,11 @@ namespace CppSharp.Generators.CSharp
}
else
{
if (prop.HasGetter)
GeneratePropertyGetter(prop.GetMethod, @class);
if (prop.HasGetter)
GeneratePropertyGetter(prop.QualifiedType, prop.GetMethod, @class);
if (prop.HasSetter)
GeneratePropertySetter(prop.GetMethod != null ?
prop.GetMethod.ReturnType : prop.SetMethod.Parameters[0].QualifiedType,
prop.SetMethod, @class);
GeneratePropertySetter(prop.QualifiedType, prop.SetMethod, @class);
}
WriteCloseBraceIndent();
@ -1260,7 +1242,7 @@ namespace CppSharp.Generators.CSharp @@ -1260,7 +1242,7 @@ namespace CppSharp.Generators.CSharp
WriteLine("public static {0} {1}", type, variable.Name);
WriteStartBraceIndent();
GeneratePropertyGetter(variable, @class);
GeneratePropertyGetter(variable.QualifiedType, variable, @class);
if (!variable.QualifiedType.Qualifiers.IsConst)
GeneratePropertySetter(variable.QualifiedType, variable, @class);
@ -2185,8 +2167,8 @@ namespace CppSharp.Generators.CSharp @@ -2185,8 +2167,8 @@ namespace CppSharp.Generators.CSharp
GenerateVTableClassSetupCall(@class);
}
public void GenerateInternalFunctionCall(Function function,
List<Parameter> parameters = null)
public void GenerateInternalFunctionCall(Function function,
List<Parameter> parameters = null, Type returnType = null)
{
if (parameters == null)
parameters = function.Parameters;
@ -2194,11 +2176,11 @@ namespace CppSharp.Generators.CSharp @@ -2194,11 +2176,11 @@ namespace CppSharp.Generators.CSharp
CheckArgumentRange(function);
var functionName = string.Format("Internal.{0}",
GetFunctionNativeIdentifier(function));
GenerateFunctionCall(functionName, parameters, function);
GenerateFunctionCall(functionName, parameters, function, returnType);
}
public void GenerateFunctionCall(string functionName, List<Parameter> parameters,
Function function)
public void GenerateFunctionCall(string functionName, List<Parameter> parameters,
Function function, Type returnType = null)
{
if (function.IsPure)
{
@ -2206,7 +2188,9 @@ namespace CppSharp.Generators.CSharp @@ -2206,7 +2188,9 @@ namespace CppSharp.Generators.CSharp
return;
}
var retType = function.OriginalReturnType;
var retType = function.OriginalReturnType;
if (returnType == null)
returnType = retType.Type;
var needsReturn = !retType.Type.IsPrimitiveType(PrimitiveType.Void);
var isValueType = false;
@ -2365,10 +2349,14 @@ namespace CppSharp.Generators.CSharp @@ -2365,10 +2349,14 @@ namespace CppSharp.Generators.CSharp
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore);
WriteLine(
TypePrinter.ContextKind == CSharpTypePrinterContextKind.PrimitiveIndexer
? "return *{0};"
: "return {0};", marshal.Context.Return);
// Special case for indexer - needs to dereference if the internal
// function is a pointer type and the property is not.
if (retType.Type.IsAddress() &&
retType.Type.GetPointee().Equals(returnType) &&
returnType.IsPrimitiveType())
WriteLine("return *{0};", marshal.Context.Return);
else
WriteLine("return {0};", marshal.Context.Return);
}
}

27
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -97,21 +97,24 @@ namespace CppSharp.Passes @@ -97,21 +97,24 @@ namespace CppSharp.Passes
GetMethod = @operator
};
if (!@operator.ReturnType.Qualifiers.IsConst && @operator.ReturnType.Type.IsAddress())
property.SetMethod = @operator;
var returnType = @operator.Type;
if (returnType.IsAddress())
{
var pointer = returnType as PointerType;
var qualifiedPointee = pointer.QualifiedPointee;
if (!qualifiedPointee.Qualifiers.IsConst)
property.SetMethod = @operator;
}
// 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);
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.Parameters.AddRange(@operator.Parameters);

6
src/Generator/Types/CppTypePrinter.cs

@ -17,10 +17,12 @@ namespace CppSharp.Types @@ -17,10 +17,12 @@ namespace CppSharp.Types
{
public CppTypePrintScopeKind PrintScopeKind;
public bool PrintLogicalNames;
public bool PrintTypeQualifiers;
public CppTypePrinter(ITypeMapDatabase database)
public CppTypePrinter(ITypeMapDatabase database, bool printTypeQualifiers = true)
{
PrintScopeKind = CppTypePrintScopeKind.GlobalQualified;
PrintTypeQualifiers = printTypeQualifiers;
}
public string VisitTagType(TagType tag, TypeQualifiers quals)
@ -78,7 +80,7 @@ namespace CppSharp.Types @@ -78,7 +80,7 @@ namespace CppSharp.Types
var pointeeType = pointer.Pointee.Visit(this, quals);
var mod = ConvertModifierToString(pointer.Modifier);
var s = quals.IsConst ? "const " : string.Empty;
var s = PrintTypeQualifiers && quals.IsConst ? "const " : string.Empty;
s += string.Format("{0}{1}", pointeeType, mod);
return s;

22
tests/Basic/Basic.Tests.cs

@ -238,11 +238,23 @@ public class BasicTests : GeneratorTestFixture @@ -238,11 +238,23 @@ public class BasicTests : GeneratorTestFixture
[Test]
public unsafe void TestIndexers()
{
var properties = new TestIndexedProperties();
Assert.AreEqual(1, properties[0]);
Assert.AreEqual(1, properties["foo"]);
properties[0] = 2;
Assert.AreEqual(2, properties[0]);
var indexedProperties = new TestIndexedProperties();
Assert.AreEqual(1, indexedProperties[0]);
Assert.AreEqual(1, indexedProperties["foo"]);
indexedProperties[0] = 2;
Assert.AreEqual(2, indexedProperties[0]);
indexedProperties[0f] = 3;
Assert.AreEqual(3, indexedProperties[0f]);
var properties = indexedProperties[(byte)0];
Assert.AreEqual(0, properties.Field);
var newProperties = new TestProperties();
newProperties.Field = 4;
indexedProperties[(byte)0] = newProperties;
Assert.AreEqual(4, indexedProperties[(byte)0].Field);
newProperties = indexedProperties[(short)0];
Assert.AreEqual(4, newProperties.Field);
newProperties.Field = 5;
Assert.AreEqual(5, indexedProperties[(byte)0].Field);
}
[Test]

15
tests/Basic/Basic.h

@ -393,17 +393,30 @@ void TestProperties::setFieldValue(int Value) { Field = Value; } @@ -393,17 +393,30 @@ void TestProperties::setFieldValue(int Value) { Field = Value; }
class DLL_API TestIndexedProperties
{
foo_t p;
TestProperties f;
public:
TestIndexedProperties();
// Should lead to a read/write indexer with return type uint
foo_t& operator[](int i);
// Should lead to a read/write indexer with return type uint
foo_t* operator[](float f);
// Should lead to a read-only indexer with return type uint
foo_t operator[](const char* name);
// Should lead to a read-only indexer with return type uint*
const foo_t& operator[](double d);
// Should lead to a read/write indexer with return type TestProperties
TestProperties* operator[](unsigned char b);
// Should lead to a read-only indexer with return type TestProperties
const TestProperties& operator[](short b);
};
TestIndexedProperties::TestIndexedProperties() : p(1) {}
TestIndexedProperties::TestIndexedProperties() : p(1), f() {}
foo_t& TestIndexedProperties::operator[](int i) { return p; }
foo_t TestIndexedProperties::operator[](const char* name) { return p; }
foo_t* TestIndexedProperties::operator[](float f) { return &p; }
const foo_t& TestIndexedProperties::operator[](double f) { return p; }
TestProperties* TestIndexedProperties::operator[](unsigned char b) { return &f; }
const TestProperties& TestIndexedProperties::operator[](short b) { return f; }
enum struct MyEnum { A, B, C };

Loading…
Cancel
Save