Skip to content

Commit d3da266

Browse files
committed
Add incremental INotifyPropertyChangedGenerator
1 parent ddeddd8 commit d3da266

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Immutable;
6+
using System.Linq;
7+
using CommunityToolkit.Mvvm.SourceGenerators.Diagnostics;
8+
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
9+
using CommunityToolkit.Mvvm.SourceGenerators.Input.Models;
10+
using Microsoft.CodeAnalysis;
11+
using Microsoft.CodeAnalysis.CSharp.Syntax;
12+
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
13+
14+
namespace CommunityToolkit.Mvvm.SourceGenerators;
15+
16+
/// <summary>
17+
/// A source generator for the <c>INotifyPropertyChangedAttribute</c> type.
18+
/// </summary>
19+
[Generator(LanguageNames.CSharp)]
20+
public sealed class INotifyPropertyChangedGenerator2 : TransitiveMembersGenerator2<INotifyPropertyChangedInfo>
21+
{
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="INotifyPropertyChangedGenerator2"/> class.
24+
/// </summary>
25+
public INotifyPropertyChangedGenerator2()
26+
: base("global::CommunityToolkit.Mvvm.ComponentModel.INotifyPropertyChangedAttribute")
27+
{
28+
}
29+
30+
/// <inheritdoc/>
31+
protected override INotifyPropertyChangedInfo GetInfo(AttributeData attributeData)
32+
{
33+
if (attributeData.TryGetNamedArgument("IncludeAdditionalHelperMethods", out bool includeAdditionalHelperMethods))
34+
{
35+
return new(includeAdditionalHelperMethods);
36+
}
37+
38+
return new(false);
39+
}
40+
41+
/// <inheritdoc/>
42+
protected override bool ValidateTargetType(
43+
INamedTypeSymbol typeSymbol,
44+
INotifyPropertyChangedInfo info,
45+
out ImmutableArray<Diagnostic> diagnostics)
46+
{
47+
ImmutableArray<Diagnostic>.Builder builder = ImmutableArray.CreateBuilder<Diagnostic>();
48+
49+
// Check if the type already implements INotifyPropertyChanged
50+
if (typeSymbol.AllInterfaces.Any(i => i.HasFullyQualifiedName("global::System.ComponentModel.INotifyPropertyChanged")))
51+
{
52+
builder.Add(DuplicateINotifyPropertyChangedInterfaceForINotifyPropertyChangedAttributeError, typeSymbol, typeSymbol);
53+
54+
diagnostics = builder.ToImmutable();
55+
56+
return false;
57+
}
58+
59+
diagnostics = builder.ToImmutable();
60+
61+
return true;
62+
}
63+
64+
/// <inheritdoc/>
65+
protected override ImmutableArray<MemberDeclarationSyntax> FilterDeclaredMembers(INotifyPropertyChangedInfo info, ClassDeclarationSyntax classDeclaration)
66+
{
67+
// If requested, only include the event and the basic methods to raise it, but not the additional helpers
68+
if (!info.IncludeAdditionalHelperMethods)
69+
{
70+
return classDeclaration.Members.Where(
71+
static member => member
72+
is EventFieldDeclarationSyntax
73+
or MethodDeclarationSyntax { Identifier.ValueText: "OnPropertyChanged" }).ToImmutableArray();
74+
}
75+
76+
return classDeclaration.Members.ToImmutableArray();
77+
}
78+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.Mvvm.SourceGenerators.Input.Models;
6+
7+
/// <summary>
8+
/// A model with gathered info on a given <c>INotifyPropertyChangedAttribute</c> instance.
9+
/// </summary>
10+
/// <param name="IncludeAdditionalHelperMethods">Whether to also generate helper methods in the target type.</param>
11+
public sealed record INotifyPropertyChangedInfo(bool IncludeAdditionalHelperMethods);

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.Incremental.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ public abstract partial class TransitiveMembersGenerator2<TInfo> : IIncrementalG
4848
/// </summary>
4949
/// <param name="attributeType">The fully qualified name of the attribute type to look for.</param>
5050
/// <param name="comparer">An <see cref="IEqualityComparer{T}"/> instance to compare intermediate models.</param>
51-
protected TransitiveMembersGenerator2(string attributeType, IEqualityComparer<TInfo> comparer)
51+
private protected TransitiveMembersGenerator2(string attributeType, IEqualityComparer<TInfo>? comparer = null)
5252
{
5353
this.attributeType = attributeType;
54-
this.comparer = comparer;
54+
this.comparer = comparer ?? EqualityComparer<TInfo>.Default;
5555

5656
string attributeTypeName = attributeType.Split('.').Last();
5757
string filename = $"CommunityToolkit.Mvvm.SourceGenerators.EmbeddedResources.{attributeTypeName.Replace("Attribute", string.Empty)}.cs";

0 commit comments

Comments
 (0)