File: Wrapping\Edit.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using Microsoft.CodeAnalysis.PooledObjects;
 
namespace Microsoft.CodeAnalysis.Wrapping;
 
/// <summary>
/// Represents an edit between two tokens.  Specifically, provides the new trailing trivia for
/// the <see cref="Left"/> token and the new leading trivia for the <see
/// cref="Right"/> token.
/// </summary>
internal readonly struct Edit
{
    public readonly SyntaxToken Left;
    public readonly SyntaxToken Right;
    public readonly SyntaxTriviaList NewLeftTrailingTrivia;
    public readonly SyntaxTriviaList NewRightLeadingTrivia;
 
    private Edit(
        SyntaxToken left, SyntaxTriviaList newLeftTrailingTrivia,
        SyntaxToken right, SyntaxTriviaList newRightLeadingTrivia)
    {
        if (left.Span.End > right.Span.Start)
            throw new InvalidEditException(left, right);
 
        Left = left;
        Right = right;
        NewLeftTrailingTrivia = newLeftTrailingTrivia;
        NewRightLeadingTrivia = newRightLeadingTrivia;
    }
 
    public string GetNewTrivia()
    {
        var result = PooledStringBuilder.GetInstance();
        AppendTrivia(result, NewLeftTrailingTrivia);
        AppendTrivia(result, NewRightLeadingTrivia);
        return result.ToStringAndFree();
    }
 
    private static void AppendTrivia(PooledStringBuilder result, SyntaxTriviaList triviaList)
    {
        foreach (var trivia in triviaList)
        {
            result.Builder.Append(trivia.ToFullString());
        }
    }
 
    /// <summary>
    /// Create the Edit representing the deletion of all trivia between left and right.
    /// </summary>
    public static Edit DeleteBetween(SyntaxNodeOrToken left, SyntaxNodeOrToken right)
        => UpdateBetween(left, default, default(SyntaxTriviaList), right);
 
    public static Edit UpdateBetween(
        SyntaxNodeOrToken left, SyntaxTriviaList leftTrailingTrivia,
        SyntaxTrivia rightLeadingTrivia, SyntaxNodeOrToken right)
    {
        return UpdateBetween(left, leftTrailingTrivia, new SyntaxTriviaList(rightLeadingTrivia), right);
    }
 
    public static Edit UpdateBetween(
        SyntaxNodeOrToken left, SyntaxTriviaList leftTrailingTrivia,
        SyntaxTriviaList rightLeadingTrivia, SyntaxNodeOrToken right)
    {
        var leftLastToken = left.IsToken ? left.AsToken() : left.AsNode()!.GetLastToken();
        var rightFirstToken = right.IsToken ? right.AsToken() : right.AsNode()!.GetFirstToken();
        return new Edit(leftLastToken, leftTrailingTrivia, rightFirstToken, rightLeadingTrivia);
    }
 
    private sealed class InvalidEditException(SyntaxToken left, SyntaxToken right) : Exception($"Left token had an end '{left.Span.End}' past the start of right token '{right.Span.Start}'")
    {
        // Used for analyzing dumps
#pragma warning disable IDE0052 // Remove unread private members
        private readonly SyntaxTree? _tree = left.SyntaxTree;
        private readonly SyntaxToken _left = left;
        private readonly SyntaxToken _right = right;
    }
}