diff --git a/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs b/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs
index 269472de..8aa4a57f 100644
--- a/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs
+++ b/CommunityToolkit.Mvvm.SourceGenerators/Extensions/ISymbolExtensions.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
@@ -64,6 +65,32 @@ internal static class ISymbolExtensions
return false;
}
+ ///
+ /// Tries to get an attribute with the specified full name.
+ ///
+ /// The input instance to check.
+ /// The attribute name to look for.
+ /// The resulting attribute, if it was found.
+ /// Whether or not has an attribute with the specified name.
+ public static bool TryGetAttributeWithFullyQualifiedName(this ISymbol symbol, string name, [NotNullWhen(true)] out AttributeData? attributeData)
+ {
+ ImmutableArray attributes = symbol.GetAttributes();
+
+ foreach (AttributeData attribute in attributes)
+ {
+ if (attribute.AttributeClass?.HasFullyQualifiedName(name) == true)
+ {
+ attributeData = attribute;
+
+ return true;
+ }
+ }
+
+ attributeData = null;
+
+ return false;
+ }
+
///
/// Calculates the effective accessibility for a given symbol.
///
diff --git a/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs b/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs
index 06e2c7bc..8e0660f7 100644
--- a/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs
+++ b/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs
@@ -23,40 +23,33 @@ public sealed partial class RelayCommandGenerator : IIncrementalGenerator
///
public void Initialize(IncrementalGeneratorInitializationContext context)
{
- // Get all method declarations with at least one attribute
- IncrementalValuesProvider methodSymbols =
+ // Gather info for all annotated command methods (starting from method declarations with at least one attribute)
+ IncrementalValuesProvider<(HierarchyInfo Hierarchy, Result Info)> commandInfoWithErrors =
context.SyntaxProvider
.CreateSyntaxProvider(
static (node, _) => node is MethodDeclarationSyntax { Parent: ClassDeclarationSyntax, AttributeLists.Count: > 0 },
- static (context, _) =>
+ static (context, token) =>
{
if (!context.SemanticModel.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp8))
{
return default;
}
- return (IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!;
+ IMethodSymbol methodSymbol = (IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, token)!;
+
+ // Filter the methods using [RelayCommand]
+ if (!methodSymbol.TryGetAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.Input.RelayCommandAttribute", out AttributeData? attribute))
+ {
+ return default;
+ }
+
+ // Produce the incremental models
+ HierarchyInfo hierarchy = HierarchyInfo.From(methodSymbol.ContainingType);
+ CommandInfo? commandInfo = Execute.GetInfo(methodSymbol, attribute, out ImmutableArray diagnostics);
+
+ return (Hierarchy: hierarchy, new Result(commandInfo, diagnostics));
})
- .Where(static item => item is not null)!;
-
- // Filter the methods using [RelayCommand]
- IncrementalValuesProvider<(IMethodSymbol Symbol, AttributeData Attribute)> methodSymbolsWithAttributeData =
- methodSymbols
- .Select(static (item, _) => (
- item,
- Attribute: item.GetAttributes().FirstOrDefault(a => a.AttributeClass?.HasFullyQualifiedName("global::CommunityToolkit.Mvvm.Input.RelayCommandAttribute") == true)))
- .Where(static item => item.Attribute is not null)!;
-
- // Gather info for all annotated command methods
- IncrementalValuesProvider<(HierarchyInfo Hierarchy, Result Info)> commandInfoWithErrors =
- methodSymbolsWithAttributeData
- .Select(static (item, _) =>
- {
- HierarchyInfo hierarchy = HierarchyInfo.From(item.Symbol.ContainingType);
- CommandInfo? commandInfo = Execute.GetInfo(item.Symbol, item.Attribute, out ImmutableArray diagnostics);
-
- return (hierarchy, new Result(commandInfo, diagnostics));
- });
+ .Where(static item => item.Hierarchy is not null);
// Output the diagnostics
context.ReportDiagnostics(commandInfoWithErrors.Select(static (item, _) => item.Info.Errors));
@@ -66,7 +59,7 @@ public sealed partial class RelayCommandGenerator : IIncrementalGenerator
commandInfoWithErrors
.Where(static item => item.Info.Value is not null)
.Select(static (item, _) => (item.Hierarchy, item.Info.Value!))
- .WithComparers(HierarchyInfo.Comparer.Default, CommandInfo.Comparer.Default);
+ .WithComparers(HierarchyInfo.Comparer.Default, CommandInfo.Comparer.Default);
// Generate the commands
context.RegisterSourceOutput(commandInfo, static (context, item) =>