// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests.Diagnostics; using Roslyn.Utilities; using Xunit; using System.Collections.Concurrent; namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics { public abstract class AbstractDiagnosticProviderBasedUserDiagnosticTest : AbstractUserDiagnosticTest { private readonly ConcurrentDictionary> _analyzerAndFixerMap = new ConcurrentDictionary>(); internal abstract Tuple CreateDiagnosticProviderAndFixer(Workspace workspace); private Tuple GetOrCreateDiagnosticProviderAndFixer(Workspace workspace) { return _analyzerAndFixerMap.GetOrAdd(workspace, CreateDiagnosticProviderAndFixer); } internal override IEnumerable GetDiagnostics(TestWorkspace workspace) { var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace); var provider = providerAndFixer.Item1; TextSpan span; var document = GetDocumentAndSelectSpan(workspace, out span); var allDiagnostics = DiagnosticProviderTestUtilities.GetAllDiagnostics(provider, document, span); AssertNoAnalyzerExceptionDiagnostics(allDiagnostics); return allDiagnostics; } internal override IEnumerable> GetDiagnosticAndFixes(TestWorkspace workspace, string fixAllActionId) { var providerAndFixer = GetOrCreateDiagnosticProviderAndFixer(workspace); var provider = providerAndFixer.Item1; Document document; TextSpan span; string annotation = null; if (!TryGetDocumentAndSelectSpan(workspace, out document, out span)) { document = GetDocumentAndAnnotatedSpan(workspace, out annotation, out span); } using (var testDriver = new TestDiagnosticAnalyzerDriver(document.Project, provider)) { var diagnostics = testDriver.GetAllDiagnostics(provider, document, span); AssertNoAnalyzerExceptionDiagnostics(diagnostics); var fixer = providerAndFixer.Item2; var ids = new HashSet(fixer.FixableDiagnosticIds); var dxs = diagnostics.Where(d => ids.Contains(d.Id)).ToList(); return GetDiagnosticAndFixes(dxs, provider, fixer, testDriver, document, span, annotation, fixAllActionId); } } /// /// The internal method does /// essentially this, but due to linked files between projects, this project cannot have internals visible /// access to the Microsoft.CodeAnalysis project without the cascading effect of many extern aliases, so it /// is re-implemented here in a way that is potentially overly agressive with the knowledge that if this method /// starts failing on non-analyzer exception diagnostics, it can be appropriately tuned or re-evaluated. /// private void AssertNoAnalyzerExceptionDiagnostics(IEnumerable diagnostics) { Assert.Equal(0, diagnostics.Count(diag => diag.Descriptor.CustomTags.Contains(WellKnownDiagnosticTags.AnalyzerException))); } } }