internal sealed override async Task <CodeAction> GetFixAsync( ImmutableDictionary <Document, ImmutableArray <Diagnostic> > documentsAndDiagnosticsToFixMap, FixAllState fixAllState, CancellationToken cancellationToken) { // Process all documents in parallel. var updatedDocumentTasks = documentsAndDiagnosticsToFixMap.Select( kvp => FixDocumentAsync(fixAllState, kvp.Key, kvp.Value, cancellationToken)); await Task.WhenAll(updatedDocumentTasks).ConfigureAwait(false); var currentSolution = fixAllState.Solution; foreach (var task in updatedDocumentTasks) { // 'await' the tasks so that if any completed in a canceled manner then we'll // throw the right exception here. Calling .Result on the tasks might end up // with AggregateExceptions being thrown instead. var updatedDocument = await task.ConfigureAwait(false); currentSolution = currentSolution.WithDocumentSyntaxRoot( updatedDocument.Id, await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false)); } var title = fixAllState.GetDefaultFixAllTitle(); return(new CodeAction.SolutionChangeAction(title, _ => Task.FromResult(currentSolution))); }
public static void LogState(FixAllState fixAllState, bool isInternalCodeFixProvider) { Logger.Log(FunctionId.CodeFixes_FixAllOccurrencesContext, KeyValueLogMessage.Create(m => { m[CorrelationId] = fixAllState.CorrelationId; if (isInternalCodeFixProvider) { m[CodeFixProvider] = fixAllState.CodeFixProvider.GetType().FullName; m[CodeActionEquivalenceKey] = fixAllState.CodeActionEquivalenceKey; m[LanguageName] = fixAllState.Project.Language; } else { m[CodeFixProvider] = fixAllState.CodeFixProvider.GetType().FullName.GetHashCode().ToString(); m[CodeActionEquivalenceKey] = fixAllState.CodeActionEquivalenceKey != null ? fixAllState.CodeActionEquivalenceKey.GetHashCode().ToString() : null; m[LanguageName] = fixAllState.Project.Language.GetHashCode().ToString(); } m[FixAllScope] = fixAllState.Scope.ToString(); switch (fixAllState.Scope) { case CodeFixes.FixAllScope.Project: m[DocumentCount] = fixAllState.Project.DocumentIds.Count; break; case CodeFixes.FixAllScope.Solution: m[DocumentCount] = fixAllState.Solution.Projects.Sum(p => p.DocumentIds.Count); break; } })); }
private async Task <ImmutableArray <(Diagnostic diagnostic, CodeAction action)> > GetDiagnosticsAndCodeActions( ImmutableDictionary <Document, ImmutableArray <Diagnostic> > documentsAndDiagnosticsToFixMap, FixAllState fixAllState, CancellationToken cancellationToken) { var fixesBag = new ConcurrentBag <(Diagnostic diagnostic, CodeAction action)>(); using (Logger.LogBlock( FunctionId.CodeFixes_FixAllOccurrencesComputation_Document_Fixes, FixAllLogger.CreateCorrelationLogMessage(fixAllState.CorrelationId), cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); var tasks = new List <Task>(); foreach (var kvp in documentsAndDiagnosticsToFixMap) { var document = kvp.Key; var diagnosticsToFix = kvp.Value; Debug.Assert(!diagnosticsToFix.IsDefaultOrEmpty); if (!diagnosticsToFix.IsDefaultOrEmpty) { tasks.Add(AddDocumentFixesAsync( document, diagnosticsToFix, fixesBag, fixAllState, cancellationToken)); } } await Task.WhenAll(tasks).ConfigureAwait(false); } return(fixesBag.ToImmutableArray()); }
internal override async Task <CodeAction> GetFixAsync( ImmutableDictionary <Document, ImmutableArray <Diagnostic> > documentsAndDiagnosticsToFixMap, FixAllState fixAllState, CancellationToken cancellationToken) { if (documentsAndDiagnosticsToFixMap?.Any() == true) { FixAllLogger.LogDiagnosticsStats(fixAllState.CorrelationId, documentsAndDiagnosticsToFixMap); var diagnosticsAndCodeActions = await GetDiagnosticsAndCodeActions( documentsAndDiagnosticsToFixMap, fixAllState, cancellationToken).ConfigureAwait(false); if (diagnosticsAndCodeActions.Length > 0) { var functionId = FunctionId.CodeFixes_FixAllOccurrencesComputation_Document_Merge; using (Logger.LogBlock(functionId, FixAllLogger.CreateCorrelationLogMessage(fixAllState.CorrelationId), cancellationToken)) { FixAllLogger.LogFixesToMergeStats(functionId, fixAllState.CorrelationId, diagnosticsAndCodeActions.Length); return(await TryGetMergedFixAsync( diagnosticsAndCodeActions, fixAllState, cancellationToken).ConfigureAwait(false)); } } } return(null); }
internal FixAllContext( FixAllState state, IProgressTracker progressTracker, CancellationToken cancellationToken) { State = state; this.ProgressTracker = progressTracker; this.CancellationToken = cancellationToken; }
public CodeFixCollection( object provider, TextSpan span, ImmutableArray <CodeFix> fixes, FixAllState fixAllState, ImmutableArray <FixAllScope> supportedScopes, Diagnostic firstDiagnostic) { Provider = provider; TextSpan = span; Fixes = fixes.NullToEmpty(); FixAllState = fixAllState; SupportedScopes = supportedScopes.NullToEmpty(); FirstDiagnostic = firstDiagnostic; }
private async Task <Document> FixDocumentAsync( FixAllState fixAllState, Document document, ImmutableArray <Diagnostic> diagnostics, CancellationToken cancellationToken) { // Ensure that diagnostics for this document are always in document location // order. This provides a consistent and deterministic order for fixers // that want to update a document. // Also ensure that we do not pass in duplicates by invoking Distinct. // See https://github.com/dotnet/roslyn/issues/31381, that seems to be causing duplicate diagnostics. var filteredDiagnostics = diagnostics.Distinct() .WhereAsArray(d => _codeFixProvider.IncludeDiagnosticDuringFixAll(fixAllState, d, cancellationToken)) .Sort((d1, d2) => d1.Location.SourceSpan.Start - d2.Location.SourceSpan.Start); // PERF: Do not invoke FixAllAsync on the code fix provider if there are no diagnostics to be fixed. if (filteredDiagnostics.Length == 0) { return(document); } return(await _codeFixProvider.FixAllAsync(document, filteredDiagnostics, cancellationToken).ConfigureAwait(false)); }
internal FixSomeCodeAction( FixAllState fixAllState, bool showPreviewChangesDialog) { FixAllState = fixAllState; _showPreviewChangesDialog = showPreviewChangesDialog; }
internal virtual Task <CodeAction> GetFixAsync( ImmutableDictionary <Project, ImmutableArray <Diagnostic> > projectsAndDiagnosticsToFixMap, FixAllState fixAllState, CancellationToken cancellationToken) { return(Task.FromResult <CodeAction>(null)); }
/// <summary> /// Whether or not this diagnostic should be included when performing a FixAll. This is /// useful for providers that create multiple diagnostics for the same issue (For example, /// one main diagnostic and multiple 'faded out code' diagnostics). FixAll can be invoked /// from any of those, but we'll only want perform an edit for only one diagnostic for each /// of those sets of diagnostics. /// /// This overload differs from <see cref="IncludeDiagnosticDuringFixAll(Diagnostic)"/> in /// that it also passes along the <see cref="FixAllState"/> in case that would be useful /// (for example if the <see cref="FixAllState.CodeActionEquivalenceKey"/> is used. /// /// Only one of these two overloads needs to be overridden if you want to customize /// behavior. /// </summary> protected virtual bool IncludeDiagnosticDuringFixAll(FixAllState fixAllState, Diagnostic diagnostic, CancellationToken cancellationToken) => IncludeDiagnosticDuringFixAll(diagnostic);