// Licensed to the .NET Foundation under one or more agreements. // 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.Immutable; using System.Linq; using CommunityToolkit.Mvvm.SourceGenerators.Diagnostics; using CommunityToolkit.Mvvm.SourceGenerators.Extensions; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using static CommunityToolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors; namespace CommunityToolkit.Mvvm.SourceGenerators; /// /// A source generator for the ObservableObjectAttribute type. /// [Generator(LanguageNames.CSharp)] public sealed class ObservableObjectGenerator : TransitiveMembersGenerator { /// /// Initializes a new instance of the class. /// public ObservableObjectGenerator() : base("global::CommunityToolkit.Mvvm.ComponentModel.ObservableObjectAttribute") { } /// 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) { ImmutableArray.Builder builder = ImmutableArray.CreateBuilder(); // Check if the type already implements INotifyPropertyChanged... if (typeSymbol.AllInterfaces.Any(i => i.HasFullyQualifiedName("global::System.ComponentModel.INotifyPropertyChanged"))) { builder.Add(DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError, typeSymbol, typeSymbol); diagnostics = builder.ToImmutable(); return false; } // ...or INotifyPropertyChanging if (typeSymbol.AllInterfaces.Any(i => i.HasFullyQualifiedName("global::System.ComponentModel.INotifyPropertyChanging"))) { builder.Add(DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError, typeSymbol, typeSymbol); diagnostics = builder.ToImmutable(); return false; } // Check if the type uses [INotifyPropertyChanged] or [ObservableObject] already (in the type hierarchy too) if (typeSymbol.InheritsAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.ObservableObjectAttribute") || typeSymbol.HasOrInheritsAttributeWithFullyQualifiedName("global::CommunityToolkit.Mvvm.ComponentModel.INotifyPropertyChangedAttribute")) { builder.Add(InvalidAttributeCombinationForObservableObjectAttributeError, typeSymbol, typeSymbol); diagnostics = builder.ToImmutable(); return false; } diagnostics = builder.ToImmutable(); return true; } /// protected override ImmutableArray FilterDeclaredMembers(object? info, ImmutableArray memberDeclarations) { return memberDeclarations; } }