File: ExternalAccess\UnitTesting\SolutionCrawler\AbstractUnitTestingDocumentDifferenceService.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 System.Threading;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.Api;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.ExternalAccess.UnitTesting.SolutionCrawler;
 
internal abstract class AbstractUnitTestingDocumentDifferenceService : IUnitTestingDocumentDifferenceService
{
    public UnitTestingDocumentDifferenceResult? GetDifference(Document oldDocument, Document newDocument, CancellationToken cancellationToken)
    {
        try
        {
            var syntaxFactsService = newDocument.Project.Services.GetService<ISyntaxFactsService>();
            if (syntaxFactsService == null)
            {
                // somehow, we can't get the service. without it, there is nothing we can do.
                return new UnitTestingDocumentDifferenceResult(UnitTestingInvocationReasons.DocumentChanged);
            }
            // this is based on the implementation detail where opened documents use strong references
            // to tree and text rather than recoverable versions.
            if (!oldDocument.TryGetText(out var oldText) ||
                !newDocument.TryGetText(out var newText))
            {
                // no cheap way to determine top level changes. assumes top level has changed
                return new UnitTestingDocumentDifferenceResult(UnitTestingInvocationReasons.DocumentChanged);
            }
            // quick check whether two tree versions are same
            if (oldDocument.TryGetSyntaxVersion(out var oldVersion) &&
                newDocument.TryGetSyntaxVersion(out var newVersion) &&
                oldVersion.Equals(newVersion))
            {
                // nothing has changed. don't do anything.
                // this could happen if a document is opened/closed without any buffer change
                return null;
            }
 
            var range = newText.GetEncompassingTextChangeRange(oldText);
            if (range == default)
            {
                // nothing has changed. don't do anything
                return null;
            }
 
            return new UnitTestingDocumentDifferenceResult(UnitTestingInvocationReasons.DocumentChanged);
        }
        catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
        {
            throw ExceptionUtilities.Unreachable();
        }
    }
}