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. 66
      src/AST/TypeExtensions.cs
  2. 20
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  3. 24
      src/Generator/Generators/CLI/CLIMarshal.cs
  4. 48
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  5. 780
      src/Generator/Generators/CLI/CLITypePrinter.cs
  6. 4
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  7. 21
      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. 24
      tests/Basic/Basic.Tests.cs
  12. 5
      tests/Basic/Basic.cpp
  13. 27
      tests/Basic/Basic.h

66
src/AST/TypeExtensions.cs

@ -90,26 +90,19 @@
if (ptr == null) if (ptr == null)
return false; return false;
return ptr.Pointee.IsPrimitiveType(primitive); return ptr.Pointee.IsPrimitiveType(primitive);
} }
public static bool IsPointerTo<T>(this Type t, out T type) where T : Type public static bool IsPointerTo<T>(this Type t, out T type) where T : Type
{ {
var ptr = t as PointerType; var pointee = t.GetPointee();
type = pointee as T;
if (ptr == null) if (type == null)
{ {
var functionPointer = t as MemberPointerType; var attributedType = pointee as AttributedType;
if (functionPointer != null) if (attributedType != null)
{ type = attributedType.Modified.Type as T;
type = functionPointer.Pointee as T; }
return type != null; return type != null;
}
type = null;
return false;
}
type = ptr.Pointee as T;
return type != null;
} }
public static bool IsTagDecl<T>(this Type t, out T decl) where T : Declaration public static bool IsTagDecl<T>(this Type t, out T decl) where T : Declaration
@ -154,6 +147,39 @@
} }
return t; 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;
} }
} }
} }

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

@ -615,16 +615,19 @@ namespace CppSharp.Generators.CLI
public void GenerateIndexer(Property property) public void GenerateIndexer(Property property)
{ {
var type = property.QualifiedType.Visit(TypePrinter); 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(); WriteStartBraceIndent();
if (property.HasGetter) if (property.HasGetter)
WriteLine("{0} get(int index);", type); WriteLine("{0} get({1} {2});", type, indexParameterType, indexParameter.Name);
if (property.HasSetter) if (property.HasSetter)
WriteLine("void set(int index, {0});", type); WriteLine("void set({1} {2}, {0} value);", type, indexParameterType, indexParameter.Name);
WriteCloseBraceIndent(); WriteCloseBraceIndent();
} }
@ -635,7 +638,10 @@ namespace CppSharp.Generators.CLI
return; return;
PushBlock(CLIBlockKind.Property, property); PushBlock(CLIBlockKind.Property, property);
var type = property.QualifiedType.Visit(TypePrinter); var type = property.QualifiedType.Visit(TypePrinter);
if (property.IsStatic)
Write("static ");
if (property.IsIndexer) if (property.IsIndexer)
{ {

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

@ -90,12 +90,16 @@ namespace CppSharp.Generators.CLI
} }
if (pointee.IsPrimitiveType(out primitive)) 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) if (pointer.Pointee is TypedefType)
Context.Return.Write("reinterpret_cast<{0}>({1})", pointer, Context.Return.Write("reinterpret_cast<{0}>({1})", pointer,
Context.ReturnVarName); returnVarName);
else else
Context.Return.Write(Context.ReturnVarName); Context.Return.Write(returnVarName);
return true; return true;
} }
@ -436,10 +440,10 @@ namespace CppSharp.Generators.CLI
if (Context.Function == null) if (Context.Function == null)
Context.Return.Write("&"); Context.Return.Write("&");
return pointee.Visit(this, quals); return pointee.Visit(this, quals);
} }
PrimitiveType primitive; var finalPointee = pointer.GetFinalPointee();
if (pointee.IsPrimitiveType(out primitive)) if (finalPointee.IsPrimitiveType())
{ {
var cppTypePrinter = new CppTypePrinter(Context.Driver.TypeDatabase); var cppTypePrinter = new CppTypePrinter(Context.Driver.TypeDatabase);
var cppTypeName = pointer.Visit(cppTypePrinter, quals); var cppTypeName = pointer.Visit(cppTypePrinter, quals);
@ -506,7 +510,7 @@ namespace CppSharp.Generators.CLI
} }
PrimitiveType primitive; PrimitiveType primitive;
if (decl.Type.Desugar().IsPrimitiveType(out primitive)) if (decl.Type.IsPrimitiveType(out primitive))
{ {
Context.Return.Write("(::{0})", typedef.Declaration.QualifiedOriginalName); Context.Return.Write("(::{0})", typedef.Declaration.QualifiedOriginalName);
} }

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

@ -329,36 +329,37 @@ namespace CppSharp.Generators.CLI
GeneratePropertyGetter(property.GetMethod, realOwner, property.Name, GeneratePropertyGetter(property.GetMethod, realOwner, property.Name,
property.Type); property.Type);
if (property.HasSetter) if (property.HasSetter)
GeneratePropertySetter(property.SetMethod, realOwner, property.Name, if (property.IsIndexer)
property.Type); GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type, property.GetMethod.Parameters[0]);
else
GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type);
} }
PopBlock(); 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 where T : Declaration, ITypedDecl
{ {
if (decl == null) if (decl == null)
return; return;
var method = decl as Method; var args = new List<string>();
var isIndexer = method != null && var isIndexer = indexParameter != null;
method.OperatorKind == CXXOperatorKind.Subscript; if (isIndexer)
args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name));
var args = new List<string>();
if (isIndexer)
args.Add("int index");
var function = decl as Function; 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)); args.Add(string.Format("{0} {1}", type, argName));
WriteLine("void {0}::{1}::set({2})", QualifiedIdentifier(@class), WriteLine("void {0}::{1}::set({2})", QualifiedIdentifier(@class),
name, string.Join(", ", args)); name, string.Join(", ", args));
WriteStartBraceIndent(); WriteStartBraceIndent();
if (decl is Function && !isIndexer) if (decl is Function && !isIndexer)
{ {
var func = decl as Function; var func = decl as Function;
@ -397,7 +398,7 @@ namespace CppSharp.Generators.CLI
@class.QualifiedOriginalName, decl.OriginalName); @class.QualifiedOriginalName, decl.OriginalName);
if (isIndexer) if (isIndexer)
variable += "(index)"; variable += string.Format("({0})", indexParameter.Name);
if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore))
Write(marshal.Context.SupportBefore); Write(marshal.Context.SupportBefore);
@ -419,9 +420,12 @@ namespace CppSharp.Generators.CLI
var isIndexer = method != null && var isIndexer = method != null &&
method.OperatorKind == CXXOperatorKind.Subscript; method.OperatorKind == CXXOperatorKind.Subscript;
var args = new List<string>(); var args = new List<string>();
if (isIndexer) 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), WriteLine("{0} {1}::{2}::get({3})", type, QualifiedIdentifier(@class),
name, string.Join(", ", args)); name, string.Join(", ", args));
@ -966,7 +970,7 @@ namespace CppSharp.Generators.CLI
if (Driver.Options.MarshalCharAsManagedChar) if (Driver.Options.MarshalCharAsManagedChar)
{ {
foreach (var param in method.Parameters.Where( 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); WriteLine("if ({0} < System::Char::MinValue || {0} > System::SByte::MaxValue)", param.Name);
WriteLineIndent( WriteLineIndent(

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

@ -1,386 +1,394 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.AST.Extensions; using CppSharp.AST.Extensions;
using CppSharp.Types; using CppSharp.Types;
using Type = CppSharp.AST.Type; using Type = CppSharp.AST.Type;
namespace CppSharp.Generators.CLI namespace CppSharp.Generators.CLI
{ {
public class CLITypePrinterContext : TypePrinterContext public class CLITypePrinterContext : TypePrinterContext
{ {
public CLITypePrinterContext() public CLITypePrinterContext()
{ {
} }
public CLITypePrinterContext(TypePrinterContextKind kind) public CLITypePrinterContext(TypePrinterContextKind kind)
: base(kind) : base(kind)
{ {
} }
} }
public class CLITypePrinter : ITypePrinter<string>, IDeclVisitor<string> public class CLITypePrinter : ITypePrinter<string>, IDeclVisitor<string>
{ {
public Driver Driver { get; set; } public Driver Driver { get; set; }
public CLITypePrinterContext Context { get; set; } public CLITypePrinterContext Context { get; set; }
readonly ITypeMapDatabase TypeMapDatabase; readonly ITypeMapDatabase TypeMapDatabase;
readonly DriverOptions Options; readonly DriverOptions Options;
public CLITypePrinter(Driver driver) public CLITypePrinter(Driver driver)
{ {
Driver = driver; Driver = driver;
TypeMapDatabase = driver.TypeDatabase; TypeMapDatabase = driver.TypeDatabase;
Options = driver.Options; Options = driver.Options;
Context = new CLITypePrinterContext(); Context = new CLITypePrinterContext();
} }
public CLITypePrinter(Driver driver, CLITypePrinterContext context) public CLITypePrinter(Driver driver, CLITypePrinterContext context)
: this(driver) : this(driver)
{ {
Context = context; Context = context;
} }
public string VisitTagType(TagType tag, TypeQualifiers quals) public string VisitTagType(TagType tag, TypeQualifiers quals)
{ {
TypeMap typeMap = null; TypeMap typeMap = null;
if (TypeMapDatabase.FindTypeMap(tag, out typeMap)) if (TypeMapDatabase.FindTypeMap(tag, out typeMap))
{ {
typeMap.Type = tag; typeMap.Type = tag;
Context.Type = tag; Context.Type = tag;
return typeMap.CLISignature(Context); return typeMap.CLISignature(Context);
} }
Declaration decl = tag.Declaration; Declaration decl = tag.Declaration;
if (decl == null) if (decl == null)
return string.Empty; return string.Empty;
return VisitDeclaration(decl, quals); return VisitDeclaration(decl, quals);
} }
public string VisitArrayType(ArrayType array, TypeQualifiers quals) public string VisitArrayType(ArrayType array, TypeQualifiers quals)
{ {
return string.Format("cli::array<{0}>^", array.Type.Visit(this)); return string.Format("cli::array<{0}>^", array.Type.Visit(this));
} }
public string VisitFunctionType(FunctionType function, TypeQualifiers quals) public string VisitFunctionType(FunctionType function, TypeQualifiers quals)
{ {
var arguments = function.Parameters; var arguments = function.Parameters;
var returnType = function.ReturnType; var returnType = function.ReturnType;
var args = string.Empty; var args = string.Empty;
if (arguments.Count > 0) if (arguments.Count > 0)
args = VisitParameters(function.Parameters, hasNames: false); args = VisitParameters(function.Parameters, hasNames: false);
if (returnType.Type.IsPrimitiveType(PrimitiveType.Void)) if (returnType.Type.IsPrimitiveType(PrimitiveType.Void))
{ {
if (!string.IsNullOrEmpty(args)) if (!string.IsNullOrEmpty(args))
args = string.Format("<{0}>", args); args = string.Format("<{0}>", args);
return string.Format("System::Action{0}", args); return string.Format("System::Action{0}", args);
} }
if (!string.IsNullOrEmpty(args)) if (!string.IsNullOrEmpty(args))
args = string.Format(", {0}", args); args = string.Format(", {0}", args);
return string.Format("System::Func<{0}{1}>", returnType.Visit(this), args); return string.Format("System::Func<{0}{1}>", returnType.Visit(this), args);
} }
public string VisitParameters(IEnumerable<Parameter> @params, public string VisitParameters(IEnumerable<Parameter> @params,
bool hasNames) bool hasNames)
{ {
var args = new List<string>(); var args = new List<string>();
foreach (var param in @params) foreach (var param in @params)
args.Add(VisitParameter(param, hasNames)); args.Add(VisitParameter(param, hasNames));
return string.Join(", ", args); return string.Join(", ", args);
} }
public string VisitParameter(Parameter param, bool hasName = true) public string VisitParameter(Parameter param, bool hasName = true)
{ {
Context.Parameter = param; Context.Parameter = param;
var type = param.Type.Visit(this, param.QualifiedType.Qualifiers); var type = param.Type.Visit(this, param.QualifiedType.Qualifiers);
Context.Parameter = null; Context.Parameter = null;
var str = string.Empty; var str = string.Empty;
if(param.Usage == ParameterUsage.Out) if(param.Usage == ParameterUsage.Out)
str += "[System::Runtime::InteropServices::Out] "; str += "[System::Runtime::InteropServices::Out] ";
str += type; str += type;
if(param.Usage == ParameterUsage.Out || if(param.Usage == ParameterUsage.Out ||
param.Usage == ParameterUsage.InOut) param.Usage == ParameterUsage.InOut)
str += "%"; str += "%";
if (hasName && !string.IsNullOrEmpty(param.Name)) if (hasName && !string.IsNullOrEmpty(param.Name))
str += " " + param.Name; str += " " + param.Name;
return str; return str;
} }
public string VisitDelegate(FunctionType function) public string VisitDelegate(FunctionType function)
{ {
return string.Format("delegate {0} {{0}}({1})", return string.Format("delegate {0} {{0}}({1})",
function.ReturnType.Visit(this), function.ReturnType.Visit(this),
VisitParameters(function.Parameters, hasNames: true)); VisitParameters(function.Parameters, hasNames: true));
} }
public string VisitPointerType(PointerType pointer, TypeQualifiers quals) public string VisitPointerType(PointerType pointer, TypeQualifiers quals)
{ {
var pointee = pointer.Pointee.Desugar(); var pointee = pointer.Pointee.Desugar();
if (pointee is FunctionType) if (pointee is FunctionType)
{ {
var function = pointee as FunctionType; var function = pointee as FunctionType;
return string.Format("{0}^", function.Visit(this, quals)); return string.Format("{0}^", function.Visit(this, quals));
} }
if (pointee.IsPrimitiveType(PrimitiveType.Char) && quals.IsConst) if (pointee.IsPrimitiveType(PrimitiveType.Char) && quals.IsConst)
{ {
return "System::String^"; return "System::String^";
} }
PrimitiveType primitive; // From http://msdn.microsoft.com/en-us/library/y31yhkeb.aspx
if (pointee.IsPrimitiveType(out primitive)) // Any of the following types may be a pointer type:
{ // * sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
var param = Context.Parameter; // * Any enum type.
if (param != null && (param.IsOut || param.IsInOut)) // * Any pointer type.
return VisitPrimitiveType(primitive); // * Any user-defined struct type that contains fields of unmanaged types only.
var finalPointee = pointer.GetFinalPointee();
return VisitPrimitiveType(primitive, quals) + "*"; if (finalPointee.IsPrimitiveType())
} {
// Skip one indirection if passed by reference
Enumeration @enum; var param = Context.Parameter;
if (pointee.IsTagDecl(out @enum)) if (param != null && (param.IsOut || param.IsInOut)
{ && pointee == finalPointee)
var typeName = @enum.Visit(this); return pointee.Visit(this, quals);
return string.Format("{0}*", typeName);
} return pointee.Visit(this, quals) + "*";
}
return pointee.Visit(this, quals);
} Enumeration @enum;
if (pointee.IsTagDecl(out @enum))
public string VisitMemberPointerType(MemberPointerType member, {
TypeQualifiers quals) var typeName = @enum.Visit(this);
{ return string.Format("{0}*", typeName);
throw new NotImplementedException(); }
}
return pointee.Visit(this, quals);
public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals) }
{
return VisitPrimitiveType(builtin.Type); public string VisitMemberPointerType(MemberPointerType member,
} TypeQualifiers quals)
{
public string VisitPrimitiveType(PrimitiveType primitive) throw new NotImplementedException();
{ }
switch (primitive)
{ public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
case PrimitiveType.Bool: return "bool"; {
case PrimitiveType.Void: return "void"; return VisitPrimitiveType(builtin.Type);
case PrimitiveType.Char16: }
case PrimitiveType.WideChar: return "System::Char";
case PrimitiveType.Int8: return Options.MarshalCharAsManagedChar ? "System::Char" : "char"; public string VisitPrimitiveType(PrimitiveType primitive)
case PrimitiveType.UInt8: return "unsigned char"; {
case PrimitiveType.Int16: return "short"; switch (primitive)
case PrimitiveType.UInt16: return "unsigned short"; {
case PrimitiveType.Int32: return "int"; case PrimitiveType.Bool: return "bool";
case PrimitiveType.UInt32: return "unsigned int"; case PrimitiveType.Void: return "void";
case PrimitiveType.Int64: return "long long"; case PrimitiveType.Char16:
case PrimitiveType.UInt64: return "unsigned long long"; case PrimitiveType.WideChar: return "System::Char";
case PrimitiveType.Float: return "float"; case PrimitiveType.Int8: return Options.MarshalCharAsManagedChar ? "System::Char" : "char";
case PrimitiveType.Double: return "double"; case PrimitiveType.UInt8: return "unsigned char";
case PrimitiveType.IntPtr: return "IntPtr"; case PrimitiveType.Int16: return "short";
case PrimitiveType.UIntPtr: return "UIntPtr"; case PrimitiveType.UInt16: return "unsigned short";
} case PrimitiveType.Int32: return "int";
case PrimitiveType.UInt32: return "unsigned int";
throw new NotSupportedException(); case PrimitiveType.Int64: return "long long";
} case PrimitiveType.UInt64: return "unsigned long long";
case PrimitiveType.Float: return "float";
public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals) case PrimitiveType.Double: return "double";
{ case PrimitiveType.IntPtr: return "IntPtr";
var decl = typedef.Declaration; case PrimitiveType.UIntPtr: return "UIntPtr";
}
TypeMap typeMap = null;
if (TypeMapDatabase.FindTypeMap(decl, out typeMap)) throw new NotSupportedException();
{ }
typeMap.Type = typedef;
Context.Type = typedef; public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
return typeMap.CLISignature(Context); {
} var decl = typedef.Declaration;
FunctionType func; TypeMap typeMap = null;
if (decl.Type.IsPointerTo<FunctionType>(out func)) if (TypeMapDatabase.FindTypeMap(decl, out typeMap))
{ {
// TODO: Use SafeIdentifier() typeMap.Type = typedef;
return string.Format("{0}^", VisitDeclaration(decl)); Context.Type = typedef;
} return typeMap.CLISignature(Context);
}
return decl.Type.Visit(this);
} FunctionType func;
if (decl.Type.IsPointerTo<FunctionType>(out func))
public string VisitAttributedType(AttributedType attributed, TypeQualifiers quals) {
{ // TODO: Use SafeIdentifier()
return attributed.Modified.Visit(this); return string.Format("{0}^", VisitDeclaration(decl));
} }
public string VisitDecayedType(DecayedType decayed, TypeQualifiers quals) return decl.Type.Visit(this);
{ }
return decayed.Decayed.Visit(this);
} public string VisitAttributedType(AttributedType attributed, TypeQualifiers quals)
{
public string VisitTemplateSpecializationType(TemplateSpecializationType template, return attributed.Modified.Visit(this);
TypeQualifiers quals) }
{
var decl = template.Template.TemplatedDecl; public string VisitDecayedType(DecayedType decayed, TypeQualifiers quals)
{
TypeMap typeMap = null; return decayed.Decayed.Visit(this);
if (TypeMapDatabase.FindTypeMap(template, out typeMap)) }
{
typeMap.Declaration = decl; public string VisitTemplateSpecializationType(TemplateSpecializationType template,
typeMap.Type = template; TypeQualifiers quals)
Context.Type = template; {
return typeMap.CLISignature(Context); var decl = template.Template.TemplatedDecl;
}
TypeMap typeMap = null;
return decl.Name; if (TypeMapDatabase.FindTypeMap(template, out typeMap))
} {
typeMap.Declaration = decl;
public string VisitTemplateParameterType(TemplateParameterType param, typeMap.Type = template;
TypeQualifiers quals) Context.Type = template;
{ return typeMap.CLISignature(Context);
return param.Parameter.Name; }
}
return decl.Name;
public string VisitTemplateParameterSubstitutionType( }
TemplateParameterSubstitutionType param, TypeQualifiers quals)
{ public string VisitTemplateParameterType(TemplateParameterType param,
throw new NotImplementedException(); TypeQualifiers quals)
} {
return param.Parameter.Name;
public string VisitInjectedClassNameType(InjectedClassNameType injected, TypeQualifiers quals) }
{
throw new NotImplementedException(); public string VisitTemplateParameterSubstitutionType(
} TemplateParameterSubstitutionType param, TypeQualifiers quals)
{
public string VisitDependentNameType(DependentNameType dependent, TypeQualifiers quals) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitInjectedClassNameType(InjectedClassNameType injected, TypeQualifiers quals)
{
public string VisitPackExpansionType(PackExpansionType packExpansionType, TypeQualifiers quals) throw new NotImplementedException();
{ }
return string.Empty;
} public string VisitDependentNameType(DependentNameType dependent, TypeQualifiers quals)
{
public string VisitCILType(CILType type, TypeQualifiers quals) throw new NotImplementedException();
{ }
return type.Type.FullName.Replace(".", "::") + "^";
} public string VisitPackExpansionType(PackExpansionType packExpansionType, TypeQualifiers quals)
{
public string VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals) return string.Empty;
{ }
return VisitPrimitiveType(type);
} public string VisitCILType(CILType type, TypeQualifiers quals)
{
public string VisitDeclaration(Declaration decl, TypeQualifiers quals) return type.Type.FullName.Replace(".", "::") + "^";
{ }
return VisitDeclaration(decl);
} public string VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals)
{
public string VisitDeclaration(Declaration decl) return VisitPrimitiveType(type);
{ }
var names = new List<string>();
public string VisitDeclaration(Declaration decl, TypeQualifiers quals)
if (Options.GenerateLibraryNamespace) {
names.Add(Driver.Options.OutputNamespace); return VisitDeclaration(decl);
}
if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName))
names.Add(decl.Namespace.QualifiedName); public string VisitDeclaration(Declaration decl)
{
names.Add(decl.Visit(this)); var names = new List<string>();
return string.Join("::", names); if (Options.GenerateLibraryNamespace)
} names.Add(Driver.Options.OutputNamespace);
public string VisitClassDecl(Class @class) if (!string.IsNullOrEmpty(decl.Namespace.QualifiedName))
{ names.Add(decl.Namespace.QualifiedName);
if (@class.CompleteDeclaration != null)
return VisitClassDecl(@class.CompleteDeclaration as Class); names.Add(decl.Visit(this));
return string.Format("{0}{1}", @class.Name, @class.IsRefType ? "^" return string.Join("::", names);
: string.Empty); }
}
public string VisitClassDecl(Class @class)
public string VisitFieldDecl(Field field) {
{ if (@class.CompleteDeclaration != null)
throw new NotImplementedException(); return VisitClassDecl(@class.CompleteDeclaration as Class);
}
return string.Format("{0}{1}", @class.Name, @class.IsRefType ? "^"
public string VisitFunctionDecl(Function function) : string.Empty);
{ }
throw new NotImplementedException();
} public string VisitFieldDecl(Field field)
{
public string VisitMethodDecl(Method method) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitFunctionDecl(Function function)
{
public string VisitParameterDecl(Parameter parameter) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitMethodDecl(Method method)
{
public string VisitTypedefDecl(TypedefDecl typedef) throw new NotImplementedException();
{ }
return typedef.Name;
} public string VisitParameterDecl(Parameter parameter)
{
public string VisitEnumDecl(Enumeration @enum) throw new NotImplementedException();
{ }
return @enum.Name;
} public string VisitTypedefDecl(TypedefDecl typedef)
{
public string VisitVariableDecl(Variable variable) return typedef.Name;
{ }
throw new NotImplementedException();
} public string VisitEnumDecl(Enumeration @enum)
{
public string VisitClassTemplateDecl(ClassTemplate template) return @enum.Name;
{ }
throw new NotImplementedException();
} public string VisitVariableDecl(Variable variable)
{
public string VisitFunctionTemplateDecl(FunctionTemplate template) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitClassTemplateDecl(ClassTemplate template)
{
public string VisitMacroDefinition(MacroDefinition macro) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitFunctionTemplateDecl(FunctionTemplate template)
{
public string VisitNamespace(Namespace @namespace) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitMacroDefinition(MacroDefinition macro)
{
public string VisitEvent(Event @event) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitNamespace(Namespace @namespace)
{
public string VisitProperty(Property property) throw new NotImplementedException();
{ }
throw new NotImplementedException();
} public string VisitEvent(Event @event)
{
public string ToString(Type type) throw new NotImplementedException();
{ }
return type.Visit(this);
} public string VisitProperty(Property property)
} {
} throw new NotImplementedException();
}
public string ToString(Type type)
{
return type.Visit(this);
}
}
}

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

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

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

@ -208,18 +208,27 @@ namespace CppSharp.Generators.CSharp
if (IsConstCharString(pointer)) if (IsConstCharString(pointer))
return isManagedContext ? "string" : "global::System.IntPtr"; return isManagedContext ? "string" : "global::System.IntPtr";
PrimitiveType primitive;
var desugared = pointee.Desugar(); var desugared = pointee.Desugar();
if (desugared.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())
{ {
if (isManagedContext && Context.Parameter != null && // Skip one indirection if passed by reference
(Context.Parameter.IsOut || Context.Parameter.IsInOut)) var param = Context.Parameter;
return VisitPrimitiveType(primitive, quals); if (isManagedContext && param != null && (param.IsOut || param.IsInOut)
&& pointee == finalPointee)
return pointee.Visit(this, quals);
if (ContextKind == CSharpTypePrinterContextKind.GenericDelegate) if (ContextKind == CSharpTypePrinterContextKind.GenericDelegate)
return "global::System.IntPtr"; return "global::System.IntPtr";
return VisitPrimitiveType(primitive, quals) + "*"; return pointee.Visit(this, quals) + "*";
} }
Enumeration @enum; Enumeration @enum;

2
src/Generator/Passes/CheckIgnoredDecls.cs

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

16
src/Generator/Passes/CheckOperatorsOverloads.cs

@ -100,14 +100,18 @@ namespace CppSharp.Passes
if (!@operator.ReturnType.Qualifiers.IsConst && @operator.ReturnType.Type.IsAddress()) if (!@operator.ReturnType.Qualifiers.IsConst && @operator.ReturnType.Type.IsAddress())
property.SetMethod = @operator; property.SetMethod = @operator;
// C++/CLI uses "default" as the indexer property name.
if (Driver.Options.IsCLIGenerator) 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.Name = "default";
}
property.GetMethod.Parameters[0].Name = "index";
if (property.SetMethod != null)
property.SetMethod.Parameters[0].Name = "index";
property.Parameters.AddRange(@operator.Parameters); property.Parameters.AddRange(@operator.Parameters);

11
src/Generator/Types/Types.cs

@ -127,6 +127,17 @@ namespace CppSharp
Ignore(); Ignore();
return base.VisitTemplateSpecializationType(template, quals); 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);
} }
} }

24
tests/Basic/Basic.Tests.cs

@ -22,7 +22,17 @@ public class BasicTests : GeneratorTestFixture
Assert.That(hello.AddFoo(foo), Is.EqualTo(11)); Assert.That(hello.AddFoo(foo), Is.EqualTo(11));
Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11)); Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11));
Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11)); Assert.That(hello.AddFooPtr(foo), Is.EqualTo(11));
Assert.That(hello.AddFooRef(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 }; var bar = new Bar { A = 4, B = 7 };
Assert.That(hello.AddBar(bar), Is.EqualTo(11)); Assert.That(hello.AddBar(bar), Is.EqualTo(11));
@ -166,6 +176,13 @@ 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);
}
[Test]
public void TestAttributedDelegate()
{
var result = basic.AttributedDelegate(2);
Assert.AreEqual(4, result);
} }
[Test] [Test]
@ -223,7 +240,10 @@ public class BasicTests : GeneratorTestFixture
public unsafe void TestIndexers() public unsafe void TestIndexers()
{ {
var someStruct = new SomeStruct(); var someStruct = new SomeStruct();
Assert.That(someStruct[0], Is.EqualTo(1)); 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] [Test]

5
tests/Basic/Basic.cpp

@ -2,6 +2,11 @@
Foo::Foo() 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() const char* Foo::GetANSI()

27
tests/Basic/Basic.h

@ -18,7 +18,11 @@ public:
// TODO: VC++ does not support char16 // TODO: VC++ does not support char16
// char16 chr16; // char16 chr16;
float nested_array[2][2]; // Not properly handled yet - ignore
float nested_array[2][2];
// Primitive pointer types
const int* SomePointer;
const int** SomePointerPointer;
}; };
struct DLL_API Bar struct DLL_API Bar
@ -243,14 +247,26 @@ typedef int (*DelegateInGlobalNamespace)(int);
struct DLL_API TestDelegates struct DLL_API TestDelegates
{ {
typedef int (*DelegateInClass)(int); 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; } static int Double(int N) { return N * 2; }
int Triple(int N) { return N * 3; }
DelegateInClass A; DelegateInClass A;
DelegateInGlobalNamespace B; 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 // Tests memory leaks in constructors
// C#: Marshal.FreeHGlobal(arg0); // C#: Marshal.FreeHGlobal(arg0);
struct DLL_API TestMemoryLeaks struct DLL_API TestMemoryLeaks
@ -307,8 +323,9 @@ typedef unsigned long foo_t;
typedef struct DLL_API SomeStruct typedef struct DLL_API SomeStruct
{ {
SomeStruct() : p(1) {} 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; foo_t p;
} }
SomeStruct; SomeStruct;
@ -368,4 +385,4 @@ struct DLL_API TestGetterSetterToProperties
{ {
int getWidth() { return 640; } int getWidth() { return 640; }
int getHeight() { return 480; } int getHeight() { return 480; }
}; };

Loading…
Cancel
Save