diff --git a/src/AST/TypeExtensions.cs b/src/AST/TypeExtensions.cs index 3db0bbf1..72ef07f2 100644 --- a/src/AST/TypeExtensions.cs +++ b/src/AST/TypeExtensions.cs @@ -349,8 +349,10 @@ public static bool IsConstRefToPrimitive(this QualifiedType type) { Type desugared = type.Type.Desugar(); + Type pointee = desugared.GetFinalPointee().Desugar(); + pointee = (pointee.GetFinalPointee() ?? pointee).Desugar(); return desugared.IsReference() && - desugared.GetFinalPointee().Desugar().IsPrimitiveType() && type.IsConst(); + (pointee.IsPrimitiveType() || pointee.IsEnum()) && type.IsConst(); } private static bool IsConst(this QualifiedType type) diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 7a8ae0cb..2e464b6e 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -153,7 +153,7 @@ namespace CppSharp.Generators.CSharp if (isRefParam) { - Context.Return.Write("_{0}", param.Name); + Context.Return.Write(Generator.GeneratedIdentifier(param.Name)); return true; } @@ -172,9 +172,11 @@ namespace CppSharp.Generators.CSharp } else { - var templateParameter = type as TemplateParameterType; - if (templateParameter != null) - Context.Return.Write($"({templateParameter.Parameter.Name}) (object) *"); + var substitution = pointer.Pointee.Desugar( + resolveTemplateSubstitution: false) as TemplateParameterSubstitutionType; + if (substitution != null) + Context.Return.Write($@"({ + substitution.ReplacedParameter.Parameter.Name}) (object) *"); } } @@ -492,49 +494,6 @@ namespace CppSharp.Generators.CSharp if (!VisitType(pointer, quals)) return false; - var qualifiedPointer = new QualifiedType(pointer, quals); - - var templateSubstitution = pointer.Pointee as TemplateParameterSubstitutionType; - PointerType realPointer = null; - if (templateSubstitution != null) - realPointer = templateSubstitution.Replacement.Type.Desugar() as PointerType; - realPointer = realPointer ?? pointer; - if (Context.Function != null && - (realPointer.IsPrimitiveTypeConvertibleToRef() || - (templateSubstitution != null && realPointer.Pointee.IsEnumType())) && - Context.MarshalKind != MarshalKind.VTableReturnValue) - { - var refParamPtr = $"__refParamPtr{Context.ParameterIndex}"; - if (templateSubstitution != null) - { - var castParam = $"__{Context.Parameter.Name}{Context.ParameterIndex}"; - Context.Before.Write($"var {castParam} = ({templateSubstitution}) "); - if (realPointer != pointer) - Context.Before.Write($"({CSharpTypePrinter.IntPtrType}) "); - Context.Before.WriteLine($"(object) {Context.Parameter.Name};"); - Context.Before.WriteLine($"var {refParamPtr} = &{castParam};"); - Context.Return.Write(refParamPtr); - return true; - } - if (Context.Function.OperatorKind != CXXOperatorKind.Subscript) - { - if (Context.Parameter.Kind == ParameterKind.PropertyValue || - qualifiedPointer.IsConstRefToPrimitive()) - { - Context.Return.Write($"&{Context.Parameter.Name}"); - } - else - { - Context.Before.WriteLine( - $"fixed ({realPointer} {refParamPtr} = &{Context.Parameter.Name})"); - Context.HasCodeBlock = true; - Context.Before.WriteOpenBraceAndIndent(); - Context.Return.Write(refParamPtr); - } - return true; - } - } - var param = Context.Parameter; var isRefParam = param != null && (param.IsInOut || param.IsOut); @@ -543,23 +502,69 @@ namespace CppSharp.Generators.CSharp { if (param.IsOut) { + MarshalString(pointee); Context.Return.Write("IntPtr.Zero"); Context.ArgumentPrefix.Write("&"); return true; } - pointer.QualifiedPointee.Visit(this); if (param.IsInOut) + { + MarshalString(pointee); + pointer.QualifiedPointee.Visit(this); Context.ArgumentPrefix.Write("&"); + } else - Context.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Context.ArgName); + { + pointer.QualifiedPointee.Visit(this); + Context.Cleanup.WriteLine($"Marshal.FreeHGlobal({Context.ArgName});"); + } return true; } - if (pointee is FunctionType) - return VisitDelegateType(); + var finalPointee = (pointee.GetFinalPointee() ?? pointee).Desugar(); + if (finalPointee.IsPrimitiveType(out PrimitiveType primitive) || + finalPointee.IsEnumType()) + { + if (isRefParam) + { + var local = Generator.GeneratedIdentifier($@"{ + param.Name}{Context.ParameterIndex}"); + Context.Before.WriteLine($@"fixed ({ + pointer.Visit(typePrinter)} {local} = &{param.Name})"); + Context.HasCodeBlock = true; + Context.Before.WriteOpenBraceAndIndent(); + Context.Return.Write(local); + return true; + } - Class @class; - if (pointee.TryGetClass(out @class) && @class.IsValueType) + if (Context.Context.Options.MarshalCharAsManagedChar && + primitive == PrimitiveType.Char) + { + Context.Return.Write($"({typePrinter.PrintNative(pointer)}) "); + Context.Return.Write(param.Name); + return true; + } + + pointer.QualifiedPointee.Visit(this); + bool isVoid = primitive == PrimitiveType.Void && pointee.IsAddress(); + if (pointer.Pointee.Desugar(false) is TemplateParameterSubstitutionType || + isVoid) + { + var local = Generator.GeneratedIdentifier($@"{ + param.Name}{Context.ParameterIndex}"); + string cast = isVoid ? $@"({pointee.Visit( + new CppTypePrinter { PrintTypeQualifiers = false })}) " : string.Empty; + Context.Before.WriteLine($"var {local} = {cast}{Context.Return};"); + Context.Return.StringBuilder.Clear(); + Context.Return.Write(local); + } + if (new QualifiedType(pointer, quals).IsConstRefToPrimitive()) + Context.Return.StringBuilder.Insert(0, '&'); + + return true; + } + + if (pointee.TryGetClass(out Class @class) && @class.IsValueType) { if (Context.Parameter.Usage == ParameterUsage.Out) { @@ -581,54 +586,6 @@ namespace CppSharp.Generators.CSharp return true; } - var finalPointee = pointer.GetFinalPointee(); - PrimitiveType primitive; - 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 - // and then assign this value to the parameter. - - if (isRefParam) - { - var typeName = Type.TypePrinterDelegate(finalPointee); - if (Context.Function.OperatorKind == CXXOperatorKind.Subscript) - Context.Return.Write(param.Name); - else - { - if (param.IsInOut) - Context.Before.WriteLine($"{typeName} _{param.Name} = {param.Name};"); - else - Context.Before.WriteLine($"{typeName} _{param.Name};"); - - Context.Return.Write($"&_{param.Name}"); - } - } - else - { - if (Context.Context.Options.MarshalCharAsManagedChar && - primitive == PrimitiveType.Char) - Context.Return.Write($"({typePrinter.PrintNative(pointer)}) "); - - if (qualifiedPointer.IsConstRefToPrimitive()) - { - if (primitive == PrimitiveType.Void && pointee.IsAddress()) - { - string ptr = $@"{Helpers.PtrIdentifier}{ - Context.ParameterIndex}"; - Context.Before.WriteLine($@"var {ptr} = { - Context.Parameter.Name}.ToPointer();"); - Context.Return.Write($"&{ptr}"); - return true; - } - Context.Return.Write("&"); - } - Context.Return.Write(Context.Parameter.Name); - } - - return true; - } - return pointer.QualifiedPointee.Visit(this); } @@ -636,8 +593,6 @@ namespace CppSharp.Generators.CSharp { switch (primitive) { - case PrimitiveType.Void: - return true; case PrimitiveType.Bool: if (Context.MarshalKind == MarshalKind.NativeField) { @@ -657,24 +612,21 @@ namespace CppSharp.Generators.CSharp if (!VisitType(typedef, quals)) return false; - var decl = typedef.Declaration; - - FunctionType func; - if (decl.Type.IsPointerTo(out func)) - { - VisitDelegateType(); - return true; - } - - return decl.Type.Visit(this); + return typedef.Declaration.Type.Visit(this); } public override bool VisitTemplateParameterSubstitutionType(TemplateParameterSubstitutionType param, TypeQualifiers quals) { var replacement = param.Replacement.Type.Desugar(); - Class @class; - if (!replacement.IsAddress() && !replacement.TryGetClass(out @class)) - Context.Return.Write($"({replacement}) (object) "); + if (replacement.IsPrimitiveType() || + replacement.IsPointerToPrimitiveType() || + replacement.IsEnum()) + { + Context.Return.Write($"({replacement}) "); + if (replacement.IsPointerToPrimitiveType()) + Context.Return.Write($"({CSharpTypePrinter.IntPtrType}) "); + Context.Return.Write("(object) "); + } return base.VisitTemplateParameterSubstitutionType(param, quals); } @@ -811,18 +763,18 @@ namespace CppSharp.Generators.CSharp return VisitClassDecl(template.TemplatedClass); } - public override bool VisitFunctionTemplateDecl(FunctionTemplate template) - { - return template.TemplatedFunction.Visit(this); - } - - private bool VisitDelegateType() + public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals) { Context.Return.Write("{0} == null ? global::System.IntPtr.Zero : Marshal.GetFunctionPointerForDelegate({0})", Context.Parameter.Name); return true; } + public override bool VisitFunctionTemplateDecl(FunctionTemplate template) + { + return template.TemplatedFunction.Visit(this); + } + private void ThrowArgumentOutOfRangeException() { Context.Before.WriteLineIndent( @@ -883,6 +835,17 @@ namespace CppSharp.Generators.CSharp Context.Return.Write(intermediateArray); } + private void MarshalString(Type pointee) + { + var marshal = new CSharpMarshalNativeToManagedPrinter(Context); + Context.ReturnVarName = Context.ArgName; + Context.ReturnType = Context.Parameter.QualifiedType; + pointee.Visit(marshal); + Context.Cleanup.WriteLine($@"{Context.Parameter.Name} = { + marshal.Context.Return};"); + Context.Return.StringBuilder.Clear(); + } + private readonly CSharpTypePrinter typePrinter; } } diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 805d3c7d..7f80228c 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -859,9 +859,6 @@ namespace CppSharp.Generators.CSharp Kind = ParameterKind.PropertyValue }; - if (!property.Type.Equals(param.Type) && property.Type.IsEnumType()) - param.Name = "&" + param.Name; - var parameters = new List { param }; var @void = new QualifiedType(new BuiltinType(PrimitiveType.Void)); if (property.SetMethod.SynthKind == FunctionSynthKind.AbstractImplCall) @@ -2843,20 +2840,9 @@ namespace CppSharp.Generators.CSharp } WriteLine("{0}({1});", functionName, string.Join(", ", names)); - var cleanups = new List(); - GenerateFunctionCallOutParams(@params, cleanups); - - cleanups.AddRange( - from param in @params - select param.Context - into context - where context != null && !string.IsNullOrWhiteSpace(context.Cleanup) - select context.Cleanup); - - foreach (var cleanup in cleanups) - { + foreach (TextGenerator cleanup in from p in @params + select p.Context.Cleanup) Write(cleanup); - } if (needsReturn) { @@ -2939,39 +2925,6 @@ namespace CppSharp.Generators.CSharp return indirectReturnTypeIndex >= 0 ? ++indirectReturnTypeIndex : 0; } - private void GenerateFunctionCallOutParams(IEnumerable @params, - ICollection cleanups) - { - foreach (var paramInfo in @params) - { - var param = paramInfo.Param; - if (!(param.IsOut || param.IsInOut)) continue; - if (param.Type.Desugar().IsPrimitiveTypeConvertibleToRef()) - continue; - - var nativeVarName = paramInfo.Name; - - var ctx = new CSharpMarshalContext(Context, CurrentIndentation) - { - Parameter = param, - ArgName = nativeVarName, - ReturnVarName = nativeVarName, - ReturnType = param.QualifiedType - }; - - var marshal = new CSharpMarshalNativeToManagedPrinter(ctx); - param.QualifiedType.Visit(marshal); - - if (!string.IsNullOrWhiteSpace(marshal.Context.Before)) - Write(marshal.Context.Before); - - WriteLine("{0} = {1};", param.Name, marshal.Context.Return); - - if (!string.IsNullOrWhiteSpace(marshal.Context.Cleanup)) - cleanups.Add(marshal.Context.Cleanup); - } - } - public struct ParamMarshal { public string Name; diff --git a/tests/CSharp/CSharpTemplates.h b/tests/CSharp/CSharpTemplates.h index edfa5bcd..8a4edb09 100644 --- a/tests/CSharp/CSharpTemplates.h +++ b/tests/CSharp/CSharpTemplates.h @@ -692,11 +692,11 @@ void forceUseSpecializations(IndependentFields _1, IndependentFields VirtualTemplate _6, VirtualTemplate _7, HasDefaultTemplateArgument _8, DerivedChangesTypeName _9, TemplateWithIndexer _10, TemplateWithIndexer _11, - TemplateWithIndexer _12, TemplateWithIndexer _13, + TemplateWithIndexer _12, TemplateWithIndexer _13, TemplateDerivedFromRegularDynamic _14, IndependentFields> _15, DependentPointerFields _16, IndependentFields _17, - std::string s); + TemplateWithIndexer _18, std::string s); void hasIgnoredParam(DependentValueFields> ii); @@ -726,6 +726,7 @@ template class DLL_API VirtualTemplate; template class DLL_API HasDefaultTemplateArgument; template class DLL_API DerivedChangesTypeName; template class DLL_API TemplateWithIndexer; +template class DLL_API TemplateWithIndexer; template class DLL_API TemplateWithIndexer; template class DLL_API TemplateWithIndexer; template class DLL_API TemplateWithIndexer;