private async static Task<Solution> GetFixedSolutionAsync(FixAllContext fixAllContext) { var newSolution = fixAllContext.Solution; foreach (var projectId in newSolution.ProjectIds) newSolution = await GetFixedProjectAsync(fixAllContext, newSolution.GetProject(projectId)).ConfigureAwait(false); return newSolution; }
public static void LogContext(FixAllContext fixAllContext, bool isInternalCodeFixProvider) { Logger.Log(FunctionId.CodeFixes_FixAllOccurrencesContext, KeyValueLogMessage.Create(m => { if (isInternalCodeFixProvider) { m[s_codeFixProvider] = fixAllContext.CodeFixProvider.GetType().FullName; m[s_codeActionEquivalenceKey] = fixAllContext.CodeActionEquivalenceKey; m[s_languageName] = fixAllContext.Project.Language; } else { m[s_codeFixProvider] = fixAllContext.CodeFixProvider.GetType().FullName.GetHashCode().ToString(); m[s_codeActionEquivalenceKey] = fixAllContext.CodeActionEquivalenceKey != null ? fixAllContext.CodeActionEquivalenceKey.GetHashCode().ToString() : null; m[s_languageName] = fixAllContext.Project.Language.GetHashCode().ToString(); } m[s_fixAllScope] = fixAllContext.Scope.ToString(); switch (fixAllContext.Scope) { case CodeFixes.FixAllScope.Project: m[s_documentCount] = fixAllContext.Project.DocumentIds.Count; break; case CodeFixes.FixAllScope.Solution: m[s_documentCount] = fixAllContext.Solution.Projects.Sum(p => p.DocumentIds.Count); break; } })); }
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); if (diagnostics.IsEmpty) { return null; } SyntaxNode syntaxRoot = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); var replaceMap = new Dictionary<SyntaxNode, SyntaxNode>(); foreach (Diagnostic diagnostic in diagnostics) { var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, false, true) as ThisExpressionSyntax; if (node == null || node.IsMissing) { continue; } replaceMap[node.Parent] = GenerateReplacementNode(node); } return syntaxRoot.ReplaceNodes(replaceMap.Keys, (originalNode, rewrittenNode) => replaceMap[originalNode]); }
public virtual async Task<CodeAction> GetFixAsync( ImmutableDictionary<Document, ImmutableArray<Diagnostic>> documentsAndDiagnosticsToFixMap, FixAllContext fixAllContext) { if (documentsAndDiagnosticsToFixMap != null && documentsAndDiagnosticsToFixMap.Any()) { FixAllLogger.LogDiagnosticsStats(documentsAndDiagnosticsToFixMap); var fixesBag = new ConcurrentBag<CodeAction>(); using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Fixes, fixAllContext.CancellationToken)) { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var documents = documentsAndDiagnosticsToFixMap.Keys; var tasks = documents.Select(d => AddDocumentFixesAsync(d, documentsAndDiagnosticsToFixMap[d], fixesBag.Add, fixAllContext)) .ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); } if (fixesBag.Any()) { using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Merge, fixAllContext.CancellationToken)) { FixAllLogger.LogFixesToMergeStats(fixesBag); return await TryGetMergedFixAsync(fixesBag, fixAllContext).ConfigureAwait(false); } } } return null; }
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); if (diagnostics.IsEmpty) { return null; } var newDocument = document; var root = await newDocument.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); // First annotate all expressions that need parenthesis with a temporary annotation. // With this annotation we can find the nodes that need parenthesis even if // the source span changes. foreach (var diagnostic in diagnostics) { SyntaxNode node = root.FindNode(diagnostic.Location.SourceSpan); if (node.IsMissing) { continue; } root = root.ReplaceNode(node, node.WithAdditionalAnnotations(NeedsParenthesisAnnotation)); } return root.ReplaceNodes(root.GetAnnotatedNodes(NeedsParenthesisAnnotation), this.AddParentheses); }
public static async Task<ImmutableDictionary<Project, ImmutableArray<Diagnostic>>> GetProjectDiagnosticsToFixAsync(FixAllContext fixAllContext) { var project = fixAllContext.Project; if (project != null) { switch (fixAllContext.Scope) { case FixAllScope.Project: var diagnostics = await fixAllContext.GetProjectDiagnosticsAsync(project).ConfigureAwait(false); return ImmutableDictionary<Project, ImmutableArray<Diagnostic>>.Empty.SetItem(project, diagnostics); case FixAllScope.Solution: var projectsAndDiagnostics = new ConcurrentDictionary<Project, ImmutableArray<Diagnostic>>(); var options = new ParallelOptions() { CancellationToken = fixAllContext.CancellationToken }; Parallel.ForEach(project.Solution.Projects, options, proj => { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var projectDiagnosticsTask = fixAllContext.GetProjectDiagnosticsAsync(proj); projectDiagnosticsTask.Wait(fixAllContext.CancellationToken); var projectDiagnostics = projectDiagnosticsTask.Result; if (projectDiagnostics.Any()) { projectsAndDiagnostics.TryAdd(proj, projectDiagnostics); } }); return projectsAndDiagnostics.ToImmutableDictionary(); } } return ImmutableDictionary<Project, ImmutableArray<Diagnostic>>.Empty; }
public override Task<CodeAction> GetFixAsync(FixAllContext fixAllContext) { switch (fixAllContext.Scope) { case FixAllScope.Document: { return Task.FromResult(CodeAction.Create(UseEmptyStringCodeFixProvider.MessageFormat, async ct => { var newFixAllContext = fixAllContext.WithCancellationToken(ct); var diagnostics = await newFixAllContext.GetDocumentDiagnosticsAsync(newFixAllContext.Document).ConfigureAwait(false); var root = await GetFixedDocumentAsync(newFixAllContext.Document, diagnostics, ct).ConfigureAwait(false); return newFixAllContext.Document.WithSyntaxRoot(root); })); } case FixAllScope.Project: return Task.FromResult(CodeAction.Create(UseEmptyStringCodeFixProvider.MessageFormat, ct => { var newFixAllContext = fixAllContext.WithCancellationToken(ct); return GetFixedProjectAsync(newFixAllContext, newFixAllContext.WithCancellationToken(ct).Project); })); case FixAllScope.Solution: return Task.FromResult(CodeAction.Create(UseEmptyStringCodeFixProvider.MessageFormat, ct => GetFixedSolutionAsync(fixAllContext.WithCancellationToken(ct)))); } return null; }
private FixAllState( FixAllProvider fixAllProvider, Document document, Project project, CodeFixProvider codeFixProvider, FixAllScope scope, string codeActionEquivalenceKey, IEnumerable<string> diagnosticIds, FixAllContext.DiagnosticProvider fixAllDiagnosticProvider) { Contract.ThrowIfNull(project); if (diagnosticIds == null) { throw new ArgumentNullException(nameof(diagnosticIds)); } if (diagnosticIds.Any(d => d == null)) { throw new ArgumentException(WorkspacesResources.Supplied_diagnostic_cannot_be_null, nameof(diagnosticIds)); } this.FixAllProvider = fixAllProvider; this.Document = document; this.Project = project; this.CodeFixProvider = codeFixProvider ?? throw new ArgumentNullException(nameof(codeFixProvider)); this.Scope = scope; this.CodeActionEquivalenceKey = codeActionEquivalenceKey; this.DiagnosticIds = ImmutableHashSet.CreateRange(diagnosticIds); this.DiagnosticProvider = fixAllDiagnosticProvider ?? throw new ArgumentNullException(nameof(fixAllDiagnosticProvider)); }
private async Task<CodeAction> GetFixAllCodeActionAsync(FixAllProvider fixAllProvider, FixAllContext fixAllContext) { using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation, fixAllContext.CancellationToken)) { CodeAction action = null; try { action = await fixAllProvider.GetFixAsync(fixAllContext).ConfigureAwait(false); } catch (OperationCanceledException) { FixAllLogger.LogComputationResult(completed: false); } finally { if (action != null) { FixAllLogger.LogComputationResult(completed: true); } else { FixAllLogger.LogComputationResult(completed: false, timedOut: true); } } return action; } }
public override async Task AddDocumentFixesAsync(Document document, ImmutableArray<Diagnostic> diagnostics, Action<CodeAction> addFix, FixAllContext fixAllContext) { var changedDocument = await AddSimplifierAnnotationsAsync(document, diagnostics, fixAllContext).ConfigureAwait(false); var title = GetFixAllTitle(fixAllContext); var codeAction = new MyCodeAction(title, (c) => Task.FromResult(changedDocument)); addFix(codeAction); }
public virtual async Task<CodeAction> GetFixAsync( ImmutableDictionary<Document, ImmutableArray<Diagnostic>> documentsAndDiagnosticsToFixMap, FixAllContext fixAllContext) { if (documentsAndDiagnosticsToFixMap != null && documentsAndDiagnosticsToFixMap.Any()) { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var documents = documentsAndDiagnosticsToFixMap.Keys.ToImmutableArray(); var fixesBag = new List<CodeAction>[documents.Length]; var options = new ParallelOptions() { CancellationToken = fixAllContext.CancellationToken }; Parallel.ForEach(documents, options, (document, state, index) => { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); fixesBag[index] = new List<CodeAction>(); this.AddDocumentFixesAsync(document, documentsAndDiagnosticsToFixMap[document], fixesBag[index].Add, fixAllContext).Wait(fixAllContext.CancellationToken); }); if (fixesBag.Any(fixes => fixes.Count > 0)) { return await this.TryGetMergedFixAsync(fixesBag.SelectMany(i => i), fixAllContext).ConfigureAwait(false); } } return null; }
public override async Task<CodeAction> GetFixAsync(FixAllContext fixAllContext) { switch (fixAllContext.Scope) { case FixAllScope.Document: var newRoot = await this.FixAllInDocumentAsync(fixAllContext, fixAllContext.Document).ConfigureAwait(false); return CodeAction.Create(MaintainabilityResources.SA1407SA1408CodeFix, token => Task.FromResult(fixAllContext.Document.WithSyntaxRoot(newRoot))); case FixAllScope.Project: Solution solution = await this.GetProjectFixesAsync(fixAllContext, fixAllContext.Project).ConfigureAwait(false); return CodeAction.Create(MaintainabilityResources.SA1407SA1408CodeFix, token => Task.FromResult(solution)); case FixAllScope.Solution: var newSolution = fixAllContext.Solution; var projectIds = newSolution.ProjectIds; for (int i = 0; i < projectIds.Count; i++) { newSolution = await this.GetProjectFixesAsync(fixAllContext, newSolution.GetProject(projectIds[i])).ConfigureAwait(false); } return CodeAction.Create(MaintainabilityResources.SA1407SA1408CodeFix, token => Task.FromResult(newSolution)); case FixAllScope.Custom: default: return null; } }
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); if (diagnostics.IsEmpty) { return null; } SyntaxNode syntaxRoot = await document.GetSyntaxRootAsync().ConfigureAwait(false); List<SyntaxNode> nodesNeedingQualification = new List<SyntaxNode>(diagnostics.Length); foreach (Diagnostic diagnostic in diagnostics) { var node = syntaxRoot.FindNode(diagnostic.Location.SourceSpan, false, true) as SimpleNameSyntax; if (node == null || node.IsMissing) { continue; } nodesNeedingQualification.Add(node); } return syntaxRoot.ReplaceNodes(nodesNeedingQualification, (originalNode, rewrittenNode) => SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, ThisExpressionSyntax, (SimpleNameSyntax)rewrittenNode.WithoutTrivia().WithoutFormatting()) .WithTriviaFrom(rewrittenNode) .WithoutFormatting()); }
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); if (diagnostics.IsEmpty) { return null; } DocumentEditor editor = await DocumentEditor.CreateAsync(document, fixAllContext.CancellationToken).ConfigureAwait(false); SyntaxNode root = editor.GetChangedRoot(); ImmutableList<SyntaxNode> nodesToChange = ImmutableList.Create<SyntaxNode>(); // Make sure all nodes we care about are tracked foreach (var diagnostic in diagnostics) { var location = diagnostic.Location; var syntaxNode = root.FindNode(location.SourceSpan); if (syntaxNode != null) { editor.TrackNode(syntaxNode); nodesToChange = nodesToChange.Add(syntaxNode); } } foreach (var node in nodesToChange) { editor.ReplaceNode(node, node.WithLeadingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed)); } return editor.GetChangedRoot(); }
public override async Task<CodeAction> GetFixAsync(FixAllContext fixAllContext) { Solution newSolution; switch (fixAllContext.Scope) { case FixAllScope.Document: newSolution = await FixDocumentAsync(fixAllContext, fixAllContext.Document).ConfigureAwait(false); break; case FixAllScope.Project: newSolution = await GetProjectFixesAsync(fixAllContext, fixAllContext.Project).ConfigureAwait(false); break; case FixAllScope.Solution: newSolution = fixAllContext.Solution; var projectIds = newSolution.ProjectIds; for (int i = 0; i < projectIds.Count; i++) { newSolution = await GetProjectFixesAsync(fixAllContext, newSolution.GetProject(projectIds[i])).ConfigureAwait(false); } break; case FixAllScope.Custom: default: return null; } return CodeAction.Create( string.Format(MaintainabilityResources.SA1412CodeFix, fixAllContext.CodeActionEquivalenceKey.Substring(fixAllContext.CodeActionEquivalenceKey.IndexOf('.') + 1)), token => Task.FromResult(newSolution)); }
public override Task<CodeAction> GetFixAsync(FixAllContext fixAllContext) { CodeAction fixAction; switch (fixAllContext.Scope) { case FixAllScope.Document: fixAction = CodeAction.Create( this.CodeActionTitle, cancellationToken => this.GetDocumentFixesAsync(fixAllContext.WithCancellationToken(cancellationToken)), nameof(DocumentBasedFixAllProvider)); break; case FixAllScope.Project: fixAction = CodeAction.Create( this.CodeActionTitle, cancellationToken => this.GetProjectFixesAsync(fixAllContext.WithCancellationToken(cancellationToken), fixAllContext.Project), nameof(DocumentBasedFixAllProvider)); break; case FixAllScope.Solution: fixAction = CodeAction.Create( this.CodeActionTitle, cancellationToken => this.GetSolutionFixesAsync(fixAllContext.WithCancellationToken(cancellationToken)), nameof(DocumentBasedFixAllProvider)); break; case FixAllScope.Custom: default: fixAction = null; break; } return Task.FromResult(fixAction); }
public virtual async Task<CodeAction> GetFixAsync( ImmutableDictionary<Document, ImmutableArray<Diagnostic>> documentsAndDiagnosticsToFixMap, FixAllContext fixAllContext) { if (documentsAndDiagnosticsToFixMap != null && documentsAndDiagnosticsToFixMap.Any()) { FixAllLogger.LogDiagnosticsStats(documentsAndDiagnosticsToFixMap); var fixesBag = new ConcurrentBag<CodeAction>(); using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Fixes, fixAllContext.CancellationToken)) { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var documents = documentsAndDiagnosticsToFixMap.Keys.ToImmutableArray(); var options = new ParallelOptions() { CancellationToken = fixAllContext.CancellationToken }; Parallel.ForEach(documents, options, document => { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); AddDocumentFixesAsync(document, documentsAndDiagnosticsToFixMap[document], fixesBag.Add, fixAllContext).Wait(fixAllContext.CancellationToken); }); } if (fixesBag.Any()) { using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Merge, fixAllContext.CancellationToken)) { FixAllLogger.LogFixesToMergeStats(fixesBag); return await TryGetMergedFixAsync(fixesBag, fixAllContext).ConfigureAwait(false); } } } return null; }
private static async Task<DiagnosticsInDoc> GetDiagnosticsInDocAsync(FixAllContext fixAllContext, Document document) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); if (!diagnostics.Any()) return DiagnosticsInDoc.Empty; var root = await document.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); var doc = DiagnosticsInDoc.Create(document.Id, diagnostics, root); return doc; }
private async static Task<Solution> GetFixedProjectAsync(FixAllContext fixAllContext, Project project) { var solution = project.Solution; var newDocuments = project.Documents.ToDictionary(d => d.Id, d => GetFixedDocumentAsync(fixAllContext, d)); await Task.WhenAll(newDocuments.Values).ConfigureAwait(false); foreach (var newDoc in newDocuments) solution = solution.WithDocumentSyntaxRoot(newDoc.Key, newDoc.Value.Result); return solution; }
private async static Task<SolutionWithDocs> GetSolutionWithDocsAsync(FixAllContext fixAllContext, Document document) { var docs = new List<DiagnosticsInDoc>(); var doc = await GetDiagnosticsInDocAsync(fixAllContext, document); docs.Add(doc); var newSolution = document.Project.Solution.WithDocumentSyntaxRoot(document.Id, doc.TrackedRoot); var sol = new SolutionWithDocs { Docs = docs, Solution = newSolution }; return sol; }
private async Task<Document> AddSimplifierAnnotationsAsync(Document document, ImmutableArray<Diagnostic> diagnostics, FixAllContext fixAllContext) { var cancellationToken = fixAllContext.CancellationToken; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Find all nodes to simplify corresponding to diagnostic spans. var nodesToSimplify = new List<SyntaxNode>(); foreach (var diagnostic in diagnostics) { string codeActionEquivalenceKey; var node = GetNodeToSimplify(root, model, diagnostic, fixAllContext.Solution.Workspace, out codeActionEquivalenceKey, cancellationToken); if (node != null && fixAllContext.CodeActionEquivalenceKey == codeActionEquivalenceKey) { nodesToSimplify.Add(node); } } // Add simplifier and formatter annotations to all nodes to simplify. // If the fix all provider needs to fixup any of the parent nodes, then we iterate through each of the nodesToSimplify // and fixup any parenting node, computing a new document with required simplifier annotations in each iteration. // Otherwise, if the fix all provider doesn't need parent fixup, we just add simplifier annotation to all nodesToSimplify. if (!NeedsParentFixup) { root = root.ReplaceNodes(nodesToSimplify, (o, n) => n.WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation)); } else { // Add a custom annotation to nodesToSimplify so we can get back to them later. var annotation = new SyntaxAnnotation(); root = root.ReplaceNodes(nodesToSimplify, (o, n) => o.WithAdditionalAnnotations(annotation)); document = document.WithSyntaxRoot(root); while (true) { root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var annotatedNodes = root.GetAnnotatedNodes(annotation); // Get the next un-processed node to simplify, processed nodes should have simplifier annotation. var annotatedNode = annotatedNodes.FirstOrDefault(n => !n.HasAnnotation(Simplifier.Annotation)); if (annotatedNode == null) { // All nodesToSimplify have been processed. // Remove all the custom annotations added for tracking nodesToSimplify. root = root.ReplaceNodes(annotatedNodes, (o, n) => o.WithoutAnnotations(annotation)); break; } document = await AddSimplifyAnnotationsAsync(document, annotatedNode, cancellationToken).ConfigureAwait(false); } } return document.WithSyntaxRoot(root); }
public async Task<IEnumerable<CodeActionOperation>> GetFixAllOperationsAsync(FixAllProvider fixAllProvider, FixAllContext fixAllContext, bool showPreviewChangesDialog) { var codeAction = await GetFixAllCodeActionAsync(fixAllProvider, fixAllContext).ConfigureAwait(false); if (codeAction == null) { return null; } return await GetFixAllOperationsAsync(codeAction, fixAllContext, showPreviewChangesDialog).ConfigureAwait(false); }
private async Task<Document> GetDocumentFixesAsync(FixAllContext fixAllContext) { var newRoot = await this.FixAllInDocumentAsync(fixAllContext, fixAllContext.Document).ConfigureAwait(false); if (newRoot == null) { return fixAllContext.Document; } return fixAllContext.Document.WithSyntaxRoot(newRoot); }
public static async Task<ImmutableDictionary<Document, ImmutableArray<Diagnostic>>> GetDocumentDiagnosticsToFixAsync(FixAllContext fixAllContext) { var allDiagnostics = ImmutableArray<Diagnostic>.Empty; var projectsToFix = ImmutableArray<Project>.Empty; var document = fixAllContext.Document; var project = fixAllContext.Project; switch (fixAllContext.Scope) { case FixAllScope.Document: if (document != null) { var documentDiagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); return ImmutableDictionary<Document, ImmutableArray<Diagnostic>>.Empty.SetItem(document, documentDiagnostics); } break; case FixAllScope.Project: projectsToFix = ImmutableArray.Create(project); allDiagnostics = await GetAllDiagnosticsAsync(fixAllContext, project).ConfigureAwait(false); break; case FixAllScope.Solution: projectsToFix = project.Solution.Projects .Where(p => p.Language == project.Language) .ToImmutableArray(); var diagnostics = new ConcurrentDictionary<ProjectId, ImmutableArray<Diagnostic>>(); var tasks = new Task[projectsToFix.Length]; for (int i = 0; i < projectsToFix.Length; i++) { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var projectToFix = projectsToFix[i]; tasks[i] = Task.Run( async () => { var projectDiagnostics = await GetAllDiagnosticsAsync(fixAllContext, projectToFix).ConfigureAwait(false); diagnostics.TryAdd(projectToFix.Id, projectDiagnostics); }, fixAllContext.CancellationToken); } await Task.WhenAll(tasks).ConfigureAwait(false); allDiagnostics = allDiagnostics.AddRange(diagnostics.SelectMany(i => i.Value.Where(x => fixAllContext.DiagnosticIds.Contains(x.Id)))); break; } if (allDiagnostics.IsEmpty) { return ImmutableDictionary<Document, ImmutableArray<Diagnostic>>.Empty; } return await GetDocumentDiagnosticsToFixAsync(allDiagnostics, projectsToFix, fixAllContext.CancellationToken).ConfigureAwait(false); }
private async static Task<Solution> GetFixedProjectAsync(FixAllContext fixAllContext, Project project) { var solution = project.Solution; foreach (var document in project.Documents) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); var newRoot = await GetFixedDocumentAsync(document, diagnostics, fixAllContext.CancellationToken).ConfigureAwait(false); solution = solution.WithDocumentSyntaxRoot(document.Id, newRoot); } return solution; }
private static async Task<Solution> GetDocumentFixesAsync(FixAllContext fixAllContext) { var documentDiagnosticsToFix = await FixAllContextHelper.GetDocumentDiagnosticsToFixAsync(fixAllContext).ConfigureAwait(false); ImmutableArray<Diagnostic> diagnostics; if (!documentDiagnosticsToFix.TryGetValue(fixAllContext.Document, out diagnostics)) { return fixAllContext.Document.Project.Solution; } return await FixDocumentAsync(fixAllContext.Document.Project.Solution, fixAllContext.Document.Id, diagnostics, fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken).ConfigureAwait(false); }
public async Task<Solution> GetFixAllChangedSolutionAsync(FixAllProvider fixAllProvider, FixAllContext fixAllContext) { var codeAction = await GetFixAllCodeActionAsync(fixAllProvider, fixAllContext).ConfigureAwait(false); if (codeAction == null) { return fixAllContext.Solution; } fixAllContext.CancellationToken.ThrowIfCancellationRequested(); return await codeAction.GetChangedSolutionInternalAsync(cancellationToken: fixAllContext.CancellationToken).ConfigureAwait(false); }
protected override async Task<SyntaxNode> FixAllInDocumentAsync(FixAllContext fixAllContext, Document document, ImmutableArray<Diagnostic> diagnostics) { if (diagnostics.IsEmpty) { return null; } var settings = SettingsHelper.GetStyleCopSettings(document.Project.AnalyzerOptions, fixAllContext.CancellationToken); Document updatedDocument = await FixEndOfFileAsync(document, diagnostics[0], settings.LayoutRules.NewlineAtEndOfFile, fixAllContext.CancellationToken).ConfigureAwait(false); return await updatedDocument.GetSyntaxRootAsync(fixAllContext.CancellationToken).ConfigureAwait(false); }
private static async Task<SyntaxNode> CreateNewDocumentSyntaxRootAsync(FixAllContext fixAllContext, Document document, CancellationToken cancellationToken) { var diagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var nodesToFix = diagnostics.Select(diagnostic => DefaulIfNullExpressionHelper.GetTargetExpression(diagnostic, root)); return root.ReplaceNodes(nodesToFix, (orignalNode, rewritten) => DefaulIfNullExpressionHelper.CreateRelacementNode(rewritten)); }
public async virtual Task AddDocumentFixesAsync(Document document, ImmutableArray<Diagnostic> diagnostics, Action<CodeAction> addFix, FixAllContext fixAllContext) { Debug.Assert(!diagnostics.IsDefault, "!diagnostics.IsDefault"); var cancellationToken = fixAllContext.CancellationToken; var fixerTasks = new Task[diagnostics.Length]; var fixes = new List<CodeAction>[diagnostics.Length]; for (var i = 0; i < diagnostics.Length; i++) { int currentFixIndex = i; cancellationToken.ThrowIfCancellationRequested(); var diagnostic = diagnostics[i]; fixerTasks[i] = Task.Run(async () => { var localFixes = new List<CodeAction>(); var context = new CodeFixContext( document, diagnostic, (a, d) => { // TODO: Can we share code between similar lambdas that we pass to this API in BatchFixAllProvider.cs, CodeFixService.cs and CodeRefactoringService.cs? // Serialize access for thread safety - we don't know what thread the fix provider will call this delegate from. lock (localFixes) { localFixes.Add(a); } }, cancellationToken); // TODO: Wrap call to ComputeFixesAsync() below in IExtensionManager.PerformFunctionAsync() so that // a buggy extension that throws can't bring down the host? var task = fixAllContext.CodeFixProvider.RegisterCodeFixesAsync(context) ?? SpecializedTasks.CompletedTask; await task.ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); localFixes.RemoveAll(action => action.EquivalenceKey != fixAllContext.CodeActionEquivalenceKey); fixes[currentFixIndex] = localFixes; }); } await Task.WhenAll(fixerTasks).ConfigureAwait(false); foreach (List<CodeAction> fix in fixes) { if (fix == null) { continue; } foreach (CodeAction action in fix) { addFix(action); } } }
public virtual async Task <ImmutableDictionary <Project, ImmutableArray <Diagnostic> > > GetProjectDiagnosticsToFixAsync(FixAllContext fixAllContext) { using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Diagnostics, fixAllContext.CancellationToken)) { var project = fixAllContext.Project; if (project != null) { switch (fixAllContext.Scope) { case FixAllScope.Project: var diagnostics = await fixAllContext.GetProjectDiagnosticsAsync(project).ConfigureAwait(false); var kvp = SpecializedCollections.SingletonEnumerable(KeyValuePair.Create(project, diagnostics)); return(ImmutableDictionary.CreateRange(kvp)); case FixAllScope.Solution: var projectsAndDiagnostics = new ConcurrentDictionary <Project, ImmutableArray <Diagnostic> >(); var options = new ParallelOptions() { CancellationToken = fixAllContext.CancellationToken }; Parallel.ForEach(project.Solution.Projects, options, proj => { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var projectDiagnostics = fixAllContext.GetProjectDiagnosticsAsync(proj).WaitAndGetResult(fixAllContext.CancellationToken); if (projectDiagnostics.Any()) { projectsAndDiagnostics.TryAdd(proj, projectDiagnostics); } }); return(projectsAndDiagnostics.ToImmutableDictionary()); } } return(ImmutableDictionary <Project, ImmutableArray <Diagnostic> > .Empty); } }
static async Task <ImmutableDictionary <Document, ImmutableArray <Diagnostic> > > GetDocumentDiagnosticsToFixWorkerAsync(FixAllContext fixAllContext) { if (fixAllContext.State.DiagnosticProvider is FixAllState.FixMultipleDiagnosticProvider fixMultipleDiagnosticProvider) { return(fixMultipleDiagnosticProvider.DocumentDiagnosticsMap); } using (Logger.LogBlock( FunctionId.CodeFixes_FixAllOccurrencesComputation_Document_Diagnostics, FixAllLogger.CreateCorrelationLogMessage(fixAllContext.State.CorrelationId), fixAllContext.CancellationToken)) { return(await FixAllContextHelper.GetDocumentDiagnosticsToFixAsync(fixAllContext).ConfigureAwait(false)); } }
public override async Task AddDocumentFixesAsync(Document document, ImmutableArray <Diagnostic> diagnostics, Action <CodeAction> addFix, FixAllContext fixAllContext) { var changedDocument = await AddSimplifierAnnotationsAsync(document, diagnostics, fixAllContext).ConfigureAwait(false); var title = GetFixAllTitle(fixAllContext); var codeAction = new MyCodeAction(title, (c) => Task.FromResult(changedDocument)); addFix(codeAction); }
/// <summary> /// Produce a suitable title for the fix-all <see cref="CodeAction"/> this type creates in <see /// cref="GetFixAsync(FixAllContext)"/>. Override this if customizing that title is desired. /// </summary> protected virtual string GetFixAllTitle(FixAllContext fixAllContext) => fixAllContext.GetDefaultFixAllTitle();
public sealed override Task <CodeAction?> GetFixAsync(FixAllContext fixAllContext) => DefaultFixAllProviderHelpers.GetFixAsync( fixAllContext.GetDefaultFixAllTitle(), fixAllContext, FixAllContextsHelperAsync);
private Task <Solution?> FixAllContextsHelperAsync(FixAllContext originalFixAllContext, ImmutableArray <FixAllContext> fixAllContexts) => DocumentBasedFixAllProviderHelpers.FixAllContextsAsync(originalFixAllContext, fixAllContexts, originalFixAllContext.GetProgressTracker(), this.GetFixAllTitle(originalFixAllContext), DetermineDiagnosticsAndGetFixedDocumentsAsync);
public virtual async Task <CodeAction> TryGetMergedFixAsync(IEnumerable <CodeAction> batchOfFixes, FixAllContext fixAllContext) { Contract.ThrowIfNull(batchOfFixes); Contract.ThrowIfFalse(batchOfFixes.Any()); var solution = fixAllContext.Solution; var cancellationToken = fixAllContext.CancellationToken; var newSolution = await TryMergeFixesAsync(solution, batchOfFixes, cancellationToken).ConfigureAwait(false); if (newSolution != null && newSolution != solution) { var title = GetFixAllTitle(fixAllContext); return(new CodeAction.SolutionChangeAction(title, _ => Task.FromResult(newSolution))); } return(null); }
public virtual async Task <ImmutableDictionary <Document, ImmutableArray <Diagnostic> > > GetDocumentDiagnosticsToFixAsync(FixAllContext fixAllContext) { using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Diagnostics, fixAllContext.CancellationToken)) { var allDiagnostics = ImmutableArray <Diagnostic> .Empty; var projectsToFix = ImmutableArray <Project> .Empty; var document = fixAllContext.Document; var project = fixAllContext.Project; var generatedCodeServices = project.Solution.Workspace.Services.GetService <IGeneratedCodeRecognitionService>(); switch (fixAllContext.Scope) { case FixAllScope.Document: if (document != null && !generatedCodeServices.IsGeneratedCode(document)) { var documentDiagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); var kvp = SpecializedCollections.SingletonEnumerable(KeyValuePair.Create(document, documentDiagnostics)); return(ImmutableDictionary.CreateRange(kvp)); } break; case FixAllScope.Project: projectsToFix = ImmutableArray.Create(project); allDiagnostics = await fixAllContext.GetAllDiagnosticsAsync(project).ConfigureAwait(false); break; case FixAllScope.Solution: projectsToFix = project.Solution.Projects .Where(p => p.Language == project.Language) .ToImmutableArray(); var diagnostics = new ConcurrentBag <Diagnostic>(); var tasks = new Task[projectsToFix.Length]; for (int i = 0; i < projectsToFix.Length; i++) { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); var projectToFix = projectsToFix[i]; tasks[i] = Task.Run(async() => { var projectDiagnostics = await fixAllContext.GetAllDiagnosticsAsync(projectToFix).ConfigureAwait(false); foreach (var diagnostic in projectDiagnostics) { fixAllContext.CancellationToken.ThrowIfCancellationRequested(); diagnostics.Add(diagnostic); } }, fixAllContext.CancellationToken); } await Task.WhenAll(tasks).ConfigureAwait(false); allDiagnostics = allDiagnostics.AddRange(diagnostics); break; } if (allDiagnostics.IsEmpty) { return(ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Empty); } return(await GetDocumentDiagnosticsToFixAsync(allDiagnostics, projectsToFix, generatedCodeServices.IsGeneratedCode, fixAllContext.CancellationToken).ConfigureAwait(false)); } }
private static Task <Solution?> GetProjectFixesAsync(FixAllContext fixAllContext, FixAllContexts fixAllContextsAsync) => fixAllContextsAsync(fixAllContext, ImmutableArray.Create(fixAllContext.WithDocumentAndProject(document: null, fixAllContext.Project)));
private static async Task <ImmutableDictionary <Document, ImmutableArray <Diagnostic> > > GetDocumentDiagnosticsToFixAsync(FixAllContext fixAllContext) { var result = await FixAllContextHelper.GetDocumentDiagnosticsToFixAsync(fixAllContext).ConfigureAwait(false); // Filter out any documents that we don't have any diagnostics for. return(result.Where(kvp => !kvp.Value.IsDefaultOrEmpty).ToImmutableDictionary()); }
public sealed override async Task <CodeAction?> GetFixAsync(FixAllContext fixAllContext) { var documentsAndDiagnosticsToFixMap = await GetDocumentDiagnosticsToFixAsync(fixAllContext).ConfigureAwait(false); return(await GetFixAsync(documentsAndDiagnosticsToFixMap, fixAllContext).ConfigureAwait(false)); }
public virtual Task AddProjectFixesAsync(Project project, IEnumerable <Diagnostic> diagnostics, Action <CodeAction> addFix, FixAllContext fixAllContext) { throw new NotImplementedException(); }
/// <summary> /// Determines all the diagnostics we should be fixing for the given <paramref name="fixAllContext"/>. /// </summary> private static async Task <ImmutableDictionary <Document, ImmutableArray <Diagnostic> > > DetermineDiagnosticsAsync(FixAllContext fixAllContext, IProgressTracker progressTracker) { using var _ = progressTracker.ItemCompletedScope(); return(await FixAllContextHelper.GetDocumentDiagnosticsToFixAsync(fixAllContext).ConfigureAwait(false)); }
/// <summary> /// Gets fix all occurrences fix for the given fixAllContext. /// </summary> public abstract Task <CodeAction> GetFixAsync(FixAllContext fixAllContext);
public static string GetDefaultFixAllTitle(FixAllContext fixAllContext) => GetDefaultFixAllTitle(fixAllContext.Scope, fixAllContext.DiagnosticIds, fixAllContext.Document, fixAllContext.Project);
internal virtual async Task <ImmutableDictionary <Project, ImmutableArray <Diagnostic> > > GetProjectDiagnosticsToFixAsync(FixAllContext fixAllContext) { using (Logger.LogBlock(FunctionId.CodeFixes_FixAllOccurrencesComputation_Diagnostics, fixAllContext.CancellationToken)) { var project = fixAllContext.Project; if (project != null) { switch (fixAllContext.Scope) { case FixAllScope.Project: var diagnostics = await fixAllContext.GetProjectDiagnosticsAsync(project).ConfigureAwait(false); var kvp = SpecializedCollections.SingletonEnumerable(KeyValuePair.Create(project, diagnostics)); return(ImmutableDictionary.CreateRange(kvp)); case FixAllScope.Solution: var projectsAndDiagnostics = ImmutableDictionary.CreateBuilder <Project, ImmutableArray <Diagnostic> >(); var tasks = project.Solution.Projects.Select(async p => new { Project = p, Diagnostics = await fixAllContext.GetProjectDiagnosticsAsync(p).ConfigureAwait(false) }).ToArray(); await Task.WhenAll(tasks).ConfigureAwait(false); foreach (var task in tasks) { if (task.Result.Diagnostics.Any()) { projectsAndDiagnostics[task.Result.Project] = task.Result.Diagnostics; } } return(projectsAndDiagnostics.ToImmutable()); } } return(ImmutableDictionary <Project, ImmutableArray <Diagnostic> > .Empty); } }
/// <summary> /// Fix all the <paramref name="diagnostics"/> present in <paramref name="document"/>. The document returned /// will only be examined for its content (e.g. it's <see cref="SyntaxTree"/> or <see cref="SourceText"/>. No /// other aspects of (like it's properties), or changes to the <see cref="Project"/> or <see cref="Solution"/> /// it points at will be considered. /// </summary> /// <param name="fixAllContext">The context for the Fix All operation.</param> /// <param name="document">The document to fix.</param> /// <param name="diagnostics">The diagnostics to fix in the document.</param> /// <returns> /// <para>The new <see cref="Document"/> representing the content fixed document.</para> /// <para>-or-</para> /// <para><see langword="null"/>, if no changes were made to the document.</para> /// </returns> protected abstract Task <Document?> FixAllAsync(FixAllContext fixAllContext, Document document, ImmutableArray <Diagnostic> diagnostics);
> GetDocumentDiagnosticsToFixAsync(FixAllContext fixAllContext) { var cancellationToken = fixAllContext.CancellationToken; var allDiagnostics = ImmutableArray <Diagnostic> .Empty; var document = fixAllContext.Document; var project = fixAllContext.Project; var progressTracker = fixAllContext.GetProgressTracker(); switch (fixAllContext.Scope) { case FixAllScope.Document: if ( document != null && !await document .IsGeneratedCodeAsync(cancellationToken) .ConfigureAwait(false) ) { var documentDiagnostics = await fixAllContext .GetDocumentDiagnosticsAsync(document) .ConfigureAwait(false); return(ImmutableDictionary < Document, ImmutableArray <Diagnostic> > .Empty.SetItem(document, documentDiagnostics)); } break; case FixAllScope.Project: allDiagnostics = await fixAllContext .GetAllDiagnosticsAsync(project) .ConfigureAwait(false); break; case FixAllScope.Solution: var projectsToFix = project.Solution.Projects .Where(p => p.Language == project.Language) .ToImmutableArray(); // Update the progress dialog with the count of projects to actually fix. We'll update the progress // bar as we get all the documents in AddDocumentDiagnosticsAsync. progressTracker.AddItems(projectsToFix.Length); var diagnostics = new ConcurrentDictionary <ProjectId, ImmutableArray <Diagnostic> >(); using ( var _ = ArrayBuilder <Task> .GetInstance(projectsToFix.Length, out var tasks) ) { foreach (var projectToFix in projectsToFix) { tasks.Add( Task.Run( async() => await AddDocumentDiagnosticsAsync(diagnostics, projectToFix) .ConfigureAwait(false), cancellationToken ) ); } await Task.WhenAll(tasks).ConfigureAwait(false); allDiagnostics = allDiagnostics.AddRange( diagnostics.SelectMany(i => i.Value) ); } break; } if (allDiagnostics.IsEmpty) { return(ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Empty); } return(await GetDocumentDiagnosticsToFixAsync( fixAllContext.Solution, allDiagnostics, fixAllContext.CancellationToken ) .ConfigureAwait(false)); async Task AddDocumentDiagnosticsAsync( ConcurrentDictionary <ProjectId, ImmutableArray <Diagnostic> > diagnostics, Project projectToFix ) { try { var projectDiagnostics = await fixAllContext .GetAllDiagnosticsAsync(projectToFix) .ConfigureAwait(false); diagnostics.TryAdd(projectToFix.Id, projectDiagnostics); } finally { progressTracker.ItemCompleted(); } } }
private async Task <Document> AddSimplifierAnnotationsAsync(Document document, ImmutableArray <Diagnostic> diagnostics, FixAllContext fixAllContext) { var cancellationToken = fixAllContext.CancellationToken; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); // Find all nodes to simplify corresponding to diagnostic spans. var nodesToSimplify = new List <SyntaxNode>(); foreach (var diagnostic in diagnostics) { string codeActionEquivalenceKey; var node = GetNodeToSimplify(root, model, diagnostic, fixAllContext.Solution.Workspace, out codeActionEquivalenceKey, cancellationToken); if (node != null && fixAllContext.CodeActionEquivalenceKey == codeActionEquivalenceKey) { nodesToSimplify.Add(node); } } // Add simplifier and formatter annotations to all nodes to simplify. // If the fix all provider needs to fixup any of the parent nodes, then we iterate through each of the nodesToSimplify // and fixup any parenting node, computing a new document with required simplifier annotations in each iteration. // Otherwise, if the fix all provider doesn't need parent fixup, we just add simplifier annotation to all nodesToSimplify. if (!NeedsParentFixup) { root = root.ReplaceNodes(nodesToSimplify, (o, n) => n.WithAdditionalAnnotations(Simplifier.Annotation, Formatter.Annotation)); } else { // Add a custom annotation to nodesToSimplify so we can get back to them later. var annotation = new SyntaxAnnotation(); root = root.ReplaceNodes(nodesToSimplify, (o, n) => o.WithAdditionalAnnotations(annotation)); document = document.WithSyntaxRoot(root); while (true) { root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var annotatedNodes = root.GetAnnotatedNodes(annotation); // Get the next un-processed node to simplify, processed nodes should have simplifier annotation. var annotatedNode = annotatedNodes.FirstOrDefault(n => !n.HasAnnotation(Simplifier.Annotation)); if (annotatedNode == null) { // All nodesToSimplify have been processed. // Remove all the custom annotations added for tracking nodesToSimplify. root = root.ReplaceNodes(annotatedNodes, (o, n) => o.WithoutAnnotations(annotation)); break; } document = await AddSimplifyAnnotationsAsync(document, annotatedNode, cancellationToken).ConfigureAwait(false); } } return(document.WithSyntaxRoot(root)); }
public static async Task <ImmutableDictionary <Document, ImmutableArray <Diagnostic> > > GetDocumentDiagnosticsToFixAsync( FixAllContext fixAllContext, IProgressTracker progressTrackerOpt) { var cancellationToken = fixAllContext.CancellationToken; var allDiagnostics = ImmutableArray <Diagnostic> .Empty; var projectsToFix = ImmutableArray <Project> .Empty; var document = fixAllContext.Document; var project = fixAllContext.Project; switch (fixAllContext.Scope) { case FixAllScope.Document: if (document != null && !await document.IsGeneratedCodeAsync(cancellationToken).ConfigureAwait(false)) { var documentDiagnostics = await fixAllContext.GetDocumentDiagnosticsAsync(document).ConfigureAwait(false); return(ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Empty.SetItem(document, documentDiagnostics)); } break; case FixAllScope.Project: projectsToFix = ImmutableArray.Create(project); allDiagnostics = await fixAllContext.GetAllDiagnosticsAsync(project).ConfigureAwait(false); break; case FixAllScope.Solution: projectsToFix = project.Solution.Projects .Where(p => p.Language == project.Language) .ToImmutableArray(); progressTrackerOpt?.AddItems(projectsToFix.Length); var diagnostics = new ConcurrentDictionary <ProjectId, ImmutableArray <Diagnostic> >(); var tasks = new Task[projectsToFix.Length]; for (var i = 0; i < projectsToFix.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); var projectToFix = projectsToFix[i]; tasks[i] = Task.Run(async() => { var projectDiagnostics = await fixAllContext.GetAllDiagnosticsAsync(projectToFix).ConfigureAwait(false); diagnostics.TryAdd(projectToFix.Id, projectDiagnostics); progressTrackerOpt?.ItemCompleted(); }, cancellationToken); } await Task.WhenAll(tasks).ConfigureAwait(false); allDiagnostics = allDiagnostics.AddRange(diagnostics.SelectMany(i => i.Value)); break; } if (allDiagnostics.IsEmpty) { return(ImmutableDictionary <Document, ImmutableArray <Diagnostic> > .Empty); } return(await GetDocumentDiagnosticsToFixAsync( allDiagnostics, projectsToFix, fixAllContext.CancellationToken).ConfigureAwait(false)); }
internal virtual Task <CodeAction> GetFixAsync( ImmutableDictionary <Project, ImmutableArray <Diagnostic> > projectsAndDiagnosticsToFixMap, FixAllContext fixAllContext) { return(Task.FromResult <CodeAction>(null)); }
private async Task <Document> FixDocumentAsync(Document key, ImmutableArray <Diagnostic> value, FixAllContext fixAllContext, IProgressTracker progressTracker) { try { return(await FixDocumentAsync(key, value, fixAllContext).ConfigureAwait(false)); } finally { progressTracker.ItemCompleted(); } }
private static Task <Solution?> GetDocumentFixesAsync(FixAllContext fixAllContext, FixAllContexts fixAllContextsAsync) => fixAllContextsAsync(fixAllContext, ImmutableArray.Create(fixAllContext));
public async virtual Task AddDocumentFixesAsync(Document document, ImmutableArray <Diagnostic> diagnostics, Action <CodeAction> addFix, FixAllContext fixAllContext) { Debug.Assert(!diagnostics.IsDefault); var cancellationToken = fixAllContext.CancellationToken; var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var fixerTasks = new Task[diagnostics.Length]; for (var i = 0; i < diagnostics.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); var diagnostic = diagnostics[i]; fixerTasks[i] = Task.Run(async() => { var fixes = new List <CodeAction>(); var context = new CodeFixContext(document, diagnostic, // 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(a); } }, cancellationToken); // TODO: Wrap call to ComputeFixesAsync() below in IExtensionManager.PerformFunctionAsync() so that // a buggy extension that throws can't bring down the host? var task = fixAllContext.CodeFixProvider.RegisterCodeFixesAsync(context) ?? SpecializedTasks.EmptyTask; await task.ConfigureAwait(false); foreach (var fix in fixes) { cancellationToken.ThrowIfCancellationRequested(); if (fix != null && fix.EquivalenceKey == fixAllContext.CodeActionEquivalenceKey) { addFix(fix); } } }); } await Task.WhenAll(fixerTasks).ConfigureAwait(false); }