File: Diagnostics\Suppression\SuppressionTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.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.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeFixes.Suppression;
using Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Diagnostics.CSharp;
using Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.Suppression;
 
public abstract partial class CSharpSuppressionTests : AbstractSuppressionDiagnosticTest_NoEditor
{
    protected override ParseOptions GetScriptOptions() => Options.Script;
 
    protected internal override string GetLanguage() => LanguageNames.CSharp;
 
    #region "Pragma disable tests"
 
    public abstract partial class CSharpPragmaWarningDisableSuppressionTests : CSharpSuppressionTests
    {
        protected sealed override int CodeActionIndex
        {
            get { return 0; }
        }
 
        [Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
        public class CompilerDiagnosticSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
        {
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
                => Tuple.Create<DiagnosticAnalyzer, IConfigurationFixProvider>(null, new CSharpSuppressionCodeFixProvider());
 
            [Fact]
            public async Task TestPragmaWarningDirective()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        [|int x = 0;|]
    }
}",
    $@"
class Class
{{
    void Method()
    {{
#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        int x = 0;
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
    }}
}}");
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/26015")]
            public async Task TestPragmaWarningDirectiveAroundMultiLineStatement()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        [|string x = @""multi
line"";|]
    }
}",
    $@"
class Class
{{
    void Method()
    {{
#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        string x = @""multi
line"";
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
    }}
}}");
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/56165")]
            public async Task TestPragmaWarningDirectiveAroundMultiLineInterpolatedString()
            {
                await TestAsync(
        @"
using System;
 
[Obsolete]
class Session { }
 
class Class
{
    void Method()
    {
        var s = $@""
hi {[|new Session()|]}
"";
    }
}",
        $@"
using System;
 
[Obsolete]
class Session {{ }}
 
class Class
{{
    void Method()
    {{
#pragma warning disable CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
        var s = $@""
hi {{new Session()}}
"";
#pragma warning restore CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
    }}
}}");
            }
 
            [Fact]
            public async Task TestMultilineStatementPragmaWarningDirective()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        [|int x = 0
              + 1;|]
    }
}",
    $@"
class Class
{{
    void Method()
    {{
#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        int x = 0
              + 1;
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
    }}
}}");
            }
 
            [Fact]
            public async Task TestMultilineStatementPragmaWarningDirective2()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        [|int x = 0,
            y = 1;|]
    }
}",
    $@"
class Class
{{
    void Method()
    {{
#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        int x = 0,
            y = 1;
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
    }}
}}");
            }
 
            [Fact]
            public async Task TestPragmaWarningDirectiveWithExistingTrivia()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        // Start comment previous line
        /* Start comment same line */ [|int x = 0;|] // End comment same line
        /* End comment next line */
    }
}",
    $@"
class Class
{{
    void Method()
    {{
        // Start comment previous line
#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        /* Start comment same line */
        int x = 0; // End comment same line
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        /* End comment next line */
    }}
}}");
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/16681")]
            public async Task TestPragmaWarningDirectiveWithDocumentationComment1()
            {
                await TestAsync(
    @"
sealed class Class
{
    /// <summary>Text</summary>
    [|protected void Method()|]
    {
    }
}",
    $@"
sealed class Class
{{
    /// <summary>Text</summary>
#pragma warning disable CS0628 // {CSharpResources.WRN_ProtectedInSealed_Title}
    protected void Method()
#pragma warning restore CS0628 // {CSharpResources.WRN_ProtectedInSealed_Title}
    {{
    }}
}}");
            }
 
            [Fact]
            public async Task TestPragmaWarningExpressionBodiedMember1()
            {
                await TestAsync(
    @"
sealed class Class
{
    [|protected int Method()|] => 1;
}",
    $@"
sealed class Class
{{
#pragma warning disable CS0628 // {CSharpResources.WRN_ProtectedInSealed_Title}
    protected int Method() => 1;
#pragma warning restore CS0628 // {CSharpResources.WRN_ProtectedInSealed_Title}
}}");
            }
 
            [Fact]
            public async Task TestPragmaWarningExpressionBodiedMember2()
            {
                await TestAsync(
        @"
using System;
 
[Obsolete]
class Session { }
 
class Class
{
    string Method()
        => @$""hi
        {[|new Session()|]}
        "";
}",
        $@"
using System;
 
[Obsolete]
class Session {{ }}
 
class Class
{{
    string Method()
#pragma warning disable CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
        => @$""hi
        {{new Session()}}
        "";
#pragma warning restore CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
}}");
            }
 
            [Fact]
            public async Task TestPragmaWarningExpressionBodiedLocalFunction()
            {
                await TestAsync(
        @"
using System;
 
[Obsolete]
class Session { }
 
class Class
{
    void M()
    {
        string Method()
            => @$""hi
            {[|new Session()|]}
            "";
    }
}",
        $@"
using System;
 
[Obsolete]
class Session {{ }}
 
class Class
{{
    void M()
    {{
#pragma warning disable CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
        string Method()
            => @$""hi
            {{new Session()}}
            "";
#pragma warning restore CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
    }}
}}");
            }
 
            [Fact]
            public async Task TestPragmaWarningExpressionBodiedLambda()
            {
                await TestAsync(
        @"
using System;
 
[Obsolete]
class Session { }
 
class Class
{
    void M()
    {
        new Func<string>(()
            => @$""hi
            {[|new Session()|]}
            "");
    }
}",
        $@"
using System;
 
[Obsolete]
class Session {{ }}
 
class Class
{{
    void M()
    {{
#pragma warning disable CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
        new Func<string>(()
            => @$""hi
            {{new Session()}}
            "");
#pragma warning restore CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
    }}
}}");
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/16681")]
            public async Task TestPragmaWarningDirectiveWithDocumentationComment2()
            {
                await TestAsync(
    @"
sealed class Class
{
    /// <summary>Text</summary>
    /// <remarks>
    /// <see cref=""[|Class2|]""/>
    /// </remarks>
    void Method()
    {
    }
}",
    $@"
sealed class Class
{{
 
#pragma warning disable CS1574 // {CSharpResources.WRN_BadXMLRef_Title}
    /// <summary>Text</summary>
    /// <remarks>
    /// <see cref=""Class2""/>
    /// </remarks>
    void Method()
#pragma warning restore CS1574 // {CSharpResources.WRN_BadXMLRef_Title}
    {{
    }}
}}", new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose));
            }
 
            [Fact]
            public async Task TestMultipleInstancesOfPragmaWarningDirective()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        [|int x = 0, y = 0;|]
    }
}",
    $@"
class Class
{{
    void Method()
    {{
#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
        int x = 0, y = 0;
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
    }}
}}");
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/3311")]
            public async Task TestNoDuplicateSuppressionCodeFixes()
            {
                var source = @"
class Class
{
    void Method()
    {
        [|int x = 0, y = 0; string s;|]
    }
}";
                var parameters = new TestParameters();
                using var workspace = CreateWorkspaceFromOptions(source, parameters);
 
                var analyzerReference = new AnalyzerImageReference([new CSharpCompilerDiagnosticAnalyzer()]);
                workspace.TryApplyChanges(workspace.CurrentSolution.WithAnalyzerReferences([analyzerReference]));
 
                var diagnosticService = Assert.IsType<DiagnosticAnalyzerService>(workspace.ExportProvider.GetExportedValue<IDiagnosticAnalyzerService>());
                var incrementalAnalyzer = diagnosticService.CreateIncrementalAnalyzer(workspace);
                var suppressionProvider = CreateDiagnosticProviderAndFixer(workspace).Item2;
                var suppressionProviderFactory = new Lazy<IConfigurationFixProvider, CodeChangeProviderMetadata>(() => suppressionProvider,
                    new CodeChangeProviderMetadata("SuppressionProvider", languages: [LanguageNames.CSharp]));
                var fixService = new CodeFixService(
                    diagnosticService,
                    loggers: [],
                    fixers: [],
                    [suppressionProviderFactory]);
                var document = GetDocumentAndSelectSpan(workspace, out var span);
                var diagnostics = await diagnosticService.GetDiagnosticsForSpanAsync(document, span, CancellationToken.None);
                Assert.Equal(2, diagnostics.Where(d => d.Id == "CS0219").Count());
 
                var allFixes = (await fixService.GetFixesAsync(document, span, CancellationToken.None))
                    .SelectMany(fixCollection => fixCollection.Fixes);
 
                var cs0219Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0219").ToArray();
 
                // Ensure that there are no duplicate suppression fixes.
                Assert.Equal(1, cs0219Fixes.Length);
                var cs0219EquivalenceKey = cs0219Fixes[0].Action.EquivalenceKey;
                Assert.NotNull(cs0219EquivalenceKey);
 
                // Ensure that there *is* a fix for the other warning and that it has a *different*
                // equivalence key so that it *doesn't* get de-duplicated
                Assert.Equal(1, diagnostics.Where(d => d.Id == "CS0168").Count());
                var cs0168Fixes = allFixes.Where(fix => fix.PrimaryDiagnostic.Id == "CS0168");
                var cs0168EquivalenceKey = cs0168Fixes.Single().Action.EquivalenceKey;
                Assert.NotNull(cs0168EquivalenceKey);
                Assert.NotEqual(cs0219EquivalenceKey, cs0168EquivalenceKey);
            }
 
            [Fact]
            public async Task TestErrorAndWarningScenario()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
        return 0;
        [|int x = ""0"";|]
    }
}",
    $@"
class Class
{{
    void Method()
    {{
        return 0;
#pragma warning disable CS0162 // {CSharpResources.WRN_UnreachableCode_Title}
        int x = ""0"";
#pragma warning restore CS0162 // {CSharpResources.WRN_UnreachableCode_Title}
    }}
}}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/956453")]
            public async Task TestWholeFilePragmaWarningDirective()
            {
                await TestAsync(
    @"class Class { void Method() { [|int x = 0;|] } }",
    $@"#pragma warning disable CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}
class Class {{ void Method() {{ int x = 0; }} }}
#pragma warning restore CS0219 // {CSharpResources.WRN_UnreferencedVarAssg_Title}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/970129")]
            public async Task TestSuppressionAroundSingleToken()
            {
                await TestAsync(
    @"
using System;
[Obsolete]
class Session { }
class Program
{
    static void Main()
    {
      [|Session|]
    }
}",
    $@"
using System;
[Obsolete]
class Session {{ }}
class Program
{{
    static void Main()
    {{
#pragma warning disable CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
        Session
#pragma warning restore CS0612 // {CSharpResources.WRN_DeprecatedSymbol_Title}
    }}
}}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1066576")]
            public async Task TestPragmaWarningDirectiveAroundTrivia1()
            {
                await TestAsync(
    @"
class Class
{
    void Method()
    {
 
// Comment
// Comment
[|#pragma abcde|]
 
    }    // Comment   
 
 
 
}",
    $@"
class Class
{{
    void Method()
#pragma warning disable CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
    {{
 
// Comment
// Comment
#pragma abcde
 
    }}    // Comment   
#pragma warning restore CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
 
 
 
}}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1066576")]
            public async Task TestPragmaWarningDirectiveAroundTrivia2()
            {
                await TestAsync(
    @"[|#pragma abcde|]",
    $@"#pragma warning disable CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
#pragma abcde
#pragma warning restore CS1633 // {CSharpResources.WRN_IllegalPragma_Title}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1066576")]
            public async Task TestPragmaWarningDirectiveAroundTrivia3()
            {
                await TestAsync(
    @"[|#pragma abcde|]  ",
    $@"#pragma warning disable CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
#pragma abcde  
#pragma warning restore CS1633 // {CSharpResources.WRN_IllegalPragma_Title}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1066576")]
            public async Task TestPragmaWarningDirectiveAroundTrivia4()
            {
                await TestAsync(
    @"
 
[|#pragma abc|]
class C { }
 
",
    $@"
 
#pragma warning disable CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
#pragma abc
class C {{ }}
#pragma warning restore CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
 
");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1066576")]
            public async Task TestPragmaWarningDirectiveAroundTrivia5()
            {
                await TestAsync(
    @"class C1 { }
[|#pragma abc|]
class C2 { }
class C3 { }",
    $@"class C1 {{ }}
#pragma warning disable CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
#pragma abc
class C2 {{ }}
#pragma warning restore CS1633 // {CSharpResources.WRN_IllegalPragma_Title}
class C3 {{ }}");
            }
 
            [Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1066576")]
            public async Task TestPragmaWarningDirectiveAroundTrivia6()
            {
                await TestAsync(
    @"class C1 { }
class C2 { } /// <summary><see [|cref=""abc""|]/></summary>
class C3 { } // comment
  // comment
// comment",
$@"class C1 {{ }}
#pragma warning disable CS1574 // {CSharpResources.WRN_BadXMLRef_Title}
class C2 {{ }} /// <summary><see cref=""abc""/></summary>
class
#pragma warning restore CS1574 // {CSharpResources.WRN_BadXMLRef_Title}
C3 {{ }} // comment
  // comment
// comment", CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.Diagnose));
            }
        }
 
        public class UserHiddenDiagnosticSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
        {
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new CSharpSimplifyTypeNamesDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            public async Task TestHiddenDiagnosticCannotBeSuppressed()
            {
                await TestMissingAsync(
    @"
using System;
 
class Class
{
int Method()
{
    [|System.Int32 x = 0;|]
    return x;
}
}");
            }
        }
 
        public partial class UserInfoDiagnosticSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
        {
            private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
            {
                public static readonly DiagnosticDescriptor Decsciptor =
                    new DiagnosticDescriptor("InfoDiagnostic", "InfoDiagnostic Title", "InfoDiagnostic", "InfoDiagnostic", DiagnosticSeverity.Info, isEnabledByDefault: true);
 
                public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
                {
                    get
                    {
                        return ImmutableArray.Create(Decsciptor);
                    }
                }
 
                public override void Initialize(AnalysisContext context)
                    => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
 
                public void AnalyzeNode(SyntaxNodeAnalysisContext context)
                {
                    var classDecl = (ClassDeclarationSyntax)context.Node;
                    context.ReportDiagnostic(Diagnostic.Create(Decsciptor, classDecl.Identifier.GetLocation()));
                }
            }
 
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            public async Task TestInfoDiagnosticSuppressed()
            {
                await TestAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}",
        @"
using System;
 
#pragma warning disable InfoDiagnostic // InfoDiagnostic Title
class Class
#pragma warning restore InfoDiagnostic // InfoDiagnostic Title
{
    int Method()
    {
        int x = 0;
    }
}");
            }
        }
 
        public partial class FormattingDiagnosticSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
        {
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new CSharpFormattingAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            protected override async Task<(ImmutableArray<CodeAction>, CodeAction actionToInvoke)> GetCodeActionsAsync(TestWorkspace workspace, TestParameters parameters)
            {
                var solution = workspace.CurrentSolution;
                var compilationOptions = solution.Projects.Single().CompilationOptions;
                var specificDiagnosticOptions = new[] { KeyValuePairUtil.Create(IDEDiagnosticIds.FormattingDiagnosticId, ReportDiagnostic.Warn) };
                compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(specificDiagnosticOptions);
                var updatedSolution = solution.WithProjectCompilationOptions(solution.ProjectIds.Single(), compilationOptions);
                await workspace.ChangeSolutionAsync(updatedSolution);
 
                return await base.GetCodeActionsAsync(workspace, parameters);
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            [WorkItem("https://github.com/dotnet/roslyn/issues/38587")]
            public async Task TestFormattingDiagnosticSuppressed()
            {
                await TestAsync(
        @"
using System;
 
class Class
{
    int Method()
    {
        [|int x = 0 ;|]
    }
}",
        @"
using System;
 
class Class
{
    int Method()
    {
#pragma warning disable format
        int x = 0 ;
#pragma warning restore format
    }
}");
            }
        }
 
        public class UserErrorDiagnosticSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
        {
            private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
            {
                private readonly DiagnosticDescriptor _descriptor =
                    new DiagnosticDescriptor("ErrorDiagnostic", "ErrorDiagnostic", "ErrorDiagnostic", "ErrorDiagnostic", DiagnosticSeverity.Error, isEnabledByDefault: true);
 
                public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
                {
                    get
                    {
                        return ImmutableArray.Create(_descriptor);
                    }
                }
 
                public override void Initialize(AnalysisContext context)
                    => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
 
                public void AnalyzeNode(SyntaxNodeAnalysisContext context)
                {
                    var classDecl = (ClassDeclarationSyntax)context.Node;
                    context.ReportDiagnostic(Diagnostic.Create(_descriptor, classDecl.Identifier.GetLocation()));
                }
            }
 
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            public async Task TestErrorDiagnosticCanBeSuppressed()
            {
                await TestAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}",
        @"
using System;
 
#pragma warning disable ErrorDiagnostic // ErrorDiagnostic
class Class
#pragma warning restore ErrorDiagnostic // ErrorDiagnostic
{
    int Method()
    {
        int x = 0;
    }
}");
            }
        }
 
        public class DiagnosticWithBadIdSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
        {
            // Analyzer driver generates a no-location analyzer exception diagnostic, which we don't intend to test here.
            protected override bool IncludeNoLocationDiagnostics => false;
 
            private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
            {
                private readonly DiagnosticDescriptor _descriptor =
                    new DiagnosticDescriptor("@~DiagnosticWithBadId", "DiagnosticWithBadId", "DiagnosticWithBadId", "DiagnosticWithBadId", DiagnosticSeverity.Info, isEnabledByDefault: true);
 
                public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
                {
                    get
                    {
                        return ImmutableArray.Create(_descriptor);
                    }
                }
 
                public override void Initialize(AnalysisContext context)
                    => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
 
                public void AnalyzeNode(SyntaxNodeAnalysisContext context)
                {
                    var classDecl = (ClassDeclarationSyntax)context.Node;
                    context.ReportDiagnostic(Diagnostic.Create(_descriptor, classDecl.Identifier.GetLocation()));
                }
            }
 
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            public async Task TestDiagnosticWithBadIdSuppressed()
            {
                // Diagnostics with bad/invalid ID are not reported.
                await TestMissingAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}");
            }
        }
    }
 
    public partial class MultilineDiagnosticSuppressionTests : CSharpPragmaWarningDisableSuppressionTests
    {
        private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
        {
            public static readonly DiagnosticDescriptor Decsciptor =
                new DiagnosticDescriptor("InfoDiagnostic", "InfoDiagnostic Title", "InfoDiagnostic", "InfoDiagnostic", DiagnosticSeverity.Info, isEnabledByDefault: true);
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
            {
                get
                {
                    return ImmutableArray.Create(Decsciptor);
                }
            }
 
            public override void Initialize(AnalysisContext context)
                => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
 
            public void AnalyzeNode(SyntaxNodeAnalysisContext context)
            {
                var classDecl = (ClassDeclarationSyntax)context.Node;
                context.ReportDiagnostic(Diagnostic.Create(Decsciptor, classDecl.GetLocation()));
            }
        }
 
        internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
        {
            return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
        }
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
        [WorkItem("https://github.com/dotnet/roslyn/issues/2764")]
        public async Task TestPragmaWarningDirectiveAroundMultilineDiagnostic()
        {
            await TestAsync(
@"
[|class Class
{
}|]
",
$@"
#pragma warning disable {UserDiagnosticAnalyzer.Decsciptor.Id} // {UserDiagnosticAnalyzer.Decsciptor.Title}
class Class
{{
}}
#pragma warning restore {UserDiagnosticAnalyzer.Decsciptor.Id} // {UserDiagnosticAnalyzer.Decsciptor.Title}
");
        }
    }
    #endregion
 
    #region "SuppressMessageAttribute tests"
 
    public abstract partial class CSharpGlobalSuppressMessageSuppressionTests : CSharpSuppressionTests
    {
        protected sealed override int CodeActionIndex => 1;
 
        public class CompilerDiagnosticSuppressionTests : CSharpGlobalSuppressMessageSuppressionTests
        {
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
                => Tuple.Create<DiagnosticAnalyzer, IConfigurationFixProvider>(null, new CSharpSuppressionCodeFixProvider());
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            public async Task TestCompilerDiagnosticsCannotBeSuppressed()
            {
                // Another test verifies we have a pragma warning action for this source, this verifies there are no other suppression actions.
                await TestActionCountAsync(
    @"
class Class
{
    void Method()
    {
        [|int x = 0;|]
    }
}", 1);
            }
        }
 
        public class FormattingDiagnosticSuppressionTests : CSharpGlobalSuppressMessageSuppressionTests
        {
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return Tuple.Create<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new CSharpFormattingAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            protected override async Task<(ImmutableArray<CodeAction>, CodeAction actionToInvoke)> GetCodeActionsAsync(TestWorkspace workspace, TestParameters parameters)
            {
                var solution = workspace.CurrentSolution;
                var compilationOptions = solution.Projects.Single().CompilationOptions;
                var specificDiagnosticOptions = new[] { KeyValuePairUtil.Create(IDEDiagnosticIds.FormattingDiagnosticId, ReportDiagnostic.Warn) };
                compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(specificDiagnosticOptions);
                var updatedSolution = solution.WithProjectCompilationOptions(solution.ProjectIds.Single(), compilationOptions);
                await workspace.ChangeSolutionAsync(updatedSolution);
 
                return await base.GetCodeActionsAsync(workspace, parameters);
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            [WorkItem("https://github.com/dotnet/roslyn/issues/38587")]
            public async Task TestCompilerDiagnosticsCannotBeSuppressed()
            {
                // Another test verifies we have a pragma warning action for this source, this verifies there are no other suppression actions.
                await TestActionCountAsync(
    @"
class Class
{
    void Method()
    {
        [|int x = 0 ;|]
    }
}", 1);
            }
        }
 
        public class UserHiddenDiagnosticSuppressionTests : CSharpGlobalSuppressMessageSuppressionTests
        {
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new CSharpSimplifyTypeNamesDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
            public async Task TestHiddenDiagnosticsCannotBeSuppressed()
            {
                await TestMissingAsync(
    @"
using System;
class Class
{
    void Method()
    {
        [|System.Int32 x = 0;|]
    }
}");
            }
        }
 
        [Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
        public partial class UserInfoDiagnosticSuppressionTests : CSharpGlobalSuppressMessageSuppressionTests
        {
            private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
            {
                public static readonly DiagnosticDescriptor Descriptor =
                    new("InfoDiagnostic", "InfoDiagnostic", "InfoDiagnostic", "InfoDiagnostic", DiagnosticSeverity.Info, isEnabledByDefault: true);
 
                public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
                {
                    get
                    {
                        return ImmutableArray.Create(Descriptor);
                    }
                }
 
                public override void Initialize(AnalysisContext context)
                    => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration, SyntaxKind.EnumDeclaration, SyntaxKind.NamespaceDeclaration, SyntaxKind.MethodDeclaration, SyntaxKind.PropertyDeclaration, SyntaxKind.FieldDeclaration, SyntaxKind.EventDeclaration);
 
                public void AnalyzeNode(SyntaxNodeAnalysisContext context)
                {
                    switch (context.Node.Kind())
                    {
                        case SyntaxKind.ClassDeclaration:
                            var classDecl = (ClassDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, classDecl.Identifier.GetLocation()));
                            break;
 
                        case SyntaxKind.NamespaceDeclaration:
                            var ns = (NamespaceDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, ns.Name.GetLocation()));
                            break;
 
                        case SyntaxKind.MethodDeclaration:
                            var method = (MethodDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, method.Identifier.GetLocation()));
                            break;
 
                        case SyntaxKind.PropertyDeclaration:
                            var property = (PropertyDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, property.Identifier.GetLocation()));
                            break;
 
                        case SyntaxKind.FieldDeclaration:
                            var field = (FieldDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, field.Declaration.Variables.First().Identifier.GetLocation()));
                            break;
 
                        case SyntaxKind.EventDeclaration:
                            var e = (EventDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(Descriptor, e.Identifier.GetLocation()));
                            break;
 
                        case SyntaxKind.EnumDeclaration:
                            // Report diagnostic on each descendant comment trivia
                            foreach (var trivia in context.Node.DescendantTrivia().Where(t => t.Kind() is SyntaxKind.SingleLineCommentTrivia or SyntaxKind.MultiLineCommentTrivia))
                            {
                                context.ReportDiagnostic(Diagnostic.Create(Descriptor, trivia.GetLocation()));
                            }
 
                            break;
                    }
                }
            }
 
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37529")]
            public async Task GeneratedCodeShouldNotHaveTrailingWhitespace()
            {
                var expected =
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class"")]
";
 
                Assert.All(Regex.Split(expected, "\r?\n"), line => Assert.False(HasTrailingWhitespace(line)));
 
                await TestAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}", expected);
            }
 
            private static bool HasTrailingWhitespace(string line)
                => line.LastOrNull() is char last && char.IsWhiteSpace(last);
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37529")]
            public async Task GeneratedCodeShouldNotHaveLeadingBlankLines()
            {
                var expected =
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class"")]
";
 
                var lines = Regex.Split(expected, "\r?\n");
                Assert.False(string.IsNullOrWhiteSpace(lines.First()));
 
                await TestAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}", expected);
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/37529")]
            public async Task GeneratedCodeShouldNotHaveMoreThanOneTrailingBlankLine()
            {
                var expected =
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class"")]
";
 
                var lines = Regex.Split(expected, "\r?\n");
                Assert.False(string.IsNullOrWhiteSpace(lines[^2]));
 
                await TestAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}", expected);
            }
 
            [Fact]
            public async Task TestSuppressionOnSimpleType()
            {
                await TestAsync(
        @"
using System;
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""~T:Class"")]
 
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnNamespace()
            {
                await TestInRegularAndScriptAsync(
        @"
using System;
 
[|namespace N|]
{
    class Class
    {
        int Method()
        {
            int x = 0;
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""namespace"", Target = ""~N:N"")]
", index: 1);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""namespace"", Target = ""~N:N"")]
 
[|namespace N|]
{
    class Class
    {
        int Method()
        {
            int x = 0;
        }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnTypeInsideNamespace()
            {
                await TestAsync(
        @"
using System;
 
namespace N1
{
    namespace N2
    {
        [|class Class|]
        {
            int Method()
            {
                int x = 0;
            }
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:N1.N2.Class"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""~T:N1.N2.Class"")]
 
namespace N1
{
    namespace N2
    {
        [|class Class|]
        {
            int Method()
            {
                int x = 0;
            }
        }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnNestedType()
            {
                await TestAsync(
        @"
using System;
 
namespace N
{
    class Generic<T>
    {
        [|class Class|]
        {
            int Method()
            {
                int x = 0;
            }
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:N.Generic`1.Class"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""~T:N.Generic`1.Class"")]
 
namespace N
{
    class Generic<T>
    {
        [|class Class|]
        {
            int Method()
            {
                int x = 0;
            }
        }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnMethod()
            {
                await TestAsync(
        @"
using System;
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method()
            {
                int x = 0;
            }|]
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method~System.Int32"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method~System.Int32"")]
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method()|]
            {
                int x = 0;
            }
        }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnOverloadedMethod()
            {
                await TestAsync(
        @"
using System;
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method(int y, ref char z)
            {
                int x = 0;
            }|]
 
            int Method()
            {
                int x = 0;
            }
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method(System.Int32,System.Char@)~System.Int32"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method(System.Int32,System.Char@)~System.Int32"")]
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method(int y, ref char z)|]
            {
                int x = 0;
            }
 
            int Method()
            {
                int x = 0;
            }
        }
    }
}");
 
                await TestAsync(
    @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method(System.Int32,System.Char@)~System.Int32"")]
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method(int y, ref char z)
            {
                int x = 0;
            }
 
            int Method()
            {
                int x = 0;
            }|]
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method~System.Int32"")]
");
            }
 
            [Fact]
            public async Task TestSuppressionOnGenericMethod()
            {
                await TestAsync(
        @"
using System;
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method<U>(U u)
            {
                int x = 0;
            }|]
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method``1(``0)~System.Int32"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~M:N.Generic`1.Class.Method``1(``0)~System.Int32"")]
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method<U>(U u)|]
            {
                int x = 0;
            }
        }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnProperty()
            {
                await TestAsync(
        @"
using System;
 
namespace N
{
    class Generic
    {
        class Class
        {
            [|int Property|]
            {
                get { int x = 0; }
            }
        }
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~P:N.Generic.Class.Property"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~P:N.Generic.Class.Property"")]
 
namespace N
{
    class Generic
    {
        class Class
        {
            [|int Property|]
            {
                get { int x = 0; }
            }
        }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnField()
            {
                await TestAsync(
        @"
using System;
 
class Class
{
    [|int field = 0;|]
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~F:Class.field"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~F:Class.field"")]
 
class Class
{
    [|int field = 0;|]
}");
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/6379")]
            public async Task TestSuppressionOnTriviaBetweenFields()
            {
                await TestAsync(
        @"
using System;
 
// suppressions on field are not relevant.
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~F:E.Field1"")]
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~F:E.Field2"")]
 
enum E
{
    [|
    Field1, // trailing trivia for comma token which doesn't belong to span of any of the fields
    Field2
    |]
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:E"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:E"")]
 
enum E
{
    [|
    Field1, // trailing trivia for comma token which doesn't belong to span of any of the fields
    Field2
    |]
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnField2()
            {
                await TestAsync(
        @"
using System;
 
class Class
{
    int [|field = 0|], field2 = 1;
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~F:Class.field"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~F:Class.field"")]
 
class Class
{
    int [|field|] = 0, field2 = 1;
}");
            }
 
            [Fact]
            public async Task TestSuppressionOnEvent()
            {
                await TestAsync(
        @"
using System;
 
public class SampleEventArgs
{
    public SampleEventArgs(string s) { Text = s; }
    public String Text {get; private set;} // readonly
        }
 
class Class
{
    // Declare the delegate (if using non-generic pattern). 
    public delegate void SampleEventHandler(object sender, SampleEventArgs e);
 
    // Declare the event. 
    [|public event SampleEventHandler SampleEvent
    {
        add { }
        remove { }
    }|]
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""member"", Target = ""~E:Class.SampleEvent"")]
");
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                await TestMissingAsync(
        @"
using System;
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""member"", Target = ""~E:Class.SampleEvent"")]
 
public class SampleEventArgs
{
    public SampleEventArgs(string s) { Text = s; }
    public String Text {get; private set;} // readonly
}
 
class Class
{
    // Declare the delegate (if using non-generic pattern).
    public delegate void SampleEventHandler(object sender, SampleEventArgs e);
 
    // Declare the event.
    [|public event SampleEventHandler SampleEvent|]
    {
        add { }
        remove { }
    }
}");
            }
 
            [Fact]
            public async Task TestSuppressionWithExistingGlobalSuppressionsDocument()
            {
                var initialMarkup = @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"" AssemblyName=""Proj1"">
        <Document FilePath=""CurrentDocument.cs""><![CDATA[
using System;
 
class Class { }
 
[|class Class2|] { }
]]>
        </Document>
        <Document FilePath=""GlobalSuppressions.cs""><![CDATA[// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
]]>
        </Document>
    </Project>
</Workspace>";
                var expectedText =
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class2"")]
";
 
                await TestAsync(initialMarkup, expectedText);
            }
 
            [Fact]
            public async Task TestSuppressionWithExistingGlobalSuppressionsDocument2()
            {
                // Own custom file named GlobalSuppressions.cs
                var initialMarkup = @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"" AssemblyName=""Proj1"">
        <Document FilePath=""CurrentDocument.cs""><![CDATA[
using System;
 
class Class { }
 
[|class Class2|] { }
]]>
        </Document>
        <Document FilePath=""GlobalSuppressions.cs""><![CDATA[
// My own file named GlobalSuppressions.cs.
using System;
class Class { }
]]>
        </Document>
    </Project>
</Workspace>";
                var expectedText =
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class2"")]
";
 
                await TestAsync(initialMarkup, expectedText);
            }
 
            [Fact]
            public async Task TestSuppressionWithExistingGlobalSuppressionsDocument3()
            {
                // Own custom file named GlobalSuppressions.cs + existing GlobalSuppressions2.cs with global suppressions
                var initialMarkup = @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"" AssemblyName=""Proj1"">
        <Document FilePath=""CurrentDocument.cs""><![CDATA[
using System;
 
class Class { }
 
[|class Class2|] { }
]]>
        </Document>
        <Document FilePath=""GlobalSuppressions.cs""><![CDATA[
// My own file named GlobalSuppressions.cs.
using System;
class Class { }
]]>
        </Document>
         <Document FilePath=""GlobalSuppressions2.cs""><![CDATA[// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
]]>
        </Document>
    </Project>
</Workspace>";
                var expectedText =
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class2"")]
";
 
                await TestAsync(initialMarkup, expectedText);
            }
 
            [Fact]
            public async Task TestSuppressionWithUsingDirectiveInExistingGlobalSuppressionsDocument()
            {
                var initialMarkup = @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"" AssemblyName=""Proj1"">
        <Document FilePath=""CurrentDocument.cs""><![CDATA[
using System;
 
class Class { }
 
[|class Class2|] { }
]]>
        </Document>
        <Document FilePath=""GlobalSuppressions.cs""><![CDATA[
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
]]>
        </Document>
    </Project>
</Workspace>";
                var expectedText =
                    $@"
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class2"")]
";
 
                await TestAsync(initialMarkup, expectedText);
            }
 
            [Fact]
            public async Task TestSuppressionWithoutUsingDirectiveInExistingGlobalSuppressionsDocument()
            {
                var initialMarkup = @"<Workspace>
    <Project Language=""C#"" CommonReferences=""true"" AssemblyName=""Proj1"">
        <Document FilePath=""CurrentDocument.cs""><![CDATA[
using System;
 
class Class { }
 
[|class Class2|] { }
]]>
        </Document>
        <Document FilePath=""GlobalSuppressions.cs""><![CDATA[
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
]]>
        </Document>
    </Project>
</Workspace>";
                var expectedText =
$@"
using System.Diagnostics.CodeAnalysis;
 
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""<Pending>"", Scope = ""type"", Target = ""Class"")]
[assembly: SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"", Scope = ""type"", Target = ""~T:Class2"")]
";
 
                await TestAsync(initialMarkup, expectedText);
            }
        }
    }
 
    public abstract class CSharpLocalSuppressMessageSuppressionTests : CSharpSuppressionTests
    {
        protected sealed override int CodeActionIndex => 2;
 
        [Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
        public class UserInfoDiagnosticSuppressionTests : CSharpLocalSuppressMessageSuppressionTests
        {
            private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
            {
                private readonly DiagnosticDescriptor _descriptor =
                    new("InfoDiagnostic", "InfoDiagnostic", "InfoDiagnostic", "InfoDiagnostic", DiagnosticSeverity.Info, isEnabledByDefault: true);
 
                public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(_descriptor);
 
                public override void Initialize(AnalysisContext context)
                    => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration, SyntaxKind.NamespaceDeclaration, SyntaxKind.MethodDeclaration);
 
                public void AnalyzeNode(SyntaxNodeAnalysisContext context)
                {
                    switch (context.Node.Kind())
                    {
                        case SyntaxKind.ClassDeclaration:
                            var classDecl = (ClassDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(_descriptor, classDecl.Identifier.GetLocation()));
                            break;
 
                        case SyntaxKind.NamespaceDeclaration:
                            var ns = (NamespaceDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(_descriptor, ns.Name.GetLocation()));
                            break;
 
                        case SyntaxKind.MethodDeclaration:
                            var method = (MethodDeclarationSyntax)context.Node;
                            context.ReportDiagnostic(Diagnostic.Create(_descriptor, method.Identifier.GetLocation()));
                            break;
                    }
                }
            }
 
            internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
            {
                return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                    new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
            }
 
            [Fact]
            public async Task TestSuppressionOnSimpleType()
            {
                var initial = @"
using System;
 
// Some trivia
/* More Trivia */ [|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}";
                var expected = $@"
using System;
 
// Some trivia
/* More Trivia */
[System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
class Class
{{
    int Method()
    {{
        int x = 0;
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("class Class", "[|class Class|]");
                await TestMissingAsync(expected);
            }
 
            [Fact]
            public async Task TestSuppressionOnSimpleType2()
            {
                // Type already has attributes.
                var initial = @"
using System;
 
// Some trivia
/* More Trivia */
[System.Diagnostics.CodeAnalysis.SuppressMessage(""SomeOtherDiagnostic"", ""SomeOtherDiagnostic:Title"", Justification = ""<Pending>"")]
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}";
                var expected = $@"
using System;
 
// Some trivia
/* More Trivia */
[System.Diagnostics.CodeAnalysis.SuppressMessage(""SomeOtherDiagnostic"", ""SomeOtherDiagnostic:Title"", Justification = ""<Pending>"")]
[System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
class Class
{{
    int Method()
    {{
        int x = 0;
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("class Class", "[|class Class|]");
                await TestMissingAsync(expected);
            }
 
            [Fact]
            public async Task TestSuppressionOnSimpleType3()
            {
                // Type already has attributes with trailing trivia.
                var initial = @"
using System;
 
// Some trivia
/* More Trivia */
[System.Diagnostics.CodeAnalysis.SuppressMessage(""SomeOtherDiagnostic"", ""SomeOtherDiagnostic:Title"", Justification = ""<Pending>"")]
/* Some More Trivia */
[|class Class|]
{
    int Method()
    {
        int x = 0;
    }
}";
                var expected = $@"
using System;
 
// Some trivia
/* More Trivia */
[System.Diagnostics.CodeAnalysis.SuppressMessage(""SomeOtherDiagnostic"", ""SomeOtherDiagnostic:Title"", Justification = ""<Pending>"")]
[System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
/* Some More Trivia */
class Class
{{
    int Method()
    {{
        int x = 0;
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("class Class", "[|class Class|]");
                await TestMissingAsync(expected);
            }
 
            [Fact]
            public async Task TestSuppressionOnTypeInsideNamespace()
            {
                var initial = @"
using System;
 
namespace N1
{
    namespace N2
    {
        [|class Class|]
        {
            int Method()
            {
                int x = 0;
            }
        }
    }
}";
                var expected = $@"
using System;
 
namespace N1
{{
    namespace N2
    {{
        [System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
        class Class
        {{
            int Method()
            {{
                int x = 0;
            }}
        }}
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("class Class", "[|class Class|]");
                await TestMissingAsync(expected);
            }
 
            [Fact]
            public async Task TestSuppressionOnNestedType()
            {
                var initial = @"
using System;
 
namespace N
{
    class Generic<T>
    {
        [|class Class|]
        {
            int Method()
            {
                int x = 0;
            }
        }
    }
}";
                var expected = $@"
using System;
 
namespace N
{{
    class Generic<T>
    {{
        [System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
        class Class
        {{
            int Method()
            {{
                int x = 0;
            }}
        }}
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("class Class", "[|class Class|]");
                await TestMissingAsync(expected);
            }
 
            [Fact]
            public async Task TestSuppressionOnMethod()
            {
                var initial = @"
using System;
 
namespace N
{
    class Generic<T>
    {
        class Class
        {
            [|int Method()|]
            {
                int x = 0;
            }
        }
    }
}";
                var expected = $@"
using System;
 
namespace N
{{
    class Generic<T>
    {{
        class Class
        {{
            [System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
            int Method()
            {{
                int x = 0;
            }}
        }}
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("int Method()", "[|int Method()|]");
                await TestMissingAsync(expected);
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47427")]
            public async Task TestSuppressionOnMethodWithXmlDoc()
            {
                var initial = @"
using System;
 
namespace ClassLibrary10
{
    public class Class1
    {
        int x;
 
        /// <summary>
        /// This is a description
        /// </summary>
        [|public void Method(int unused)|] { }
    }
}";
                var expected = $@"
using System;
 
namespace ClassLibrary10
{{
    public class Class1
    {{
        int x;
 
        /// <summary>
        /// This is a description
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
        public void Method(int unused) {{ }}
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("public void Method(int unused)", "[|public void Method(int unused)|]");
                await TestMissingAsync(expected);
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47427")]
            public async Task TestSuppressionOnMethodWithNoTrivia()
            {
                var initial = @"
using System;
 
namespace ClassLibrary10
{
    public class Class1
    {
        int x;
[|public void Method(int unused)|] { }
    }
}";
                var expected = $@"
using System;
 
namespace ClassLibrary10
{{
    public class Class1
    {{
        int x;
        [System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
        public void Method(int unused) {{ }}
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("public void Method(int unused)", "[|public void Method(int unused)|]");
                await TestMissingAsync(expected);
            }
 
            [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/47427")]
            public async Task TestSuppressionOnMethodWithTriviaStartsOnTheSameLine()
            {
                var initial = @"
using System;
 
namespace ClassLibrary10
{
    public class Class1
    {
        int x;
        /*test*/[|public void Method(int unused)|] { }
    }
}";
                var expected = $@"
using System;
 
namespace ClassLibrary10
{{
    public class Class1
    {{
        int x;
        /*test*/
        [System.Diagnostics.CodeAnalysis.SuppressMessage(""InfoDiagnostic"", ""InfoDiagnostic:InfoDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
        public void Method(int unused) {{ }}
    }}
}}";
                await TestAsync(initial, expected);
 
                // Also verify that the added attribute does indeed suppress the diagnostic.
                expected = expected.Replace("public void Method(int unused)", "[|public void Method(int unused)|]");
                await TestMissingAsync(expected);
            }
        }
    }
 
    #endregion
 
    #region NoLocation Diagnostics tests
 
    public partial class CSharpDiagnosticWithoutLocationSuppressionTests : CSharpSuppressionTests
    {
        private class UserDiagnosticAnalyzer : DiagnosticAnalyzer
        {
            public static readonly DiagnosticDescriptor Descriptor =
                new("NoLocationDiagnostic", "NoLocationDiagnostic", "NoLocationDiagnostic", "NoLocationDiagnostic", DiagnosticSeverity.Info, isEnabledByDefault: true);
 
            public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
                => ImmutableArray.Create(Descriptor);
 
            public override void Initialize(AnalysisContext context)
                => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
 
            public void AnalyzeNode(SyntaxNodeAnalysisContext context)
                => context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.None));
        }
 
        internal override Tuple<DiagnosticAnalyzer, IConfigurationFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
        {
            return new Tuple<DiagnosticAnalyzer, IConfigurationFixProvider>(
                new UserDiagnosticAnalyzer(), new CSharpSuppressionCodeFixProvider());
        }
 
        protected override int CodeActionIndex => 0;
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSuppression)]
        [WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1073825")]
        public async Task TestDiagnosticWithoutLocationCanBeSuppressed()
        {
            await TestAsync(
    @"[||]
using System;
 
class Class
{
    int Method()
    {
        int x = 0;
    }
}",
$@"// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
 
using System.Diagnostics.CodeAnalysis;
 
[assembly: SuppressMessage(""NoLocationDiagnostic"", ""NoLocationDiagnostic:NoLocationDiagnostic"", Justification = ""{FeaturesResources.Pending}"")]
");
        }
    }
 
    #endregion
}