File: Diagnostics\SuppressMessageAttributeWorkspaceTests.cs
Web Access
Project: src\src\EditorFeatures\Test\Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.EditorFeatures.UnitTests)
// 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.Immutable;
using System.Linq;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics;
 
[UseExportProvider]
public class SuppressMessageAttributeWorkspaceTests : SuppressMessageAttributeTests
{
    private static readonly TestComposition s_compositionWithMockDiagnosticUpdateSourceRegistrationService = EditorTestCompositions.EditorFeatures;
 
    private static readonly Lazy<MetadataReference> _unconditionalSuppressMessageRef = new(() =>
    {
        const string unconditionalSuppressMessageDef = @"
namespace System.Diagnostics.CodeAnalysis
{
    [System.AttributeUsage(System.AttributeTargets.All, AllowMultiple=true, Inherited=false)]
    public sealed class UnconditionalSuppressMessageAttribute : System.Attribute
    {
        public UnconditionalSuppressMessageAttribute(string category, string checkId)
        {
            Category = category;
            CheckId = checkId;
        }
        public string Category { get; }
        public string CheckId { get; }
        public string Scope { get; set; }
        public string Target { get; set; }
        public string MessageId { get; set; }
        public string Justification { get; set; }
    }
}";
        return CSharpCompilation.Create("unconditionalsuppress",
             options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
            syntaxTrees: [CSharpSyntaxTree.ParseText(unconditionalSuppressMessageDef)],
            references: [TestBase.MscorlibRef]).EmitToImageReference();
    }, LazyThreadSafetyMode.PublicationOnly);
 
    protected override async Task VerifyAsync(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] expectedDiagnostics, string rootNamespace = null)
    {
        using var workspace = CreateWorkspaceFromFile(source, language, rootNamespace);
 
        workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences(
        [
            new AnalyzerImageReference(analyzers.ToImmutableArray())
        ]).WithProjectMetadataReferences(
            workspace.Projects.Single().Id,
            workspace.Projects.Single().MetadataReferences.Append(_unconditionalSuppressMessageRef.Value)));
 
        var documentId = workspace.Documents[0].Id;
        var document = workspace.CurrentSolution.GetDocument(documentId);
        var span = (await document.GetSyntaxRootAsync()).FullSpan;
 
        var actualDiagnostics = await DiagnosticProviderTestUtilities.GetAllDiagnosticsAsync(workspace, document, span);
        actualDiagnostics.Verify(expectedDiagnostics);
    }
 
    private static TestWorkspace CreateWorkspaceFromFile(string source, string language, string rootNamespace)
    {
        if (language == LanguageNames.CSharp)
        {
            return TestWorkspace.CreateCSharp(source, composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService);
        }
        else
        {
            return TestWorkspace.CreateVisualBasic(
                source,
                compilationOptions: new VisualBasic.VisualBasicCompilationOptions(
                    OutputKind.DynamicallyLinkedLibrary, rootNamespace: rootNamespace),
                composition: s_compositionWithMockDiagnosticUpdateSourceRegistrationService);
        }
    }
 
    protected override bool ConsiderArgumentsForComparingDiagnostics
    {
        get
        {
            // Round tripping diagnostics from DiagnosticData causes the Arguments info stored within compiler DiagnosticWithInfo to be lost, so don't compare Arguments in IDE.
            // NOTE: We will still compare squiggled text for the diagnostics, which is also a sufficient test.
            return false;
        }
    }
 
    [Fact]
    public async Task AnalyzerExceptionDiagnosticsWithDifferentContext()
    {
        var diagnostic = Diagnostic("AD0001", null);
 
        // expect 3 different diagnostics with 3 different contexts.
        await VerifyCSharpAsync(@"
public class C
{
}
public class C1
{
}
public class C2
{
}
",
            [new ThrowExceptionForEachNamedTypeAnalyzer(ExceptionDispatchInfo.Capture(new Exception()))],
            diagnostics: [diagnostic, diagnostic, diagnostic]);
    }
 
    [Fact]
    public async Task AnalyzerExceptionFromSupportedDiagnosticsCall()
    {
        var diagnostic = Diagnostic("AD0001", null);
 
        await VerifyCSharpAsync("public class C { }",
            [new ThrowExceptionFromSupportedDiagnostics(new Exception())],
            diagnostics: [diagnostic]);
    }
}