File: src\Workspaces\SharedUtilitiesAndExtensions\Compiler\Core\Extensions\SourceTextExtensions_SharedWithCodeStyle.cs
Web Access
Project: src\src\CodeStyle\Core\Analyzers\Microsoft.CodeAnalysis.CodeStyle.csproj (Microsoft.CodeAnalysis.CodeStyle)
// 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.Threading;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Shared.Extensions;
 
internal static partial class SourceTextExtensions
{
    /// <summary>
    /// Returns the leading whitespace of the line located at the specified position in the given snapshot.
    /// </summary>
    public static string GetLeadingWhitespaceOfLineAtPosition(this SourceText text, int position)
    {
        Contract.ThrowIfNull(text);
 
        var line = text.Lines.GetLineFromPosition(position);
        var linePosition = line.GetFirstNonWhitespacePosition();
        if (!linePosition.HasValue)
        {
            return line.ToString();
        }
 
        var lineText = line.ToString();
        return lineText[..(linePosition.Value - line.Start)];
    }
 
    public static bool OverlapsHiddenPosition(
        this SourceText text, TextSpan span, Func<int, CancellationToken, bool> isPositionHidden, CancellationToken cancellationToken)
    {
        var result = TryOverlapsHiddenPosition(text, span, isPositionHidden, cancellationToken);
        cancellationToken.ThrowIfCancellationRequested();
        return result;
    }
 
    /// <summary>
    /// Same as OverlapsHiddenPosition but doesn't throw on cancellation.  Instead, returns false
    /// in that case.
    /// </summary>
    public static bool TryOverlapsHiddenPosition(
        this SourceText text, TextSpan span, Func<int, CancellationToken, bool> isPositionHidden,
        CancellationToken cancellationToken)
    {
        var startLineNumber = text.Lines.IndexOf(span.Start);
        var endLineNumber = text.Lines.IndexOf(span.End);
 
        // NOTE(cyrusn): It's safe to examine the start of a line because you can't have a line
        // with both a pp directive and code on it.  so, for example, if a node crosses a region
        // then it must be the case that the start of some line from the start of the node to
        // the end is hidden.  i.e.:
#if false
'           class C
'           {
'#line hidden
'           }
'#line default
#endif
        // The start of the line with the } on it is hidden, and thus the node overlaps a hidden
        // region.
 
        for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                break;
            }
 
            var linePosition = text.Lines[lineNumber].Start;
            var isHidden = isPositionHidden(linePosition, cancellationToken);
            if (isHidden)
            {
                return true;
            }
        }
 
        return false;
    }
 
    public static bool AreOnSameLine(this SourceText text, SyntaxToken token1, SyntaxToken token2)
        => token1.RawKind != 0 &&
           token2.RawKind != 0 &&
           text.AreOnSameLine(token1.Span.End, token2.SpanStart);
 
    public static bool AreOnSameLine(this SourceText text, int pos1, int pos2)
        => text.Lines.IndexOf(pos1) == text.Lines.IndexOf(pos2);
}