Пример #1
0
            private void ProcessFixCollection(
                Workspace workspace,
                IDictionary <CodeFixGroupKey, IList <SuggestedAction> > map,
                ArrayBuilder <CodeFixGroupKey> order,
                bool includeSuppressionFixes,
                CodeFixCollection fixCollection)
            {
                var fixes    = fixCollection.Fixes;
                var fixCount = fixes.Length;

                Func <CodeAction, SuggestedActionSet> getFixAllSuggestedActionSet =
                    codeAction => GetFixAllSuggestedActionSet(
                        codeAction, fixCount, fixCollection.FixAllState,
                        fixCollection.SupportedScopes, fixCollection.FirstDiagnostic,
                        workspace);

                var nonSupressionCodeFixes = fixes.WhereAsArray(f => !(f.Action is TopLevelSuppressionCodeAction));
                var supressionCodeFixes    = fixes.WhereAsArray(f => f.Action is TopLevelSuppressionCodeAction);

                AddCodeActions(workspace, map, order, fixCollection,
                               getFixAllSuggestedActionSet, nonSupressionCodeFixes);

                // Add suppression fixes to the end of a given SuggestedActionSet so that they
                // always show up last in a group.
                if (includeSuppressionFixes)
                {
                    AddCodeActions(workspace, map, order, fixCollection,
                                   getFixAllSuggestedActionSet, supressionCodeFixes);
                }
            }
Пример #2
0
            private void AddCodeActions(
                Workspace workspace, IDictionary <CodeFixGroupKey, IList <SuggestedAction> > map,
                ArrayBuilder <CodeFixGroupKey> order, CodeFixCollection fixCollection,
                Func <CodeAction, SuggestedActionSet> getFixAllSuggestedActionSet,
                ImmutableArray <CodeFix> codeFixes)
            {
                foreach (var fix in codeFixes)
                {
                    SuggestedAction suggestedAction;
                    if (fix.Action.NestedCodeActions.Length > 0)
                    {
                        var nestedActions = fix.Action.NestedCodeActions.SelectAsArray(
                            nestedAction => new CodeFixSuggestedAction(
                                _owner, workspace, _subjectBuffer, fix, fixCollection.Provider,
                                nestedAction, getFixAllSuggestedActionSet(nestedAction)));

                        var set = new SuggestedActionSet(
                            nestedActions, SuggestedActionSetPriority.Medium,
                            fix.PrimaryDiagnostic.Location.SourceSpan.ToSpan());

                        suggestedAction = new SuggestedActionWithNestedActions(
                            _owner, workspace, _subjectBuffer,
                            fixCollection.Provider, fix.Action, set);
                    }
                    else
                    {
                        suggestedAction = new CodeFixSuggestedAction(
                            _owner, workspace, _subjectBuffer, fix, fixCollection.Provider,
                            fix.Action, getFixAllSuggestedActionSet(fix.Action));
                    }

                    AddFix(fix, suggestedAction, map, order);
                }
            }
        private static void ProcessFixCollection(
            Workspace workspace,
            IDictionary <CodeFixGroupKey, IList <UnifiedSuggestedAction> > map,
            ArrayBuilder <CodeFixGroupKey> order,
            CodeFixCollection fixCollection)
        {
            var fixes    = fixCollection.Fixes;
            var fixCount = fixes.Length;

            var nonSupressionCodeFixes = fixes.WhereAsArray(f => !IsTopLevelSuppressionAction(f.Action));
            var supressionCodeFixes    = fixes.WhereAsArray(f => IsTopLevelSuppressionAction(f.Action));

            AddCodeActions(workspace, map, order, fixCollection,
                           GetFixAllSuggestedActionSet, nonSupressionCodeFixes);

            // Add suppression fixes to the end of a given SuggestedActionSet so that they
            // always show up last in a group.
            AddCodeActions(workspace, map, order, fixCollection,
                           GetFixAllSuggestedActionSet, supressionCodeFixes);

            return;

            // Local functions
            UnifiedSuggestedActionSet?GetFixAllSuggestedActionSet(CodeAction codeAction)
            => GetUnifiedFixAllSuggestedActionSet(
                codeAction, fixCount, fixCollection.FixAllState,
                fixCollection.SupportedScopes, fixCollection.FirstDiagnostic,
                workspace);
        }
Пример #4
0
        private static async Task ProcessFixCollectionAsync(
            Workspace workspace,
            IDictionary <CodeFixGroupKey, IList <IUnifiedSuggestedAction> > map,
            ArrayBuilder <CodeFixGroupKey> order,
            CodeFixCollection fixCollection,
            CancellationToken cancellationToken)
        {
            var fixes    = fixCollection.Fixes;
            var fixCount = fixes.Length;

            var nonSupressionCodeFixes = fixes.WhereAsArray(f => !IsTopLevelSuppressionAction(f.Action));
            var supressionCodeFixes    = fixes.WhereAsArray(f => IsTopLevelSuppressionAction(f.Action));

            await AddCodeActionsAsync(workspace, map, order, fixCollection, GetFixAllSuggestedActionSetAsync, nonSupressionCodeFixes).ConfigureAwait(false);

            // Add suppression fixes to the end of a given SuggestedActionSet so that they
            // always show up last in a group.
            await AddCodeActionsAsync(workspace, map, order, fixCollection, GetFixAllSuggestedActionSetAsync, supressionCodeFixes).ConfigureAwait(false);

            return;

            // Local functions
            Task <UnifiedSuggestedActionSet?> GetFixAllSuggestedActionSetAsync(CodeAction codeAction)
            => GetUnifiedFixAllSuggestedActionSetAsync(
                codeAction, fixCount, fixCollection.FixAllState,
                fixCollection.SupportedScopes, fixCollection.FirstDiagnostic,
                workspace, cancellationToken);
        }
Пример #5
0
        internal IEnumerable <Tuple <Diagnostic, CodeFixCollection> > GetDiagnosticAndFixes(
            IEnumerable <Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            TextSpan span,
            string annotation,
            string fixAllActionId)
        {
            foreach (var diagnostic in diagnostics)
            {
                if (annotation == null)
                {
                    var fixes   = new List <CodeFix>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => fixes.Add(new CodeFix(a, d)), CancellationToken.None);
                    fixer.RegisterCodeFixesAsync(context).Wait();
                    if (fixes.Any())
                    {
                        var codeFix = new CodeFixCollection(fixer, diagnostic.Location.SourceSpan, fixes);
                        yield return(Tuple.Create(diagnostic, codeFix));
                    }
                }
                else
                {
                    var fixAllProvider = fixer.GetFixAllProvider();
                    Assert.NotNull(fixAllProvider);
                    FixAllScope scope = GetFixAllScope(annotation);

                    Func <Document, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getDocumentDiagnosticsAsync =
                        (d, diagIds, c) =>
                    {
                        var root  = d.GetSyntaxRootAsync().Result;
                        var diags = testDriver.GetDocumentDiagnostics(provider, d, root.FullSpan);
                        diags = diags.Where(diag => diagIds.Contains(diag.Id));
                        return(Task.FromResult(diags));
                    };

                    Func <Project, bool, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getProjectDiagnosticsAsync =
                        (p, includeAllDocumentDiagnostics, diagIds, c) =>
                    {
                        var diags = includeAllDocumentDiagnostics ?
                                    testDriver.GetAllDiagnostics(provider, p) :
                                    testDriver.GetProjectDiagnostics(provider, p);
                        diags = diags.Where(diag => diagIds.Contains(diag.Id));
                        return(Task.FromResult(diags));
                    };

                    var diagnosticIds            = ImmutableHashSet.Create(diagnostic.Id);
                    var fixAllDiagnosticProvider = new FixAllCodeActionContext.FixAllDiagnosticProvider(diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
                    var fixAllContext            = new FixAllContext(document, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None);
                    var fixAllFix = fixAllProvider.GetFixAsync(fixAllContext).WaitAndGetResult(CancellationToken.None);
                    if (fixAllFix != null)
                    {
                        var codeFix = new CodeFixCollection(fixAllProvider, diagnostic.Location.SourceSpan, ImmutableArray.Create(new CodeFix(fixAllFix, diagnostic)));
                        yield return(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }
        }
Пример #6
0
        private async Task <IEnumerable <Tuple <Diagnostic, CodeFixCollection> > > GetDiagnosticAndFixesAsync(
            IEnumerable <Diagnostic> diagnostics,
            DiagnosticAnalyzer provider,
            CodeFixProvider fixer,
            TestDiagnosticAnalyzerDriver testDriver,
            Document document,
            TextSpan span,
            FixAllScope?scope,
            string fixAllActionId)
        {
            Assert.NotEmpty(diagnostics);
            var result = new List <Tuple <Diagnostic, CodeFixCollection> >();

            if (scope == null)
            {
                // Simple code fix.
                foreach (var diagnostic in diagnostics)
                {
                    var fixes   = new List <CodeFix>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => fixes.Add(new CodeFix(document.Project, a, d)), CancellationToken.None);

                    await fixer.RegisterCodeFixesAsync(context);

                    if (fixes.Any())
                    {
                        var codeFix = new CodeFixCollection(
                            fixer, diagnostic.Location.SourceSpan, fixes.ToImmutableArray(),
                            fixAllState: null, supportedScopes: ImmutableArray <FixAllScope> .Empty, firstDiagnostic: null);
                        result.Add(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }
            else
            {
                // Fix all fix.
                var fixAllProvider = fixer.GetFixAllProvider();
                Assert.NotNull(fixAllProvider);

                var fixAllState   = GetFixAllState(fixAllProvider, diagnostics, provider, fixer, testDriver, document, scope.Value, fixAllActionId);
                var fixAllContext = fixAllState.CreateFixAllContext(new ProgressTracker(), CancellationToken.None);
                var fixAllFix     = await fixAllProvider.GetFixAsync(fixAllContext);

                if (fixAllFix != null)
                {
                    // Same fix applies to each diagnostic in scope.
                    foreach (var diagnostic in diagnostics)
                    {
                        var diagnosticSpan = diagnostic.Location.IsInSource ? diagnostic.Location.SourceSpan : default(TextSpan);
                        var codeFix        = new CodeFixCollection(
                            fixAllProvider, diagnosticSpan, ImmutableArray.Create(new CodeFix(document.Project, fixAllFix, diagnostic)),
                            fixAllState: null, supportedScopes: ImmutableArray <FixAllScope> .Empty, firstDiagnostic: null);
                        result.Add(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }

            return(result);
        }
Пример #7
0
        private static void AddCodeActions(
            Workspace workspace,
            IDictionary <CodeFixGroupKey, IList <UnifiedSuggestedAction> > map,
            ArrayBuilder <CodeFixGroupKey> order,
            CodeFixCollection fixCollection,
            Func <CodeAction, UnifiedSuggestedActionSet?> getFixAllSuggestedActionSet,
            ImmutableArray <CodeFix> codeFixes
            )
        {
            foreach (var fix in codeFixes)
            {
                var unifiedSuggestedAction = GetUnifiedSuggestedAction(fix.Action, fix);
                AddFix(fix, unifiedSuggestedAction, map, order);
            }

            return;

            // Local functions
            UnifiedSuggestedAction GetUnifiedSuggestedAction(CodeAction action, CodeFix fix)
            {
                if (action.NestedCodeActions.Length > 0)
                {
                    var nestedActions = action.NestedCodeActions.SelectAsArray(
                        nestedAction => GetUnifiedSuggestedAction(nestedAction, fix)
                        );

                    var set = new UnifiedSuggestedActionSet(
                        categoryName: null,
                        actions: nestedActions,
                        title: null,
                        priority: GetUnifiedSuggestedActionSetPriority(action.Priority),
                        applicableToSpan: fix.PrimaryDiagnostic.Location.SourceSpan
                        );

                    return(new UnifiedSuggestedActionWithNestedActions(
                               workspace,
                               action,
                               action.Priority,
                               fixCollection.Provider,
                               ImmutableArray.Create(set)
                               ));
                }
                else
                {
                    return(new UnifiedCodeFixSuggestedAction(
                               workspace,
                               action,
                               action.Priority,
                               fix,
                               fixCollection.Provider,
                               getFixAllSuggestedActionSet(action)
                               ));
                }
            }
        }
Пример #8
0
            private async Task AppendFixesOrSuppressionsAsync(
                Document document,
                TextSpan span,
                IEnumerable <DiagnosticData> diagnosticsWithSameSpan,
                IList <CodeFixCollection> result,
                object fixer,
                Func <Diagnostic, bool> hasFix,
                Func <ImmutableArray <Diagnostic>, Task <ImmutableArray <CodeFix> > > getFixes,
                CancellationToken cancellationToken)
            {
                var allDiagnostics =
                    await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity)
                    .ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false);

                var diagnostics = allDiagnostics.Where(hasFix).AsImmutable();

                if (diagnostics.Length <= 0)
                {
                    // this can happen for suppression case where all diagnostics can't be suppressed
                    return;
                }

                var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>();
                var fixes            = await extensionManager.PerformFunctionAsync(fixer,
                                                                                   () => getFixes(diagnostics),
                                                                                   defaultValue : ImmutableArray <CodeFix> .Empty).ConfigureAwait(false);

                if (fixes.IsDefaultOrEmpty)
                {
                    return;
                }

                // If the fix provider supports fix all occurrences, then get the corresponding FixAllProviderInfo and fix all context.
                var fixAllProviderInfo = extensionManager.PerformFunction(fixer, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, fixer, FixAllProviderInfo.Create), defaultValue: null);

                FixAllState fixAllState     = null;
                var         supportedScopes = ImmutableArray <FixAllScope> .Empty;

                if (fixAllProviderInfo != null)
                {
                    var codeFixProvider = (fixer as CodeFixProvider) ?? new WrapperCodeFixProvider((ISuppressionFixProvider)fixer, diagnostics.Select(d => d.Id));
                    fixAllState = FixAllState.Create(
                        fixAllProviderInfo.FixAllProvider,
                        document, fixAllProviderInfo, codeFixProvider, diagnostics,
                        GetDocumentDiagnosticsAsync, GetProjectDiagnosticsAsync);
                    supportedScopes = fixAllProviderInfo.SupportedScopes.AsImmutable();
                }

                var codeFix = new CodeFixCollection(
                    fixer, span, fixes, fixAllState,
                    supportedScopes, diagnostics.First());

                result.Add(codeFix);
            }
        private static CodeFixCollection?FilterIndividuallyOnAnyThread(CodeFixCollection collection)
        {
            var applicableFixes = collection.Fixes;

            return(applicableFixes.Length == 0
                ? null
                : applicableFixes.Length == collection.Fixes.Length
                    ? collection
                    : new CodeFixCollection(
                       collection.Provider, collection.TextSpan, applicableFixes,
                       collection.FixAllState, collection.SupportedScopes, collection.FirstDiagnostic));
        }
            private CodeFixCollection FilterOnUIThread(CodeFixCollection collection, Workspace workspace)
            {
                this.AssertIsForeground();

                var applicableFixes = collection.Fixes.Where(f => IsApplicable(f.Action, workspace)).ToList();

                return(applicableFixes.Count == 0
                    ? null
                    : applicableFixes.Count == collection.Fixes.Length
                        ? collection
                        : new CodeFixCollection(collection.Provider, collection.TextSpan, applicableFixes, collection.FixAllContext));
            }
Пример #11
0
        private static async Task AddCodeActionsAsync(
            Workspace workspace,
            Solution originalSolution,
            IDictionary <CodeFixGroupKey, IList <IUnifiedSuggestedAction> > map,
            ArrayBuilder <CodeFixGroupKey> order,
            CodeFixCollection fixCollection,
            Func <CodeAction, Task <UnifiedSuggestedActionSet?> > getFixAllSuggestedActionSetAsync,
            ImmutableArray <CodeFix> codeFixes)
        {
            foreach (var fix in codeFixes)
            {
                var unifiedSuggestedAction = await GetUnifiedSuggestedActionAsync(originalSolution, fix.Action, fix).ConfigureAwait(false);

                AddFix(fix, unifiedSuggestedAction, map, order);
            }

            return;

            // Local functions
            async Task <IUnifiedSuggestedAction> GetUnifiedSuggestedActionAsync(Solution originalSolution, CodeAction action, CodeFix fix)
            {
                if (action.NestedCodeActions.Length > 0)
                {
                    using var _ = ArrayBuilder <IUnifiedSuggestedAction> .GetInstance(action.NestedCodeActions.Length, out var unifiedNestedActions);

                    foreach (var nestedAction in action.NestedCodeActions)
                    {
                        var unifiedNestedAction = await GetUnifiedSuggestedActionAsync(originalSolution, nestedAction, fix).ConfigureAwait(false);

                        unifiedNestedActions.Add(unifiedNestedAction);
                    }

                    var set = new UnifiedSuggestedActionSet(
                        originalSolution,
                        categoryName: null,
                        actions: unifiedNestedActions.ToImmutable(),
                        title: null,
                        priority: GetUnifiedSuggestedActionSetPriority(action.Priority),
                        applicableToSpan: fix.PrimaryDiagnostic.Location.SourceSpan);

                    return(new UnifiedSuggestedActionWithNestedActions(
                               workspace, action, action.Priority, fixCollection.Provider, ImmutableArray.Create(set)));
                }
                else
                {
                    return(new UnifiedCodeFixSuggestedAction(
                               workspace, action, action.Priority, fix, fixCollection.Provider,
                               await getFixAllSuggestedActionSetAsync(action).ConfigureAwait(false)));
                }
            }
        }
        private static CodeFixCollection?FilterIndividuallyOnUIThread(
            CodeFixCollection collection,
            Workspace workspace)
        {
            var applicableFixes = collection.Fixes.WhereAsArray(f => IsApplicable(f.Action, workspace));

            return(applicableFixes.Length == 0
                ? null
                : applicableFixes.Length == collection.Fixes.Length
                    ? collection
                    : new CodeFixCollection(
                       collection.Provider, collection.TextSpan, applicableFixes,
                       collection.FixAllState, collection.SupportedScopes, collection.FirstDiagnostic));
        }
Пример #13
0
            private CodeFixCollection FilterOnUIThread(
                CodeFixCollection collection,
                Workspace workspace)
            {
                this.AssertIsForeground();

                var applicableFixes = collection.Fixes.WhereAsArray(f => IsApplicable(f.Action, workspace));

                return(applicableFixes.Length == 0
                    ? null
                    : applicableFixes.Length == collection.Fixes.Length
                        ? collection
                        : new CodeFixCollection(
                           collection.Provider, collection.TextSpan, applicableFixes,
                           collection.FixAllState, collection.SupportedScopes, collection.FirstDiagnostic));
            }
 static int GetDistance(CodeFixCollection fixCollection, int caretOffset)
 {
     return(fixCollection.TextSpan.End < caretOffset ? caretOffset - fixCollection.TextSpan.End : fixCollection.TextSpan.Start - caretOffset);
 }
Пример #15
0
        internal override IEnumerable <Tuple <Diagnostic, CodeFixCollection> > GetDiagnosticAndFixes(TestWorkspace workspace, string fixAllActionId)
        {
            var providerAndFixer = CreateDiagnosticProviderAndFixer(workspace);

            var      provider = providerAndFixer.Item1;
            Document document;
            TextSpan span;
            string   annotation = null;

            if (!TryGetDocumentAndSelectSpan(workspace, out document, out span))
            {
                document = GetDocumentAndAnnotatedSpan(workspace, out annotation, out span);
            }

            var diagnostics = DiagnosticProviderTestUtilities.GetAllDiagnostics(provider, document, span);

            var fixer = providerAndFixer.Item2;
            var ids   = new HashSet <string>(fixer.FixableDiagnosticIds);
            var dxs   = diagnostics.Where(d => ids.Contains(d.Id)).ToList();

            foreach (var diagnostic in dxs)
            {
                if (annotation == null)
                {
                    var fixes   = new List <CodeFix>();
                    var context = new CodeFixContext(document, diagnostic, (a, d) => fixes.Add(new CodeFix(a, d)), CancellationToken.None);
                    fixer.RegisterCodeFixesAsync(context).Wait();
                    if (fixes.Any())
                    {
                        var codeFix = new CodeFixCollection(fixer, diagnostic.Location.SourceSpan, fixes);
                        yield return(Tuple.Create(diagnostic, codeFix));
                    }
                }
                else
                {
                    var fixAllProvider = fixer.GetFixAllProvider();
                    Assert.NotNull(fixAllProvider);
                    FixAllScope scope = GetFixAllScope(annotation);

                    Func <Document, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getDocumentDiagnosticsAsync =
                        (d, diagIds, c) =>
                    {
                        var root  = d.GetSyntaxRootAsync().Result;
                        var diags = DiagnosticProviderTestUtilities.GetDocumentDiagnostics(provider, d, root.FullSpan);
                        diags = diags.Where(diag => diagIds.Contains(diag.Id));
                        return(Task.FromResult(diags));
                    };

                    Func <Project, bool, ImmutableHashSet <string>, CancellationToken, Task <IEnumerable <Diagnostic> > > getProjectDiagnosticsAsync =
                        (p, includeAllDocumentDiagnostics, diagIds, c) =>
                    {
                        var diags = includeAllDocumentDiagnostics ?
                                    DiagnosticProviderTestUtilities.GetAllDiagnostics(provider, p) :
                                    DiagnosticProviderTestUtilities.GetProjectDiagnostics(provider, p);
                        diags = diags.Where(diag => diagIds.Contains(diag.Id));
                        return(Task.FromResult(diags));
                    };

                    var diagnosticIds            = ImmutableHashSet.Create(diagnostic.Id);
                    var fixAllDiagnosticProvider = new FixAllCodeActionContext.FixAllDiagnosticProvider(diagnosticIds, getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync);
                    var fixAllContext            = new FixAllContext(document, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None);
                    var fixAllFix = fixAllProvider.GetFixAsync(fixAllContext).WaitAndGetResult(CancellationToken.None);
                    if (fixAllFix != null)
                    {
                        var codeFix = new CodeFixCollection(fixAllProvider, diagnostic.Location.SourceSpan, ImmutableArray.Create(new CodeFix(fixAllFix, diagnostic)));
                        yield return(Tuple.Create(diagnostic, codeFix));
                    }
                }
            }
        }