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;
}
}
}