Browse Source

Properly handled nulls passed to C++ refs by throwing an exception.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/591/head
Dimitar Dobrev 10 years ago
parent
commit
d328b7ce34
  1. 19
      src/Generator/Generators/CLI/CLIMarshal.cs
  2. 23
      src/Generator/Generators/CSharp/CSharpMarshal.cs
  3. 11
      tests/CSharp/CSharp.Tests.cs
  4. 9
      tests/Common/Common.Tests.cs
  5. 5
      tests/Common/Common.cpp
  6. 1
      tests/Common/Common.h

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

@ -679,14 +679,28 @@ namespace CppSharp.Generators.CLI
private void MarshalRefClass(Class @class) private void MarshalRefClass(Class @class)
{ {
TypeMap typeMap = null; TypeMap typeMap;
if (Context.Driver.TypeDatabase.FindTypeMap(@class, out typeMap) && typeMap.DoesMarshalling) if (Context.Driver.TypeDatabase.FindTypeMap(@class, out typeMap) && typeMap.DoesMarshalling)
{ {
typeMap.CLIMarshalToNative(Context); typeMap.CLIMarshalToNative(Context);
return; return;
} }
if (!Context.Parameter.Type.Desugar().SkipPointerRefs().IsPointer()) var type = Context.Parameter.Type.Desugar();
var method = Context.Function as Method;
if (type.IsReference() && (method == null ||
// redundant for comparison operators, they are handled in a special way
(method.OperatorKind != CXXOperatorKind.EqualEqual &&
method.OperatorKind != CXXOperatorKind.ExclaimEqual)))
{
Context.SupportBefore.WriteLine("if (ReferenceEquals({0}, nullptr))", Context.Parameter.Name);
Context.SupportBefore.WriteLineIndent(
"throw gcnew ::System::ArgumentNullException(\"{0}\", " +
"\"{0} cannot be null because it is a C++ reference (&).\");",
Context.Parameter.Name);
}
if (!type.SkipPointerRefs().IsPointer())
{ {
Context.Return.Write("*"); Context.Return.Write("*");
@ -694,7 +708,6 @@ namespace CppSharp.Generators.CLI
VarPrefix.Write("&"); VarPrefix.Write("&");
} }
var method = Context.Function as Method;
if (method != null if (method != null
&& method.Conversion == MethodConversionKind.FunctionToInstanceMethod && method.Conversion == MethodConversionKind.FunctionToInstanceMethod
&& Context.ParameterIndex == 0) && Context.ParameterIndex == 0)

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

@ -654,12 +654,31 @@ namespace CppSharp.Generators.CSharp
if (type.TryGetClass(out decl) && decl.IsValueType) if (type.TryGetClass(out decl) && decl.IsValueType)
Context.Return.Write("{0}.{1}", param, Helpers.InstanceIdentifier); Context.Return.Write("{0}.{1}", param, Helpers.InstanceIdentifier);
else else
{
if (type.IsPointer())
{
Context.Return.Write("{0}{1}.{2}", Context.Return.Write("{0}{1}.{2}",
method != null && method.OperatorKind == CXXOperatorKind.EqualEqual method != null && method.OperatorKind == CXXOperatorKind.EqualEqual
? string.Empty ? string.Empty
: string.Format("ReferenceEquals({0}, null) ? global::System.IntPtr.Zero : ", param), : string.Format("ReferenceEquals({0}, null) ? global::System.IntPtr.Zero : ", param),
param, param, Helpers.InstanceIdentifier, type);
Helpers.InstanceIdentifier, type); }
else
{
if (method == null ||
// redundant for comparison operators, they are handled in a special way
(method.OperatorKind != CXXOperatorKind.EqualEqual &&
method.OperatorKind != CXXOperatorKind.ExclaimEqual))
{
Context.SupportBefore.WriteLine("if (ReferenceEquals({0}, null))", param);
Context.SupportBefore.WriteLineIndent(
"throw new global::System.ArgumentNullException(\"{0}\", " +
"\"{0} cannot be null because it is a C++ reference (&).\");",
param);
}
Context.Return.Write("{0}.{1}", param, Helpers.InstanceIdentifier);
}
}
return; return;
} }

11
tests/CSharp/CSharp.Tests.cs

@ -103,18 +103,25 @@ public class CSharpTests : GeneratorTestFixture
Assert.That(proprietor.Value, Is.EqualTo(20)); Assert.That(proprietor.Value, Is.EqualTo(20));
proprietor.Prop = 50; proprietor.Prop = 50;
Assert.That(proprietor.Prop, Is.EqualTo(50)); Assert.That(proprietor.Prop, Is.EqualTo(50));
var p = new P((IQux) null) { Value = 20 }; using (var qux = new Qux())
{
using (var p = new P((IQux) qux) { Value = 20 })
{
Assert.That(p.Value, Is.EqualTo(30)); Assert.That(p.Value, Is.EqualTo(30));
p.Prop = 50; p.Prop = 50;
Assert.That(p.Prop, Is.EqualTo(150)); Assert.That(p.Prop, Is.EqualTo(150));
ComplexType complexType = new ComplexType(); using (var complexType = new ComplexType())
{
p.ComplexType = complexType; p.ComplexType = complexType;
Assert.That(p.ComplexType.Check(), Is.EqualTo(5)); Assert.That(p.ComplexType.Check(), Is.EqualTo(5));
}
Assert.That(p.Test, Is.True); Assert.That(p.Test, Is.True);
Assert.That(p.IsBool, Is.False); Assert.That(p.IsBool, Is.False);
} }
}
}
[Test] [Test]
public void TestAttributes() public void TestAttributes()

9
tests/Common/Common.Tests.cs

@ -590,6 +590,15 @@ public class CommonTests : GeneratorTestFixture
Assert.That(Foo.charArray, Is.EqualTo("abc")); Assert.That(Foo.charArray, Is.EqualTo("abc"));
} }
[Test]
public void TestPassingNullToRef()
{
using (var foo = new Foo())
{
Assert.Catch<ArgumentNullException>(() => foo.TakesRef(null));
}
}
private class CustomDerivedFromVirtual : AbstractWithVirtualDtor private class CustomDerivedFromVirtual : AbstractWithVirtualDtor
{ {
public override void @abstract() public override void @abstract()

5
tests/Common/Common.cpp

@ -23,6 +23,11 @@ void Foo::TakesTypedefedPtr(FooPtr date)
{ {
} }
int Foo::TakesRef(const Foo &other)
{
return other.A;
}
bool Foo::operator ==(const Foo& other) const bool Foo::operator ==(const Foo& other) const
{ {
return A == other.A && B == other.B; return A == other.A && B == other.B;

1
tests/Common/Common.h

@ -59,6 +59,7 @@ public:
typedef Foo* FooPtr; typedef Foo* FooPtr;
void TakesTypedefedPtr(FooPtr date); void TakesTypedefedPtr(FooPtr date);
int TakesRef(const Foo& other);
bool operator ==(const Foo& other) const; bool operator ==(const Foo& other) const;
}; };

Loading…
Cancel
Save