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