File: Panels\WorkspacePanel.xaml.cs
Web Access
Project: src\src\VisualStudio\VisualStudioDiagnosticsToolWindow\Roslyn.VisualStudio.DiagnosticsWindow.csproj (Roslyn.VisualStudio.DiagnosticsWindow)
// 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.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
 
namespace Roslyn.VisualStudio.DiagnosticsWindow
{
    /// <summary>
    /// Interaction logic for TelemetryPanel.xaml
    /// </summary>
    public sealed partial class WorkspacePanel : UserControl
    {
        private readonly DiagnosticsWindow _window;
 
        public WorkspacePanel(DiagnosticsWindow window)
        {
            _window = window;
            InitializeComponent();
        }
 
        private void OnDiagnose(object sender, RoutedEventArgs e)
        {
            _ = OnDiagnoseImplAsync();
 
            async Task OnDiagnoseImplAsync()
            {
                DiagnoseButton.IsEnabled = false;
                GenerationProgresBar.IsIndeterminate = true;
                Result.Text = "Comparing in-proc solution snapshot with files on disk ...";
 
                var text = await Task.Run(
                    async () =>
                    {
                        try
                        {
                            return await DiagnoseAsync(CancellationToken.None).ConfigureAwait(false);
                        }
                        catch (Exception e)
                        {
                            return e.ToString();
                        }
                    }).ConfigureAwait(true);
 
                GenerationProgresBar.IsIndeterminate = false;
                DiagnoseButton.IsEnabled = true;
                Result.Text = text;
            }
        }
 
        private async Task<string> DiagnoseAsync(CancellationToken cancellationToken)
        {
            var workspace = _window.Workspace;
            if (workspace == null)
            {
                return "Workspace unavailable";
            }
 
            var output = new StringBuilder();
            await CompareClosedDocumentsWithFileSystemAsync(workspace, output, cancellationToken).ConfigureAwait(false);
            return output.ToString();
        }
 
        private static async Task CompareClosedDocumentsWithFileSystemAsync(Workspace workspace, StringBuilder output, CancellationToken cancellationToken)
        {
            var solution = workspace.CurrentSolution;
            var outOfDateCount = 0;
            var gate = new object();
 
            var tasks = from project in solution.Projects
                        from document in project.Documents
                        where document.FilePath != null
                        where !workspace.IsDocumentOpen(document.Id)
                        select CompareDocumentAsync(document);
 
            async Task CompareDocumentAsync(Document document)
            {
                cancellationToken.ThrowIfCancellationRequested();
 
                var snapshotText = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false);
                var snapshotChecksum = snapshotText.GetChecksum();
 
                using var fileStream = File.OpenRead(document.FilePath);
                var fileText = SourceText.From(fileStream, snapshotText.Encoding, snapshotText.ChecksumAlgorithm);
                var fileChecksum = fileText.GetChecksum();
 
                if (!fileChecksum.SequenceEqual(snapshotChecksum))
                {
                    lock (gate)
                    {
                        output.AppendLine($"{document.FilePath}: {BitConverter.ToString([.. snapshotChecksum])} : {BitConverter.ToString([.. fileChecksum])}");
                        outOfDateCount++;
                    }
                }
            }
 
            await Task.WhenAll(tasks).ConfigureAwait(false);
 
            output.AppendLine(outOfDateCount == 0
                ? "All closed documents up to date."
                : $"{Environment.NewLine}{outOfDateCount} documents out of date.");
        }
    }
}