Skip to content

Commit afc7232

Browse files
committed
Improve custom filtering support in TransitiveMembersGenerator<TInfo>
1 parent a7e0f2c commit afc7232

File tree

5 files changed

+56
-26
lines changed

5 files changed

+56
-26
lines changed

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/INotifyPropertyChangedGenerator.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System.Collections.Generic;
65
using System.Collections.Immutable;
76
using System.Linq;
87
using CommunityToolkit.Mvvm.SourceGenerators.Diagnostics;
98
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
109
using CommunityToolkit.Mvvm.SourceGenerators.Input.Models;
1110
using Microsoft.CodeAnalysis;
12-
using Microsoft.CodeAnalysis.CSharp;
1311
using Microsoft.CodeAnalysis.CSharp.Syntax;
1412
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
1513

@@ -30,11 +28,18 @@ public INotifyPropertyChangedGenerator()
3028
}
3129

3230
/// <inheritdoc/>
33-
protected override INotifyPropertyChangedInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
31+
protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, INotifyPropertyChangedInfo Info)> GetInfo(
32+
IncrementalGeneratorInitializationContext context,
33+
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
3434
{
35-
bool includeAdditionalHelperMethods = attributeData.GetNamedArgument<bool>("IncludeAdditionalHelperMethods", true);
35+
static INotifyPropertyChangedInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
36+
{
37+
bool includeAdditionalHelperMethods = attributeData.GetNamedArgument<bool>("IncludeAdditionalHelperMethods", true);
38+
39+
return new(includeAdditionalHelperMethods);
40+
}
3641

37-
return new(includeAdditionalHelperMethods);
42+
return source.Select(static (item, _) => (item.Symbol, GetInfo(item.Symbol, item.AttributeData)));
3843
}
3944

4045
/// <inheritdoc/>

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableObjectGenerator.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ public ObservableObjectGenerator()
2828
}
2929

3030
/// <inheritdoc/>
31-
protected override object? GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
31+
protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, object? Info)> GetInfo(
32+
IncrementalGeneratorInitializationContext context,
33+
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
3234
{
33-
return null;
35+
return source.Select(static (item, _) => (item.Symbol, (object?)null));
3436
}
3537

3638
/// <inheritdoc/>

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,25 @@ public ObservableRecipientGenerator()
3030
}
3131

3232
/// <inheritdoc/>
33-
protected override ObservableRecipientInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
33+
protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, ObservableRecipientInfo Info)> GetInfo(
34+
IncrementalGeneratorInitializationContext context,
35+
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
3436
{
35-
string typeName = typeSymbol.Name;
36-
bool hasExplicitConstructors = !(typeSymbol.InstanceConstructors.Length == 1 && typeSymbol.InstanceConstructors[0] is { Parameters.IsEmpty: true, IsImplicitlyDeclared: true });
37-
bool isAbstract = typeSymbol.IsAbstract;
38-
bool isObservableValidator = typeSymbol.InheritsFrom("global::CommunityToolkit.Mvvm.ComponentModel.ObservableValidator");
39-
40-
return new(
41-
typeName,
42-
hasExplicitConstructors,
43-
isAbstract,
44-
isObservableValidator);
37+
static ObservableRecipientInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
38+
{
39+
string typeName = typeSymbol.Name;
40+
bool hasExplicitConstructors = !(typeSymbol.InstanceConstructors.Length == 1 && typeSymbol.InstanceConstructors[0] is { Parameters.IsEmpty: true, IsImplicitlyDeclared: true });
41+
bool isAbstract = typeSymbol.IsAbstract;
42+
bool isObservableValidator = typeSymbol.InheritsFrom("global::CommunityToolkit.Mvvm.ComponentModel.ObservableValidator");
43+
44+
return new(
45+
typeName,
46+
hasExplicitConstructors,
47+
isAbstract,
48+
isObservableValidator);
49+
}
50+
51+
return source.Select(static (item, _) => (item.Symbol, GetInfo(item.Symbol, item.AttributeData)));
4552
}
4653

4754
/// <inheritdoc/>

CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
8080
static (context, _) => (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
8181

8282
// Filter the types with the target attribute
83-
IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> typeSymbolsWithInfo =
83+
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> typeSymbolsWithAttributeData =
8484
typeSymbols
8585
.Select((item, _) => (
8686
Symbol: item,
8787
Attribute: item.GetAttributes().FirstOrDefault(a => a.AttributeClass?.HasFullyQualifiedName(this.attributeType) == true)))
88-
.Where(static item => item.Attribute is not null)!
89-
.Select((item, _) => (item.Symbol, GetInfo(item.Symbol, item.Attribute!)));
88+
.Where(static item => item.Attribute is not null)!;
89+
90+
// Transform the input data
91+
IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> typeSymbolsWithInfo = GetInfo(context, typeSymbolsWithAttributeData);
9092

9193
// Filter by language version
9294
context.FilterWithLanguageVersion(ref typeSymbolsWithInfo, LanguageVersion.CSharp8, UnsupportedCSharpLanguageVersionError);
@@ -129,12 +131,14 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
129131
}
130132

131133
/// <summary>
132-
/// Gets an info model from a retrieved <see cref="AttributeData"/> instance.
134+
/// Gathers info from a source <see cref="IncrementalValuesProvider{TValues}"/> input.
133135
/// </summary>
134-
/// <param name="typeSymbol">The <see cref="INamedTypeSymbol"/> instance for the target type.</param>
135-
/// <param name="attributeData">The input <see cref="AttributeData"/> to get info from.</param>
136-
/// <returns>A <typeparamref name="TInfo"/> instance with data extracted from <paramref name="attributeData"/>.</returns>
137-
protected abstract TInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData);
136+
/// <param name="context">The <see cref="IncrementalGeneratorInitializationContext"/> instance in use.</param>
137+
/// <param name="source">The source <see cref="IncrementalValuesProvider{TValues}"/> input.</param>
138+
/// <returns>A transformed <see cref="IncrementalValuesProvider{TValues}"/> instance with the gathered data.</returns>
139+
protected abstract IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> GetInfo(
140+
IncrementalGeneratorInitializationContext context,
141+
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source);
138142

139143
/// <summary>
140144
/// Validates a target type being processed.

CommunityToolkit.Mvvm.SourceGenerators/EmbeddedResources/ObservableRecipient.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ protected ObservableRecipient(global::CommunityToolkit.Mvvm.Messaging.IMessenger
4242
public bool IsActive
4343
{
4444
get => this.isActive;
45+
46+
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
47+
"When this property is set to true, the OnActivated() method will be invoked, which will register all necessary message handlers for this recipient. " +
48+
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
49+
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
50+
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type. " +
51+
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
4552
set
4653
{
4754
if (SetProperty(ref this.isActive, value, true))
@@ -69,6 +76,11 @@ public bool IsActive
6976
/// If you need more fine tuned control, want to register messages individually or just prefer
7077
/// the lambda-style syntax for message registration, override this method and register manually.
7178
/// </remarks>
79+
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
80+
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
81+
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
82+
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type. " +
83+
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
7284
protected virtual void OnActivated()
7385
{
7486
global::CommunityToolkit.Mvvm.Messaging.IMessengerExtensions.RegisterAll(Messenger, this);

0 commit comments

Comments
 (0)