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