diff --git a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs index 320db7f0f..3fdbf8aaa 100644 --- a/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs +++ b/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs @@ -21,31 +21,43 @@ public sealed partial class ObservableValidatorValidateAllPropertiesGenerator : /// public void Initialize(IncrementalGeneratorInitializationContext context) { - // Get all class declarations. We intentionally skip generating code for abstract types, as that would never be used. - // The methods that are generated by this generator are retrieved through reflection using the type of the invoking - // instance as discriminator, which means a type that is abstract could never be used (since it couldn't be instantiated). - IncrementalValuesProvider typeSymbols = + // Get the types that inherit from ObservableValidator and gather their info + IncrementalValuesProvider validationInfo = context.SyntaxProvider .CreateSyntaxProvider( static (node, _) => node is ClassDeclarationSyntax, - static (context, _) => + static (context, token) => { if (!context.SemanticModel.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp8)) { return default; } - return (context.Node, Symbol: (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node)!); - }) - .Where(static item => item.Symbol is { IsAbstract: false, IsGenericType: false } && item.Node.IsFirstSyntaxDeclarationForSymbol(item.Symbol)) - .Select(static (item, _) => item.Symbol); + INamedTypeSymbol typeSymbol = (INamedTypeSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, token)!; - // Get the types that inherit from ObservableValidator and gather their info - IncrementalValuesProvider validationInfo = - typeSymbols - .Where(Execute.IsObservableValidator) - .Select(static (item, _) => Execute.GetInfo(item)) - .WithComparer(ValidationInfo.Comparer.Default); + // Skip generating code for abstract types, as that would never be used. The methods that are generated by + // this generator are retrieved through reflection using the type of the invoking instance as discriminator, + // which means a type that is abstract could never be used (since it couldn't be instantiated). + if (typeSymbol is not { IsAbstract: false, IsGenericType: false }) + { + return default; + } + + // Just like in IMessengerRegisterAllGenerator, only select the first declaration for this type symbol + if (!context.Node.IsFirstSyntaxDeclarationForSymbol(typeSymbol)) + { + return default; + } + + // Only select types inheriting from ObservableValidator + if (!Execute.IsObservableValidator(typeSymbol)) + { + return default; + } + + return Execute.GetInfo(typeSymbol); + }) + .Where(static item => item is not null)!; // Check whether the header file is needed IncrementalValueProvider isHeaderFileNeeded =