Example #1
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);

            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 tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var dx = diagnostic.ToDiagnostic(tree);

            if (hasSuppressionFixer && lazySuppressionProvider.Value.CanBeSuppressed(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?
                                             (a, d) =>
            {
                // 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(a, d));
                }
            },
                                             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);
        }
Example #2
0
        private async Task <bool> ContainsAnyFix(Document document, DiagnosticData diagnostic, CancellationToken cancellationToken)
        {
            // TODO: We don't return true here if the only available fixes are suppressions.
            // This is to avoid the problem where lightbulb would show up for every green warning
            // squiggle in the editor thereby diluting the promise of the light bulb from
            // "I have a fix" to "I have some action". This is temporary until the editor team exposes
            // some mechanism (e.g. a faded out lightbulb) that would allow us to say "I have an action
            // but not a fix".

            ImmutableArray <CodeFixProvider> workspaceFixers = ImmutableArray <CodeFixProvider> .Empty;
            List <CodeFixProvider>           projectFixers   = null;

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

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

            var allFixers = ImmutableArray <CodeFixProvider> .Empty;

            if (hasAnySharedFixer)
            {
                allFixers = workspaceFixers;
            }

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

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

            var dx = diagnostic.ToDiagnostic(tree);

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

            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?
                                             (a, d) =>
            {
                // 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(a, d));
                }
            },
                                             verifyArguments: false,
                                             cancellationToken: cancellationToken);

            // 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);
        }