using System; using System.Linq; using Microsoft.CodeAnalysis; namespace Vellum.Generator { /// /// Describes a type parameter marked [Saveable] that shouldn't be, as plain data an incremental generator step /// can compare between runs. /// public sealed class SaveableMark : IEquatable { public enum Problems { /// /// The type parameter isn't one of a SaveConverter's. /// NotAConverter, /// /// The type parameter is the one a converter family stands for every type of. /// FamilySubject, } public readonly string Name; public readonly string Owner; public readonly Problems Problem; public readonly SourcePlace Place; public SaveableMark(string name, string owner, Problems problem, SourcePlace place) { Name = name; Owner = owner; Problem = problem; Place = place; } /// /// Returns what is wrong with marking , or null if it's fine to. /// public static SaveableMark Of(ITypeParameterSymbol parameter, INamedTypeSymbol converterBase) { Problems problem; var owner = parameter.ContainingSymbol as INamedTypeSymbol; ITypeSymbol converted = null; if (owner != null) { converted = ConverterScan.ConvertedByAnyKind(owner, converterBase); } if (converted == null) { problem = Problems.NotAConverter; } else if (SymbolEqualityComparer.Default.Equals(converted, parameter)) { problem = Problems.FamilySubject; } else { return null; } return new SaveableMark(parameter.Name, parameter.ContainingSymbol.Name, problem, SourcePlace.Of(parameter.Locations.FirstOrDefault())); } /// /// Returns the problem as a diagnostic where the type parameter is declared in /// . /// public Diagnostic ToDiagnostic(Compilation compilation) { DiagnosticDescriptor descriptor = VellumDiagnostics.MarkOutsideAConverter; if (Problem == Problems.FamilySubject) { descriptor = VellumDiagnostics.MarkedFamilySubject; } return Diagnostic.Create(descriptor, Place.LocationIn(compilation), Name, Owner); } public bool Equals(SaveableMark other) { return other != null && Name == other.Name && Owner == other.Owner && Problem == other.Problem && Place.Equals(other.Place); } public override bool Equals(object obj) { return Equals(obj as SaveableMark); } public override int GetHashCode() { return (Name.GetHashCode() * 31 + Owner.GetHashCode()) * 31 + (int)Problem; } } }