| File: Language\SpanComputer.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.Diagnostics; using Microsoft.AspNetCore.Razor.Language.Syntax; using Microsoft.CodeAnalysis.Text; namespace Microsoft.AspNetCore.Razor.Language; /// <summary> /// Helper that can be used to efficiently build up a <see cref="SourceSpan"/> or /// <see cref="CodeAnalysis.Text.TextSpan"/> from a set of syntax tokens. /// </summary> internal ref struct SpanComputer() { private SyntaxToken _firstToken; private SyntaxToken _lastToken; public void Add(SyntaxToken token) { if (token.Kind == SyntaxKind.None) { return; } if (_firstToken.Kind == SyntaxKind.None) { _firstToken = token; } _lastToken = token; } public void Add(SyntaxTokenList tokenList) { if (tokenList.Count == 0) { return; } if (_firstToken.Kind == SyntaxKind.None) { _firstToken = tokenList[0]; } _lastToken = tokenList[^1]; } public void Add(SyntaxTokenList? tokenList) { if (tokenList is not [_, ..] tokens) { return; } if (_firstToken.Kind == SyntaxKind.None) { _firstToken = tokens[0]; } _lastToken = tokens[^1]; } public void Add(CSharpEphemeralTextLiteralSyntax? literal) { Add(literal?.LiteralTokens); } public void Add(CSharpExpressionLiteralSyntax? literal) { Add(literal?.LiteralTokens); } public void Add(CSharpStatementLiteralSyntax? literal) { Add(literal?.LiteralTokens); } public void Add(MarkupEphemeralTextLiteralSyntax? literal) { Add(literal?.LiteralTokens); } public void Add(MarkupTextLiteralSyntax? literal) { Add(literal?.LiteralTokens); } public void Add(UnclassifiedTextLiteralSyntax? literal) { Add(literal?.LiteralTokens); } public readonly SourceSpan ToSourceSpan(RazorSourceDocument source) { if (_firstToken.Kind == SyntaxKind.None) { return default; } Debug.Assert(_lastToken.Kind != SyntaxKind.None, "Last token should not be None when first token is set."); var start = _firstToken.Span.Start; var end = _lastToken.Span.End; Debug.Assert(start <= end, "Start position should not be greater than end position."); var length = end - start; var text = source.Text; var startLinePosition = text.Lines.GetLinePosition(start); var endLinePosition = text.Lines.GetLinePosition(end); var lineCount = endLinePosition.Line - startLinePosition.Line; return new SourceSpan(source.FilePath, absoluteIndex: start, startLinePosition.Line, startLinePosition.Character, length, lineCount, endLinePosition.Character); } public readonly TextSpan ToTextSpan() { if (_firstToken.Kind == SyntaxKind.None) { return default; } Debug.Assert(_lastToken.Kind != SyntaxKind.None, "Last token should not be None when first token is set."); var start = _firstToken.Span.Start; var end = _lastToken.Span.End; Debug.Assert(start <= end, "Start position should not be greater than end position."); return TextSpan.FromBounds(start, end); } }