public async Task <ImmutableArray <CodeFix> > GetFixesAsync(
            Project project,
            IEnumerable <Diagnostic> diagnostics,
            CancellationToken cancellationToken
            )
        {
            if (!project.SupportsCompilation)
            {
                return(ImmutableArray <CodeFix> .Empty);
            }

            var compilation = await project
                              .GetCompilationAsync(cancellationToken)
                              .ConfigureAwait(false);

            var suppressionTargetInfo = new SuppressionTargetInfo()
            {
                TargetSymbol = compilation.Assembly
            };

            return(await GetSuppressionsAsync(
                       documentOpt : null,
                       project : project,
                       diagnostics : diagnostics,
                       suppressionTargetInfo : suppressionTargetInfo,
                       skipSuppressMessage : false,
                       skipUnsuppress : false,
                       cancellationToken : cancellationToken
                       )
                   .ConfigureAwait(false));
        }
Exemple #2
0
            public static async Task <RemoveSuppressionCodeAction> CreateAsync(
                SuppressionTargetInfo suppressionTargetInfo,
                Document documentOpt,
                Project project,
                Diagnostic diagnostic,
                AbstractSuppressionCodeFixProvider fixer,
                CancellationToken cancellationToken)
            {
                var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var attribute = diagnostic.GetSuppressionInfo(compilation).Attribute;

                if (attribute != null)
                {
                    return(AttributeRemoveAction.Create(attribute, project, diagnostic, fixer));
                }
                else if (documentOpt != null && !SuppressionHelpers.IsSynthesizedExternalSourceDiagnostic(diagnostic))
                {
                    return(PragmaRemoveAction.Create(suppressionTargetInfo, documentOpt, diagnostic, fixer));
                }
                else
                {
                    return(null);
                }
            }
            internal static async Task <Document> GetChangeDocumentWithPragmaAdjustedAsync(
                Document document,
                TextSpan diagnosticSpan,
                SuppressionTargetInfo suppressionTargetInfo,
                Func <SyntaxToken, TextSpan, SyntaxToken> getNewStartToken,
                Func <SyntaxToken, TextSpan, SyntaxToken> getNewEndToken,
                CancellationToken cancellationToken
                )
            {
                var startToken     = suppressionTargetInfo.StartToken;
                var endToken       = suppressionTargetInfo.EndToken;
                var nodeWithTokens = suppressionTargetInfo.NodeWithTokens;
                var root           = await nodeWithTokens.SyntaxTree
                                     .GetRootAsync(cancellationToken)
                                     .ConfigureAwait(false);

                var startAndEndTokenAreTheSame = startToken == endToken;
                var newStartToken = getNewStartToken(startToken, diagnosticSpan);

                var newEndToken = endToken;

                if (startAndEndTokenAreTheSame)
                {
                    var annotation = new SyntaxAnnotation();
                    newEndToken = root.ReplaceToken(
                        startToken,
                        newStartToken.WithAdditionalAnnotations(annotation)
                        )
                                  .GetAnnotatedTokens(annotation)
                                  .Single();
                    var spanChange =
                        newStartToken.LeadingTrivia.FullSpan.Length
                        - startToken.LeadingTrivia.FullSpan.Length;
                    diagnosticSpan = new TextSpan(
                        diagnosticSpan.Start + spanChange,
                        diagnosticSpan.Length
                        );
                }

                newEndToken = getNewEndToken(newEndToken, diagnosticSpan);

                SyntaxNode newNode;

                if (startAndEndTokenAreTheSame)
                {
                    newNode = nodeWithTokens.ReplaceToken(startToken, newEndToken);
                }
                else
                {
                    newNode = nodeWithTokens.ReplaceTokens(
                        new[] { startToken, endToken },
                        (o, n) => o == startToken ? newStartToken : newEndToken
                        );
                }

                var newRoot = root.ReplaceNode(nodeWithTokens, newNode);

                return(document.WithSyntaxRoot(newRoot));
            }
 private PragmaRemoveAction(
     SuppressionTargetInfo suppressionTargetInfo,
     Document document,
     Diagnostic diagnostic,
     AbstractSuppressionCodeFixProvider fixer,
     bool forFixMultipleContext = false)
     : base(document, diagnostic, fixer, forFixMultipleContext)
 {
     _suppressionTargetInfo = suppressionTargetInfo;
 }
Exemple #5
0
 private PragmaRemoveAction(
     SuppressionTargetInfo suppressionTargetInfo,
     Document document,
     Diagnostic diagnostic,
     AbstractSuppressionCodeFixProvider fixer,
     bool forFixMultipleContext = false)
     : base(diagnostic, fixer, forFixMultipleContext)
 {
     _document = document;
     _suppressionTargetInfo = suppressionTargetInfo;
 }
            public static PragmaWarningCodeAction Create(
                SuppressionTargetInfo suppressionTargetInfo,
                Document document,
                Diagnostic diagnostic,
                AbstractSuppressionCodeFixProvider fixer)
            {
                // We need to normalize the leading trivia on start token to account for
                // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token).
                PragmaHelpers.NormalizeTriviaOnTokens(fixer, ref document, ref suppressionTargetInfo);

                return(new PragmaWarningCodeAction(suppressionTargetInfo, document, diagnostic, fixer));
            }
            public static PragmaWarningCodeAction Create(
                    SuppressionTargetInfo suppressionTargetInfo,
                    Document document,
                    Diagnostic diagnostic,
                    AbstractSuppressionCodeFixProvider fixer)
            {
                // We need to normalize the leading trivia on start token to account for
                // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token).
                PragmaHelpers.NormalizeTriviaOnTokens(fixer, ref document, ref suppressionTargetInfo);

                return new PragmaWarningCodeAction(suppressionTargetInfo, document, diagnostic, fixer);
            }
 private PragmaWarningCodeAction(
     SuppressionTargetInfo suppressionTargetInfo,
     Document document,
     Diagnostic diagnostic,
     AbstractSuppressionCodeFixProvider fixer,
     bool forFixMultipleContext = false)
     : base(fixer, title: FeaturesResources.in_Source)
 {
     _suppressionTargetInfo = suppressionTargetInfo;
     _document              = document;
     _diagnostic            = diagnostic;
     _forFixMultipleContext = forFixMultipleContext;
 }
 private PragmaWarningCodeAction(
     SuppressionTargetInfo suppressionTargetInfo,
     Document document,
     Diagnostic diagnostic,
     AbstractSuppressionCodeFixProvider fixer,
     bool forFixMultipleContext = false)
     : base(fixer, title: FeaturesResources.SuppressWithPragma)
 {
     _suppressionTargetInfo = suppressionTargetInfo;
     _document = document;
     _diagnostic = diagnostic;
     _forFixMultipleContext = forFixMultipleContext;
 }
 public static async Task<RemoveSuppressionCodeAction> CreateAsync(                
     SuppressionTargetInfo suppressionTargetInfo,
     Document document,
     Diagnostic diagnostic,
     AbstractSuppressionCodeFixProvider fixer,
     CancellationToken cancellationToken)
 {
     var compilation = await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
     var attribute = diagnostic.GetSuppressionInfo(compilation).Attribute;
     if (attribute != null)
     {
         return AttributeRemoveAction.Create(attribute, document, diagnostic, fixer);
     }
     else
     {
         return PragmaRemoveAction.Create(suppressionTargetInfo, document, diagnostic, fixer);
     }
 }
            internal async static Task<Document> GetChangeDocumentWithPragmaAdjustedAsync(
                Document document,
                TextSpan diagnosticSpan,
                SuppressionTargetInfo suppressionTargetInfo,
                Func<SyntaxToken, TextSpan, Task<SyntaxToken>> getNewStartToken,
                Func<SyntaxToken, TextSpan, Task<SyntaxToken>> getNewEndToken,
                CancellationToken cancellationToken)
            {
                var startToken = suppressionTargetInfo.StartToken;
                var endToken = suppressionTargetInfo.EndToken;
                var nodeWithTokens = suppressionTargetInfo.NodeWithTokens;
                var root = await nodeWithTokens.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

                var startAndEndTokenAreTheSame = startToken == endToken;
                SyntaxToken newStartToken = await getNewStartToken(startToken, diagnosticSpan).ConfigureAwait(false);

                SyntaxToken newEndToken = endToken;
                if (startAndEndTokenAreTheSame)
                {
                    var annotation = new SyntaxAnnotation();
                    newEndToken = root.ReplaceToken(startToken, newStartToken.WithAdditionalAnnotations(annotation)).GetAnnotatedTokens(annotation).Single();
                    var spanChange = newStartToken.LeadingTrivia.FullSpan.Length - startToken.LeadingTrivia.FullSpan.Length;
                    diagnosticSpan = new TextSpan(diagnosticSpan.Start + spanChange, diagnosticSpan.Length);
                }

                newEndToken = await getNewEndToken(newEndToken, diagnosticSpan).ConfigureAwait(false);

                SyntaxNode newNode;
                if (startAndEndTokenAreTheSame)
                {
                    newNode = nodeWithTokens.ReplaceToken(startToken, newEndToken);
                }
                else
                {
                    newNode = nodeWithTokens.ReplaceTokens(new[] { startToken, endToken }, (o, n) => o == startToken ? newStartToken : newEndToken);
                }

                var newRoot = root.ReplaceNode(nodeWithTokens, newNode);
                return document.WithSyntaxRoot(newRoot);
            }
 public static async Task<RemoveSuppressionCodeAction> CreateAsync(
     SuppressionTargetInfo suppressionTargetInfo,
     Document documentOpt,
     Project project,
     Diagnostic diagnostic,
     AbstractSuppressionCodeFixProvider fixer,
     CancellationToken cancellationToken)
 {
     var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
     var attribute = diagnostic.GetSuppressionInfo(compilation).Attribute;
     if (attribute != null)
     {
         return AttributeRemoveAction.Create(attribute, project, diagnostic, fixer);
     }
     else if (documentOpt != null && !SuppressionHelpers.IsSynthesizedExternalSourceDiagnostic(diagnostic))
     {
         return PragmaRemoveAction.Create(suppressionTargetInfo, documentOpt, diagnostic, fixer);
     }
     else
     {
         return null;
     }
 }
        private async Task <IEnumerable <CodeFix> > GetSuppressionsAsync(Document documentOpt, Project project, IEnumerable <Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, bool skipSuppressMessage, bool skipUnsuppress, CancellationToken cancellationToken)
        {
            // We only care about diagnostics that can be suppressed/unsuppressed.
            diagnostics = diagnostics.Where(CanBeSuppressedOrUnsuppressed);
            if (diagnostics.IsEmpty())
            {
                return(SpecializedCollections.EmptyEnumerable <CodeFix>());
            }

            if (!skipSuppressMessage)
            {
                var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var suppressMessageAttribute = compilation.SuppressMessageAttributeType();
                skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute();
            }

            var result = new List <CodeFix>();

            foreach (var diagnostic in diagnostics)
            {
                if (!diagnostic.IsSuppressed)
                {
                    var nestedActions = new List <NestedSuppressionCodeAction>();

                    if (diagnostic.Location.IsInSource && documentOpt != null)
                    {
                        // pragma warning disable.
                        nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, diagnostic, this));
                    }

                    // SuppressMessageAttribute suppression is not supported for compiler diagnostics.
                    if (!skipSuppressMessage && !SuppressionHelpers.IsCompilerDiagnostic(diagnostic))
                    {
                        // global assembly-level suppress message attribute.
                        nestedActions.Add(new GlobalSuppressMessageCodeAction(suppressionTargetInfo.TargetSymbol, project, diagnostic, this));
                    }

                    result.Add(new CodeFix(new SuppressionCodeAction(diagnostic, nestedActions), diagnostic));
                }
                else if (!skipUnsuppress)
                {
                    var codeAction = await RemoveSuppressionCodeAction.CreateAsync(suppressionTargetInfo, documentOpt, project, diagnostic, this, cancellationToken).ConfigureAwait(false);

                    if (codeAction != null)
                    {
                        result.Add(new CodeFix(codeAction, diagnostic));
                    }
                }
            }

            return(result);
        }
                private static void NormalizeTriviaOnTokens(AbstractSuppressionCodeFixProvider fixer, ref Document document, ref SuppressionTargetInfo suppressionTargetInfo)
                {
                    var startToken = suppressionTargetInfo.StartToken;
                    var endToken = suppressionTargetInfo.EndToken;
                    var nodeWithTokens = suppressionTargetInfo.NodeWithTokens;
                    var startAndEndTokensAreSame = startToken == endToken;

                    var previousOfStart = startToken.GetPreviousToken();
                    var nextOfEnd = endToken.GetNextToken();
                    if (!previousOfStart.HasTrailingTrivia && !nextOfEnd.HasLeadingTrivia)
                    {
                        return;
                    }

                    var root = nodeWithTokens.SyntaxTree.GetRoot();
                    var subtreeRoot = root.FindNode(new TextSpan(previousOfStart.FullSpan.Start, nextOfEnd.FullSpan.End - previousOfStart.FullSpan.Start));

                    var currentStartToken = startToken;
                    var currentEndToken = endToken;
                    var newStartToken = startToken.WithLeadingTrivia(previousOfStart.TrailingTrivia.Concat(startToken.LeadingTrivia));

                    SyntaxToken newEndToken = currentEndToken;
                    if (startAndEndTokensAreSame)
                    {
                        newEndToken = newStartToken;
                    }

                    newEndToken = newEndToken.WithTrailingTrivia(endToken.TrailingTrivia.Concat(nextOfEnd.LeadingTrivia));

                    var newPreviousOfStart = previousOfStart.WithTrailingTrivia();
                    var newNextOfEnd = nextOfEnd.WithLeadingTrivia();

                    var newSubtreeRoot = subtreeRoot.ReplaceTokens(new[] { startToken, previousOfStart, endToken, nextOfEnd },
                        (o, n) =>
                        {
                            if (o == currentStartToken)
                            {
                                return newStartToken;
                            }
                            else if (o == previousOfStart)
                            {
                                return newPreviousOfStart;
                            }
                            else if (o == currentEndToken)
                            {
                                return newEndToken;
                            }
                            else if (o == nextOfEnd)
                            {
                                return newNextOfEnd;
                            }
                            else
                            {
                                return n;
                            }
                        });

                    root = root.ReplaceNode(subtreeRoot, newSubtreeRoot);
                    document = document.WithSyntaxRoot(root);
                    suppressionTargetInfo.StartToken = root.FindToken(startToken.SpanStart);
                    suppressionTargetInfo.EndToken = root.FindToken(endToken.SpanStart);
                    suppressionTargetInfo.NodeWithTokens = fixer.GetNodeWithTokens(suppressionTargetInfo.StartToken, suppressionTargetInfo.EndToken, root);
                }
            internal static void NormalizeTriviaOnTokens(AbstractSuppressionCodeFixProvider fixer, ref Document document, ref SuppressionTargetInfo suppressionTargetInfo)
            {
                // For pragma suppression fixes, we need to normalize the leading trivia on start token to account for
                // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token).

                var startToken = suppressionTargetInfo.StartToken;
                var endToken = suppressionTargetInfo.EndToken;
                var nodeWithTokens = suppressionTargetInfo.NodeWithTokens;
                var startAndEndTokensAreSame = startToken == endToken;
                var isEndTokenEOF = fixer.IsEndOfFileToken(endToken);

                var previousOfStart = startToken.GetPreviousToken(includeZeroWidth: true);
                var nextOfEnd = !isEndTokenEOF ? endToken.GetNextToken(includeZeroWidth: true) : default(SyntaxToken);
                if (!previousOfStart.HasTrailingTrivia && !nextOfEnd.HasLeadingTrivia)
                {
                    return;
                }

                var root = nodeWithTokens.SyntaxTree.GetRoot();
                var spanEnd = !isEndTokenEOF ? nextOfEnd.FullSpan.End : endToken.FullSpan.End;
                var subtreeRoot = root.FindNode(new TextSpan(previousOfStart.FullSpan.Start, spanEnd - previousOfStart.FullSpan.Start));

                var currentStartToken = startToken;
                var currentEndToken = endToken;
                var newStartToken = startToken.WithLeadingTrivia(previousOfStart.TrailingTrivia.Concat(startToken.LeadingTrivia));

                SyntaxToken newEndToken = currentEndToken;
                if (startAndEndTokensAreSame)
                {
                    newEndToken = newStartToken;
                }

                newEndToken = newEndToken.WithTrailingTrivia(endToken.TrailingTrivia.Concat(nextOfEnd.LeadingTrivia));

                var newPreviousOfStart = previousOfStart.WithTrailingTrivia();
                var newNextOfEnd = nextOfEnd.WithLeadingTrivia();

                var newSubtreeRoot = subtreeRoot.ReplaceTokens(new[] { startToken, previousOfStart, endToken, nextOfEnd },
                    (o, n) =>
                    {
                        if (o == currentStartToken)
                        {
                            return startAndEndTokensAreSame ? newEndToken : newStartToken;
                        }
                        else if (o == previousOfStart)
                        {
                            return newPreviousOfStart;
                        }
                        else if (o == currentEndToken)
                        {
                            return newEndToken;
                        }
                        else if (o == nextOfEnd)
                        {
                            return newNextOfEnd;
                        }
                        else
                        {
                            return n;
                        }
                    });

                root = root.ReplaceNode(subtreeRoot, newSubtreeRoot);
                document = document.WithSyntaxRoot(root);
                suppressionTargetInfo.StartToken = root.FindToken(startToken.SpanStart);
                suppressionTargetInfo.EndToken = root.FindToken(endToken.SpanStart);
                suppressionTargetInfo.NodeWithTokens = fixer.GetNodeWithTokens(suppressionTargetInfo.StartToken, suppressionTargetInfo.EndToken, root);
            }
Exemple #16
0
            internal static void NormalizeTriviaOnTokens(AbstractSuppressionCodeFixProvider fixer, ref Document document, ref SuppressionTargetInfo suppressionTargetInfo)
            {
                // For pragma suppression fixes, we need to normalize the leading trivia on start token to account for
                // the trailing trivia on its previous token (and similarly normalize trailing trivia for end token).

                var startToken               = suppressionTargetInfo.StartToken;
                var endToken                 = suppressionTargetInfo.EndToken;
                var nodeWithTokens           = suppressionTargetInfo.NodeWithTokens;
                var startAndEndTokensAreSame = startToken == endToken;
                var isEndTokenEOF            = fixer.IsEndOfFileToken(endToken);

                var previousOfStart = startToken.GetPreviousToken(includeZeroWidth: true);
                var nextOfEnd       = !isEndTokenEOF?endToken.GetNextToken(includeZeroWidth : true) : default(SyntaxToken);

                if (!previousOfStart.HasTrailingTrivia && !nextOfEnd.HasLeadingTrivia)
                {
                    return;
                }

                var root        = nodeWithTokens.SyntaxTree.GetRoot();
                var spanEnd     = !isEndTokenEOF ? nextOfEnd.FullSpan.End : endToken.FullSpan.End;
                var subtreeRoot = root.FindNode(new TextSpan(previousOfStart.FullSpan.Start, spanEnd - previousOfStart.FullSpan.Start));

                var currentStartToken = startToken;
                var currentEndToken   = endToken;
                var newStartToken     = startToken.WithLeadingTrivia(previousOfStart.TrailingTrivia.Concat(startToken.LeadingTrivia));

                SyntaxToken newEndToken = currentEndToken;

                if (startAndEndTokensAreSame)
                {
                    newEndToken = newStartToken;
                }

                newEndToken = newEndToken.WithTrailingTrivia(endToken.TrailingTrivia.Concat(nextOfEnd.LeadingTrivia));

                var newPreviousOfStart = previousOfStart.WithTrailingTrivia();
                var newNextOfEnd       = nextOfEnd.WithLeadingTrivia();

                var newSubtreeRoot = subtreeRoot.ReplaceTokens(new[] { startToken, previousOfStart, endToken, nextOfEnd },
                                                               (o, n) =>
                {
                    if (o == currentStartToken)
                    {
                        return(startAndEndTokensAreSame ? newEndToken : newStartToken);
                    }
                    else if (o == previousOfStart)
                    {
                        return(newPreviousOfStart);
                    }
                    else if (o == currentEndToken)
                    {
                        return(newEndToken);
                    }
                    else if (o == nextOfEnd)
                    {
                        return(newNextOfEnd);
                    }
                    else
                    {
                        return(n);
                    }
                });

                root     = root.ReplaceNode(subtreeRoot, newSubtreeRoot);
                document = document.WithSyntaxRoot(root);
                suppressionTargetInfo.StartToken     = root.FindToken(startToken.SpanStart);
                suppressionTargetInfo.EndToken       = root.FindToken(endToken.SpanStart);
                suppressionTargetInfo.NodeWithTokens = fixer.GetNodeWithTokens(suppressionTargetInfo.StartToken, suppressionTargetInfo.EndToken, root);
            }
        private async Task<IEnumerable<CodeFix>> GetSuppressionsAsync(Document documentOpt, Project project, IEnumerable<Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, bool skipSuppressMessage, bool skipUnsuppress, CancellationToken cancellationToken)
        {
            // We only care about diagnostics that can be suppressed/unsuppressed.
            diagnostics = diagnostics.Where(CanBeSuppressedOrUnsuppressed);
            if (diagnostics.IsEmpty())
            {
                return SpecializedCollections.EmptyEnumerable<CodeFix>();
            }

            if (!skipSuppressMessage)
            {
                var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
                var suppressMessageAttribute = compilation.SuppressMessageAttributeType();
                skipSuppressMessage = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute();
            }

            var result = new List<CodeFix>();
            foreach (var diagnostic in diagnostics)
            {
                if (!diagnostic.IsSuppressed)
                {
                    var nestedActions = new List<NestedSuppressionCodeAction>();

                    if (diagnostic.Location.IsInSource && documentOpt != null)
                    {
                        // pragma warning disable.
                        nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, diagnostic, this));
                    }

                    // SuppressMessageAttribute suppression is not supported for compiler diagnostics.
                    if (!skipSuppressMessage && !SuppressionHelpers.IsCompilerDiagnostic(diagnostic))
                    {
                        // global assembly-level suppress message attribute.
                        nestedActions.Add(new GlobalSuppressMessageCodeAction(suppressionTargetInfo.TargetSymbol, project, diagnostic, this));
                    }

                    result.Add(new CodeFix(new SuppressionCodeAction(diagnostic, nestedActions), diagnostic));
                }
                else if (!skipUnsuppress)
                {
                    var codeAction = await RemoveSuppressionCodeAction.CreateAsync(suppressionTargetInfo, documentOpt, project, diagnostic, this, cancellationToken).ConfigureAwait(false);
                    if (codeAction != null)
                    {
                        result.Add(new CodeFix(codeAction, diagnostic));
                    }
                }
            }

            return result;
        }
Exemple #18
0
        private async Task <ImmutableArray <CodeFix> > GetSuppressionsAsync(
            Document documentOpt, Project project, IEnumerable <Diagnostic> diagnostics, SuppressionTargetInfo suppressionTargetInfo, bool skipSuppressMessage, bool skipUnsuppress, CancellationToken cancellationToken)
        {
            // We only care about diagnostics that can be suppressed/unsuppressed.
            diagnostics = diagnostics.Where(IsFixableDiagnostic);
            if (diagnostics.IsEmpty())
            {
                return(ImmutableArray <CodeFix> .Empty);
            }

            INamedTypeSymbol suppressMessageAttribute = null;

            if (!skipSuppressMessage)
            {
                var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                suppressMessageAttribute = compilation.SuppressMessageAttributeType();
                skipSuppressMessage      = suppressMessageAttribute == null || !suppressMessageAttribute.IsAttribute();
            }

            var lazyFormattingOptions = (SyntaxFormattingOptions)null;
            var result = ArrayBuilder <CodeFix> .GetInstance();

            foreach (var diagnostic in diagnostics)
            {
                if (!diagnostic.IsSuppressed)
                {
                    var nestedActions = ArrayBuilder <NestedSuppressionCodeAction> .GetInstance();

                    if (diagnostic.Location.IsInSource && documentOpt != null)
                    {
                        // pragma warning disable.
                        lazyFormattingOptions ??= await SyntaxFormattingOptions.FromDocumentAsync(documentOpt, cancellationToken).ConfigureAwait(false);

                        nestedActions.Add(PragmaWarningCodeAction.Create(suppressionTargetInfo, documentOpt, lazyFormattingOptions, diagnostic, this));
                    }

                    // SuppressMessageAttribute suppression is not supported for compiler diagnostics.
                    if (!skipSuppressMessage && SuppressionHelpers.CanBeSuppressedWithAttribute(diagnostic))
                    {
                        // global assembly-level suppress message attribute.
                        nestedActions.Add(new GlobalSuppressMessageCodeAction(
                                              suppressionTargetInfo.TargetSymbol, suppressMessageAttribute, project, diagnostic, this));

                        // local suppress message attribute
                        // please note that in order to avoid issues with existing unit tests referencing the code fix
                        // by their index this needs to be the last added to nestedActions
                        if (suppressionTargetInfo.TargetMemberNode != null && suppressionTargetInfo.TargetSymbol.Kind != SymbolKind.Namespace)
                        {
                            nestedActions.Add(new LocalSuppressMessageCodeAction(
                                                  this, suppressionTargetInfo.TargetSymbol, suppressMessageAttribute, suppressionTargetInfo.TargetMemberNode, documentOpt, diagnostic));
                        }
                    }

                    if (nestedActions.Count > 0)
                    {
                        var codeAction = new TopLevelSuppressionCodeAction(
                            diagnostic, nestedActions.ToImmutableAndFree());
                        result.Add(new CodeFix(project, codeAction, diagnostic));
                    }
                }
                else if (!skipUnsuppress)
                {
                    var codeAction = await RemoveSuppressionCodeAction.CreateAsync(suppressionTargetInfo, documentOpt, project, diagnostic, this, cancellationToken).ConfigureAwait(false);

                    if (codeAction != null)
                    {
                        result.Add(new CodeFix(project, codeAction, diagnostic));
                    }
                }
            }

            return(result.ToImmutableAndFree());
        }
        public async Task<IEnumerable<CodeFix>> GetSuppressionsAsync(Project project, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken)
        {
            if (!project.SupportsCompilation)
            {
                return SpecializedCollections.EmptyEnumerable<CodeFix>();
            }

            var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
            var suppressionTargetInfo = new SuppressionTargetInfo() { TargetSymbol = compilation.Assembly };
            return await GetSuppressionsAsync(documentOpt: null, project: project, diagnostics: diagnostics,
                suppressionTargetInfo: suppressionTargetInfo, skipSuppressMessage: false, skipUnsuppress: false, cancellationToken: cancellationToken).ConfigureAwait(false);
        }