private static DiagnosticData CreateLiveDiagnostic(DiagnosticDescriptor descriptor, DiagnosticData diagnostic)
 {
     return new DiagnosticData(
         descriptor.Id,
         descriptor.Category,
         diagnostic.Message,
         descriptor.MessageFormat.ToString(DiagnosticData.USCultureInfo),
         diagnostic.Severity,
         descriptor.DefaultSeverity,
         descriptor.IsEnabledByDefault,
         diagnostic.WarningLevel,
         descriptor.CustomTags.ToImmutableArray(),
         diagnostic.Properties,
         diagnostic.Workspace,
         diagnostic.ProjectId,
         diagnostic.DocumentId,
         diagnostic.HasTextSpan ? diagnostic.TextSpan : (TextSpan?)null,
         diagnostic.MappedFilePath, diagnostic.MappedStartLine, diagnostic.MappedStartColumn, diagnostic.MappedEndLine, diagnostic.MappedEndColumn,
         diagnostic.OriginalFilePath, diagnostic.OriginalStartLine, diagnostic.OriginalStartColumn, diagnostic.OriginalEndLine, diagnostic.OriginalEndColumn,
         descriptor.Title.ToString(CultureInfo.CurrentUICulture),
         descriptor.Description.ToString(CultureInfo.CurrentUICulture),
         descriptor.HelpLinkUri);
 }
        private DiagnosticData UpdatePosition(DiagnosticData diagnostic, SyntaxTree tree, int delta)
        {
            Debug.Assert(diagnostic.AdditionalLocations == null || diagnostic.AdditionalLocations.Count == 0);
            var newDiagnosticLocation = UpdateDiagnosticLocation(diagnostic.DataLocation, tree, delta);

            return new DiagnosticData(
                diagnostic.Id,
                diagnostic.Category,
                diagnostic.Message,
                diagnostic.ENUMessageForBingSearch,
                diagnostic.Severity,
                diagnostic.DefaultSeverity,
                diagnostic.IsEnabledByDefault,
                diagnostic.WarningLevel,
                diagnostic.CustomTags,
                diagnostic.Properties,
                diagnostic.Workspace,
                diagnostic.ProjectId,
                newDiagnosticLocation,
                additionalLocations: diagnostic.AdditionalLocations,
                description: diagnostic.Description,
                helpLink: diagnostic.HelpLink,
                isSuppressed: diagnostic.IsSuppressed);
        }
Esempio n. 3
0
 private static IEnumerable <DiagnosticData> GetDiagnosticData(Document document, SyntaxTree tree, TextSpan?span, IEnumerable <Diagnostic> diagnostics)
 {
     return(diagnostics != null?diagnostics.Where(dx => ShouldIncludeDiagnostic(dx, tree, span)).Select(d => DiagnosticData.Create(document, d)) : null);
 }
Esempio n. 4
0
 public void AddError(ProjectId key, DiagnosticData diagnostic)
 {
     AddError(_projectMap, key, diagnostic);
 }
Esempio n. 5
0
 internal static DiagnosticTableItem Create(Workspace workspace, DiagnosticData data)
 {
     GetProjectNameAndGuid(workspace, data.ProjectId, out var projectName, out var projectGuid);
     return(new DiagnosticTableItem(workspace, data, projectName, projectGuid, projectNames: Array.Empty <string>(), projectGuids: Array.Empty <Guid>()));
 }
        public async ValueTask <ImmutableArray <Diagnostic> > GetDocumentDiagnosticsAsync(Document document, Document designTimeDocument, ActiveStatementSpanProvider activeStatementSpanProvider, CancellationToken cancellationToken)
        {
            var client = await RemoteHostClient.TryGetClientAsync(Workspace, cancellationToken).ConfigureAwait(false);

            if (client == null)
            {
                var diagnostics = await GetLocalService().GetDocumentDiagnosticsAsync(document, activeStatementSpanProvider, cancellationToken).ConfigureAwait(false);

                if (designTimeDocument != document)
                {
                    diagnostics = diagnostics.SelectAsArray(diagnostic => RemapLocation(designTimeDocument, DiagnosticData.Create(diagnostic, document.Project)));
                }

                return(diagnostics);
            }

            var diagnosticData = await client.TryInvokeAsync <IRemoteEditAndContinueService, ImmutableArray <DiagnosticData> >(
                document.Project.Solution,
                (service, solutionInfo, callbackId, cancellationToken) => service.GetDocumentDiagnosticsAsync(solutionInfo, callbackId, document.Id, cancellationToken),
                callbackTarget : new ActiveStatementSpanProviderCallback(activeStatementSpanProvider),
                cancellationToken).ConfigureAwait(false);

            if (!diagnosticData.HasValue)
            {
                return(ImmutableArray <Diagnostic> .Empty);
            }

            var project = document.Project;

            using var _ = ArrayBuilder <Diagnostic> .GetInstance(out var result);

            foreach (var data in diagnosticData.Value)
            {
                Debug.Assert(data.DataLocation != null);

                Diagnostic diagnostic;

                // Workaround for solution crawler not supporting mapped locations to make Razor work.
                // We pretend the diagnostic is in the original document, but use the mapped line span.
                // Razor will ignore the column (which will be off because #line directives can't currently map columns) and only use the line number.
                if (designTimeDocument != document && data.DataLocation.IsMapped)
                {
                    diagnostic = RemapLocation(designTimeDocument, data);
                }
                else
                {
                    diagnostic = await data.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false);
                }

                result.Add(diagnostic);
            }

            return(result.ToImmutable());
        }
Esempio n. 7
0
 public static bool IsNotConfigurableDiagnostic(DiagnosticData diagnostic)
 {
     return(HasCustomTag(diagnostic.CustomTags, WellKnownDiagnosticTags.NotConfigurable));
 }
Esempio n. 8
0
 static bool IsDocumentDiagnostic(DiagnosticData d) => d.DataLocation != null && d.HasTextSpan;
        public void ReportDiagnostics(Solution solution, ProjectId?projectId, IEnumerable <Diagnostic> diagnostics)
        {
            RoslynDebug.Assert(solution != null);

            var updateEvent = DiagnosticsUpdated;

            if (updateEvent == null)
            {
                return;
            }

            using var _1 = ArrayBuilder <DiagnosticData> .GetInstance(out var documentDiagnosticData);

            using var _2 = ArrayBuilder <DiagnosticData> .GetInstance(out var nonDocumentDiagnosticData);

            var workspace = solution.Workspace;
            var options   = solution.Options;
            var project   = (projectId != null) ? solution.GetProject(projectId) : null;

            foreach (var diagnostic in diagnostics)
            {
                var document = solution.GetDocument(diagnostic.Location.SourceTree);

                if (document != null)
                {
                    documentDiagnosticData.Add(DiagnosticData.Create(diagnostic, document));
                }
                else if (project != null)
                {
                    nonDocumentDiagnosticData.Add(DiagnosticData.Create(diagnostic, project));
                }
                else
                {
                    nonDocumentDiagnosticData.Add(DiagnosticData.Create(diagnostic, options));
                }
            }

            if (documentDiagnosticData.Count > 0)
            {
                foreach (var(documentId, diagnosticData) in documentDiagnosticData.ToDictionary(data => data.DocumentId))
                {
                    var diagnosticGroupId = (this, documentId, projectId);

                    updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                    diagnosticGroupId,
                                    workspace,
                                    solution,
                                    projectId,
                                    documentId: documentId,
                                    diagnostics: diagnosticData));
                }
            }

            if (nonDocumentDiagnosticData.Count > 0)
            {
                var diagnosticGroupId = (this, projectId);

                updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                diagnosticGroupId,
                                workspace,
                                solution,
                                projectId,
                                documentId: null,
                                diagnostics: nonDocumentDiagnosticData.ToImmutable()));
            }
        }
Esempio n. 10
0
            public async Task AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken)
            {
                // if closed file diagnostic is off and document is not opened, then don't do anything
                if (!CheckOptions(document))
                {
                    return;
                }

                var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                var diagnostics = tree.GetDiagnostics(cancellationToken);

                Contract.Requires(document.Project.Solution.Workspace == _workspace);

                var diagnosticData = diagnostics == null ? ImmutableArray <DiagnosticData> .Empty : diagnostics.Select(d => DiagnosticData.Create(document, d)).ToImmutableArrayOrEmpty();

                _service.RaiseDiagnosticsUpdated(
                    DiagnosticsUpdatedArgs.DiagnosticsCreated(new MiscUpdateArgsId(document.Id),
                                                              _workspace, document.Project.Solution, document.Project.Id, document.Id, diagnosticData));
            }
 protected override IErrorTag CreateTag(Workspace workspace, DiagnosticData diagnostic)
 => new ErrorTag(
     PredefinedErrorTypeNames.HintedSuggestion,
     CreateToolTipContent(workspace, diagnostic));
 protected internal override bool IncludeDiagnostic(DiagnosticData diagnostic)
 => diagnostic.Severity == DiagnosticSeverity.Info;
            private void AddError <T>(Dictionary <T, HashSet <DiagnosticData> > map, T key, DiagnosticData diagnostic)
            {
                var errors = GetErrorSet(map, key);

                errors.Add(diagnostic);
            }
 protected override bool ShouldIncludeDiagnostic(DiagnosticData diagnostic)
 {
     return _diagnosticIds == null || _diagnosticIds.Contains(diagnostic.Id);
 }
Esempio n. 15
0
 public static bool IsCompilerDiagnostic(DiagnosticData diagnostic)
 {
     return(HasCustomTag(diagnostic.CustomTags, WellKnownDiagnosticTags.Compiler));
 }
        private DiagnosticData UpdatePosition(DiagnosticData diagnostic, SyntaxTree tree, int delta)
        {
            var start = Math.Min(Math.Max(diagnostic.TextSpan.Start + delta, 0), tree.Length);
            var newSpan = new TextSpan(start, start >= tree.Length ? 0 : diagnostic.TextSpan.Length);

            var mappedLineInfo = tree.GetMappedLineSpan(newSpan);
            var originalLineInfo = tree.GetLineSpan(newSpan);

            return new DiagnosticData(
                diagnostic.Id,
                diagnostic.Category,
                diagnostic.Message,
                diagnostic.ENUMessageForBingSearch,
                diagnostic.Severity,
                diagnostic.DefaultSeverity,
                diagnostic.IsEnabledByDefault,
                diagnostic.WarningLevel,
                diagnostic.CustomTags,
                diagnostic.Properties,
                diagnostic.Workspace,
                diagnostic.ProjectId,
                diagnostic.DocumentId,
                newSpan,
                mappedFilePath: mappedLineInfo.GetMappedFilePathIfExist(),
                mappedStartLine: mappedLineInfo.StartLinePosition.Line,
                mappedStartColumn: mappedLineInfo.StartLinePosition.Character,
                mappedEndLine: mappedLineInfo.EndLinePosition.Line,
                mappedEndColumn: mappedLineInfo.EndLinePosition.Character,
                originalFilePath: originalLineInfo.Path,
                originalStartLine: originalLineInfo.StartLinePosition.Line,
                originalStartColumn: originalLineInfo.StartLinePosition.Character,
                originalEndLine: originalLineInfo.EndLinePosition.Line,
                originalEndColumn: originalLineInfo.EndLinePosition.Character,
                description: diagnostic.Description,
                helpLink: diagnostic.HelpLink);
        }
Esempio n. 17
0
 public static bool IsSynthesizedExternalSourceDiagnostic(DiagnosticData diagnostic)
 {
     return(HasCustomTag(diagnostic.CustomTags, SynthesizedExternalSourceDiagnosticTag));
 }
 protected virtual bool ShouldIncludeDiagnostic(DiagnosticData diagnostic) => true;
Esempio n. 19
0
 private bool ShouldInclude(DiagnosticData diagnostic)
 {
     return(diagnostic.DocumentId == _document.Id && _range.IntersectsWith(diagnostic.GetTextSpan()) &&
            (_includeSuppressedDiagnostics || !diagnostic.IsSuppressed) &&
            (_diagnosticId == null || _diagnosticId == diagnostic.Id));
 }
Esempio n. 20
0
 protected override DiagnosticTag[] ConvertTags(DiagnosticData diagnosticData)
 {
     // All workspace diagnostics are potential duplicates given that they can be overridden by the diagnostics
     // produced by document diagnostics.
     return(ConvertTags(diagnosticData, potentialDuplicate: true));
 }
        /// <summary>
        /// Reports diagnostics.
        /// </summary>
        /// <returns>Returns ids of documents that belong to <paramref name="projectId"/> and containing one or more diagnostics.</returns>
        public ImmutableArray <DocumentId> ReportDiagnostics(object errorId, Solution solution, ProjectId projectId, IEnumerable <Diagnostic> diagnostics)
        {
            Debug.Assert(errorId != null);
            Debug.Assert(solution != null);
            Debug.Assert(projectId != null);

            var updateEvent = DiagnosticsUpdated;
            var documentIds = PooledHashSet <DocumentId> .GetInstance();

            var documentDiagnosticData = ArrayBuilder <DiagnosticData> .GetInstance();

            var projectDiagnosticData = ArrayBuilder <DiagnosticData> .GetInstance();

            var project = solution.GetProject(projectId);

            foreach (var diagnostic in diagnostics)
            {
                var documentOpt = solution.GetDocument(diagnostic.Location.SourceTree);

                if (documentOpt != null)
                {
                    if (updateEvent != null)
                    {
                        documentDiagnosticData.Add(DiagnosticData.Create(documentOpt, diagnostic));
                    }

                    // only add documents from the current project:
                    if (documentOpt.Project.Id == projectId)
                    {
                        documentIds.Add(documentOpt.Id);
                    }
                }
                else if (updateEvent != null)
                {
                    projectDiagnosticData.Add(DiagnosticData.Create(project, diagnostic));
                }
            }

            foreach (var documentDiagnostics in documentDiagnosticData.ToDictionary(data => data.DocumentId))
            {
                updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                errorId,
                                solution.Workspace,
                                solution,
                                projectId,
                                documentId: documentDiagnostics.Key,
                                diagnostics: documentDiagnostics.Value));
            }

            if (projectDiagnosticData.Count > 0)
            {
                updateEvent(this, DiagnosticsUpdatedArgs.DiagnosticsCreated(
                                errorId,
                                solution.Workspace,
                                solution,
                                projectId,
                                documentId: null,
                                diagnostics: projectDiagnosticData.ToImmutable()));
            }

            var result = documentIds.AsImmutableOrEmpty();

            documentDiagnosticData.Free();
            projectDiagnosticData.Free();
            documentIds.Free();
            return(result);
        }
 private static DiagnosticData CreateLiveDiagnostic(DiagnosticDescriptor descriptor, DiagnosticData diagnostic)
 {
     return(new DiagnosticData(
                descriptor.Id,
                descriptor.Category,
                diagnostic.Message,
                descriptor.GetBingHelpMessage(),
                diagnostic.Severity,
                descriptor.DefaultSeverity,
                descriptor.IsEnabledByDefault,
                diagnostic.WarningLevel,
                descriptor.CustomTags.ToImmutableArray(),
                diagnostic.Properties,
                diagnostic.Workspace,
                diagnostic.ProjectId,
                diagnostic.DataLocation,
                diagnostic.AdditionalLocations,
                descriptor.Title.ToString(CultureInfo.CurrentUICulture),
                descriptor.Description.ToString(CultureInfo.CurrentUICulture),
                descriptor.HelpLinkUri,
                isSuppressed: diagnostic.IsSuppressed));
 }
        protected internal override ITagSpan <IErrorTag> CreateTagSpan(bool isLiveUpdate, SnapshotSpan span, DiagnosticData data)
        {
            var errorTag = CreateErrorTag(data);

            if (errorTag == null)
            {
                return(null);
            }

            // Live update squiggles have to be at least 1 character long.
            var minimumLength = isLiveUpdate ? 1 : 0;
            var adjustedSpan  = AdjustSnapshotSpan(span, minimumLength);

            if (adjustedSpan.Length == 0)
            {
                return(null);
            }

            return(new TagSpan <IErrorTag>(adjustedSpan, errorTag));
        }
Esempio n. 24
0
 public void AddError(DocumentId key, DiagnosticData diagnostic)
 {
     AddError(_documentMap, key, diagnostic);
 }
Esempio n. 25
0
 static bool DataHasTag(DiagnosticData desc, string tag)
 {
     return(desc.CustomTags.Any(c => CultureInfo.InvariantCulture.CompareInfo.Compare(c, tag) == 0));
 }
Esempio n. 26
0
            private void AddError <T>(Dictionary <T, Dictionary <DiagnosticData, int> > map, T key, DiagnosticData diagnostic)
            {
                var errors = GetErrorSet(map, key);

                AddError(errors, diagnostic);
            }
        private void AddDiagnostics(
            ref Dictionary <DocumentId, List <DiagnosticData> > lazyLocals, SyntaxTree tree, IEnumerable <Diagnostic> diagnostics)
        {
            foreach (var diagnostic in diagnostics)
            {
                // REVIEW: what is our plan for additional locations?
                switch (diagnostic.Location.Kind)
                {
                case LocationKind.ExternalFile:
                {
                    // TODO: currently additional file location is not supported.
                    break;
                }

                case LocationKind.None:
                {
                    _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                    _lazyOthers.Add(DiagnosticData.Create(Project, diagnostic));
                    break;
                }

                case LocationKind.SourceFile:
                {
                    if (tree != null && diagnostic.Location.SourceTree == tree)
                    {
                        var document = GetDocument(diagnostic);
                        if (document != null)
                        {
                            // local diagnostics to a file
                            lazyLocals = lazyLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                            lazyLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                            AddDocumentToSet(document);
                        }
                    }
                    else if (diagnostic.Location.SourceTree != null)
                    {
                        var document = Project.GetDocument(diagnostic.Location.SourceTree);
                        if (document != null)
                        {
                            // non local diagnostics to a file
                            _lazyNonLocals = _lazyNonLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                            _lazyNonLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                            AddDocumentToSet(document);
                        }
                    }
                    else
                    {
                        // non local diagnostics without location
                        _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                        _lazyOthers.Add(DiagnosticData.Create(Project, diagnostic));
                    }

                    break;
                }

                case LocationKind.MetadataFile:
                case LocationKind.XmlFile:
                {
                    // something we don't care
                    continue;
                }

                default:
                {
                    Contract.Fail("should not reach");
                    break;
                }
                }
            }
        }
            private bool CanReuseDiagnostic(DiagnosticData diagnostic)
            {
                // We can't reuse diagnostics that contain additional locations.  It's too 
                // difficult to ensure that all the locations will be moved to the right

                return diagnostic.AdditionalLocations == null || diagnostic.AdditionalLocations.Count == 0;
            }
        private void AddExternalDiagnostics(
            ref Dictionary <DocumentId, List <DiagnosticData> > lazyLocals, DocumentId documentId, IEnumerable <Diagnostic> diagnostics)
        {
            Contract.ThrowIfTrue(Project.SupportsCompilation);

            foreach (var diagnostic in diagnostics)
            {
                // REVIEW: what is our plan for additional locations?
                switch (diagnostic.Location.Kind)
                {
                case LocationKind.ExternalFile:
                {
                    var diagnosticDocumentId = GetExternalDocumentId(diagnostic);
                    if (documentId == diagnosticDocumentId)
                    {
                        var document = Project.GetDocument(diagnosticDocumentId);
                        if (document != null)
                        {
                            // local diagnostics to a file
                            lazyLocals = lazyLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                            lazyLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                            AddDocumentToSet(document);
                        }
                    }
                    else if (diagnosticDocumentId != null)
                    {
                        var document = Project.GetDocument(diagnosticDocumentId);
                        if (document != null)
                        {
                            // non local diagnostics to a file
                            _lazyNonLocals = _lazyNonLocals ?? new Dictionary <DocumentId, List <DiagnosticData> >();
                            _lazyNonLocals.GetOrAdd(document.Id, _ => new List <DiagnosticData>()).Add(DiagnosticData.Create(document, diagnostic));

                            AddDocumentToSet(document);
                        }
                    }
                    else
                    {
                        // non local diagnostics without location
                        _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                        _lazyOthers.Add(DiagnosticData.Create(Project, diagnostic));
                    }

                    break;
                }

                case LocationKind.None:
                {
                    _lazyOthers = _lazyOthers ?? new List <DiagnosticData>();
                    _lazyOthers.Add(DiagnosticData.Create(Project, diagnostic));
                    break;
                }

                case LocationKind.SourceFile:
                case LocationKind.MetadataFile:
                case LocationKind.XmlFile:
                {
                    // something we don't care
                    continue;
                }

                default:
                {
                    Contract.Fail("should not reach");
                    break;
                }
                }
            }
        }
 private bool ShouldIncludeSuppressedDiagnostic(DiagnosticData diagnostic)
 {
     return IncludeSuppressedDiagnostics || !diagnostic.IsSuppressed;
 }
Esempio n. 31
0
 public FirstDiagnosticResult(bool partialResult, bool hasFix, DiagnosticData diagnostic)
 {
     this.PartialResult = partialResult;
     this.HasFix        = hasFix;
     this.Diagnostic    = diagnostic;
 }
 protected virtual bool ShouldIncludeDiagnostic(DiagnosticData diagnostic) => true;
 private bool ShouldIncludeSuppressedDiagnostic(DiagnosticData diagnostic)
 => IncludeSuppressedDiagnostics || !diagnostic.IsSuppressed;
 private static DiagnosticData CreateLiveDiagnostic(DiagnosticDescriptor descriptor, DiagnosticData diagnostic)
 {
     return new DiagnosticData(
         descriptor.Id,
         descriptor.Category,
         diagnostic.Message,
         descriptor.MessageFormat.ToString(DiagnosticData.USCultureInfo),
         diagnostic.Severity,
         descriptor.DefaultSeverity,
         descriptor.IsEnabledByDefault,
         diagnostic.WarningLevel,
         descriptor.CustomTags.ToImmutableArray(),
         diagnostic.Properties,
         diagnostic.Workspace,
         diagnostic.ProjectId,
         diagnostic.DataLocation,
         diagnostic.AdditionalLocations,
         descriptor.Title.ToString(CultureInfo.CurrentUICulture),
         descriptor.Description.ToString(CultureInfo.CurrentUICulture),
         descriptor.HelpLinkUri,
         isSuppressed: diagnostic.IsSuppressed);
 }
Esempio n. 35
0
        private async Task <bool> ContainsAnyFix(Document document, DiagnosticData diagnostic, bool considerSuppressionFixes, CancellationToken cancellationToken)
        {
            ImmutableArray <CodeFixProvider> workspaceFixers = ImmutableArray <CodeFixProvider> .Empty;
            List <CodeFixProvider>           projectFixers   = null;

            Lazy <ImmutableDictionary <DiagnosticId, ImmutableArray <CodeFixProvider> > > fixerMap;
            bool hasAnySharedFixer  = _workspaceFixersMap.TryGetValue(document.Project.Language, out fixerMap) && fixerMap.Value.TryGetValue(diagnostic.Id, out workspaceFixers);
            var  hasAnyProjectFixer = GetProjectFixers(document.Project).TryGetValue(diagnostic.Id, out projectFixers);

            // TODO (https://github.com/dotnet/roslyn/issues/4932): Don't restrict CodeFixes in Interactive
            if (hasAnySharedFixer && document.Project.Solution.Workspace.Kind == WorkspaceKind.Interactive)
            {
                workspaceFixers   = workspaceFixers.WhereAsArray(IsInteractiveCodeFixProvider);
                hasAnySharedFixer = workspaceFixers.Any();
            }

            Lazy <ISuppressionFixProvider> lazySuppressionProvider = null;
            var hasSuppressionFixer =
                considerSuppressionFixes &&
                _suppressionProvidersMap.TryGetValue(document.Project.Language, out lazySuppressionProvider) &&
                lazySuppressionProvider.Value != null;

            if (!hasAnySharedFixer && !hasAnyProjectFixer && !hasSuppressionFixer)
            {
                return(false);
            }

            var allFixers = ImmutableArray <CodeFixProvider> .Empty;

            if (hasAnySharedFixer)
            {
                allFixers = workspaceFixers;
            }

            if (hasAnyProjectFixer)
            {
                allFixers = allFixers.AddRange(projectFixers);
            }

            var dx = await diagnostic.ToDiagnosticAsync(document.Project, cancellationToken).ConfigureAwait(false);

            if (hasSuppressionFixer && lazySuppressionProvider.Value.CanBeSuppressedOrUnsuppressed(dx))
            {
                return(true);
            }

            var fixes   = new List <CodeFix>();
            var context = new CodeFixContext(document, dx,

                                             // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs?
                                             (action, applicableDiagnostics) =>
            {
                // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from.
                lock (fixes)
                {
                    fixes.Add(new CodeFix(document.Project, action, applicableDiagnostics));
                }
            },
                                             verifyArguments: false,
                                             cancellationToken: cancellationToken);

            var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>();

            // we do have fixer. now let's see whether it actually can fix it
            foreach (var fixer in allFixers)
            {
                await extensionManager.PerformActionAsync(fixer, () => fixer.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask).ConfigureAwait(false);

                if (!fixes.Any())
                {
                    continue;
                }

                return(true);
            }

            return(false);
        }