diff --git a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/INotifyPropertyChangedGenerator.cs b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/INotifyPropertyChangedGenerator.cs
index 2831b6a1..37882bc0 100644
--- a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/INotifyPropertyChangedGenerator.cs
+++ b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/INotifyPropertyChangedGenerator.cs
@@ -28,33 +28,18 @@ public INotifyPropertyChangedGenerator()
}
///
- protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, INotifyPropertyChangedInfo Info)> GetInfo(
- IncrementalGeneratorInitializationContext context,
- IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
- {
- static INotifyPropertyChangedInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData)
- {
- bool includeAdditionalHelperMethods = attributeData.GetNamedArgument("IncludeAdditionalHelperMethods", true);
-
- return new(includeAdditionalHelperMethods);
- }
-
- return source.Select(static (item, _) => (item.Symbol, GetInfo(item.Symbol, item.AttributeData)));
- }
-
- ///
- protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, INotifyPropertyChangedInfo info, out ImmutableArray diagnostics)
+ protected override INotifyPropertyChangedInfo? ValidateTargetTypeAndGetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData, Compilation compilation, out ImmutableArray diagnostics)
{
ImmutableArray.Builder builder = ImmutableArray.CreateBuilder();
+ INotifyPropertyChangedInfo? info = null;
+
// Check if the type already implements INotifyPropertyChanged
if (typeSymbol.AllInterfaces.Any(i => i.HasFullyQualifiedName("global::System.ComponentModel.INotifyPropertyChanged")))
{
builder.Add(DuplicateINotifyPropertyChangedInterfaceForINotifyPropertyChangedAttributeError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
// Check if the type uses [INotifyPropertyChanged] or [ObservableObject] already (in the type hierarchy too)
@@ -63,14 +48,17 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, INotifyP
{
builder.Add(InvalidAttributeCombinationForINotifyPropertyChangedAttributeError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
+ bool includeAdditionalHelperMethods = attributeData.GetNamedArgument("IncludeAdditionalHelperMethods", true);
+
+ info = new INotifyPropertyChangedInfo(includeAdditionalHelperMethods);
+
+ End:
diagnostics = builder.ToImmutable();
- return true;
+ return info;
}
///
diff --git a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableObjectGenerator.cs b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableObjectGenerator.cs
index 114cb937..c101ad09 100644
--- a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableObjectGenerator.cs
+++ b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableObjectGenerator.cs
@@ -27,15 +27,7 @@ public ObservableObjectGenerator()
}
///
- protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, object? Info)> GetInfo(
- IncrementalGeneratorInitializationContext context,
- IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
- {
- return source.Select(static (item, _) => (item.Symbol, (object?)null));
- }
-
- ///
- protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, object? info, out ImmutableArray diagnostics)
+ protected override object? ValidateTargetTypeAndGetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData, Compilation compilation, out ImmutableArray diagnostics)
{
ImmutableArray.Builder builder = ImmutableArray.CreateBuilder();
@@ -44,9 +36,7 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, object?
{
builder.Add(DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
// ...or INotifyPropertyChanging
@@ -54,9 +44,7 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, object?
{
builder.Add(DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
// Check if the type uses [INotifyPropertyChanged] or [ObservableObject] already (in the type hierarchy too)
@@ -65,14 +53,13 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, object?
{
builder.Add(InvalidAttributeCombinationForObservableObjectAttributeError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
+ End:
diagnostics = builder.ToImmutable();
- return true;
+ return null;
}
///
diff --git a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs
index e16a161d..af217683 100644
--- a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs
+++ b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableRecipientGenerator.cs
@@ -30,53 +30,18 @@ public ObservableRecipientGenerator()
}
///
- protected override IncrementalValuesProvider<(INamedTypeSymbol Symbol, ObservableRecipientInfo Info)> GetInfo(
- IncrementalGeneratorInitializationContext context,
- IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source)
- {
- static ObservableRecipientInfo GetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData, bool isRequiresUnreferencedCodeAttributeAvailable)
- {
- 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.InheritsFromFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableValidator");
- bool hasOnActivatedMethod = typeSymbol.GetMembers().Any(m => m is IMethodSymbol { Parameters.IsEmpty: true, Name: "OnActivated" });
- bool hasOnDeactivatedMethod = typeSymbol.GetMembers().Any(m => m is IMethodSymbol { Parameters.IsEmpty: true, Name: "OnDeactivated" });
-
- return new(
- typeName,
- hasExplicitConstructors,
- isAbstract,
- isObservableValidator,
- isRequiresUnreferencedCodeAttributeAvailable,
- hasOnActivatedMethod,
- hasOnDeactivatedMethod);
- }
-
- // Check whether [RequiresUnreferencedCode] is available
- IncrementalValueProvider isRequiresUnreferencedCodeAttributeAvailable =
- context.CompilationProvider
- .Select(static (item, _) => item.GetTypeByMetadataName("System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute") is { DeclaredAccessibility: Accessibility.Public });
-
- return
- source
- .Combine(isRequiresUnreferencedCodeAttributeAvailable)
- .Select(static (item, _) => (item.Left.Symbol, GetInfo(item.Left.Symbol, item.Left.AttributeData, item.Right)));
- }
-
- ///
- protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, ObservableRecipientInfo info, out ImmutableArray diagnostics)
+ protected override ObservableRecipientInfo? ValidateTargetTypeAndGetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData, Compilation compilation, out ImmutableArray diagnostics)
{
ImmutableArray.Builder builder = ImmutableArray.CreateBuilder();
+ ObservableRecipientInfo? info = null;
+
// Check if the type already inherits from ObservableRecipient
if (typeSymbol.InheritsFromFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableRecipient"))
{
builder.Add(DuplicateObservableRecipientError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
// Check if the type already inherits [ObservableRecipient]
@@ -84,9 +49,7 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, Observab
{
builder.Add(InvalidAttributeCombinationForObservableRecipientAttributeError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
// In order to use [ObservableRecipient], the target type needs to inherit from ObservableObject,
@@ -99,14 +62,31 @@ protected override bool ValidateTargetType(INamedTypeSymbol typeSymbol, Observab
{
builder.Add(MissingBaseObservableObjectFunctionalityError, typeSymbol, typeSymbol);
- diagnostics = builder.ToImmutable();
-
- return false;
+ goto End;
}
+ // Gather all necessary info to propagate down the pipeline
+ 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.InheritsFromFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableValidator");
+ bool isRequiresUnreferencedCodeAttributeAvailable = compilation.HasAccessibleTypeWithMetadataName("System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute");
+ bool hasOnActivatedMethod = typeSymbol.GetMembers().Any(m => m is IMethodSymbol { Parameters.IsEmpty: true, Name: "OnActivated" });
+ bool hasOnDeactivatedMethod = typeSymbol.GetMembers().Any(m => m is IMethodSymbol { Parameters.IsEmpty: true, Name: "OnDeactivated" });
+
+ info = new ObservableRecipientInfo(
+ typeName,
+ hasExplicitConstructors,
+ isAbstract,
+ isObservableValidator,
+ isRequiresUnreferencedCodeAttributeAvailable,
+ hasOnActivatedMethod,
+ hasOnDeactivatedMethod);
+
+ End:
diagnostics = builder.ToImmutable();
- return true;
+ return info;
}
///
diff --git a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs
index 8b0a01a0..95fc8967 100644
--- a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs
+++ b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs
@@ -11,7 +11,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
-using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
namespace CommunityToolkit.Mvvm.SourceGenerators;
@@ -70,46 +69,40 @@ private protected TransitiveMembersGenerator(string attributeType, IEqualityComp
///
public void Initialize(IncrementalGeneratorInitializationContext context)
{
- // Get all class declarations
- IncrementalValuesProvider typeSymbols =
+ // Gather all generation info, and any diagnostics
+ IncrementalValuesProvider> generationInfoWithErrors =
context.SyntaxProvider
.CreateSyntaxProvider(
static (node, _) => node is ClassDeclarationSyntax { AttributeLists.Count: > 0 },
- static (context, _) =>
+ (context, token) =>
{
if (!context.SemanticModel.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp8))
{
return default;
}
- return (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!;
- })
- .Where(static item => item is not null)!;
+ INamedTypeSymbol typeSymbol = (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, token)!;
- // Filter the types with the target attribute
- 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)!;
+ // Filter the types with the target attribute
+ if (!typeSymbol.TryGetAttributeWithFullyQualifiedName(this.attributeType, out AttributeData? attributeData))
+ {
+ return default;
+ }
- // Transform the input data
- IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> typeSymbolsWithInfo = GetInfo(context, typeSymbolsWithAttributeData);
+ // Gather all generation info, and any diagnostics
+ TInfo? info = ValidateTargetTypeAndGetInfo(typeSymbol, attributeData, context.SemanticModel.Compilation, out ImmutableArray diagnostics);
- // Gather all generation info, and any diagnostics
- IncrementalValuesProvider> generationInfoWithErrors =
- typeSymbolsWithInfo.Select((item, _) =>
- {
- if (ValidateTargetType(item.Symbol, item.Info, out ImmutableArray diagnostics))
- {
- return new Result<(HierarchyInfo, bool, TInfo)>(
- (HierarchyInfo.From(item.Symbol), item.Symbol.IsSealed, item.Info),
- ImmutableArray.Empty);
- }
+ // If there are any diagnostics, there's no need to compute the hierarchy info at all, just return them
+ if (diagnostics.Length > 0)
+ {
+ return new Result<(HierarchyInfo, bool, TInfo?)>(default, diagnostics);
+ }
+
+ HierarchyInfo hierarchy = HierarchyInfo.From(typeSymbol);
- return new Result<(HierarchyInfo, bool, TInfo)>(default, diagnostics);
- });
+ return new Result<(HierarchyInfo, bool, TInfo?)>((hierarchy, typeSymbol.IsSealed, info), diagnostics);
+ })
+ .Where(static item => item is not null)!;
// Emit the diagnostic, if needed
context.ReportDiagnostics(generationInfoWithErrors.Select(static (item, _) => item.Errors));
@@ -118,7 +111,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
IncrementalValuesProvider<(HierarchyInfo Hierarchy, bool IsSealed, TInfo Info)> generationInfo =
generationInfoWithErrors
.Where(static item => item.Errors.IsEmpty)
- .Select(static (item, _) => item.Value)
+ .Select(static (item, _) => item.Value)!
.WithComparers(HierarchyInfo.Comparer.Default, EqualityComparer.Default, this.comparer);
// Generate the required members
@@ -133,23 +126,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
}
///
- /// Gathers info from a source input.
+ /// Validates the target type being processes, gets the info if possible and produces all necessary diagnostics.
///
- /// The instance in use.
- /// The source input.
- /// A transformed instance with the gathered data.
- protected abstract IncrementalValuesProvider<(INamedTypeSymbol Symbol, TInfo Info)> GetInfo(
- IncrementalGeneratorInitializationContext context,
- IncrementalValuesProvider<(INamedTypeSymbol Symbol, AttributeData AttributeData)> source);
-
- ///
- /// Validates a target type being processed.
- ///
- /// The instance for the target type.
- /// The instance with the current processing info.
- /// The resulting diagnostics from the processing operation.
- /// Whether or not the target type is valid and can be processed normally.
- protected abstract bool ValidateTargetType(INamedTypeSymbol typeSymbol, TInfo info, out ImmutableArray diagnostics);
+ /// The instance currently being processed.
+ /// The instance for the attribute used over .
+ /// The compilation that belongs to.
+ /// The resulting diagnostics, if any.
+ /// The extracted info for the current type, if possible.
+ /// If is empty, the returned info will always be ignored and no sources will be produced.
+ protected abstract TInfo? ValidateTargetTypeAndGetInfo(INamedTypeSymbol typeSymbol, AttributeData attributeData, Compilation compilation, out ImmutableArray diagnostics);
///
/// Filters the nodes to generate from the input parsed tree.