From bf754e4bc3845cc98c7dbf2d7432174b3909553c Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Thu, 21 Sep 2023 14:51:11 +0900 Subject: [PATCH] Fix code generation for formatter of Enum nested in a class. --- .../SerializationFormatterNameMapper.cs | 47 ++++---- .../CodeAnalysis/SerializationInfo.cs | 13 ++- .../SerializationInfoCollector.cs | 9 +- .../CodeGen/EnumTemplate.cs | 8 +- .../CodeGen/EnumTemplate.tt | 4 +- ...emoryPackFormatterRegistrationGenerator.cs | 2 +- .../MessagePackFormatterResolverGenerator.cs | 2 +- .../MagicOnionCompiler.cs | 21 ++-- .../SerializationInfoCollectorTest.cs | 104 +++++++++--------- .../GenerateEnumFormatterTest.cs | 43 ++++++++ 10 files changed, 162 insertions(+), 91 deletions(-) diff --git a/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationFormatterNameMapper.cs b/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationFormatterNameMapper.cs index bc6713273..c8a04600d 100644 --- a/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationFormatterNameMapper.cs +++ b/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationFormatterNameMapper.cs @@ -3,8 +3,8 @@ namespace MagicOnion.Generator.CodeAnalysis; public interface ISerializationFormatterNameMapper { IWellKnownSerializationTypes WellKnownTypes { get; } - bool TryMapGeneric(MagicOnionTypeInfo type, out string formatterName); - string MapArray(MagicOnionTypeInfo type); + bool TryMapGeneric(MagicOnionTypeInfo type, out string formatterName, out string formatterConstructorArgs); + (string FormatterName, string FormatterConstructorArgs) MapArray(MagicOnionTypeInfo type); } @@ -30,38 +30,43 @@ public MessagePackFormatterNameMapper(string userDefinedFormatterNamespace) this.userDefinedFormatterNamespace = userDefinedFormatterNamespace; } - public bool TryMapGeneric(MagicOnionTypeInfo type, out string formatterName) + public bool TryMapGeneric(MagicOnionTypeInfo type, out string formatterName, out string formatterConstructorArgs) { formatterName = null; + formatterConstructorArgs = null; + var genericTypeArgs = string.Join(", ", type.GenericArguments.Select(x => x.FullName)); if (type is { Namespace: "MagicOnion", Name: "DynamicArgumentTuple" }) { // MagicOnion.DynamicArgumentTuple var ctorArguments = string.Join(", ", type.GenericArguments.Select(x => $"default({x.FullName})")); - formatterName = $"global::MagicOnion.DynamicArgumentTupleFormatter<{genericTypeArgs}>({ctorArguments})"; + formatterName = $"global::MagicOnion.DynamicArgumentTupleFormatter<{genericTypeArgs}>"; + formatterConstructorArgs = $"({ctorArguments})"; } else if (MessagePackWellKnownSerializationTypes.Instance.GenericFormattersMap.TryGetValue(type.FullNameOpenType, out var mappedFormatterName)) { // Well-known generic types (Nullable, IList, List, Dictionary ...) - formatterName = $"{mappedFormatterName}<{genericTypeArgs}>()"; + formatterName = $"{mappedFormatterName}<{genericTypeArgs}>"; + formatterConstructorArgs = "()"; } else { // User-defined generic types - formatterName = $"{userDefinedFormatterNamespace}{(string.IsNullOrWhiteSpace(userDefinedFormatterNamespace) ? "" : ".")}{type.ToDisplayName(MagicOnionTypeInfo.DisplayNameFormat.Namespace | MagicOnionTypeInfo.DisplayNameFormat.WithoutGenericArguments)}Formatter<{genericTypeArgs}>()"; + formatterName = $"{userDefinedFormatterNamespace}{(string.IsNullOrWhiteSpace(userDefinedFormatterNamespace) ? "" : ".")}{type.ToDisplayName(MagicOnionTypeInfo.DisplayNameFormat.Namespace | MagicOnionTypeInfo.DisplayNameFormat.WithoutGenericArguments)}Formatter<{genericTypeArgs}>"; + formatterConstructorArgs = "()"; } return formatterName != null; } - public string MapArray(MagicOnionTypeInfo type) + public (string FormatterName, string FormatterConstructorArgs) MapArray(MagicOnionTypeInfo type) { return type.ArrayRank switch { - 1 => $"global::MessagePack.Formatters.ArrayFormatter<{type.ElementType.FullName}>()", - 2 => $"global::MessagePack.Formatters.TwoDimensionalArrayFormatter<{type.ElementType.FullName}>()", - 3 => $"global::MessagePack.Formatters.ThreeDimensionalArrayFormatter<{type.ElementType.FullName}>()", - 4 => $"global::MessagePack.Formatters.FourDimensionalArrayFormatter<{type.ElementType.FullName}>()", + 1 => ($"global::MessagePack.Formatters.ArrayFormatter<{type.ElementType.FullName}>", "()"), + 2 => ($"global::MessagePack.Formatters.TwoDimensionalArrayFormatter<{type.ElementType.FullName}>", "()"), + 3 => ($"global::MessagePack.Formatters.ThreeDimensionalArrayFormatter<{type.ElementType.FullName}>", "()"), + 4 => ($"global::MessagePack.Formatters.FourDimensionalArrayFormatter<{type.ElementType.FullName}>", "()"), _ => throw new IndexOutOfRangeException($"An array of rank must be less than 5. ({type.FullName})"), }; } @@ -181,33 +186,37 @@ public MemoryPackFormatterNameMapper() { } - public bool TryMapGeneric(MagicOnionTypeInfo type, out string formatterName) + public bool TryMapGeneric(MagicOnionTypeInfo type, out string formatterName, out string formatterConstructorArgs) { formatterName = null; + formatterConstructorArgs = null; + var genericTypeArgs = string.Join(", ", type.GenericArguments.Select(x => x.FullName)); if (type is { Namespace: "MagicOnion", Name: "DynamicArgumentTuple" }) { // MagicOnion.DynamicArgumentTuple var ctorArguments = string.Join(", ", type.GenericArguments.Select(x => $"default({x.FullName})")); - formatterName = $"global::MagicOnion.Serialization.MemoryPack.DynamicArgumentTupleFormatter<{genericTypeArgs}>()"; + formatterName = $"global::MagicOnion.Serialization.MemoryPack.DynamicArgumentTupleFormatter<{genericTypeArgs}>"; + formatterConstructorArgs = "()"; } else if (MessagePackWellKnownSerializationTypes.Instance.GenericFormattersMap.TryGetValue(type.FullNameOpenType, out var mappedFormatterName)) { // Well-known generic types (Nullable, IList, List, Dictionary ...) - formatterName = $"{mappedFormatterName}<{genericTypeArgs}>()"; + formatterName = $"{mappedFormatterName}<{genericTypeArgs}>"; + formatterConstructorArgs = "()"; } return formatterName != null; } - public string MapArray(MagicOnionTypeInfo type) + public (string FormatterName, string FormatterConstructorArgs) MapArray(MagicOnionTypeInfo type) { return type.ArrayRank switch { - 1 => $"global::MemoryPack.Formatters.ArrayFormatter<{type.ElementType.FullName}>()", - 2 => $"global::MemoryPack.Formatters.TwoDimensionalArrayFormatter<{type.ElementType.FullName}>()", - 3 => $"global::MemoryPack.Formatters.ThreeDimensionalArrayFormatter<{type.ElementType.FullName}>()", - 4 => $"global::MemoryPack.Formatters.FourDimensionalArrayFormatter<{type.ElementType.FullName}>()", + 1 => ($"global::MemoryPack.Formatters.ArrayFormatter<{type.ElementType.FullName}>", "()"), + 2 => ($"global::MemoryPack.Formatters.TwoDimensionalArrayFormatter<{type.ElementType.FullName}>", "()"), + 3 => ($"global::MemoryPack.Formatters.ThreeDimensionalArrayFormatter<{type.ElementType.FullName}>", "()"), + 4 => ($"global::MemoryPack.Formatters.FourDimensionalArrayFormatter<{type.ElementType.FullName}>", "()"), _ => throw new IndexOutOfRangeException($"An array of rank must be less than 5. ({type.FullName})"), }; } diff --git a/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfo.cs b/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfo.cs index 51b8f13a0..d34759296 100644 --- a/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfo.cs +++ b/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfo.cs @@ -5,6 +5,8 @@ public interface ISerializationFormatterRegisterInfo { string FullName { get; } string FormatterName { get; } + string FormatterConstructorArgs { get; } + string FormatterNameWithConstructorArgs { get; } // e.g. MyEnumFormatter(), DynamicArgumentTupleFormatter(default, default) ... IReadOnlyList IfDirectiveConditions { get; } bool HasIfDirectiveConditions { get; } @@ -15,14 +17,17 @@ public class GenericSerializationInfo : ISerializationFormatterRegisterInfo public string FullName { get; } public string FormatterName { get; } + public string FormatterConstructorArgs { get; } + public string FormatterNameWithConstructorArgs => FormatterName + FormatterConstructorArgs; public IReadOnlyList IfDirectiveConditions { get; } public bool HasIfDirectiveConditions => IfDirectiveConditions.Any(); - public GenericSerializationInfo(string fullName, string formatterName, IReadOnlyList ifDirectiveConditions) + public GenericSerializationInfo(string fullName, string formatterName, string formatterConstructorArgs, IReadOnlyList ifDirectiveConditions) { FullName = fullName; FormatterName = formatterName; + FormatterConstructorArgs = formatterConstructorArgs; IfDirectiveConditions = ifDirectiveConditions; } } @@ -34,7 +39,9 @@ public class EnumSerializationInfo : ISerializationFormatterRegisterInfo public string FullName { get; } public string UnderlyingType { get; } - public string FormatterName => Name + "Formatter()"; + public string FormatterName => $"{Name.Replace(".", "_")}Formatter"; + public string FormatterConstructorArgs => "()"; + public string FormatterNameWithConstructorArgs => FormatterName + FormatterConstructorArgs; public IReadOnlyList IfDirectiveConditions { get; } public bool HasIfDirectiveConditions => IfDirectiveConditions.Any(); @@ -54,6 +61,8 @@ public class SerializationTypeHintInfo : ISerializationFormatterRegisterInfo public string FullName { get; } string ISerializationFormatterRegisterInfo.FormatterName => string.Empty; // Dummy + string ISerializationFormatterRegisterInfo.FormatterConstructorArgs => string.Empty; // Dummy + string ISerializationFormatterRegisterInfo.FormatterNameWithConstructorArgs => string.Empty; // Dummy public IReadOnlyList IfDirectiveConditions { get; } public bool HasIfDirectiveConditions => IfDirectiveConditions.Any(); diff --git a/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfoCollector.cs b/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfoCollector.cs index 83727428e..20bc45722 100644 --- a/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfoCollector.cs +++ b/src/MagicOnion.GeneratorCore/CodeAnalysis/SerializationInfoCollector.cs @@ -113,7 +113,9 @@ public MagicOnionSerializationInfoCollection Collect(IEnumerable\r\n {\r\n public void Serialize(ref MessagePackWriter writer, "); this.Write(this.ToStringHelper.ToStringWithCulture(info.FullName)); @@ -58,7 +58,7 @@ public virtual string TransformText() } } this.Write("\r\n}\r\n\r\n#pragma warning restore 168\r\n#pragma warning restore 219\r\n#pragma warning " + - "restore 414\r\n#pragma warning restore 612\r\n#pragma warning restore 618"); + "restore 414\r\n#pragma warning restore 612\r\n#pragma warning restore 618\r\n"); return this.GenerationEnvironment.ToString(); } } @@ -81,7 +81,7 @@ public class EnumTemplateBase /// /// The string builder that generation-time code is using to assemble generated output /// - protected System.Text.StringBuilder GenerationEnvironment + public System.Text.StringBuilder GenerationEnvironment { get { diff --git a/src/MagicOnion.GeneratorCore/CodeGen/EnumTemplate.tt b/src/MagicOnion.GeneratorCore/CodeGen/EnumTemplate.tt index 93af8d960..a7191396b 100644 --- a/src/MagicOnion.GeneratorCore/CodeGen/EnumTemplate.tt +++ b/src/MagicOnion.GeneratorCore/CodeGen/EnumTemplate.tt @@ -19,7 +19,7 @@ namespace <#= Namespace #> <# if (info.HasIfDirectiveConditions) { #> #if <#= string.Join(" || ", info.IfDirectiveConditions.Select(y => $"({y})")) #> <# } #> - public sealed class <#= info.Name #>Formatter : global::MessagePack.Formatters.IMessagePackFormatter<<#= info.FullName #>> + public sealed class <#= info.FormatterName #> : global::MessagePack.Formatters.IMessagePackFormatter<<#= info.FullName #>> { public void Serialize(ref MessagePackWriter writer, <#= info.FullName #> value, MessagePackSerializerOptions options) { @@ -42,4 +42,4 @@ namespace <#= Namespace #> #pragma warning restore 219 #pragma warning restore 414 #pragma warning restore 612 -#pragma warning restore 618 \ No newline at end of file +#pragma warning restore 618 diff --git a/src/MagicOnion.GeneratorCore/CodeGen/MemoryPackFormatterRegistrationGenerator.cs b/src/MagicOnion.GeneratorCore/CodeGen/MemoryPackFormatterRegistrationGenerator.cs index 5d628732c..c310a419d 100644 --- a/src/MagicOnion.GeneratorCore/CodeGen/MemoryPackFormatterRegistrationGenerator.cs +++ b/src/MagicOnion.GeneratorCore/CodeGen/MemoryPackFormatterRegistrationGenerator.cs @@ -69,7 +69,7 @@ public static void RegisterFormatters() using (ctx.TextWriter.IfDirective(string.Join(" || ", resolverInfo.IfDirectiveConditions.Select(y => $"({y})")))) { ctx.TextWriter.WriteLines($$""" - global::MemoryPack.MemoryPackFormatterProvider.Register(new {{(resolverInfo.FormatterName.StartsWith("global::") ? resolverInfo.FormatterName : (string.IsNullOrWhiteSpace(ctx.FormatterNamespace) ? "" : ctx.FormatterNamespace + ".") + resolverInfo.FormatterName)}}); + global::MemoryPack.MemoryPackFormatterProvider.Register(new {{(resolverInfo.FormatterName.StartsWith("global::") || string.IsNullOrWhiteSpace(ctx.FormatterNamespace) ? "" : ctx.FormatterNamespace + ".") + resolverInfo.FormatterName}}{{resolverInfo.FormatterConstructorArgs}}); """); } } diff --git a/src/MagicOnion.GeneratorCore/CodeGen/MessagePackFormatterResolverGenerator.cs b/src/MagicOnion.GeneratorCore/CodeGen/MessagePackFormatterResolverGenerator.cs index 2a08370c8..79b16707e 100644 --- a/src/MagicOnion.GeneratorCore/CodeGen/MessagePackFormatterResolverGenerator.cs +++ b/src/MagicOnion.GeneratorCore/CodeGen/MessagePackFormatterResolverGenerator.cs @@ -140,7 +140,7 @@ internal static object GetFormatter(Type t) using (ctx.TextWriter.IfDirective(string.Join(" || ", resolverInfo.IfDirectiveConditions.Select(y => $"({y})")))) { ctx.TextWriter.WriteLines($$""" - case {{index}}: return new {{(resolverInfo.FormatterName.StartsWith("global::") ? resolverInfo.FormatterName : (string.IsNullOrWhiteSpace(ctx.FormatterNamespace) ? "" : ctx.FormatterNamespace + ".") + resolverInfo.FormatterName)}}; + case {{index}}: return new {{(resolverInfo.FormatterName.StartsWith("global::") || string.IsNullOrWhiteSpace(ctx.FormatterNamespace) ? "" : ctx.FormatterNamespace + ".") + resolverInfo.FormatterName}}{{resolverInfo.FormatterConstructorArgs}}; """); } } diff --git a/src/MagicOnion.GeneratorCore/MagicOnionCompiler.cs b/src/MagicOnion.GeneratorCore/MagicOnionCompiler.cs index f0428b451..1de96a1c5 100644 --- a/src/MagicOnion.GeneratorCore/MagicOnionCompiler.cs +++ b/src/MagicOnion.GeneratorCore/MagicOnionCompiler.cs @@ -59,25 +59,26 @@ public async Task GenerateFileAsync( logger.Trace($"[{nameof(MagicOnionCompiler)}] RuntimeInformation.FrameworkDescription: {RuntimeInformation.FrameworkDescription}"); // Configure serialization - var serialization = serializerType switch + (ISerializationFormatterNameMapper Mapper, string Namespace, string InitializerName, ISerializerFormatterGenerator Generator, Func, string> EnumFormatterGenerator) + serialization = serializerType switch { SerializerType.MemoryPack => ( - Mapper: (ISerializationFormatterNameMapper)new MemoryPackFormatterNameMapper(), + Mapper: new MemoryPackFormatterNameMapper(), Namespace: @namespace, InitializerName: "MagicOnionMemoryPackFormatterProvider", - Generator: (ISerializerFormatterGenerator)new MemoryPackFormatterRegistrationGenerator(), - EnumFormatterGenerator: (Func, string>)(enumSerializationInfo => string.Empty) + Generator: new MemoryPackFormatterRegistrationGenerator(), + EnumFormatterGenerator: _ => string.Empty ), SerializerType.MessagePack => ( - Mapper: (ISerializationFormatterNameMapper)new MessagePackFormatterNameMapper(userDefinedFormattersNamespace), + Mapper: new MessagePackFormatterNameMapper(userDefinedFormattersNamespace), Namespace: namespaceDot + "Resolvers", InitializerName: "MagicOnionResolver", - Generator: (ISerializerFormatterGenerator)new MessagePackFormatterResolverGenerator(), - EnumFormatterGenerator: (Func, string>)(enumSerializationInfo => new EnumTemplate() + Generator: new MessagePackFormatterResolverGenerator(), + EnumFormatterGenerator: x => new EnumTemplate() { Namespace = namespaceDot + "Formatters", - EnumSerializationInfos = enumSerializationInfo.ToArray() - }.TransformText()) + EnumSerializationInfos = x.ToArray() + }.TransformText() ), _ => throw new NotImplementedException(), }; @@ -144,7 +145,7 @@ public async Task GenerateFileAsync( foreach (var enumSerializationInfo in serializationInfoCollection.Enums) { - Output(NormalizePath(output, namespaceDot + "Formatters", enumSerializationInfo.Name + "Formatter"), WithAutoGenerated(serialization.EnumFormatterGenerator(new []{ enumSerializationInfo }))); + Output(NormalizePath(output, namespaceDot + "Formatters", enumSerializationInfo.FormatterName), WithAutoGenerated(serialization.EnumFormatterGenerator(new []{ enumSerializationInfo }))); } foreach (var service in serviceCollection.Services) diff --git a/tests/MagicOnion.Generator.Tests/Collector/SerializationInfoCollectorTest.cs b/tests/MagicOnion.Generator.Tests/Collector/SerializationInfoCollectorTest.cs index 16689c481..ab85861be 100644 --- a/tests/MagicOnion.Generator.Tests/Collector/SerializationInfoCollectorTest.cs +++ b/tests/MagicOnion.Generator.Tests/Collector/SerializationInfoCollectorTest.cs @@ -54,8 +54,8 @@ public void Nullable() serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Enums.Should().BeEmpty(); serializationInfoCollection.Generics.Should().HaveCount(2); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.NullableFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.NullableFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.NullableFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.NullableFormatter()"); serializationInfoCollection.TypeHints.Should().HaveCount(4); // Non-nullable + Nullable } @@ -79,10 +79,10 @@ public void Generics_MergeIfDirectives() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(2); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); // NOTE: If there is a type without `if` condition, then merged if condition is always empty. (The type is always required by consumers) serializationInfoCollection.Generics[0].IfDirectiveConditions.Should().BeEmpty(); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.MyNamespace.YetAnotherGenericObjectFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.MyNamespace.YetAnotherGenericObjectFormatter()"); serializationInfoCollection.Generics[1].IfDirectiveConditions.Should().HaveCount(2); serializationInfoCollection.Generics[1].IfDirectiveConditions.Should().BeEquivalentTo("CONST_2 || DEBUG", "CONST_3"); serializationInfoCollection.TypeHints.Should().HaveCount(4); // int, string, MyGenericObject, YetAnotherGenericObject @@ -105,8 +105,8 @@ public void Generics_ManyTypeArguments() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(2); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); serializationInfoCollection.TypeHints.Should().HaveCount(5); // string, int, long, MyGenericObject, MyGenericObject } @@ -133,15 +133,15 @@ public void Enum() serializationInfoCollection.Enums.Should().HaveCount(3); serializationInfoCollection.Enums[0].Namespace.Should().Be("MyNamespace"); serializationInfoCollection.Enums[0].Name.Should().Be("MyEnum"); - serializationInfoCollection.Enums[0].FormatterName.Should().Be("MyEnumFormatter()"); + serializationInfoCollection.Enums[0].GetFormatterNameWithConstructorArgs().Should().Be("MyEnumFormatter()"); serializationInfoCollection.Enums[0].HasIfDirectiveConditions.Should().BeFalse(); serializationInfoCollection.Enums[1].Namespace.Should().Be("MyNamespace"); serializationInfoCollection.Enums[1].Name.Should().Be("MyEnumConditional"); - serializationInfoCollection.Enums[1].FormatterName.Should().Be("MyEnumConditionalFormatter()"); + serializationInfoCollection.Enums[1].GetFormatterNameWithConstructorArgs().Should().Be("MyEnumConditionalFormatter()"); serializationInfoCollection.Enums[1].IfDirectiveConditions.Should().BeEquivalentTo("CONST_1", "CONST_2"); serializationInfoCollection.Enums[2].Namespace.Should().Be("MyNamespace"); serializationInfoCollection.Enums[2].Name.Should().Be("YetAnotherEnum"); - serializationInfoCollection.Enums[2].FormatterName.Should().Be("YetAnotherEnumFormatter()"); + serializationInfoCollection.Enums[2].GetFormatterNameWithConstructorArgs().Should().Be("YetAnotherEnumFormatter()"); serializationInfoCollection.Enums[2].HasIfDirectiveConditions.Should().BeFalse(); serializationInfoCollection.TypeHints.Should().HaveCount(6); // MyEnum, MyEnumConditional, YetAnotherEnum, MyGenericObject, MyGenericObject, MyGenericObject } @@ -226,10 +226,10 @@ public void KnownTypes_Array_NonBuiltIn() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(4); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.ArrayFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.TwoDimensionalArrayFormatter()"); - serializationInfoCollection.Generics[2].FormatterName.Should().Be("global::MessagePack.Formatters.ThreeDimensionalArrayFormatter()"); - serializationInfoCollection.Generics[3].FormatterName.Should().Be("global::MessagePack.Formatters.FourDimensionalArrayFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ArrayFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TwoDimensionalArrayFormatter()"); + serializationInfoCollection.Generics[2].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ThreeDimensionalArrayFormatter()"); + serializationInfoCollection.Generics[3].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.FourDimensionalArrayFormatter()"); serializationInfoCollection.TypeHints.Should().HaveCount(5); // MyObject, MyObject[], MyObject[,], MyObject[,,], MyObject[,,,] } @@ -260,18 +260,18 @@ public void KnownTypes_Generics() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(12); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.ListFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceListFormatter2()"); - serializationInfoCollection.Generics[2].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceReadOnlyListFormatter()"); - serializationInfoCollection.Generics[3].FormatterName.Should().Be("global::MessagePack.Formatters.DictionaryFormatter()"); - serializationInfoCollection.Generics[4].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceDictionaryFormatter()"); - serializationInfoCollection.Generics[5].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceReadOnlyDictionaryFormatter()"); - serializationInfoCollection.Generics[6].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceCollectionFormatter2()"); - serializationInfoCollection.Generics[7].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceReadOnlyCollectionFormatter()"); - serializationInfoCollection.Generics[8].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceEnumerableFormatter()"); - serializationInfoCollection.Generics[9].FormatterName.Should().Be("global::MessagePack.Formatters.KeyValuePairFormatter()"); - serializationInfoCollection.Generics[10].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceLookupFormatter()"); - serializationInfoCollection.Generics[11].FormatterName.Should().Be("global::MessagePack.Formatters.InterfaceGroupingFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ListFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceListFormatter2()"); + serializationInfoCollection.Generics[2].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceReadOnlyListFormatter()"); + serializationInfoCollection.Generics[3].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.DictionaryFormatter()"); + serializationInfoCollection.Generics[4].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceDictionaryFormatter()"); + serializationInfoCollection.Generics[5].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceReadOnlyDictionaryFormatter()"); + serializationInfoCollection.Generics[6].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceCollectionFormatter2()"); + serializationInfoCollection.Generics[7].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceReadOnlyCollectionFormatter()"); + serializationInfoCollection.Generics[8].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceEnumerableFormatter()"); + serializationInfoCollection.Generics[9].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.KeyValuePairFormatter()"); + serializationInfoCollection.Generics[10].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceLookupFormatter()"); + serializationInfoCollection.Generics[11].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.InterfaceGroupingFormatter()"); serializationInfoCollection.TypeHints.Should().HaveCount(14); } @@ -330,14 +330,14 @@ public void KnownTypes_ValueTuple() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(8); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[2].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[3].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[4].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[5].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[6].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); - serializationInfoCollection.Generics[7].FormatterName.Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[2].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[3].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[4].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[5].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[6].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); + serializationInfoCollection.Generics[7].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.ValueTupleFormatter()"); serializationInfoCollection.TypeHints.Should().HaveCount(8 + 8); } @@ -364,14 +364,14 @@ public void KnownTypes_Tuple() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(8); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[2].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[3].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[4].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[5].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[6].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); - serializationInfoCollection.Generics[7].FormatterName.Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[2].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[3].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[4].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[5].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[6].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); + serializationInfoCollection.Generics[7].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.TupleFormatter()"); } [Fact] @@ -391,8 +391,8 @@ public void DynamicArgumentTuple() // Assert serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Generics.Should().HaveCount(2); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int64))"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int32))"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int64))"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int32))"); serializationInfoCollection.TypeHints.Should().HaveCount(5); // string, long, int, DynamicArgumentTuple, DynamicArgumentTuple } @@ -416,9 +416,9 @@ public void UserDefinedMessagePackSerializerFormattersNamespace() serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Enums.Should().BeEmpty(); serializationInfoCollection.Generics.Should().HaveCount(3); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.NullableFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int64))"); - serializationInfoCollection.Generics[2].FormatterName.Should().Be("global::MyFormatters.MyNamespace.MyGenericObjectFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.NullableFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int64))"); + serializationInfoCollection.Generics[2].GetFormatterNameWithConstructorArgs().Should().Be("global::MyFormatters.MyNamespace.MyGenericObjectFormatter()"); } [Fact] @@ -440,8 +440,14 @@ public void UserDefinedMessagePackSerializerFormattersNamespace_NotSpecified() serializationInfoCollection.Should().NotBeNull(); serializationInfoCollection.Enums.Should().BeEmpty(); serializationInfoCollection.Generics.Should().HaveCount(3); - serializationInfoCollection.Generics[0].FormatterName.Should().Be("global::MessagePack.Formatters.NullableFormatter()"); - serializationInfoCollection.Generics[1].FormatterName.Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int64))"); - serializationInfoCollection.Generics[2].FormatterName.Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); + serializationInfoCollection.Generics[0].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.NullableFormatter()"); + serializationInfoCollection.Generics[1].GetFormatterNameWithConstructorArgs().Should().Be("global::MagicOnion.DynamicArgumentTupleFormatter(default(global::System.String), default(global::System.Int64))"); + serializationInfoCollection.Generics[2].GetFormatterNameWithConstructorArgs().Should().Be("global::MessagePack.Formatters.MyNamespace.MyGenericObjectFormatter()"); } } + +file static class SerializationFormatterRegisterInfoExtensions +{ + public static string GetFormatterNameWithConstructorArgs(this ISerializationFormatterRegisterInfo serializationFormatterRegisterInfo) + => serializationFormatterRegisterInfo.FormatterName + serializationFormatterRegisterInfo.FormatterConstructorArgs; +} diff --git a/tests/MagicOnion.Generator.Tests/GenerateEnumFormatterTest.cs b/tests/MagicOnion.Generator.Tests/GenerateEnumFormatterTest.cs index fa97c9005..c96986911 100644 --- a/tests/MagicOnion.Generator.Tests/GenerateEnumFormatterTest.cs +++ b/tests/MagicOnion.Generator.Tests/GenerateEnumFormatterTest.cs @@ -171,4 +171,47 @@ await compiler.GenerateFileAsync( var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); symbols.Should().Contain(x => x.Name.EndsWith("MyEnumFormatter")); } + + [Fact] + public async Task GenerateEnumFormatter_Nested() + { + using var tempWorkspace = TemporaryProjectWorkarea.Create(); + tempWorkspace.AddFileToProject("IMyService.cs", @" +using System; +using MessagePack; +using MagicOnion; + +namespace TempProject +{ + public interface IMyService : IService + { + UnaryResult GetEnumAsync(MyClass.MyEnum? a); + } + + public class MyClass + { + public enum MyEnum + { + A, B, C + } + } +} + "); + + var compiler = new MagicOnionCompiler(new MagicOnionGeneratorTestOutputLogger(testOutputHelper), CancellationToken.None); + await compiler.GenerateFileAsync( + tempWorkspace.CsProjectPath, + tempWorkspace.OutputDirectory, + true, + "TempProject.Generated", + "", + "MessagePack.Formatters", + SerializerType.MessagePack + ); + + var compilation = tempWorkspace.GetOutputCompilation(); + compilation.GetCompilationErrors().Should().BeEmpty(); + var symbols = compilation.GetNamedTypeSymbolsFromGenerated(); + symbols.Should().Contain(x => x.Name.EndsWith("MyClass_MyEnumFormatter")); + } }