private async Task AppendFixesOrSuppressionsAsync( Document document, TextSpan span, IEnumerable <DiagnosticData> diagnosticsWithSameSpan, ArrayBuilder <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.WhereAsArray(hasFix); 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 = CreateFixAllState( fixAllProviderInfo.FixAllProvider, document, fixAllProviderInfo, codeFixProvider, diagnostics, this.GetDocumentDiagnosticsAsync, this.GetProjectDiagnosticsAsync); supportedScopes = fixAllProviderInfo.SupportedScopes; } var codeFix = new CodeFixCollection( fixer, span, fixes, fixAllState, supportedScopes, diagnostics.First()); result.Add(codeFix); }
private async Task <List <CodeFixCollection> > AppendFixesOrSuppressionsAsync( Document document, TextSpan span, IEnumerable <Diagnostic> diagnosticsWithSameSpan, List <CodeFixCollection> result, object fixer, Func <Diagnostic, bool> hasFix, Func <ImmutableArray <Diagnostic>, Task <IEnumerable <CodeFix> > > getFixes, CancellationToken cancellationToken) { var diagnostics = diagnosticsWithSameSpan.Where(d => hasFix(d)).OrderByDescending(d => d.Severity).ToImmutableArray(); if (diagnostics.Length <= 0) { // this can happen for suppression case where all diagnostics can't be suppressed return(result); } var extensionManager = document.Project.Solution.Workspace.Services.GetService <IExtensionManager>(); var fixes = await extensionManager.PerformFunctionAsync(fixer, () => getFixes(diagnostics), defaultValue : SpecializedCollections.EmptyEnumerable <CodeFix>()).ConfigureAwait(false); if (fixes != null && fixes.Any()) { FixAllCodeActionContext fixAllContext = null; var codeFixProvider = fixer as CodeFixProvider; if (codeFixProvider != null) { // If the codeFixProvider supports fix all occurrences, then get the corresponding FixAllProviderInfo and fix all context. var fixAllProviderInfo = extensionManager.PerformFunction(codeFixProvider, () => ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, codeFixProvider, FixAllProviderInfo.Create), defaultValue: null); if (fixAllProviderInfo != null) { fixAllContext = FixAllCodeActionContext.Create(document, fixAllProviderInfo, codeFixProvider, diagnostics, this.GetDocumentDiagnosticsAsync, this.GetProjectDiagnosticsAsync, cancellationToken); } } result = result ?? new List <CodeFixCollection>(); var codeFix = new CodeFixCollection(fixer, span, fixes, fixAllContext); result.Add(codeFix); } return(result); }
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 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); }
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 async Task AppendFixesOrSuppressionsAsync( Document document, TextSpan span, IEnumerable<DiagnosticData> diagnosticsWithSameSpan, ArrayBuilder<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.WhereAsArray(hasFix); 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, this.GetDocumentDiagnosticsAsync, this.GetProjectDiagnosticsAsync); supportedScopes = fixAllProviderInfo.SupportedScopes; } var codeFix = new CodeFixCollection( fixer, span, fixes, fixAllState, supportedScopes, diagnostics.First()); result.Add(codeFix); }
private async Task<List<CodeFixCollection>> AppendFixesOrSuppressionsAsync( Document document, TextSpan span, IEnumerable<DiagnosticData> diagnosticsWithSameSpan, List<CodeFixCollection> result, object fixer, Func<Diagnostic, bool> hasFix, Func<ImmutableArray<Diagnostic>, Task<IEnumerable<CodeFix>>> getFixes, CancellationToken cancellationToken) { var diagnostics = (await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity).ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false)).Where(d => hasFix(d)).ToImmutableArray(); if (diagnostics.Length <= 0) { // this can happen for suppression case where all diagnostics can't be suppressed return result; } var extensionManager = document.Project.Solution.Workspace.Services.GetService<IExtensionManager>(); var fixes = await extensionManager.PerformFunctionAsync(fixer, () => getFixes(diagnostics), defaultValue: SpecializedCollections.EmptyEnumerable<CodeFix>()).ConfigureAwait(false); if (fixes != null && fixes.Any()) { // 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); FixAllCodeActionContext fixAllContext = null; if (fixAllProviderInfo != null) { var codeFixProvider = (fixer as CodeFixProvider) ?? new WrapperCodeFixProvider((ISuppressionFixProvider)fixer, diagnostics.Select(d => d.Id)); fixAllContext = FixAllCodeActionContext.Create( document, fixAllProviderInfo, codeFixProvider, diagnostics, this.GetDocumentDiagnosticsAsync, this.GetProjectDiagnosticsAsync, cancellationToken); } result = result ?? new List<CodeFixCollection>(); var codeFix = new CodeFixCollection(fixer, span, fixes, fixAllContext); result.Add(codeFix); } return result; }
private async Task<List<CodeFixCollection>> AppendFixesOrSuppressionsAsync( Document document, TextSpan span, IEnumerable<Diagnostic> diagnosticsWithSameSpan, List<CodeFixCollection> result, object fixer, IExtensionManager extensionManager, Func<Diagnostic, bool> hasFix, Func<ImmutableArray<Diagnostic>, Task<IEnumerable<CodeFix>>> getFixes, CancellationToken cancellationToken) { var diagnostics = diagnosticsWithSameSpan.Where(d => hasFix(d)).OrderByDescending(d => d.Severity).ToImmutableArray(); if (diagnostics.Length <= 0) { // this can happen for suppression case where all diagnostics can't be suppressed return result; } var fixes = await extensionManager.PerformFunctionAsync(fixer, () => getFixes(diagnostics)).ConfigureAwait(false); if (fixes != null && fixes.Any()) { FixAllCodeActionContext fixAllContext = null; var codeFixProvider = fixer as CodeFixProvider; if (codeFixProvider != null) { // If the codeFixProvider supports fix all occurrences, then get the corresponding FixAllProviderInfo and fix all context. var fixAllProviderInfo = ImmutableInterlocked.GetOrAdd(ref _fixAllProviderMap, codeFixProvider, FixAllProviderInfo.Create); if (fixAllProviderInfo != null) { fixAllContext = new FixAllCodeActionContext(document, fixAllProviderInfo, codeFixProvider, diagnostics, this.GetDocumentDiagnosticsAsync, this.GetProjectDiagnosticsAsync, cancellationToken); } } result = result ?? new List<CodeFixCollection>(); var codeFix = new CodeFixCollection(fixer, span, fixes, fixAllContext); result.Add(codeFix); } return result; }
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, fixAllState: null, supportedScopes: null, 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: null, firstDiagnostic: null); result.Add(Tuple.Create(diagnostic, codeFix)); } } } return result; }
internal CodeFixCollection(Microsoft.CodeAnalysis.CodeFixes.CodeFixCollection inner) { _inner = inner; Fixes = inner.Fixes.Select(x => x).ToImmutableArray(); }
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 fixAllContext = new FixAllContext(document, fixer, scope, fixAllActionId, SpecializedCollections.SingletonEnumerable(diagnostic.Id), getDocumentDiagnosticsAsync, getProjectDiagnosticsAsync, 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); } } } }
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(document.Project, 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 = diagnostic.Location.IsInSource ? new FixAllContext(document, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None) : new FixAllContext(document.Project, fixer, scope, fixAllActionId, diagnosticIds, fixAllDiagnosticProvider, CancellationToken.None); var fixAllFix = fixAllProvider.GetFixAsync(fixAllContext).WaitAndGetResult(CancellationToken.None); if (fixAllFix != null) { var diagnosticSpan = diagnostic.Location.IsInSource ? diagnostic.Location.SourceSpan : default(TextSpan); var codeFix = new CodeFixCollection(fixAllProvider, diagnosticSpan, ImmutableArray.Create(new CodeFix(document.Project, fixAllFix, diagnostic))); yield return Tuple.Create(diagnostic, codeFix); } } } }
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 async Task AppendFixesOrConfigurationsAsync<TCodeFixProvider>( Document document, TextSpan fixesSpan, IEnumerable<DiagnosticData> diagnosticsWithSameSpan, bool fixAllForInSpan, ArrayBuilder<CodeFixCollection> result, TCodeFixProvider fixer, Func<Diagnostic, bool> hasFix, Func<ImmutableArray<Diagnostic>, Task<ImmutableArray<CodeFix>>> getFixes, CancellationToken cancellationToken) where TCodeFixProvider : notnull { var allDiagnostics = await diagnosticsWithSameSpan.OrderByDescending(d => d.Severity) .ToDiagnosticsAsync(document.Project, cancellationToken).ConfigureAwait(false); var diagnostics = allDiagnostics.WhereAsArray(hasFix); 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.GetRequiredService<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<FixAllProviderInfo?>(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((IConfigurationFixProvider)fixer, diagnostics.Select(d => d.Id)); var diagnosticIds = diagnostics.Where(fixAllProviderInfo.CanBeFixed) .Select(d => d.Id) .ToImmutableHashSet(); var diagnosticProvider = fixAllForInSpan ? new FixAllPredefinedDiagnosticProvider(allDiagnostics) : (FixAllContext.DiagnosticProvider)new FixAllDiagnosticProvider(this, diagnosticIds); fixAllState = new FixAllState( fixAllProvider: fixAllProviderInfo.FixAllProvider, document: document, codeFixProvider: codeFixProvider, scope: FixAllScope.Document, codeActionEquivalenceKey: null, diagnosticIds: diagnosticIds, fixAllDiagnosticProvider: diagnosticProvider); supportedScopes = fixAllProviderInfo.SupportedScopes; } var codeFix = new CodeFixCollection( fixer, fixesSpan, fixes, fixAllState, supportedScopes, diagnostics.First()); result.Add(codeFix); }