// 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 System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Shared.Extensions; internal static class TextSpanExtensions { /// <summary> /// merge provided spans to each distinct group of spans in ascending order /// </summary> public static IEnumerable<TextSpan> ToNormalizedSpans(this IEnumerable<TextSpan> spans) => new NormalizedTextSpanCollection(spans); public static ImmutableArray<TextSpan> ToNormalizedSpans(this ImmutableArray<TextSpan> spans) => [.. spans]; public static TextSpan Collapse(this IEnumerable<TextSpan> spans) { var start = int.MaxValue; var end = 0; foreach (var span in spans) { if (span.Start < start) { start = span.Start; } if (span.End > end) { end = span.End; } } if (start > end) { // there were no changes. return default; } return TextSpan.FromBounds(start, end); } /// <summary> /// Returns true if the span encompasses the specified node or token and is contained within its trivia. /// </summary> public static bool IsAround(this TextSpan span, SyntaxNodeOrToken node) => IsAround(span, node, node); /// <summary> /// Returns true if the span encompasses a span between the specified nodes or tokens /// and is contained within trivia around them. /// </summary> public static bool IsAround(this TextSpan span, SyntaxNodeOrToken startNode, SyntaxNodeOrToken endNode) { var innerSpan = TextSpan.FromBounds(startNode.Span.Start, endNode.Span.End); var outerSpan = TextSpan.FromBounds(startNode.FullSpan.Start, endNode.FullSpan.End); return span.Contains(innerSpan) && outerSpan.Contains(span); } public static IEnumerable<TextSpan> Subtract(this TextSpan span, TextSpan except) { if (except.IsEmpty) { if (span != except) { yield return span; } yield break; } var startSegmentEnd = Math.Min(span.End, except.Start); if (span.Start < startSegmentEnd) yield return TextSpan.FromBounds(span.Start, startSegmentEnd); var endSegmentStart = Math.Max(span.Start, except.End); if (endSegmentStart < span.End) yield return TextSpan.FromBounds(endSegmentStart, span.End); } public static IEnumerable<TextSpan> Subtract(this IEnumerable<TextSpan> spans, TextSpan except) => spans.SelectMany(span => span.Subtract(except)); } |