Browse Source

Reworked support for out parameters in both backends and added a test.

pull/61/merge
triton 12 years ago
parent
commit
66ef3c55ff
  1. 19
      src/Generator/Generators/CLI/CLIMarshal.cs
  2. 33
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  3. 15
      src/Generator/Generators/CLI/CLITypePrinter.cs
  4. 26
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  5. 9
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  6. 38
      src/Generator/Generators/CSharp/CSharpTypePrinter.cs
  7. 3
      src/Generator/Generators/Marshal.cs
  8. 1
      src/Generator/Types/ITypePrinter.cs
  9. 10
      tests/Basic/Basic.Tests.cs
  10. 6
      tests/Basic/Basic.cpp
  11. 1
      tests/Basic/Basic.cs
  12. 5
      tests/Basic/Basic.h

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

@ -45,6 +45,13 @@ namespace CppSharp.Generators.CLI
{ {
var pointee = pointer.Pointee; var pointee = pointer.Pointee;
var param = Context.Parameter;
if (param != null && (param.IsOut || param.IsInOut))
{
Context.Return.Write(Context.ReturnVarName);
return true;
}
if (pointee.Desugar().IsPrimitiveType(PrimitiveType.Void)) if (pointee.Desugar().IsPrimitiveType(PrimitiveType.Void))
{ {
Context.Return.Write("IntPtr({0})", Context.ReturnVarName); Context.Return.Write("IntPtr({0})", Context.ReturnVarName);
@ -234,7 +241,11 @@ namespace CppSharp.Generators.CLI
public override bool VisitParameterDecl(Parameter parameter) public override bool VisitParameterDecl(Parameter parameter)
{ {
return parameter.Type.Visit(this, parameter.QualifiedType.Qualifiers); Context.Parameter = parameter;
var ret = parameter.Type.Visit(this, parameter.QualifiedType.Qualifiers);
Context.Parameter = null;
return ret;
} }
public override bool VisitTypedefDecl(TypedefDecl typedef) public override bool VisitTypedefDecl(TypedefDecl typedef)
@ -527,7 +538,8 @@ namespace CppSharp.Generators.CLI
public void MarshalValueClass(Class @class) public void MarshalValueClass(Class @class)
{ {
var marshalVar = "_marshal" + Context.ParameterIndex++; var marshalVar = Context.MarshalVarPrefix + "_marshal" +
Context.ParameterIndex++;
Context.SupportBefore.WriteLine("auto {0} = ::{1}();", marshalVar, Context.SupportBefore.WriteLine("auto {0} = ::{1}();", marshalVar,
@class.QualifiedOriginalName); @class.QualifiedOriginalName);
@ -572,7 +584,8 @@ namespace CppSharp.Generators.CLI
var marshalCtx = new MarshalContext(Context.Driver) var marshalCtx = new MarshalContext(Context.Driver)
{ {
ArgName = fieldRef, ArgName = fieldRef,
ParameterIndex = Context.ParameterIndex++ ParameterIndex = Context.ParameterIndex++,
MarshalVarPrefix = Context.MarshalVarPrefix
}; };
var marshal = new CLIMarshalManagedToNativePrinter(marshalCtx); var marshal = new CLIMarshalManagedToNativePrinter(marshalCtx);

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

@ -632,12 +632,14 @@ namespace CppSharp.Generators.CLI
{ {
var names = new List<string>(); var names = new List<string>();
var paramIndex = 0;
foreach (var param in method.Parameters) foreach (var param in method.Parameters)
{ {
var ctx = new MarshalContext(Driver) var ctx = new MarshalContext(Driver)
{ {
Parameter = param, Parameter = param,
ArgName = param.Name, ArgName = param.Name,
ParameterIndex = paramIndex++
}; };
var marshal = new CLIMarshalManagedToNativePrinter(ctx); var marshal = new CLIMarshalManagedToNativePrinter(ctx);
@ -729,7 +731,11 @@ namespace CppSharp.Generators.CLI
WriteLine("auto {0} = ::{1}();", valueMarshalName, @class.QualifiedOriginalName); WriteLine("auto {0} = ::{1}();", valueMarshalName, @class.QualifiedOriginalName);
var param = new Parameter() { Name = "(*this)" }; var param = new Parameter() { Name = "(*this)" };
var ctx = new MarshalContext(Driver) { Parameter = param }; var ctx = new MarshalContext(Driver)
{
MarshalVarPrefix = valueMarshalName,
Parameter = param
};
var marshal = new CLIMarshalManagedToNativePrinter(ctx); var marshal = new CLIMarshalManagedToNativePrinter(ctx);
marshal.MarshalValueClassFields(@class, valueMarshalName); marshal.MarshalValueClassFields(@class, valueMarshalName);
@ -860,6 +866,8 @@ namespace CppSharp.Generators.CLI
public struct ParamMarshal public struct ParamMarshal
{ {
public string Name; public string Name;
public string Prefix;
public Parameter Param; public Parameter Param;
} }
@ -881,18 +889,21 @@ namespace CppSharp.Generators.CLI
private ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex, private ParamMarshal GenerateFunctionParamMarshal(Parameter param, int paramIndex,
Function function = null) Function function = null)
{ {
var paramMarshal = new ParamMarshal { Name = param.Name, Param = param };
if (param.Type is BuiltinType) if (param.Type is BuiltinType)
{ return paramMarshal;
return new ParamMarshal {Name = param.Name, Param = param};
}
var argName = "arg" + paramIndex.ToString(CultureInfo.InvariantCulture); var argName = "arg" + paramIndex.ToString(CultureInfo.InvariantCulture);
if (param.Usage == ParameterUsage.Out) if (param.IsOut || param.IsInOut)
{ {
var paramType = param.Type; var paramType = param.Type;
if (paramType.IsReference()) if (paramType is PointerType)
{
paramType = (paramType as PointerType).Pointee; paramType = (paramType as PointerType).Pointee;
paramMarshal.Prefix = "&";
}
var typePrinter = new CppTypePrinter(Driver.TypeDatabase); var typePrinter = new CppTypePrinter(Driver.TypeDatabase);
var type = paramType.Visit(typePrinter); var type = paramType.Visit(typePrinter);
@ -923,12 +934,18 @@ namespace CppSharp.Generators.CLI
argName = marshal.ArgumentPrefix + argName; argName = marshal.ArgumentPrefix + argName;
} }
return new ParamMarshal {Name = argName, Param = param}; paramMarshal.Name = argName;
return paramMarshal;
} }
public void GenerateFunctionParams(List<ParamMarshal> @params) public void GenerateFunctionParams(List<ParamMarshal> @params)
{ {
var names = @params.Select(param => param.Name).ToList(); var names = @params.Select(param =>
{
if (!string.IsNullOrWhiteSpace(param.Prefix))
return param.Prefix + param.Name;
return param.Name;
}).ToList();
Write(string.Join(", ", names)); Write(string.Join(", ", names));
} }

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

@ -91,10 +91,11 @@ namespace CppSharp.Generators.CLI
public string VisitParameter(Parameter param, bool hasName = true) public string VisitParameter(Parameter param, bool hasName = true)
{ {
Context.Parameter = param;
var type = param.Type.Visit(this, param.QualifiedType.Qualifiers); var type = param.Type.Visit(this, param.QualifiedType.Qualifiers);
var name = param.Name; Context.Parameter = null;
var str = "";
var str = string.Empty;
if(param.Usage == ParameterUsage.Out) if(param.Usage == ParameterUsage.Out)
str += "[System::Runtime::InteropServices::Out] "; str += "[System::Runtime::InteropServices::Out] ";
@ -103,9 +104,9 @@ namespace CppSharp.Generators.CLI
if(param.Usage == ParameterUsage.Out || if(param.Usage == ParameterUsage.Out ||
param.Usage == ParameterUsage.InOut) param.Usage == ParameterUsage.InOut)
str += "%"; str += "%";
if (hasName && !string.IsNullOrEmpty(name)) if (hasName && !string.IsNullOrEmpty(param.Name))
str += " " + name; str += " " + param.Name;
return str; return str;
} }
@ -135,6 +136,10 @@ namespace CppSharp.Generators.CLI
PrimitiveType primitive; PrimitiveType primitive;
if (pointee.Desugar().IsPrimitiveType(out primitive)) if (pointee.Desugar().IsPrimitiveType(out primitive))
{ {
var param = Context.Parameter;
if (param != null && (param.IsOut || param.IsInOut))
return VisitPrimitiveType(primitive);
return "System::IntPtr"; return "System::IntPtr";
} }

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

@ -141,6 +141,13 @@ namespace CppSharp.Generators.CSharp
PrimitiveType primitive; PrimitiveType primitive;
if (pointee.Desugar().IsPrimitiveType(out primitive)) if (pointee.Desugar().IsPrimitiveType(out primitive))
{ {
var param = Context.Parameter;
if (param != null && (param.IsOut || param.IsInOut))
{
Context.Return.Write("_{0}", param.Name);
return true;
}
Context.Return.Write(Context.ReturnVarName); Context.Return.Write(Context.ReturnVarName);
return true; return true;
} }
@ -410,7 +417,24 @@ namespace CppSharp.Generators.CSharp
PrimitiveType primitive; PrimitiveType primitive;
if (type.IsPrimitiveType(out primitive)) if (type.IsPrimitiveType(out primitive))
{ {
Context.Return.Write(Context.Parameter.Name); var param = Context.Parameter;
// 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 (param.IsOut || param.IsInOut)
{
var typeName = Type.TypePrinterDelegate(type);
Context.SupportBefore.WriteLine("{0} _{1};", typeName,
Helpers.SafeIdentifier(param.Name));
Context.Return.Write("new global::System.IntPtr(&_{0})", param.Name);
}
else
Context.Return.Write(Context.Parameter.Name);
return true; return true;
} }

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

@ -1813,13 +1813,13 @@ namespace CppSharp.Generators.CSharp
foreach (var paramInfo in @params) foreach (var paramInfo in @params)
{ {
var param = paramInfo.Param; var param = paramInfo.Param;
if (param.Usage != ParameterUsage.Out && param.Usage != ParameterUsage.InOut) if (!(param.IsOut || param.IsInOut)) continue;
continue;
var nativeVarName = paramInfo.Name; var nativeVarName = paramInfo.Name;
var ctx = new CSharpMarshalContext(Driver) var ctx = new CSharpMarshalContext(Driver)
{ {
Parameter = param,
ArgName = nativeVarName, ArgName = nativeVarName,
ReturnVarName = nativeVarName, ReturnVarName = nativeVarName,
ReturnType = param.QualifiedType ReturnType = param.QualifiedType
@ -1890,7 +1890,7 @@ namespace CppSharp.Generators.CSharp
var argName = "arg" + paramIndex.ToString(CultureInfo.InvariantCulture); var argName = "arg" + paramIndex.ToString(CultureInfo.InvariantCulture);
var paramMarshal = new ParamMarshal { Name = argName, Param = param }; var paramMarshal = new ParamMarshal { Name = argName, Param = param };
if (param.Usage == ParameterUsage.Out) if (param.IsOut || param.IsInOut)
{ {
var paramType = param.Type; var paramType = param.Type;
@ -1949,8 +1949,9 @@ namespace CppSharp.Generators.CSharp
if (param.Kind == ParameterKind.IndirectReturnType) if (param.Kind == ParameterKind.IndirectReturnType)
continue; continue;
var typeName = param.CSharpType(TypePrinter);
@params.Add(string.Format("{0}{1} {2}", GetParameterUsage(param.Usage), @params.Add(string.Format("{0}{1} {2}", GetParameterUsage(param.Usage),
param.Type, SafeIdentifier(param.Name))); typeName, SafeIdentifier(param.Name)));
} }
Write(string.Join(", ", @params)); Write(string.Join(", ", @params));

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

@ -172,10 +172,16 @@ namespace CppSharp.Generators.CSharp
if (IsConstCharString(pointer)) if (IsConstCharString(pointer))
return isManagedContext ? "string" : "global::System.IntPtr"; return isManagedContext ? "string" : "global::System.IntPtr";
PrimitiveType primitive; PrimitiveType primitive;
if (pointee.Desugar().IsPrimitiveType(out primitive)) if (pointee.Desugar().IsPrimitiveType(out primitive))
return "global::System.IntPtr"; {
if (isManagedContext && Context.Parameter != null &&
(Context.Parameter.IsOut || Context.Parameter.IsInOut))
return VisitPrimitiveType(primitive, quals);
return "global::System.IntPtr";
}
Class @class; Class @class;
if (pointee.IsTagDecl(out @class) if (pointee.IsTagDecl(out @class)
&& ContextKind == CSharpTypePrinterContextKind.Native) && ContextKind == CSharpTypePrinterContextKind.Native)
@ -363,9 +369,13 @@ namespace CppSharp.Generators.CSharp
var paramType = parameter.Type; var paramType = parameter.Type;
if (parameter.Kind == ParameterKind.IndirectReturnType) if (parameter.Kind == ParameterKind.IndirectReturnType)
return "global::System.IntPtr"; return "global::System.IntPtr";
return paramType.Visit(this); Context.Parameter = parameter;
var ret = paramType.Visit(this);
Context.Parameter = null;
return ret;
} }
public CSharpTypePrinterResult VisitTypedefDecl(TypedefDecl typedef) public CSharpTypePrinterResult VisitTypedefDecl(TypedefDecl typedef)
@ -436,11 +446,15 @@ namespace CppSharp.Generators.CSharp
public CSharpTypePrinterResult VisitParameters(IEnumerable<Parameter> @params, public CSharpTypePrinterResult 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).Type); {
Context.Parameter = param;
args.Add(VisitParameter(param, hasNames).Type);
}
Context.Parameter = null;
return string.Join(", ", args); return string.Join(", ", args);
} }

3
src/Generator/Generators/Marshal.cs

@ -9,6 +9,7 @@ namespace CppSharp.Generators
Driver = driver; Driver = driver;
SupportBefore = new TextGenerator(); SupportBefore = new TextGenerator();
Return = new TextGenerator(); Return = new TextGenerator();
MarshalVarPrefix = string.Empty;
} }
public Driver Driver { get; private set; } public Driver Driver { get; private set; }
@ -28,6 +29,8 @@ namespace CppSharp.Generators
public Parameter Parameter { get; set; } public Parameter Parameter { get; set; }
public int ParameterIndex { get; set; } public int ParameterIndex { get; set; }
public Function Function { get; set; } public Function Function { get; set; }
public string MarshalVarPrefix { get; set; }
} }
public abstract class MarshalPrinter : AstVisitor public abstract class MarshalPrinter : AstVisitor

1
src/Generator/Types/ITypePrinter.cs

@ -47,6 +47,7 @@ namespace CppSharp.Types
public TypePrinterContextKind Kind; public TypePrinterContextKind Kind;
public Declaration Declaration; public Declaration Declaration;
public Parameter Parameter;
public Type Type; public Type Type;
} }

10
tests/Basic/Basic.Tests.cs

@ -44,6 +44,16 @@ public class BasicTests
Assert.That(hello.RetEnum(Enum.F), Is.EqualTo(-9)); Assert.That(hello.RetEnum(Enum.F), Is.EqualTo(-9));
} }
[Test]
public void TestPrimitiveOutParameters()
{
var hello = new Hello();
float f;
Assert.That(hello.TestPrimitiveOut(out f), Is.True);
Assert.That(f, Is.EqualTo(10.0f));
}
[Test] [Test]
public void TestNullRef() public void TestNullRef()
{ {

6
tests/Basic/Basic.cpp

@ -95,6 +95,12 @@ Hello* Hello::RetNull()
return 0; return 0;
} }
bool Hello::TestPrimitiveOut(CS_OUT float* f)
{
*f = 10;
return true;
}
int unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int)) int unsafeFunction(const Bar& ret, char* testForString, void (*foo)(int))
{ {
return ret.A; return ret.A;

1
tests/Basic/Basic.cs

@ -15,6 +15,7 @@ namespace CppSharp.Tests
{ {
lib.SetClassAsValueType("Bar"); lib.SetClassAsValueType("Bar");
lib.SetClassAsValueType("Bar2"); lib.SetClassAsValueType("Bar2");
lib.SetMethodParameterUsage("Hello", "TestPrimitiveOut", 1, ParameterUsage.Out);
} }
static class Program static class Program

5
tests/Basic/Basic.h

@ -4,6 +4,8 @@
#define DLL_API #define DLL_API
#endif #endif
#define CS_OUT
class DLL_API Foo class DLL_API Foo
{ {
public: public:
@ -84,6 +86,9 @@ public:
int RetEnum(Enum); int RetEnum(Enum);
Hello* RetNull(); Hello* RetNull();
bool TestPrimitiveOut(CS_OUT float* f);
}; };
class DLL_API AbstractFoo class DLL_API AbstractFoo

Loading…
Cancel
Save