File: TaskList\HostDiagnosticUpdateSource.cs
Web Access
Project: ..\..\..\src\VisualStudio\Core\Def\Microsoft.VisualStudio.LanguageServices_ckcrqypr_wpftmp.csproj (Microsoft.VisualStudio.LanguageServices)
// 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;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Workspaces.ProjectSystem;
using Roslyn.Utilities;
 
namespace Microsoft.VisualStudio.LanguageServices.Implementation.TaskList
{
    // exporting both Abstract and HostDiagnosticUpdateSource is just to make testing easier.
    // use HostDiagnosticUpdateSource when abstract one is not needed for testing purpose
    [Export(typeof(AbstractHostDiagnosticUpdateSource))]
    [Export(typeof(HostDiagnosticUpdateSource))]
    internal sealed class HostDiagnosticUpdateSource : AbstractHostDiagnosticUpdateSource, IProjectSystemDiagnosticSource
    {
        private readonly Lazy<VisualStudioWorkspace> _workspace;
 
        private readonly object _gate = new();
        private readonly Dictionary<ProjectId, HashSet<object>> _diagnosticMap = new();
 
        [ImportingConstructor]
        [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")]
        public HostDiagnosticUpdateSource(Lazy<VisualStudioWorkspace> workspace, IDiagnosticUpdateSourceRegistrationService registrationService)
        {
            _workspace = workspace;
 
            registrationService.Register(this);
        }
 
        public override Workspace Workspace
        {
            get
            {
                return _workspace.Value;
            }
        }
 
        private void RaiseDiagnosticsCreatedForProject(ProjectId projectId, object key, IEnumerable<DiagnosticData> items)
        {
            var args = DiagnosticsUpdatedArgs.DiagnosticsCreated(
                CreateId(projectId, key),
                Workspace,
                solution: null,
                projectId: projectId,
                documentId: null,
                diagnostics: items.AsImmutableOrEmpty());
 
            RaiseDiagnosticsUpdated(args);
        }
 
        private void RaiseDiagnosticsRemovedForProject(ProjectId projectId, object key)
        {
            var args = DiagnosticsUpdatedArgs.DiagnosticsRemoved(
                CreateId(projectId, key),
                Workspace,
                solution: null,
                projectId: projectId,
                documentId: null);
 
            RaiseDiagnosticsUpdated(args);
        }
 
        private object CreateId(ProjectId projectId, object key) => Tuple.Create(this, projectId, key);
 
        public void UpdateDiagnosticsForProject(ProjectId projectId, object key, IEnumerable<DiagnosticData> items)
        {
            Contract.ThrowIfNull(projectId);
            Contract.ThrowIfNull(key);
            Contract.ThrowIfNull(items);
 
            lock (_gate)
            {
                _diagnosticMap.GetOrAdd(projectId, id => new HashSet<object>()).Add(key);
            }
 
            RaiseDiagnosticsCreatedForProject(projectId, key, items);
        }
 
        public void ClearAllDiagnosticsForProject(ProjectId projectId)
        {
            Contract.ThrowIfNull(projectId);
 
            HashSet<object> projectDiagnosticKeys;
            lock (_gate)
            {
                if (_diagnosticMap.TryGetValue(projectId, out projectDiagnosticKeys))
                {
                    _diagnosticMap.Remove(projectId);
                }
            }
 
            if (projectDiagnosticKeys != null)
            {
                foreach (var key in projectDiagnosticKeys)
                {
                    RaiseDiagnosticsRemovedForProject(projectId, key);
                }
            }
 
            ClearAnalyzerDiagnostics(projectId);
        }
 
        public void ClearDiagnosticsForProject(ProjectId projectId, object key)
        {
            Contract.ThrowIfNull(projectId);
            Contract.ThrowIfNull(key);
 
            var raiseEvent = false;
            lock (_gate)
            {
                if (_diagnosticMap.TryGetValue(projectId, out var projectDiagnosticKeys))
                {
                    raiseEvent = projectDiagnosticKeys.Remove(key);
                }
            }
 
            if (raiseEvent)
            {
                RaiseDiagnosticsRemovedForProject(projectId, key);
            }
        }
 
        public DiagnosticData CreateAnalyzerLoadFailureDiagnostic(AnalyzerLoadFailureEventArgs e, string fullPath, ProjectId projectId, string language)
        {
            return DocumentAnalysisExecutor.CreateAnalyzerLoadFailureDiagnostic(e, fullPath, projectId, language);
        }
    }
}