Skip to content

Commit 7922d61

Browse files
authored
[wasm] Fix JSExport on structs, records and expression bodied methos (#74763)
- Fix generating qualified name for JSExport on structs, record classes and record structs. - Fix using expression bodied methods for JSExport. - Add unit test using all these variants with and without namespace and nested types. - Rewrite concatenating method name.
1 parent c30cfbb commit 7922d61

File tree

5 files changed

+425
-11
lines changed

5 files changed

+425
-11
lines changed

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ private static bool ShouldVisitNode(SyntaxNode syntaxNode)
319319
// Verify the method has no generic types or defined implementation
320320
// and is marked static and partial.
321321
if (methodSyntax.TypeParameterList is not null
322-
|| methodSyntax.Body is null
322+
|| (methodSyntax.Body is null && methodSyntax.ExpressionBody is null)
323323
|| !methodSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)
324324
|| methodSyntax.Modifiers.Any(SyntaxKind.PartialKeyword))
325325
{

src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportStubContext.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Collections.Immutable;
7+
using System.Diagnostics;
78
using System.Linq;
9+
using System.Text;
810
using System.Threading;
911

1012
using Microsoft.CodeAnalysis;
@@ -16,6 +18,11 @@ namespace Microsoft.Interop.JavaScript
1618
{
1719
internal sealed class JSSignatureContext : IEquatable<JSSignatureContext>
1820
{
21+
private static SymbolDisplayFormat s_typeNameFormat { get; } = new SymbolDisplayFormat(
22+
globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted,
23+
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes
24+
);
25+
1926
internal static readonly string GeneratorName = typeof(JSImportGenerator).Assembly.GetName().Name;
2027

2128
internal static readonly string GeneratorVersion = typeof(JSImportGenerator).Assembly.GetName().Version.ToString();
@@ -118,14 +125,8 @@ public static JSSignatureContext Create(
118125
};
119126
int typesHash = Math.Abs((int)hash);
120127

121-
122-
123128
var fullName = $"{method.ContainingType.ToDisplayString()}.{method.Name}";
124-
string qualifiedName;
125-
var ns = string.Join(".", method.ContainingType.ToDisplayParts().Where(p => p.Kind == SymbolDisplayPartKind.NamespaceName).Select(x => x.ToString()).ToArray());
126-
var cn = string.Join("/", method.ContainingType.ToDisplayParts().Where(p => p.Kind == SymbolDisplayPartKind.ClassName).Select(x => x.ToString()).ToArray());
127-
var qclasses = method.ContainingType.ContainingNamespace == null ? ns : ns + "." + cn;
128-
qualifiedName = $"[{env.Compilation.AssemblyName}]{qclasses}:{method.Name}";
129+
string qualifiedName = GetFullyQualifiedMethodName(env, method);
129130

130131
return new JSSignatureContext()
131132
{
@@ -143,6 +144,17 @@ public static JSSignatureContext Create(
143144
};
144145
}
145146

147+
private static string GetFullyQualifiedMethodName(StubEnvironment env, IMethodSymbol method)
148+
{
149+
// Mono style nested class name format.
150+
string typeName = method.ContainingType.ToDisplayString(s_typeNameFormat).Replace(".", "/");
151+
152+
if (!method.ContainingType.ContainingNamespace.IsGlobalNamespace)
153+
typeName = $"{method.ContainingType.ContainingNamespace.ToDisplayString()}.{typeName}";
154+
155+
return $"[{env.Compilation.AssemblyName}]{typeName}:{method.Name}";
156+
}
157+
146158
private static (ImmutableArray<TypePositionInfo>, IMarshallingGeneratorFactory) GenerateTypeInformation(IMethodSymbol method, GeneratorDiagnostics diagnostics, StubEnvironment env)
147159
{
148160
ImmutableArray<IUseSiteAttributeParser> useSiteAttributeParsers = ImmutableArray.Create<IUseSiteAttributeParser>(new JSMarshalAsAttributeParser(env.Compilation));

src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,62 @@ public void JsExportString(string value)
11991199
public void JsExportStringNoNs()
12001200
{
12011201
var actual = JavaScriptTestHelper.invoke2_String("test", nameof(JavaScriptTestHelperNoNamespace.EchoString));
1202-
Assert.Equal("test!", actual);
1202+
Assert.Equal("test51", actual);
1203+
}
1204+
1205+
[Fact]
1206+
public void JsExportStructClassRecords()
1207+
{
1208+
var actual = JavaScriptTestHelper.invokeStructClassRecords("test");
1209+
Assert.Equal(48, actual.Length);
1210+
Assert.Equal("test11", actual[0]);
1211+
Assert.Equal("test12", actual[1]);
1212+
Assert.Equal("test13", actual[2]);
1213+
Assert.Equal("test14", actual[3]);
1214+
Assert.Equal("test15", actual[4]);
1215+
Assert.Equal("test16", actual[5]);
1216+
Assert.Equal("test17", actual[6]);
1217+
Assert.Equal("test18", actual[7]);
1218+
Assert.Equal("test19", actual[8]);
1219+
Assert.Equal("test21", actual[9]);
1220+
Assert.Equal("test22", actual[10]);
1221+
Assert.Equal("test23", actual[11]);
1222+
Assert.Equal("test24", actual[12]);
1223+
Assert.Equal("test25", actual[13]);
1224+
Assert.Equal("test31", actual[14]);
1225+
Assert.Equal("test32", actual[15]);
1226+
Assert.Equal("test33", actual[16]);
1227+
Assert.Equal("test34", actual[17]);
1228+
Assert.Equal("test35", actual[18]);
1229+
Assert.Equal("test41", actual[19]);
1230+
Assert.Equal("test42", actual[20]);
1231+
Assert.Equal("test43", actual[21]);
1232+
Assert.Equal("test44", actual[22]);
1233+
Assert.Equal("test45", actual[23]);
1234+
Assert.Equal("test51", actual[24]);
1235+
Assert.Equal("test52", actual[25]);
1236+
Assert.Equal("test53", actual[26]);
1237+
Assert.Equal("test54", actual[27]);
1238+
Assert.Equal("test55", actual[28]);
1239+
Assert.Equal("test56", actual[29]);
1240+
Assert.Equal("test57", actual[30]);
1241+
Assert.Equal("test58", actual[31]);
1242+
Assert.Equal("test59", actual[32]);
1243+
Assert.Equal("test61", actual[33]);
1244+
Assert.Equal("test62", actual[34]);
1245+
Assert.Equal("test63", actual[35]);
1246+
Assert.Equal("test64", actual[36]);
1247+
Assert.Equal("test65", actual[37]);
1248+
Assert.Equal("test71", actual[38]);
1249+
Assert.Equal("test72", actual[39]);
1250+
Assert.Equal("test73", actual[40]);
1251+
Assert.Equal("test74", actual[41]);
1252+
Assert.Equal("test75", actual[42]);
1253+
Assert.Equal("test81", actual[43]);
1254+
Assert.Equal("test82", actual[44]);
1255+
Assert.Equal("test83", actual[45]);
1256+
Assert.Equal("test84", actual[46]);
1257+
Assert.Equal("test85", actual[47]);
12031258
}
12041259

12051260
[Fact]

0 commit comments

Comments
 (0)