Skip to content

Commit

Permalink
Merge pull request #333 from pixsperdavid/main
Browse files Browse the repository at this point in the history
Added support for nested classes
  • Loading branch information
neuecc authored Sep 19, 2024
2 parents 1d361dc + f45bb22 commit a42cbcb
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 27 deletions.
16 changes: 8 additions & 8 deletions src/MemoryPack.Generator/DiagnosticDescriptors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ internal static class DiagnosticDescriptors
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor NestedNotAllow = new(
id: "MEMPACK002",
title: "MemoryPackable object must not be nested type",
messageFormat: "The MemoryPackable object '{0}' must be not nested type",
category: Category,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor AbstractMustUnion = new(
id: "MEMPACK003",
title: "abstract/interface type of MemoryPackable object must annotate with Union",
Expand Down Expand Up @@ -340,4 +332,12 @@ internal static class DiagnosticDescriptors
category: Category,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

public static readonly DiagnosticDescriptor NestedContainingTypesMustBePartial = new(
id: "MEMPACK042",
title: "Nested MemoryPackable object's containing type(s) must be partial",
messageFormat: "The MemoryPackable object '{0}' containing type(s) must be partial",
category: Category,
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);
}
45 changes: 42 additions & 3 deletions src/MemoryPack.Generator/MemoryPackGenerator.Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ static void Generate(TypeDeclarationSyntax syntax, Compilation compilation, stri
return;
}

// nested is not allowed
if (IsNested(syntax))
if (IsNested(syntax) && !IsNestedContainingTypesPartial(syntax))
{
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.NestedNotAllow, syntax.Identifier.GetLocation(), typeSymbol.Name));
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.NestedContainingTypesMustBePartial, syntax.Identifier.GetLocation(), typeSymbol.Name));
return;
}

Expand Down Expand Up @@ -157,6 +156,21 @@ static bool IsPartial(TypeDeclarationSyntax typeDeclaration)
return typeDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword));
}

static bool IsNestedContainingTypesPartial(TypeDeclarationSyntax typeDeclaration)
{
if (typeDeclaration.Parent is TypeDeclarationSyntax parentTypeDeclaration)
{
if (!IsPartial(parentTypeDeclaration))
return false;

return IsNestedContainingTypesPartial(parentTypeDeclaration);
}
else
{
return true;
}
}

static bool IsNested(TypeDeclarationSyntax typeDeclaration)
{
return typeDeclaration.Parent is TypeDeclarationSyntax;
Expand Down Expand Up @@ -296,6 +310,21 @@ public void Emit(StringBuilder writer, IGeneratorContext context)
(false, false) => "class",
};

var containingTypeDeclarations = new List<string>();
var containingType = Symbol.ContainingType;
while (containingType is not null)
{
containingTypeDeclarations.Add((containingType.IsRecord, containingType.IsValueType) switch
{
(true, true) => $"partial record struct {containingType.Name}",
(true, false) => $"partial record {containingType.Name}",
(false, true) => $"partial struct {containingType.Name}",
(false, false) => $"partial class {containingType.Name}",
});
containingType = containingType.ContainingType;
}
containingTypeDeclarations.Reverse();

var nullable = IsValueType ? "" : "?";

string staticRegisterFormatterMethod, staticMemoryPackableMethod, scopedRef, constraint, registerBody, registerT;
Expand Down Expand Up @@ -345,6 +374,12 @@ public void Emit(StringBuilder writer, IGeneratorContext context)
? "Serialize(ref MemoryPackWriter"
: "Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter>";

foreach (var declaration in containingTypeDeclarations)
{
writer.AppendLine(declaration);
writer.AppendLine("{");
}

writer.AppendLine($$"""
partial {{classOrStructOrRecord}} {{TypeName}} : IMemoryPackable<{{TypeName}}>{{fixedSizeInterface}}
{
Expand Down Expand Up @@ -420,6 +455,10 @@ public override void Deserialize(ref MemoryPackReader reader, {{scopedRef}} {{Ty
writer.AppendLine(code);
}

for(int i = 0; i < containingTypeDeclarations.Count; ++i)
{
writer.AppendLine("}");
}
}

private string EmitDeserializeBody()
Expand Down
33 changes: 17 additions & 16 deletions tests/MemoryPack.Tests/GeneratorDiagnosticsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,6 @@ public class Hoge
""");
}

[Fact]
public void MEMPACK002_NestedNotAllow()
{
Compile(2, """
using MemoryPack;
public partial class Hoge
{
[MemoryPackable]
public partial class Huga
{
}
}
""");
}

[Fact]
public void MEMPACK003_AbstractMustUnion()
{
Expand Down Expand Up @@ -703,6 +687,23 @@ public partial struct Tester
}
""");
}

[Fact]
public void MEMPACK042_NestedContainingTypesMustBePartial()
{
Compile(42, """
using MemoryPack;
public struct NestedContainer
{
[MemoryPackable]
public partial struct NestedStruct
{
public int I1 { get; init; }
}
}
""");
}
}

#endif
7 changes: 7 additions & 0 deletions tests/MemoryPack.Tests/GeneratorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ public void Standard()
VerifyEquivalent(new GlobalNamespaceType() { MyProperty = 10000 });
}

[Fact]
public void Nested()
{
VerifyEquivalent(new NestedContainer.StandardTypeNested() { One = 9999 });
VerifyEquivalent(new DoublyNestedContainer.DoublyNestedContainerInner.StandardTypeDoublyNested() { One = 9999 });
}

[Fact]
public void Null()
{
Expand Down
21 changes: 21 additions & 0 deletions tests/MemoryPack.Tests/Models/StandardType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ public StandardStruct()
}
}

public partial class NestedContainer
{
[MemoryPackable]
public partial class StandardTypeNested
{
public int One { get; set; }
}
}

public partial class DoublyNestedContainer
{
public partial class DoublyNestedContainerInner
{
[MemoryPackable]
public partial class StandardTypeDoublyNested
{
public int One { get; set; }
}
}
}


[MemoryPackable]
public partial class WithArray
Expand Down

0 comments on commit a42cbcb

Please sign in to comment.