| File: Language\Syntax\SyntaxToken.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.Internal; namespace Microsoft.AspNetCore.Razor.Language.Syntax; [DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)}(), nq}}")] internal readonly struct SyntaxToken : IEquatable<SyntaxToken> { internal static readonly Func<SyntaxToken, bool> NonZeroWidth = t => t.Width > 0; internal static readonly Func<SyntaxToken, bool> Any = t => true; public SyntaxNode? Parent { get; } internal GreenNode? Node { get; } internal int Index { get; } internal int Position { get; } internal SyntaxToken(SyntaxNode? parent, GreenNode? token, int position, int index) { Debug.Assert(parent == null || !parent.Green.IsList, "list cannot be a parent"); Debug.Assert(token == null || token.IsToken, "token must be a token"); Parent = parent; Node = token; Position = position; Index = index; } internal SyntaxToken(GreenNode? token) : this() { Debug.Assert(token == null || token.IsToken, "token must be a token"); Node = token; } private string GetDebuggerDisplay() => $"{GetType().Name} {Kind} {ToString()}"; // For debugging #pragma warning disable IDE0051 // Remove unused private members private string SerializedValue => SyntaxSerializer.Default.Serialize(this); #pragma warning restore IDE0051 // Remove unused private members public SyntaxKind Kind => Node?.Kind ?? 0; internal GreenNode RequiredNode { get { Debug.Assert(Node != null); return Node; } } internal int Width => Node?.Width ?? 0; public int SpanStart => Node != null ? Position : 0; public TextSpan Span => Node != null ? new TextSpan(Position, Node.Width) : default; internal int EndPosition => Node != null ? Position + Node.Width : 0; public bool IsMissing => Node?.IsMissing ?? false; public bool ContainsDiagnostics => Node?.ContainsDiagnostics ?? false; public string Content => Node != null ? ((InternalSyntax.SyntaxToken)Node).Content : string.Empty; public string Text => ToString(); public override string ToString() => Node?.ToString() ?? string.Empty; /// <summary> /// Determines whether two <see cref="SyntaxToken"/>s are equal. /// </summary> public static bool operator ==(SyntaxToken left, SyntaxToken right) => left.Equals(right); /// <summary> /// Determines whether two <see cref="SyntaxToken"/>s are unequal. /// </summary> public static bool operator !=(SyntaxToken left, SyntaxToken right) => !left.Equals(right); /// <summary> /// Determines whether the supplied <see cref="SyntaxToken"/> is equal to this /// <see cref="SyntaxToken"/>. /// </summary> public bool Equals(SyntaxToken other) => Parent == other.Parent && Node == other.Node && Position == other.Position && Index == other.Index; public override bool Equals([NotNullWhen(true)] object? obj) => obj is SyntaxToken token && Equals(token); public override int GetHashCode() { var hash = HashCodeCombiner.Start(); hash.Add(Parent); hash.Add(Node); hash.Add(Position); hash.Add(Index); return hash.CombinedHash; } /// <summary> /// Gets the token that follows this token in the syntax tree. /// </summary> /// <returns>The token that follows this token in the syntax tree.</returns> public SyntaxToken GetNextToken(bool includeZeroWidth = false) { if (Node == null) { return default; } return SyntaxNavigator.GetNextToken(this, includeZeroWidth); } /// <summary> /// Returns the token after this token in the syntax tree. /// </summary> /// <param name="predicate">Delegate applied to each token. The token is returned if the predicate returns /// true.</param> internal SyntaxToken GetNextToken(Func<SyntaxToken, bool> predicate) { if (Node == null) { return default; } return SyntaxNavigator.GetNextToken(this, predicate); } /// <summary> /// Gets the token that precedes this token in the syntax tree. /// </summary> /// <returns>The previous token that precedes this token in the syntax tree.</returns> public SyntaxToken GetPreviousToken(bool includeZeroWidth = false) { if (Node == null) { return default; } return SyntaxNavigator.GetPreviousToken(this, includeZeroWidth); } /// <summary> /// Returns the token before this token in the syntax tree. /// </summary> /// <param name="predicate">Delegate applied to each token. The token is returned if the predicate returns /// true.</param> internal SyntaxToken GetPreviousToken(Func<SyntaxToken, bool> predicate) { if (Node == null) { return default; } return SyntaxNavigator.GetPreviousToken(this, predicate); } /// <summary> /// Gets a list of all the diagnostics associated with this token and any related trivia. /// This method does not filter diagnostics based on #pragmas and compiler options /// like nowarn, warnaserror etc. /// </summary> public IEnumerable<RazorDiagnostic> GetDiagnostics() { if (Node == null) { return SpecializedCollections.EmptyEnumerable<RazorDiagnostic>(); } var diagnostics = Node.GetDiagnostics(); return diagnostics.Length == 0 ? SpecializedCollections.EmptyEnumerable<RazorDiagnostic>() : diagnostics; } }