File: EditAndContinue\DeclaratorMapDescription.cs
Web Access
Project: ..\..\..\src\EditorFeatures\TestUtilities\Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj (Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities)
// 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.
 
#nullable disable
 
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests
{
    public sealed class SyntaxMapDescription
    {
        public readonly ImmutableArray<ImmutableArray<TextSpan>> OldSpans;
        public readonly ImmutableArray<ImmutableArray<TextSpan>> NewSpans;
 
        public SyntaxMapDescription(string oldSource, string newSource)
        {
            OldSpans = GetSpans(oldSource);
            NewSpans = GetSpans(newSource);
 
            Assert.Equal(OldSpans.Length, NewSpans.Length);
            for (var i = 0; i < OldSpans.Length; i++)
            {
                Assert.Equal(OldSpans[i].Length, NewSpans[i].Length);
            }
        }
 
        private static readonly Regex s_statementPattern = new Regex(
            @"[<]N[:]      (?<Id>[0-9]+[.][0-9]+)   [>]
              (?<Node>.*)
              [<][/]N[:]   (\k<Id>)                 [>]", RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);
 
        internal static ImmutableArray<ImmutableArray<TextSpan>> GetSpans(string src)
        {
            var matches = s_statementPattern.Matches(src);
            var result = new List<List<TextSpan>>();
 
            for (var i = 0; i < matches.Count; i++)
            {
                var stmt = matches[i].Groups["Node"];
                var id = matches[i].Groups["Id"].Value.Split('.');
                var id0 = int.Parse(id[0]);
                var id1 = int.Parse(id[1]);
 
                EnsureSlot(result, id0);
 
                if (result[id0] == null)
                {
                    result[id0] = new List<TextSpan>();
                }
 
                EnsureSlot(result[id0], id1);
                result[id0][id1] = new TextSpan(stmt.Index, stmt.Length);
            }
 
            return result.Select(r => r.AsImmutableOrEmpty()).AsImmutableOrEmpty();
        }
 
        internal IEnumerable<KeyValuePair<TextSpan, TextSpan>> this[int i]
        {
            get
            {
                for (var j = 0; j < OldSpans[i].Length; j++)
                {
                    yield return KeyValuePairUtil.Create(OldSpans[i][j], NewSpans[i][j]);
                }
            }
        }
 
        private static void EnsureSlot<T>(List<T> list, int i)
        {
            while (i >= list.Count)
            {
                list.Add(default);
            }
        }
    }
}