Skip to content

Commit 4bb6067

Browse files
committed
Fix nullability annotations in generated properties
1 parent bf4b5f6 commit 4bb6067

File tree

4 files changed

+21
-20
lines changed

4 files changed

+21
-20
lines changed

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/Models/PropertyInfo.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ namespace CommunityToolkit.Mvvm.SourceGenerators.ComponentModel.Models;
1414
/// <summary>
1515
/// A model representing an generated property
1616
/// </summary>
17-
/// <param name="TypeName">The type name for the generated property.</param>
18-
/// <param name="IsNullableReferenceType">Whether or not the property is of a nullable reference type.</param>
17+
/// <param name="TypeNameWithNullabilityAnnotations">The type name for the generated property, including nullability annotations.</param>
1918
/// <param name="FieldName">The field name.</param>
2019
/// <param name="PropertyName">The generated property name.</param>
2120
/// <param name="PropertyChangingNames">The sequence of property changing properties to notify.</param>
@@ -24,8 +23,7 @@ namespace CommunityToolkit.Mvvm.SourceGenerators.ComponentModel.Models;
2423
/// <param name="AlsoBroadcastChange">Whether or not the generated property also broadcasts changes.</param>
2524
/// <param name="ValidationAttributes">The sequence of validation attributes for the generated property.</param>
2625
internal sealed record PropertyInfo(
27-
string TypeName,
28-
bool IsNullableReferenceType,
26+
string TypeNameWithNullabilityAnnotations,
2927
string FieldName,
3028
string PropertyName,
3129
ImmutableArray<string> PropertyChangingNames,
@@ -42,8 +40,7 @@ public sealed class Comparer : Comparer<PropertyInfo, Comparer>
4240
/// <inheritdoc/>
4341
protected override void AddToHashCode(ref HashCode hashCode, PropertyInfo obj)
4442
{
45-
hashCode.Add(obj.TypeName);
46-
hashCode.Add(obj.IsNullableReferenceType);
43+
hashCode.Add(obj.TypeNameWithNullabilityAnnotations);
4744
hashCode.Add(obj.FieldName);
4845
hashCode.Add(obj.PropertyName);
4946
hashCode.AddRange(obj.PropertyChangingNames);
@@ -57,8 +54,7 @@ protected override void AddToHashCode(ref HashCode hashCode, PropertyInfo obj)
5754
protected override bool AreEqual(PropertyInfo x, PropertyInfo y)
5855
{
5956
return
60-
x.TypeName == y.TypeName &&
61-
x.IsNullableReferenceType == y.IsNullableReferenceType &&
57+
x.TypeNameWithNullabilityAnnotations == y.TypeNameWithNullabilityAnnotations &&
6258
x.FieldName == y.FieldName &&
6359
x.PropertyName == y.PropertyName &&
6460
x.PropertyChangingNames.SequenceEqual(y.PropertyChangingNames) &&

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.Execute.cs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ internal static class Execute
4949
}
5050

5151
// Get the property type and name
52-
string typeName = fieldSymbol.Type.GetFullyQualifiedName();
53-
bool isNullableReferenceType = fieldSymbol.Type is { IsReferenceType: true, NullableAnnotation: NullableAnnotation.Annotated };
52+
string typeNameWithNullabilityAnnotations = fieldSymbol.Type.GetFullyQualifiedNameWithNullabilityAnnotations();
5453
string fieldName = fieldSymbol.Name;
5554
string propertyName = GetGeneratedPropertyName(fieldSymbol);
5655

@@ -124,8 +123,7 @@ internal static class Execute
124123
diagnostics = builder.ToImmutable();
125124

126125
return new(
127-
typeName,
128-
isNullableReferenceType,
126+
typeNameWithNullabilityAnnotations,
129127
fieldName,
130128
propertyName,
131129
propertyChangingNames.ToImmutable(),
@@ -406,10 +404,8 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
406404
{
407405
ImmutableArray<StatementSyntax>.Builder setterStatements = ImmutableArray.CreateBuilder<StatementSyntax>();
408406

409-
// Get the property type syntax (adding the nullability annotation, if needed)
410-
TypeSyntax propertyType = propertyInfo.IsNullableReferenceType
411-
? NullableType(IdentifierName(propertyInfo.TypeName))
412-
: IdentifierName(propertyInfo.TypeName);
407+
// Get the property type syntax
408+
TypeSyntax propertyType = IdentifierName(propertyInfo.TypeNameWithNullabilityAnnotations);
413409

414410
// In case the backing field is exactly named "value", we need to add the "this." prefix to ensure that comparisons and assignments
415411
// with it in the generated setter body are executed correctly and without conflicts with the implicit value parameter.
@@ -602,10 +598,8 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
602598
/// <returns>The generated <see cref="MemberDeclarationSyntax"/> instances for the <c>OnPropertyChanging</c> and <c>OnPropertyChanged</c> methods.</returns>
603599
public static ImmutableArray<MemberDeclarationSyntax> GetOnPropertyChangeMethodsSyntax(PropertyInfo propertyInfo)
604600
{
605-
// Get the parameter type syntax (adding the nullability annotation, if needed)
606-
TypeSyntax parameterType = propertyInfo.IsNullableReferenceType
607-
? NullableType(IdentifierName(propertyInfo.TypeName))
608-
: IdentifierName(propertyInfo.TypeName);
601+
// Get the property type syntax
602+
TypeSyntax parameterType = IdentifierName(propertyInfo.TypeNameWithNullabilityAnnotations);
609603

610604
// Construct the generated method as follows:
611605
//

CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ public static string GetFullyQualifiedName(this ISymbol symbol)
2222
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
2323
}
2424

25+
/// <summary>
26+
/// Gets the fully qualified name for a given symbol, including nullability annotations
27+
/// </summary>
28+
/// <param name="symbol">The input <see cref="ISymbol"/> instance.</param>
29+
/// <returns>The fully qualified name for <paramref name="symbol"/>.</returns>
30+
public static string GetFullyQualifiedNameWithNullabilityAnnotations(this ISymbol symbol)
31+
{
32+
return symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat.AddMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.IncludeNullableReferenceTypeModifier));
33+
}
34+
2535
/// <summary>
2636
/// Checks whether or not a given type symbol has a specified full name.
2737
/// </summary>

tests/CommunityToolkit.Mvvm.UnitTests/Test_ObservablePropertyAttribute.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.ComponentModel.DataAnnotations;
99
using System.Linq;
1010
using System.Reflection;
11+
using System.Runtime.CompilerServices;
1112
using System.Threading.Tasks;
1213
using CommunityToolkit.Mvvm.ComponentModel;
1314
using CommunityToolkit.Mvvm.Input;

0 commit comments

Comments
 (0)