Skip to content

Commit 03874e7

Browse files
authored
Fix Value Type String Member Invalid Codegen (#1778)
* Fix code generation * Generate exception on broken struct set op * Remove redundant usings
1 parent adffc99 commit 03874e7

File tree

4 files changed

+42
-4
lines changed

4 files changed

+42
-4
lines changed

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

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Linq;
34
using System.Runtime.InteropServices;
@@ -6,6 +7,7 @@
67
using CppSharp.AST.Extensions;
78
using CppSharp.Generators;
89
using CppSharp.Generators.CSharp;
10+
using Type = CppSharp.AST.Type;
911

1012
namespace CppSharp.Types.Std
1113
{
@@ -145,7 +147,7 @@ public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
145147
// would be really helpful to have ctx hold a Decl property representing the
146148
// "appropriate" Decl when we get here. When MarshalKind == NativeField, Decl would
147149
// be set to the Field we're operating on.
148-
var fieldName = ctx.ReturnVarName.Substring(ctx.ReturnVarName.LastIndexOf("->") + 2);
150+
var fieldName = ctx.ReturnVarName[Math.Max(ctx.ReturnVarName.LastIndexOf('.') + 1, ctx.ReturnVarName.LastIndexOf("->") + 2)..];
149151

150152
ctx.Before.WriteLine($"if (__{fieldName}_OwnsNativeMemory)");
151153
ctx.Before.WriteLineIndent($"Marshal.FreeHGlobal({ctx.ReturnVarName});");
@@ -326,10 +328,24 @@ public override void CSharpMarshalToNative(CSharpMarshalContext ctx)
326328
var assign = basicString.Methods.First(m => m.OriginalName == "assign");
327329
if (ctx.MarshalKind == MarshalKind.NativeField)
328330
{
331+
string var;
332+
if (ctx.ReturnVarName.LastIndexOf('.') > ctx.ReturnVarName.LastIndexOf("->"))
333+
{
334+
ctx.Before.WriteLine("throw new NotImplementedException(\"This method cannot currently be called because it would " +
335+
"leave the object in an invalid state. See https://github.com/mono/CppSharp/issues/1777\");");
336+
337+
var = Generator.GeneratedIdentifier(ctx.ArgName);
338+
ctx.Before.WriteLine($"fixed (void* {var} = &{ctx.ReturnVarName})");
339+
ctx.Before.WriteOpenBraceAndIndent();
340+
ctx.HasCodeBlock = true;
341+
}
342+
else
343+
{
344+
var = $"&{ctx.ReturnVarName}";
345+
}
329346
ctx.Return.Write($@"{qualifiedBasicString}Extensions.{
330347
Helpers.InternalStruct}.{assign.Name}(new {
331-
typePrinter.IntPtrType}(&{
332-
ctx.ReturnVarName}), ");
348+
typePrinter.IntPtrType}({var}), ");
333349
if (ctx.Parameter.Type.IsTemplateParameterType())
334350
ctx.Return.Write("(string) (object) ");
335351
ctx.Return.Write($"{ctx.Parameter.Name})");

tests/dotnet/CSharp/CSharp.CSharp.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<NoWarn>0108</NoWarn>
4+
<LangVersion>10</LangVersion>
45
</PropertyGroup>
56
<ItemGroup>
67
<Compile Include="CSharpPartialMethods.cs" />

tests/dotnet/CSharp/CSharp.Tests.cs

+13-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Linq;
44
using System.Reflection;
55
using System.Runtime.InteropServices;
6-
using System.Text;
76
using CSharp;
87
using NUnit.Framework;
98

@@ -2024,4 +2023,17 @@ public void TestOptionalIntPtr()
20242023
Assert.That(new CSharp.Optional<IntPtr>(IntPtr.MaxValue) == new CSharp.Optional<IntPtr>(IntPtr.MaxValue));
20252024
Assert.That(new CSharp.Optional<IntPtr>(IntPtr.MaxValue) == IntPtr.MaxValue);
20262025
}
2026+
2027+
[Test]
2028+
[Ignore("https://github.com/mono/CppSharp/issues/1730")]
2029+
public void TestString()
2030+
{
2031+
var test = new CSharp.ValueType();
2032+
Assert.AreEqual(string.Empty, test.StringMember);
2033+
Assert.AreEqual(null, test.CharPtrMember);
2034+
test.StringMember = "test";
2035+
test.CharPtrMember = "test2";
2036+
Assert.AreEqual("test", test.StringMember);
2037+
Assert.AreEqual("test2", test.CharPtrMember);
2038+
}
20272039
}

tests/dotnet/CSharp/CSharp.h

+9
Original file line numberDiff line numberDiff line change
@@ -1641,3 +1641,12 @@ class Optional {
16411641
// We just need a method that uses various instantiations of Optional.
16421642
inline void DLL_API InstantiateOptionalTemplate(Optional<unsigned int>, Optional<std::string>,
16431643
Optional<TestComparison>, Optional<char*>, Optional<UnionTester>) { }
1644+
1645+
CS_VALUE_TYPE class DLL_API ValueType {
1646+
public:
1647+
// Parameterless ctors are currently not generated for value types.
1648+
ValueType(int) { }
1649+
1650+
std::string string_member;
1651+
const char* char_ptr_member;
1652+
};

0 commit comments

Comments
 (0)