using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Ariadne.Generator
{
///
/// Describes where something is declared as plain data, which an incremental generator step can compare between
/// runs. A Location can't be compared that way, since each edit makes new ones.
///
public sealed class SourcePlace : IEquatable
{
///
/// Holds the file the declaration is in, or null if it isn't in source.
///
public readonly string FilePath;
public readonly TextSpan Span;
public readonly LinePositionSpan LineSpan;
public SourcePlace(string filePath, TextSpan span, LinePositionSpan lineSpan)
{
FilePath = filePath;
Span = span;
LineSpan = lineSpan;
}
///
/// Returns where is, or a place with no file if it isn't in source.
///
public static SourcePlace Of(Location location)
{
if (location == null || !location.IsInSource)
{
return new SourcePlace(null, default, default);
}
return new SourcePlace(location.SourceTree.FilePath, location.SourceSpan,
location.GetLineSpan().Span);
}
///
/// Returns this place in 's own syntax tree.
///
public Location LocationIn(Compilation compilation)
{
if (FilePath == null)
{
return Location.None;
}
// A location in a syntax tree is the only kind #pragma can suppress a diagnostic at.
foreach (SyntaxTree tree in compilation.SyntaxTrees)
{
if (tree.FilePath == FilePath)
{
return Location.Create(tree, Span);
}
}
return Location.Create(FilePath, Span, LineSpan);
}
public bool Equals(SourcePlace other)
{
return other != null && FilePath == other.FilePath && Span == other.Span && LineSpan == other.LineSpan;
}
public override bool Equals(object obj)
{
return Equals(obj as SourcePlace);
}
public override int GetHashCode()
{
return Span.GetHashCode();
}
}
}