Improve custom filtering support in TransitiveMembersGenerator<TInfo>
This commit is contained in:
Родитель
a7e0f2c370
Коммит
afc7232dc7
|
@ -2,14 +2,12 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.SourceGenerators.Diagnostics;
|
||||
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
|
||||
using CommunityToolkit.Mvvm.SourceGenerators.Input.Models;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
|
||||
|
||||
|
@ -30,11 +28,18 @@ public sealed class INotifyPropertyChangedGenerator : TransitiveMembersGenerator
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override INotifyPropertyChangedInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
|
||||
protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, INotifyPropertyChangedInfo Info)> GetInfo(
|
||||
IncrementalGeneratorInitializationContext context,
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
|
||||
{
|
||||
bool includeAdditionalHelperMethods = attributeData.GetNamedArgument<bool>("IncludeAdditionalHelperMethods", true);
|
||||
static INotifyPropertyChangedInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
|
||||
{
|
||||
bool includeAdditionalHelperMethods = attributeData.GetNamedArgument<bool>("IncludeAdditionalHelperMethods", true);
|
||||
|
||||
return new(includeAdditionalHelperMethods);
|
||||
return new(includeAdditionalHelperMethods);
|
||||
}
|
||||
|
||||
return source.Select(static (item, _) => (item.Symbol, GetInfo(item.Symbol, item.AttributeData)));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
@ -28,9 +28,11 @@ public sealed class ObservableObjectGenerator : TransitiveMembersGenerator<objec
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override object? GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
|
||||
protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, object? Info)> GetInfo(
|
||||
IncrementalGeneratorInitializationContext context,
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
|
||||
{
|
||||
return null;
|
||||
return source.Select(static (item, _) => (item.Symbol, (object?)null));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
@ -30,18 +30,25 @@ public sealed class ObservableRecipientGenerator : TransitiveMembersGenerator<Ob
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override ObservableRecipientInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
|
||||
protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, ObservableRecipientInfo Info)> GetInfo(
|
||||
IncrementalGeneratorInitializationContext context,
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
|
||||
{
|
||||
string typeName = typeSymbol.Name;
|
||||
bool hasExplicitConstructors = !(typeSymbol.InstanceConstructors.Length == 1 && typeSymbol.InstanceConstructors[0] is { Parameters.IsEmpty: true, IsImplicitlyDeclared: true });
|
||||
bool isAbstract = typeSymbol.IsAbstract;
|
||||
bool isObservableValidator = typeSymbol.InheritsFrom("global::CommunityToolkit.Mvvm.ComponentModel.ObservableValidator");
|
||||
static ObservableRecipientInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
|
||||
{
|
||||
string typeName = typeSymbol.Name;
|
||||
bool hasExplicitConstructors = !(typeSymbol.InstanceConstructors.Length == 1 && typeSymbol.InstanceConstructors[0] is { Parameters.IsEmpty: true, IsImplicitlyDeclared: true });
|
||||
bool isAbstract = typeSymbol.IsAbstract;
|
||||
bool isObservableValidator = typeSymbol.InheritsFrom("global::CommunityToolkit.Mvvm.ComponentModel.ObservableValidator");
|
||||
|
||||
return new(
|
||||
typeName,
|
||||
hasExplicitConstructors,
|
||||
isAbstract,
|
||||
isObservableValidator);
|
||||
return new(
|
||||
typeName,
|
||||
hasExplicitConstructors,
|
||||
isAbstract,
|
||||
isObservableValidator);
|
||||
}
|
||||
|
||||
return source.Select(static (item, _) => (item.Symbol, GetInfo(item.Symbol, item.AttributeData)));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
|
@ -80,13 +80,15 @@ public abstract partial class TransitiveMembersGenerator<TInfo> : IIncrementalGe
|
|||
static (context, _) => (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!);
|
||||
|
||||
// Filter the types with the target attribute
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> typeSymbolsWithInfo =
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> typeSymbolsWithAttributeData =
|
||||
typeSymbols
|
||||
.Select((item, _) => (
|
||||
Symbol: item,
|
||||
Attribute: item.GetAttributes().FirstOrDefault(a => a.AttributeClass?.HasFullyQualifiedName(this.attributeType) == true)))
|
||||
.Where(static item => item.Attribute is not null)!
|
||||
.Select((item, _) => (item.Symbol, GetInfo(item.Symbol, item.Attribute!)));
|
||||
.Where(static item => item.Attribute is not null)!;
|
||||
|
||||
// Transform the input data
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> typeSymbolsWithInfo = GetInfo(context, typeSymbolsWithAttributeData);
|
||||
|
||||
// Filter by language version
|
||||
context.FilterWithLanguageVersion(ref typeSymbolsWithInfo, LanguageVersion.CSharp8, UnsupportedCSharpLanguageVersionError);
|
||||
|
@ -129,12 +131,14 @@ public abstract partial class TransitiveMembersGenerator<TInfo> : IIncrementalGe
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an info model from a retrieved <see cref="AttributeData"/> instance.
|
||||
/// Gathers info from a source <see cref="IncrementalValuesProvider{TValues}"/> input.
|
||||
/// </summary>
|
||||
/// <param name="typeSymbol">The <see cref="INamedTypeSymbol"/> instance for the target type.</param>
|
||||
/// <param name="attributeData">The input <see cref="AttributeData"/> to get info from.</param>
|
||||
/// <returns>A <typeparamref name="TInfo"/> instance with data extracted from <paramref name="attributeData"/>.</returns>
|
||||
protected abstract TInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData);
|
||||
/// <param name="context">The <see cref="IncrementalGeneratorInitializationContext"/> instance in use.</param>
|
||||
/// <param name="source">The source <see cref="IncrementalValuesProvider{TValues}"/> input.</param>
|
||||
/// <returns>A transformed <see cref="IncrementalValuesProvider{TValues}"/> instance with the gathered data.</returns>
|
||||
protected abstract IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> GetInfo(
|
||||
IncrementalGeneratorInitializationContext context,
|
||||
IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source);
|
||||
|
||||
/// <summary>
|
||||
/// Validates a target type being processed.
|
||||
|
|
|
@ -42,6 +42,13 @@ public abstract class ObservableRecipient
|
|||
public bool IsActive
|
||||
{
|
||||
get => this.isActive;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
|
||||
"When this property is set to true, the OnActivated() method will be invoked, which will register all necessary message handlers for this recipient. " +
|
||||
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
|
||||
"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 " +
|
||||
"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. " +
|
||||
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref this.isActive, value, true))
|
||||
|
@ -69,6 +76,11 @@ public abstract class ObservableRecipient
|
|||
/// If you need more fine tuned control, want to register messages individually or just prefer
|
||||
/// the lambda-style syntax for message registration, override this method and register manually.
|
||||
/// </remarks>
|
||||
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
|
||||
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
|
||||
"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 " +
|
||||
"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. " +
|
||||
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
|
||||
protected virtual void OnActivated()
|
||||
{
|
||||
global::CommunityToolkit.Mvvm.Messaging.IMessengerExtensions.RegisterAll(Messenger, this);
|
||||
|
|
Загрузка…
Ссылка в новой задаче