Browse Source

Added type maps for primitive strings (pointers to char).

const char*, const char16_t* and const wchar_t* in particular.

This enables comparison of types when resolving ambiguity.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/1156/head
Dimitar Dobrev 6 years ago committed by João Matos
parent
commit
a4913509eb
  1. 2
      src/AST/CppTypePrinter.cs
  2. 102
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  3. 9
      src/Generator/Generators/CSharp/CSharpSources.cs
  4. 20
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  5. 104
      src/Generator/Types/Std/Stdlib.cs
  6. 33
      src/Generator/Types/TypeMapDatabase.cs
  7. 4
      tests/CSharp/CSharp.cpp
  8. 19
      tests/CSharp/CSharp.cs
  9. 5
      tests/CSharp/CSharp.h

2
src/AST/CppTypePrinter.cs

@ -181,7 +181,7 @@ namespace CppSharp.AST @@ -181,7 +181,7 @@ namespace CppSharp.AST
{
FunctionType func;
if (ResolveTypedefs && !typedef.Declaration.Type.IsPointerTo(out func))
return typedef.Declaration.Type.Visit(this);
return typedef.Declaration.Type.Visit(this, quals);
var qual = GetStringQuals(quals);
return $"{qual}{typedef.Declaration.Visit(this)}";
}

102
src/Generator/Generators/CSharp/CSharpMarshal.cs

@ -46,8 +46,6 @@ namespace CppSharp.Generators.CSharp @@ -46,8 +46,6 @@ namespace CppSharp.Generators.CSharp
typePrinter = new CSharpTypePrinter(context.Context);
}
public bool MarshalsParameter { get; set; }
public override bool VisitType(Type type, TypeQualifiers quals)
{
TypeMap typeMap;
@ -132,10 +130,11 @@ namespace CppSharp.Generators.CSharp @@ -132,10 +130,11 @@ namespace CppSharp.Generators.CSharp
// const char* and const char[] are the same so we can use a string
if (array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) &&
array.QualifiedType.Qualifiers.IsConst)
return VisitPointerType(new PointerType
{
QualifiedPointee = array.QualifiedType
}, quals);
var pointer = new PointerType { QualifiedPointee = array.QualifiedType };
Context.ReturnType = new QualifiedType(pointer);
return this.VisitPointerType(pointer, quals);
}
MarshalArray(array);
break;
case ArrayType.ArraySize.Variable:
@ -155,20 +154,13 @@ namespace CppSharp.Generators.CSharp @@ -155,20 +154,13 @@ namespace CppSharp.Generators.CSharp
var isRefParam = param != null && (param.IsInOut || param.IsOut);
var pointee = pointer.Pointee.Desugar();
bool marshalPointeeAsString = pointee.IsConstCharString() && isRefParam;
if ((pointer.IsConstCharString() && !MarshalsParameter) ||
marshalPointeeAsString)
{
Context.Return.Write(MarshalStringToManaged(Context.ReturnVarName,
pointer.GetFinalPointee().Desugar() as BuiltinType));
return true;
}
var finalPointee = pointer.GetFinalPointee();
var finalPointee = pointer.GetFinalPointee().Desugar();
PrimitiveType primitive;
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
{
if ((pointee.IsConstCharString() && isRefParam) ||
(!finalPointee.IsPrimitiveType(out primitive) &&
!finalPointee.IsEnumType()))
return pointer.QualifiedPointee.Visit(this);
if (isRefParam)
{
Context.Return.Write("_{0}", param.Name);
@ -203,33 +195,6 @@ namespace CppSharp.Generators.CSharp @@ -203,33 +195,6 @@ namespace CppSharp.Generators.CSharp
return true;
}
return pointer.QualifiedPointee.Visit(this);
}
private string MarshalStringToManaged(string varName, BuiltinType type)
{
var isChar = type.Type == PrimitiveType.Char;
var encoding = isChar ? Encoding.ASCII : Encoding.Unicode;
if (Equals(encoding, Encoding.ASCII))
encoding = Context.Context.Options.Encoding;
if (Equals(encoding, Encoding.ASCII))
return $"Marshal.PtrToStringAnsi({varName})";
if (Equals(encoding, Encoding.UTF8))
return $"Marshal.PtrToStringUTF8({varName})";
// If we reach this, we know the string is Unicode.
if (type.Type == PrimitiveType.Char ||
Context.Context.TargetInfo.WCharWidth == 16)
return $"Marshal.PtrToStringUni({varName})";
// If we reach this, we should have an UTF-32 wide string.
const string encodingName = "System.Text.Encoding.UTF32";
return $"CppSharp.Runtime.Helpers.MarshalEncodedString({varName}, {encodingName})";
}
public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers quals)
{
switch (primitive)
@ -377,11 +342,11 @@ namespace CppSharp.Generators.CSharp @@ -377,11 +342,11 @@ namespace CppSharp.Generators.CSharp
if (dtor != null && dtor.IsVirtual)
{
Context.Before.WriteLine("else {0}{1} = ({2}) {3}.{4}({5}{6});",
MarshalsParameter
Context.Parameter != null
? string.Empty
: string.Format("{0}.NativeToManagedMap[{1}] = ", qualifiedClass, Context.ReturnVarName),
ret, qualifiedIdentifier, qualifiedClass, Helpers.CreateInstanceIdentifier, Context.ReturnVarName,
MarshalsParameter ? ", skipVTables: true" : string.Empty);
Context.Parameter != null ? ", skipVTables: true" : string.Empty);
}
else
{
@ -554,7 +519,6 @@ namespace CppSharp.Generators.CSharp @@ -554,7 +519,6 @@ namespace CppSharp.Generators.CSharp
if (templateSubstitution != null)
realPointer = templateSubstitution.Replacement.Type.Desugar() as PointerType;
realPointer = realPointer ?? pointer;
var pointee = pointer.Pointee.Desugar();
if (Context.Function != null &&
(realPointer.IsPrimitiveTypeConvertibleToRef() ||
(templateSubstitution != null && realPointer.Pointee.IsEnumType())) &&
@ -597,23 +561,20 @@ namespace CppSharp.Generators.CSharp @@ -597,23 +561,20 @@ namespace CppSharp.Generators.CSharp
var param = Context.Parameter;
var isRefParam = param != null && (param.IsInOut || param.IsOut);
var pointee = pointer.Pointee.Desugar();
if (pointee.IsConstCharString() && isRefParam)
{
if (param.IsOut)
{
Context.Return.Write("IntPtr.Zero");
Context.ArgumentPrefix.Write("&");
return true;
}
else if (param.IsInOut)
{
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
pointer.QualifiedPointee.Visit(this);
if (param.IsInOut)
Context.ArgumentPrefix.Write("&");
}
else
{
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
Context.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Context.ArgName);
}
return true;
}
@ -643,11 +604,9 @@ namespace CppSharp.Generators.CSharp @@ -643,11 +604,9 @@ namespace CppSharp.Generators.CSharp
return true;
}
var marshalAsString = pointer.IsConstCharString();
var finalPointee = pointer.GetFinalPointee();
PrimitiveType primitive;
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType() ||
marshalAsString)
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
{
// From MSDN: "note that a ref or out parameter is classified as a moveable
// variable". This means we must create a local variable to hold the result
@ -670,24 +629,14 @@ namespace CppSharp.Generators.CSharp @@ -670,24 +629,14 @@ namespace CppSharp.Generators.CSharp
}
else
{
if (!marshalAsString &&
Context.Context.Options.MarshalCharAsManagedChar &&
if (Context.Context.Options.MarshalCharAsManagedChar &&
primitive == PrimitiveType.Char)
Context.Return.Write($"({typePrinter.PrintNative(pointer)}) ");
if (marshalAsString && (Context.MarshalKind == MarshalKind.NativeField ||
Context.MarshalKind == MarshalKind.VTableReturnValue ||
Context.MarshalKind == MarshalKind.Variable))
{
Context.Return.Write(MarshalStringToUnmanaged(Context.Parameter.Name));
}
else
{
if (qualifiedPointer.IsConstRefToPrimitive())
Context.Return.Write("&");
Context.Return.Write(Context.Parameter.Name);
}
}
return true;
}
@ -695,21 +644,6 @@ namespace CppSharp.Generators.CSharp @@ -695,21 +644,6 @@ namespace CppSharp.Generators.CSharp
return pointer.QualifiedPointee.Visit(this);
}
private string MarshalStringToUnmanaged(string varName)
{
if (Equals(Context.Context.Options.Encoding, Encoding.ASCII))
{
return string.Format("Marshal.StringToHGlobalAnsi({0})", varName);
}
if (Equals(Context.Context.Options.Encoding, Encoding.Unicode) ||
Equals(Context.Context.Options.Encoding, Encoding.BigEndianUnicode))
{
return string.Format("Marshal.StringToHGlobalUni({0})", varName);
}
throw new NotSupportedException(string.Format("{0} is not supported yet.",
Context.Context.Options.Encoding.EncodingName));
}
public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers quals)
{
switch (primitive)

9
src/Generator/Generators/CSharp/CSharpSources.cs

@ -927,12 +927,12 @@ namespace CppSharp.Generators.CSharp @@ -927,12 +927,12 @@ namespace CppSharp.Generators.CSharp
if (type.IsPointer())
{
Type pointee = type.GetFinalPointee();
if (pointee.IsPrimitiveType() && !type.IsConstCharString())
if (pointee.IsPrimitiveType())
{
Write($"({CSharpTypePrinter.IntPtrType}) ");
var templateSubstitution = pointee.Desugar(false) as TemplateParameterSubstitutionType;
if (templateSubstitution != null)
Write($"(object) ");
Write("(object) ");
}
}
WriteLine($"{marshal.Context.Return};");
@ -1672,11 +1672,12 @@ namespace CppSharp.Generators.CSharp @@ -1672,11 +1672,12 @@ namespace CppSharp.Generators.CSharp
{
ReturnType = param.QualifiedType,
ReturnVarName = param.Name,
ParameterIndex = i
ParameterIndex = i,
Parameter = param
};
ctx.PushMarshalKind(MarshalKind.GenericDelegate);
var marshal = new CSharpMarshalNativeToManagedPrinter(ctx) { MarshalsParameter = true };
var marshal = new CSharpMarshalNativeToManagedPrinter(ctx);
param.Visit(marshal);
ctx.PopMarshalKind();

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

@ -184,16 +184,16 @@ namespace CppSharp.Generators.CSharp @@ -184,16 +184,16 @@ namespace CppSharp.Generators.CSharp
if (allowStrings && pointer.IsConstCharString())
{
if (isManagedContext)
return "string";
if (Parameter == null || Parameter.Name == Helpers.ReturnIdentifier)
return IntPtrType;
if (Options.Encoding == Encoding.ASCII)
return string.Format("[MarshalAs(UnmanagedType.LPStr)] string");
if (Options.Encoding == Encoding.Unicode ||
Options.Encoding == Encoding.BigEndianUnicode)
return string.Format("[MarshalAs(UnmanagedType.LPWStr)] string");
throw new NotSupportedException($"{Options.Encoding.EncodingName} is not supported yet.");
TypeMap typeMap;
TypeMapDatabase.FindTypeMap(pointer, out typeMap);
var typePrinterContext = new TypePrinterContext()
{
Kind = Kind,
MarshalKind = MarshalKind,
Type = pointer.Pointee,
Parameter = Parameter
};
return typeMap.CSharpSignatureType(typePrinterContext).Visit(this);
}
var pointee = pointer.Pointee.Desugar();

104
src/Generator/Types/Std/Stdlib.cs

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
@ -81,6 +82,109 @@ namespace CppSharp.Types.Std @@ -81,6 +82,109 @@ namespace CppSharp.Types.Std
}
}
[TypeMap("const char*", GeneratorKind = GeneratorKind.CSharp)]
public class ConstCharPointer : TypeMap
{
public override Type CSharpSignatureType(TypePrinterContext ctx)
{
if (ctx.Kind == TypePrinterContextKind.Managed)
return new CILType(typeof(string));
if (ctx.Parameter == null || ctx.Parameter.Name == Helpers.ReturnIdentifier)
return new CustomType(CSharpTypePrinter.IntPtrType);
if (Options.Encoding == Encoding.ASCII)
return new CustomType("[MarshalAs(UnmanagedType.LPStr)] string");
if (Options.Encoding == Encoding.Unicode ||
Options.Encoding == Encoding.BigEndianUnicode)
return new CustomType("[MarshalAs(UnmanagedType.LPWStr)] string");
throw new System.NotSupportedException(
$"{Options.Encoding.EncodingName} is not supported yet.");
}
public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{
if (ctx.Parameter.Usage == ParameterUsage.Unknown &&
ctx.MarshalKind != MarshalKind.NativeField &&
ctx.MarshalKind != MarshalKind.VTableReturnValue &&
ctx.MarshalKind != MarshalKind.Variable)
{
ctx.Return.Write(ctx.Parameter.Name);
return;
}
if (Equals(Options.Encoding, Encoding.ASCII))
{
ctx.Return.Write($"Marshal.StringToHGlobalAnsi({ctx.Parameter.Name})");
return;
}
if (Equals(Options.Encoding, Encoding.Unicode) ||
Equals(Options.Encoding, Encoding.BigEndianUnicode))
{
ctx.Return.Write($"Marshal.StringToHGlobalUni({ctx.Parameter.Name})");
return;
}
throw new System.NotSupportedException(
$"{Options.Encoding.EncodingName} is not supported yet.");
}
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)
{
if (ctx.Parameter != null && !ctx.Parameter.IsOut &&
!ctx.Parameter.IsInOut)
{
ctx.Return.Write(ctx.Parameter.Name);
return;
}
Type type = ctx.ReturnType.Type.Desugar();
Type pointee = type.GetPointee().Desugar();
var isChar = type.IsPointerToPrimitiveType(PrimitiveType.Char) ||
(pointee.IsPointerToPrimitiveType(PrimitiveType.Char) &&
ctx.Parameter != null &&
(ctx.Parameter.IsInOut || ctx.Parameter.IsOut));
var encoding = isChar ? Encoding.ASCII : Encoding.Unicode;
if (Equals(encoding, Encoding.ASCII))
encoding = Options.Encoding;
if (Equals(encoding, Encoding.ASCII))
{
ctx.Return.Write($"Marshal.PtrToStringAnsi({ctx.ReturnVarName})");
return;
}
if (Equals(encoding, Encoding.UTF8))
{
ctx.Return.Write($"Marshal.PtrToStringUTF8({ctx.ReturnVarName})");
return;
}
// If we reach this, we know the string is Unicode.
if (isChar || ctx.Context.TargetInfo.WCharWidth == 16)
{
ctx.Return.Write($"Marshal.PtrToStringUni({ctx.ReturnVarName})");
return;
}
// If we reach this, we should have an UTF-32 wide string.
const string encodingName = "System.Text.Encoding.UTF32";
ctx.Return.Write($@"CppSharp.Runtime.Helpers.MarshalEncodedString({
ctx.ReturnVarName}, {encodingName})");
}
}
[TypeMap("const char[]", GeneratorKind = GeneratorKind.CSharp)]
public class ConstCharArray : ConstCharPointer
{
}
[TypeMap("const wchar_t*", GeneratorKind = GeneratorKind.CSharp)]
public class ConstWCharTPointer : ConstCharPointer
{
}
[TypeMap("const char16_t*", GeneratorKind = GeneratorKind.CSharp)]
public class ConstChar16TPointer : ConstCharPointer
{
}
[TypeMap("basic_string<char, char_traits<char>, allocator<char>>")]
public class String : TypeMap
{

33
src/Generator/Types/TypeMapDatabase.cs

@ -110,16 +110,6 @@ namespace CppSharp.Types @@ -110,16 +110,6 @@ namespace CppSharp.Types
return typeMap.IsEnabled;
}
Type desugared = type.Desugar();
bool printExtra = desugared.GetPointee() != null &&
desugared.GetFinalPointee().Desugar().IsPrimitiveType();
var typePrinter = new CppTypePrinter
{
PrintTypeQualifiers = printExtra,
PrintTypeModifiers = printExtra,
PrintLogicalNames = true
};
var template = type as TemplateSpecializationType;
if (template != null)
{
@ -131,22 +121,31 @@ namespace CppSharp.Types @@ -131,22 +121,31 @@ namespace CppSharp.Types
out typeMap);
}
typePrinter.PrintScopeKind = TypePrintScopeKind.Local;
if (FindTypeMap(type.Visit(typePrinter), out typeMap))
Type desugared = type.Desugar();
bool printExtra = desugared.GetPointee() != null &&
desugared.GetFinalPointee().Desugar().IsPrimitiveType();
var typePrinter = new CppTypePrinter
{
typeMap.Type = type;
typeMaps[type] = typeMap;
return true;
}
PrintTypeQualifiers = printExtra,
PrintTypeModifiers = printExtra,
PrintLogicalNames = true
};
typePrinter.PrintScopeKind = TypePrintScopeKind.Qualified;
foreach (var resolveTypeDefs in new[] { true, false })
foreach (var typePrintScopeKind in
new[] { TypePrintScopeKind.Local, TypePrintScopeKind.Qualified })
{
typePrinter.ResolveTypedefs = resolveTypeDefs;
typePrinter.PrintScopeKind = typePrintScopeKind;
if (FindTypeMap(type.Visit(typePrinter), out typeMap))
{
typeMap.Type = type;
typeMaps[type] = typeMap;
return true;
}
}
typeMap = null;
var typedef = type as TypedefType;
return typedef != null && FindTypeMap(typedef.Declaration, type, out typeMap);
}

4
tests/CSharp/CSharp.cpp

@ -2,6 +2,10 @@ @@ -2,6 +2,10 @@
#include "CSharp.h"
Foo::Foo(const QString& name)
{
}
Foo::Foo(const char* name) : publicFieldMappedToEnum(TestFlag::Flag2)
{
A = 10;

19
tests/CSharp/CSharp.cs

@ -243,6 +243,25 @@ namespace CppSharp.Tests @@ -243,6 +243,25 @@ namespace CppSharp.Tests
}
}
[TypeMap("QString")]
public class QString : TypeMap
{
public override Type CSharpSignatureType(TypePrinterContext ctx)
{
return new CILType(typeof(string));
}
public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
{
ctx.Return.Write("\"test\"");
}
public override void CSharpMarshalToManaged(CSharpMarshalContext ctx)
{
ctx.Return.Write("\"test\"");
}
}
#endregion
}

5
tests/CSharp/CSharp.h

@ -8,9 +8,14 @@ @@ -8,9 +8,14 @@
#include "AnotherUnit.h"
#include "CSharpTemplates.h"
class DLL_API QString
{
};
class DLL_API Foo
{
public:
Foo(const QString& name);
Foo(const char* name = 0);
Foo(int a, int p = 0);
Foo(char16_t ch);

Loading…
Cancel
Save