diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs index 82fb93b871026b..f6590136448336 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs @@ -319,7 +319,7 @@ private static bool ShouldVisitNode(SyntaxNode syntaxNode) // Verify the method has no generic types or defined implementation // and is marked static and partial. if (methodSyntax.TypeParameterList is not null - || methodSyntax.Body is null + || (methodSyntax.Body is null && methodSyntax.ExpressionBody is null) || !methodSyntax.Modifiers.Any(SyntaxKind.StaticKeyword) || methodSyntax.Modifiers.Any(SyntaxKind.PartialKeyword)) { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportStubContext.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportStubContext.cs index 055e81315e68e4..005e30581affea 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportStubContext.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSImportStubContext.cs @@ -4,7 +4,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; +using System.Text; using System.Threading; using Microsoft.CodeAnalysis; @@ -16,6 +18,11 @@ namespace Microsoft.Interop.JavaScript { internal sealed class JSSignatureContext : IEquatable { + private static SymbolDisplayFormat s_typeNameFormat { get; } = new SymbolDisplayFormat( + globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, + typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes + ); + internal static readonly string GeneratorName = typeof(JSImportGenerator).Assembly.GetName().Name; internal static readonly string GeneratorVersion = typeof(JSImportGenerator).Assembly.GetName().Version.ToString(); @@ -118,14 +125,8 @@ public static JSSignatureContext Create( }; int typesHash = Math.Abs((int)hash); - - var fullName = $"{method.ContainingType.ToDisplayString()}.{method.Name}"; - string qualifiedName; - var ns = string.Join(".", method.ContainingType.ToDisplayParts().Where(p => p.Kind == SymbolDisplayPartKind.NamespaceName).Select(x => x.ToString()).ToArray()); - var cn = string.Join("/", method.ContainingType.ToDisplayParts().Where(p => p.Kind == SymbolDisplayPartKind.ClassName).Select(x => x.ToString()).ToArray()); - var qclasses = method.ContainingType.ContainingNamespace == null ? ns : ns + "." + cn; - qualifiedName = $"[{env.Compilation.AssemblyName}]{qclasses}:{method.Name}"; + string qualifiedName = GetFullyQualifiedMethodName(env, method); return new JSSignatureContext() { @@ -143,6 +144,17 @@ public static JSSignatureContext Create( }; } + private static string GetFullyQualifiedMethodName(StubEnvironment env, IMethodSymbol method) + { + // Mono style nested class name format. + string typeName = method.ContainingType.ToDisplayString(s_typeNameFormat).Replace(".", "/"); + + if (!method.ContainingType.ContainingNamespace.IsGlobalNamespace) + typeName = $"{method.ContainingType.ContainingNamespace.ToDisplayString()}.{typeName}"; + + return $"[{env.Compilation.AssemblyName}]{typeName}:{method.Name}"; + } + private static (ImmutableArray, IMarshallingGeneratorFactory) GenerateTypeInformation(IMethodSymbol method, GeneratorDiagnostics diagnostics, StubEnvironment env) { var jsMarshallingAttributeParser = new JSMarshallingAttributeInfoParser(env.Compilation, diagnostics, method); diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs index 71a795545f3317..a8966dcaf521d0 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs @@ -1199,7 +1199,62 @@ public void JsExportString(string value) public void JsExportStringNoNs() { var actual = JavaScriptTestHelper.invoke2_String("test", nameof(JavaScriptTestHelperNoNamespace.EchoString)); - Assert.Equal("test!", actual); + Assert.Equal("test51", actual); + } + + [Fact] + public void JsExportStructClassRecords() + { + var actual = JavaScriptTestHelper.invokeStructClassRecords("test"); + Assert.Equal(48, actual.Length); + Assert.Equal("test11", actual[0]); + Assert.Equal("test12", actual[1]); + Assert.Equal("test13", actual[2]); + Assert.Equal("test14", actual[3]); + Assert.Equal("test15", actual[4]); + Assert.Equal("test16", actual[5]); + Assert.Equal("test17", actual[6]); + Assert.Equal("test18", actual[7]); + Assert.Equal("test19", actual[8]); + Assert.Equal("test21", actual[9]); + Assert.Equal("test22", actual[10]); + Assert.Equal("test23", actual[11]); + Assert.Equal("test24", actual[12]); + Assert.Equal("test25", actual[13]); + Assert.Equal("test31", actual[14]); + Assert.Equal("test32", actual[15]); + Assert.Equal("test33", actual[16]); + Assert.Equal("test34", actual[17]); + Assert.Equal("test35", actual[18]); + Assert.Equal("test41", actual[19]); + Assert.Equal("test42", actual[20]); + Assert.Equal("test43", actual[21]); + Assert.Equal("test44", actual[22]); + Assert.Equal("test45", actual[23]); + Assert.Equal("test51", actual[24]); + Assert.Equal("test52", actual[25]); + Assert.Equal("test53", actual[26]); + Assert.Equal("test54", actual[27]); + Assert.Equal("test55", actual[28]); + Assert.Equal("test56", actual[29]); + Assert.Equal("test57", actual[30]); + Assert.Equal("test58", actual[31]); + Assert.Equal("test59", actual[32]); + Assert.Equal("test61", actual[33]); + Assert.Equal("test62", actual[34]); + Assert.Equal("test63", actual[35]); + Assert.Equal("test64", actual[36]); + Assert.Equal("test65", actual[37]); + Assert.Equal("test71", actual[38]); + Assert.Equal("test72", actual[39]); + Assert.Equal("test73", actual[40]); + Assert.Equal("test74", actual[41]); + Assert.Equal("test75", actual[42]); + Assert.Equal("test81", actual[43]); + Assert.Equal("test82", actual[44]); + Assert.Equal("test83", actual[45]); + Assert.Equal("test84", actual[46]); + Assert.Equal("test85", actual[47]); } [Fact] diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index aaa5d16c2b8cdb..b5a89b7f48fe98 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -250,6 +250,9 @@ public static int EchoInt32([JSMarshalAs] int arg1) [JSImport("invoke2", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial string invoke2_String([JSMarshalAs] string value, [JSMarshalAs] string name); + [JSImport("invokeStructClassRecords", "JavaScriptTestHelper")] + [return: JSMarshalAs>] + internal static partial string[] invokeStructClassRecords([JSMarshalAs] string value); [JSExport] [return: JSMarshalAs] public static string EchoString([JSMarshalAs] string arg1) @@ -935,11 +938,302 @@ public static async Task InitializeAsync() } } +namespace JavaScriptTestHelperNamespace +{ + public partial class JavaScriptTestHelper + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) + { + return message + "11"; + } + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "12"; + + public partial class DoubleNestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "13"; + } + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "14"; + + public partial record class DoubleNestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "15"; + } + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "16"; + + public partial struct DoubleNestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "17"; + } + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "18"; + + public partial record struct DoubleNestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "19"; + } + } + } + + public partial class JavaScriptTestHelperStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "21"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "22"; + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "23"; + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) + { + return message + "24"; + } + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "25"; + } + } + + public partial record class JavaScriptTestHelperRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "31"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "32"; + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "33"; + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "34"; + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "35"; + } + } + + public partial record struct JavaScriptTestHelperRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "41"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "42"; + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "43"; + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "44"; + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) + { + return message + "45"; + } + } + } +} + public partial class JavaScriptTestHelperNoNamespace { [System.Runtime.InteropServices.JavaScript.JSExport] - public static string EchoString(string message) + public static string EchoString(string message) => message + "51"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "52"; + + public partial class DoubleNestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "53"; + } + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "54"; + + public partial record class DoubleNestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "55"; + } + } + + public partial struct NestedStruct { - return message + "!"; + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "56"; + + public partial struct DoubleNestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "57"; + } + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "58"; + + public partial record struct DoubleNestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "59"; + } } } + +public partial class JavaScriptTestHelperStructNoNamespace +{ + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "61"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "62"; + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "63"; + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "64"; + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "65"; + } +} + +public partial record class JavaScriptTestHelperRecordClassNoNamespace +{ + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "71"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "72"; + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "73"; + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "74"; + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "75"; + } +} + +public partial record struct JavaScriptTestHelperRecordStructNoNamespace +{ + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "81"; + + public partial class NestedClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "82"; + } + + public partial record class NestedRecordClass + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "83"; + } + + public partial struct NestedStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "84"; + } + + public partial record struct NestedRecordStruct + { + [System.Runtime.InteropServices.JavaScript.JSExport] + public static string EchoString(string message) => message + "85"; + } +} \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs index c3cc24ed73979d..314e715e16b815 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs @@ -171,6 +171,59 @@ export function invoke2(arg1, name) { return res; } +export function invokeStructClassRecords(arg1) { + return [ + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedClass.DoubleNestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedRecordClass.DoubleNestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedStruct.DoubleNestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelper.NestedRecordStruct.DoubleNestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperStruct.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperStruct.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperStruct.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperStruct.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordClass.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordClass.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordClass.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordClass.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordStruct.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordStruct.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordStruct.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNamespace.JavaScriptTestHelperRecordStruct.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedClass.DoubleNestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedRecordClass.DoubleNestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedStruct.DoubleNestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperNoNamespace.NestedRecordStruct.DoubleNestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperStructNoNamespace.EchoString(arg1), + dllExports.JavaScriptTestHelperStructNoNamespace.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperStructNoNamespace.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperStructNoNamespace.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperStructNoNamespace.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordClassNoNamespace.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordClassNoNamespace.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordClassNoNamespace.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordClassNoNamespace.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordClassNoNamespace.NestedRecordStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordStructNoNamespace.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordStructNoNamespace.NestedClass.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordStructNoNamespace.NestedRecordClass.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordStructNoNamespace.NestedStruct.EchoString(arg1), + dllExports.JavaScriptTestHelperRecordStructNoNamespace.NestedRecordStruct.EchoString(arg1), + ]; +} + export async function awaitvoid(arg1) { // console.log("awaitvoid:" + typeof arg1); await arg1;