using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis; namespace Vellum.Generator { /// /// Describes what a [Saveable] type needs checked, as plain data: whether it's a shape a converter can be written /// for, whether a hand-written converter clashes with the generated one, and whether each member's type can be /// saved. /// public sealed class SaveableChecks : IEquatable { public readonly string Name; /// /// Holds the type's name as matched against the types something has a converter for. /// public readonly string ConvertedName; /// /// Holds whether a converter is generated for the type, as opposed to the type already having one. /// public readonly bool Generates; public readonly SaveableProblem Problem; public readonly SourcePlace ProblemPlace; /// /// Holds whether the type is [Saveable] only because a class it derives from is. /// public readonly bool InheritsMark; public readonly EquatableArray Members; public SaveableChecks(string name, string convertedName, bool generates, SaveableProblem problem, SourcePlace problemPlace, bool inheritsMark, EquatableArray members) { Name = name; ConvertedName = convertedName; Generates = generates; Problem = problem; ProblemPlace = problemPlace; InheritsMark = inheritsMark; Members = members; } /// /// Returns what is wrong with the type in , given the converters found and the /// names of what they convert. /// public List Check(Compilation compilation, ConverterList converters, HashSet converted) { var returnMe = new List(); if (Problem == SaveableProblem.Unsupported) { string because = ""; if (InheritsMark) { because = " because a class it derives from, or an interface it implements, is"; } returnMe.Add(Diagnostic.Create(VellumDiagnostics.UnsupportedSaveable, ProblemPlace.LocationIn(compilation), Name, because)); } else if (Problem == SaveableProblem.PublicLoader) { returnMe.Add(Diagnostic.Create(VellumDiagnostics.PublicLoader, ProblemPlace.LocationIn(compilation), Name)); } if (Generates) { ConverterModel handWritten = converters.Usable.Items.FirstOrDefault( converter => converter.ConvertedName == ConvertedName); if (handWritten != null) { returnMe.Add(handWritten.WithProblem(ConverterProblem.Duplicate).ToDiagnostic(compilation)); } } Dictionary> families = converters.FamilyBaseNames(); Dictionary> saveableArguments = converters.SaveableArguments(); foreach (MemberCheck member in Members.Items) { if (member.Key == SaveConverters.TypeKey || member.Key == SaveConverters.ValueKey) { returnMe.Add(Diagnostic.Create(VellumDiagnostics.ReservedKey, member.Place.LocationIn(compilation), member.Key)); } if (member.HiddenIn != null) { returnMe.Add(Diagnostic.Create(VellumDiagnostics.HiddenKey, member.Place.LocationIn(compilation), member.Key, member.HiddenIn)); } int unsaveable = member.Type.FindUnsaveable(converted, families, saveableArguments); if (unsaveable >= 0) { returnMe.Add(member.Type.UnsaveableDiagnostic(member.Place.LocationIn(compilation), member.Key, unsaveable)); } } return returnMe; } public bool Equals(SaveableChecks other) { return other != null && Name == other.Name && ConvertedName == other.ConvertedName && Generates == other.Generates && Problem == other.Problem && ProblemPlace.Equals(other.ProblemPlace) && InheritsMark == other.InheritsMark && Members.Equals(other.Members); } public override bool Equals(object obj) { return Equals(obj as SaveableChecks); } public override int GetHashCode() { return (Name.GetHashCode() * 31 + Members.GetHashCode()) * 31 + (int)Problem; } } }