Skip to content

Commit e698d06

Browse files
committed
Add support for nested record types
1 parent 7f4888d commit e698d06

File tree

3 files changed

+35
-19
lines changed

3 files changed

+35
-19
lines changed

CommunityToolkit.Mvvm.SourceGenerators/Models/HierarchyInfo.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ public static HierarchyInfo From(INamedTypeSymbol typeSymbol)
4040
{
4141
hierarchy.Add(new TypeInfo(
4242
parent.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
43-
parent.TypeKind));
43+
parent.TypeKind,
44+
parent.IsRecord));
4445
}
4546

4647
return new(

CommunityToolkit.Mvvm.SourceGenerators/Models/TypeInfo.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using Microsoft.CodeAnalysis;
6+
using Microsoft.CodeAnalysis.CSharp;
67
using Microsoft.CodeAnalysis.CSharp.Syntax;
78
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
89

@@ -13,7 +14,8 @@ namespace CommunityToolkit.Mvvm.SourceGenerators.Models;
1314
/// </summary>
1415
/// <param name="QualifiedName">The qualified name for the type.</param>
1516
/// <param name="Kind">The type of the type in the hierarchy.</param>
16-
internal sealed record TypeInfo(string QualifiedName, TypeKind Kind)
17+
/// <param name="IsRecord">Whether the type is a record type.</param>
18+
internal sealed record TypeInfo(string QualifiedName, TypeKind Kind, bool IsRecord)
1719
{
1820
/// <summary>
1921
/// Creates a <see cref="TypeDeclarationSyntax"/> instance for the current info.
@@ -27,10 +29,17 @@ public TypeDeclarationSyntax GetSyntax()
2729
// <TYPE_KIND> <TYPE_NAME>
2830
// {
2931
// }
32+
//
33+
// Note that specifically for record declarations, we also need to explicitly add the open
34+
// and close brace tokens, otherwise member declarations will not be formatted correctly.
3035
return Kind switch
3136
{
3237
TypeKind.Struct => StructDeclaration(QualifiedName),
3338
TypeKind.Interface => InterfaceDeclaration(QualifiedName),
39+
TypeKind.Class when IsRecord =>
40+
RecordDeclaration(Token(SyntaxKind.RecordKeyword), QualifiedName)
41+
.WithOpenBraceToken(Token(SyntaxKind.OpenBraceToken))
42+
.WithCloseBraceToken(Token(SyntaxKind.CloseBraceToken)),
3443
_ => ClassDeclaration(QualifiedName)
3544
};
3645
}

tests/CommunityToolkit.Mvvm.UnitTests/Test_SourceGenerators.cs

+23-17
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public partial class Test_SourceGenerators
2020
public void Test_SourceGenerators_NestedTypesThatAreNotJustClasses()
2121
{
2222
// This test just needs to compile, mostly
23-
NestedStructType.NestedInterfaceType.MyViewModel model = new();
23+
NestedStructType.NestedInterfaceType.NestedRecord.MyViewModel model = new();
2424

2525
Assert.IsNull(model.Name);
2626
Assert.IsTrue(model.TestCommand is IRelayCommand);
@@ -30,16 +30,19 @@ public partial struct NestedStructType
3030
{
3131
public partial interface NestedInterfaceType
3232
{
33-
[ObservableRecipient]
34-
public partial class MyViewModel : ObservableValidator
33+
public partial record NestedRecord
3534
{
36-
[ObservableProperty]
37-
[Required]
38-
private string? name;
39-
40-
[ICommand]
41-
private void Test()
35+
[ObservableRecipient]
36+
public partial class MyViewModel : ObservableValidator
4237
{
38+
[ObservableProperty]
39+
[Required]
40+
private string? name;
41+
42+
[ICommand]
43+
private void Test()
44+
{
45+
}
4346
}
4447
}
4548
}
@@ -49,7 +52,7 @@ private void Test()
4952
public void Test_SourceGenerators_NestedTypesThatAreNotJustClassesAndWithGenerics()
5053
{
5154
// This test just needs to compile, mostly
52-
NestedStructTypeWithGenerics<int, float>.NestedInterfaceType<string>.MyViewModel model = new();
55+
NestedStructTypeWithGenerics<int, float>.NestedInterfaceType<string>.NestedRecord<string>.MyViewModel model = new();
5356

5457
Assert.IsNull(model.Name);
5558
Assert.IsTrue(model.TestCommand is IRelayCommand);
@@ -60,15 +63,18 @@ public partial struct NestedStructTypeWithGenerics<T1, T2>
6063
{
6164
public partial interface NestedInterfaceType<TFoo>
6265
{
63-
[INotifyPropertyChanged]
64-
public partial class MyViewModel
66+
public partial record NestedRecord<TBar>
6567
{
66-
[ObservableProperty]
67-
private string? name;
68-
69-
[ICommand]
70-
private void Test()
68+
[INotifyPropertyChanged]
69+
public partial class MyViewModel
7170
{
71+
[ObservableProperty]
72+
private string? name;
73+
74+
[ICommand]
75+
private void Test()
76+
{
77+
}
7278
}
7379
}
7480
}

0 commit comments

Comments
 (0)