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