|
// 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.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Diagnostics
{
[ExportWorkspaceServiceFactory(typeof(IBuildOnlyDiagnosticsService), ServiceLayer.Default), Shared]
internal sealed class BuildOnlyDiagnosticsServiceFactory : IWorkspaceServiceFactory
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public BuildOnlyDiagnosticsServiceFactory()
{
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
=> new BuildOnlyDiagnosticsService(workspaceServices.Workspace);
private sealed class BuildOnlyDiagnosticsService : IBuildOnlyDiagnosticsService
{
private readonly object _gate = new();
private readonly Dictionary<DocumentId, ImmutableArray<DiagnosticData>> _documentDiagnostics = new();
private readonly Dictionary<ProjectId, ImmutableArray<DiagnosticData>> _projectDiagnostics = new();
public BuildOnlyDiagnosticsService(Workspace workspace)
{
workspace.WorkspaceChanged += OnWorkspaceChanged;
}
private void OnWorkspaceChanged(object? sender, WorkspaceChangeEventArgs e)
{
switch (e.Kind)
{
case WorkspaceChangeKind.SolutionAdded:
case WorkspaceChangeKind.SolutionCleared:
case WorkspaceChangeKind.SolutionReloaded:
case WorkspaceChangeKind.SolutionRemoved:
ClearAllDiagnostics();
break;
case WorkspaceChangeKind.ProjectReloaded:
case WorkspaceChangeKind.ProjectRemoved:
ClearDiagnostics(e.OldSolution.GetProject(e.ProjectId));
break;
case WorkspaceChangeKind.DocumentRemoved:
case WorkspaceChangeKind.DocumentReloaded:
case WorkspaceChangeKind.AdditionalDocumentRemoved:
case WorkspaceChangeKind.AdditionalDocumentReloaded:
case WorkspaceChangeKind.AnalyzerConfigDocumentRemoved:
case WorkspaceChangeKind.AnalyzerConfigDocumentReloaded:
ClearDiagnostics(e.DocumentId);
break;
}
}
public void AddBuildOnlyDiagnostics(Solution solution, ProjectId? projectId, DocumentId? documentId, ImmutableArray<DiagnosticData> diagnostics)
{
lock (_gate)
{
if (documentId != null)
{
_documentDiagnostics[documentId] = diagnostics;
}
else if (projectId != null)
{
_projectDiagnostics[projectId] = diagnostics;
}
}
}
private void ClearAllDiagnostics()
{
lock (_gate)
{
_documentDiagnostics.Clear();
_projectDiagnostics.Clear();
}
}
private void ClearDiagnostics(DocumentId? documentId)
{
if (documentId == null)
return;
lock (_gate)
{
_documentDiagnostics.Remove(documentId);
}
}
private void ClearDiagnostics(Project? project)
{
if (project == null)
return;
lock (_gate)
{
_projectDiagnostics.Remove(project.Id);
foreach (var documentId in project.DocumentIds)
_documentDiagnostics.Remove(documentId);
}
}
public void ClearBuildOnlyDiagnostics(Solution solution, ProjectId? projectId, DocumentId? documentId)
{
if (documentId != null)
ClearDiagnostics(documentId);
else
ClearDiagnostics(solution.GetProject(projectId));
}
public ImmutableArray<DiagnosticData> GetBuildOnlyDiagnostics(DocumentId documentId)
{
lock (_gate)
{
if (_documentDiagnostics.TryGetValue(documentId, out var diagnostics))
{
return diagnostics;
}
return ImmutableArray<DiagnosticData>.Empty;
}
}
public ImmutableArray<DiagnosticData> GetBuildOnlyDiagnostics(ProjectId projectId)
{
lock (_gate)
{
if (_projectDiagnostics.TryGetValue(projectId, out var diagnostics))
{
return diagnostics;
}
return ImmutableArray<DiagnosticData>.Empty;
}
}
}
}
}
|