From ac8ea8068d9025aab9d2d6ca59e260111ede1ec2 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Sat, 3 Feb 2024 21:01:12 -0800 Subject: [PATCH] Fix type wrapping order Types were being wrapped inside out, i.e. if you have some nested type A.B.C.D, the partial type for D was being synthesized as C.B.A.D. This fixes the order for both serialization and deserialization. --- src/generator/TypeDeclContext.cs | 2 + .../Serde.Generation.Test/DeserializeTests.cs | 24 ++++++ test/Serde.Generation.Test/SerializeTests.cs | 24 ++++++ ...alClasses#A.B.C.D.IDeserialize.verified.cs | 78 +++++++++++++++++++ ...tialClasses#A.B.C.D.ISerialize.verified.cs | 24 ++++++ ...alClasses#A.B.C.D.ISerialize`1.verified.cs | 24 ++++++ 6 files changed, 176 insertions(+) create mode 100644 test/Serde.Generation.Test/test_output/DeserializeTests/NestedPartialClasses#A.B.C.D.IDeserialize.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize.verified.cs create mode 100644 test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize`1.verified.cs diff --git a/src/generator/TypeDeclContext.cs b/src/generator/TypeDeclContext.cs index a4be8c93..87bbc181 100644 --- a/src/generator/TypeDeclContext.cs +++ b/src/generator/TypeDeclContext.cs @@ -39,6 +39,8 @@ public TypeDeclContext(BaseTypeDeclarationSyntax typeDecl) break; } } + nsNames.Reverse(); + parentTypeInfos.Reverse(); NamespaceNames = nsNames; ParentTypeInfo = parentTypeInfos; TypeParameterList = typeDecl is TypeDeclarationSyntax derived diff --git a/test/Serde.Generation.Test/DeserializeTests.cs b/test/Serde.Generation.Test/DeserializeTests.cs index 21208975..66fde99b 100644 --- a/test/Serde.Generation.Test/DeserializeTests.cs +++ b/test/Serde.Generation.Test/DeserializeTests.cs @@ -177,6 +177,30 @@ public enum ColorULong : ulong { Red = 3, Green = 5, Blue = 7 } return GeneratorTestUtils.VerifyMultiFile(src); } + [Fact] + public Task NestedPartialClasses() + { + var src = """ +using Serde; + +partial class A +{ + private partial class B + { + private partial class C + { + [GenerateDeserialize] + private partial class D + { + public int Field; + } + } + } +} +"""; + return VerifyDeserialize(src); + } + private static Task VerifyDeserialize( string src, [CallerMemberName] string caller = "") diff --git a/test/Serde.Generation.Test/SerializeTests.cs b/test/Serde.Generation.Test/SerializeTests.cs index bd072f16..0cd7ede7 100644 --- a/test/Serde.Generation.Test/SerializeTests.cs +++ b/test/Serde.Generation.Test/SerializeTests.cs @@ -560,6 +560,30 @@ public enum Rgb { Red, Green, Blue } return VerifyMultiFile(src); } + [Fact] + public Task NestedPartialClasses() + { + var src = """ +using Serde; + +partial class A +{ + private partial class B + { + private partial class C + { + [GenerateSerialize] + private partial class D + { + public int Field; + } + } + } +} +"""; + return VerifySerialize(src); + } + private static Task VerifySerialize( string src, [CallerMemberName] string callerName = "") diff --git a/test/Serde.Generation.Test/test_output/DeserializeTests/NestedPartialClasses#A.B.C.D.IDeserialize.verified.cs b/test/Serde.Generation.Test/test_output/DeserializeTests/NestedPartialClasses#A.B.C.D.IDeserialize.verified.cs new file mode 100644 index 00000000..f260b950 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/DeserializeTests/NestedPartialClasses#A.B.C.D.IDeserialize.verified.cs @@ -0,0 +1,78 @@ +//HintName: A.B.C.D.IDeserialize.cs + +#nullable enable +using System; +using Serde; + +partial class A +{ + partial class B + { + partial class C + { + partial class D : Serde.IDeserialize + { + static A.B.C.D Serde.IDeserialize.Deserialize(ref D deserializer) + { + var visitor = new SerdeVisitor(); + var fieldNames = new[] + { + "Field" + }; + return deserializer.DeserializeType("D", fieldNames, visitor); + } + + private sealed class SerdeVisitor : Serde.IDeserializeVisitor + { + public string ExpectedTypeName => "A.B.C.D"; + + private struct FieldNameVisitor : Serde.IDeserialize, Serde.IDeserializeVisitor + { + public static byte Deserialize(ref D deserializer) + where D : IDeserializer => deserializer.DeserializeString(new FieldNameVisitor()); + public string ExpectedTypeName => "string"; + + byte Serde.IDeserializeVisitor.VisitString(string s) => VisitUtf8Span(System.Text.Encoding.UTF8.GetBytes(s)); + public byte VisitUtf8Span(System.ReadOnlySpan s) + { + switch (s[0]) + { + case (byte)'f'when s.SequenceEqual("field"u8): + return 1; + default: + return 0; + } + } + } + + A.B.C.D Serde.IDeserializeVisitor.VisitDictionary(ref D d) + { + int _l_field = default !; + byte _r_assignedValid = 0b0; + while (d.TryGetNextKey(out byte key)) + { + switch (key) + { + case 1: + _l_field = d.GetNextValue(); + _r_assignedValid |= ((byte)1) << 0; + break; + } + } + + if (_r_assignedValid != 0b1) + { + throw new Serde.InvalidDeserializeValueException("Not all members were assigned"); + } + + var newType = new A.B.C.D() + { + Field = _l_field, + }; + return newType; + } + } + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize.verified.cs new file mode 100644 index 00000000..8efd8ea4 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize.verified.cs @@ -0,0 +1,24 @@ +//HintName: A.B.C.D.ISerialize.cs + +#nullable enable +using System; +using Serde; + +partial class A +{ + partial class B + { + partial class C + { + partial class D : Serde.ISerialize + { + void Serde.ISerialize.Serialize(ISerializer serializer) + { + var type = serializer.SerializeType("D", 1); + type.SerializeField("field"u8, new Int32Wrap(this.Field)); + type.End(); + } + } + } + } +} \ No newline at end of file diff --git a/test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize`1.verified.cs b/test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize`1.verified.cs new file mode 100644 index 00000000..72c51978 --- /dev/null +++ b/test/Serde.Generation.Test/test_output/SerializeTests/NestedPartialClasses#A.B.C.D.ISerialize`1.verified.cs @@ -0,0 +1,24 @@ +//HintName: A.B.C.D.ISerialize`1.cs + +#nullable enable +using System; +using Serde; + +partial class A +{ + partial class B + { + partial class C + { + partial class D : Serde.ISerialize + { + void ISerialize.Serialize(A.B.C.D value, ISerializer serializer) + { + var type = serializer.SerializeType("D", 1); + type.SerializeField("field", value.Field); + type.End(); + } + } + } + } +} \ No newline at end of file