public SolutionChangeSummary(Solution oldSolution, Solution newSolution, SolutionChanges changes) { OldSolution = oldSolution; NewSolution = newSolution; foreach (var p in changes.GetProjectChanges()) { TotalProjectsAffected += 1; TotalFilesAffected += p.GetAddedDocuments().Count() + p.GetChangedDocuments().Count() + p.GetRemovedDocuments().Count() + p.GetAddedAdditionalDocuments().Count() + p.GetChangedAdditionalDocuments().Count() + p.GetRemovedAdditionalDocuments().Count(); if (p.GetAddedDocuments().Any() || p.GetRemovedDocuments().Any() || p.GetAddedAdditionalDocuments().Any() || p.GetRemovedAdditionalDocuments().Any() || p.GetAddedMetadataReferences().Any() || p.GetRemovedMetadataReferences().Any() || p.GetAddedProjectReferences().Any() || p.GetRemovedProjectReferences().Any() || p.GetAddedAnalyzerReferences().Any() || p.GetRemovedAnalyzerReferences().Any()) { TotalFilesAffected += 1; // The project file itself was affected too. } } var totalProjectsAddedOrRemoved = changes.GetAddedProjects().Count() + changes.GetRemovedProjects().Count(); TotalFilesAffected += totalProjectsAddedOrRemoved; TotalProjectsAffected += totalProjectsAddedOrRemoved; }
public SolutionChangeSummary(Solution oldSolution, Solution newSolution, SolutionChanges changes) { OldSolution = oldSolution; NewSolution = newSolution; foreach (var p in changes.GetProjectChanges()) { TotalProjectsAffected += 1; TotalFilesAffected += p.GetAddedDocuments().Count() + p.GetChangedDocuments().Count() + p.GetRemovedDocuments().Count() + p.GetAddedAdditionalDocuments().Count() + p.GetChangedAdditionalDocuments().Count() + p.GetRemovedAdditionalDocuments().Count() + p.GetAddedAnalyzerConfigDocuments().Count() + p.GetChangedAnalyzerConfigDocuments().Count() + p.GetRemovedAnalyzerConfigDocuments().Count(); if (p.GetAddedDocuments().Any() || p.GetRemovedDocuments().Any() || p.GetAddedAdditionalDocuments().Any() || p.GetRemovedAdditionalDocuments().Any() || p.GetAddedAnalyzerConfigDocuments().Any() || p.GetRemovedAnalyzerConfigDocuments().Any() || p.GetAddedMetadataReferences().Any() || p.GetRemovedMetadataReferences().Any() || p.GetAddedProjectReferences().Any() || p.GetRemovedProjectReferences().Any() || p.GetAddedAnalyzerReferences().Any() || p.GetRemovedAnalyzerReferences().Any()) { TotalFilesAffected += 1; // The project file itself was affected too. } } var totalProjectsAddedOrRemoved = changes.GetAddedProjects().Count() + changes.GetRemovedProjects().Count(); TotalFilesAffected += totalProjectsAddedOrRemoved; TotalProjectsAffected += totalProjectsAddedOrRemoved; }
/// <summary> /// Returns all the changed documents produced by fixing the list of provided <paramref /// name="orderedDiagnostics"/>. The documents will be returned such that fixed documents for a later /// diagnostic will appear later than those for an earlier diagnostic. /// </summary> private static async Task <ImmutableArray <Document> > GetAllChangedDocumentsInDiagnosticsOrderAsync( FixAllContext fixAllContext, ImmutableArray <Diagnostic> orderedDiagnostics) { var solution = fixAllContext.Solution; var cancellationToken = fixAllContext.CancellationToken; // Process each diagnostic, determine the code actions to fix it, then figure out the document changes // produced by that code action. using var _1 = ArrayBuilder <Task <ImmutableArray <Document> > > .GetInstance(out var tasks); foreach (var diagnostic in orderedDiagnostics) { var document = solution.GetRequiredDocument(diagnostic.Location.SourceTree !); cancellationToken.ThrowIfCancellationRequested(); tasks.Add(Task.Run(async() => { // Create a context that will add the reported code actions into this using var _2 = ArrayBuilder <CodeAction> .GetInstance(out var codeActions); var action = GetRegisterCodeFixAction(fixAllContext.CodeActionEquivalenceKey, codeActions); var context = new CodeFixContext(document, diagnostic.Location.SourceSpan, ImmutableArray.Create(diagnostic), action, fixAllContext.State.CodeActionOptionsProvider, isBlocking: false, cancellationToken); // Wait for the all the code actions to be reported for this diagnostic. var registerTask = fixAllContext.CodeFixProvider.RegisterCodeFixesAsync(context) ?? Task.CompletedTask; await registerTask.ConfigureAwait(false); // Now, process each code action and find out all the document changes caused by it. using var _3 = ArrayBuilder <Document> .GetInstance(out var changedDocuments); foreach (var codeAction in codeActions) { var changedSolution = await codeAction.GetChangedSolutionInternalAsync(cancellationToken: cancellationToken).ConfigureAwait(false); if (changedSolution != null) { var changedDocumentIds = new SolutionChanges(changedSolution, solution).GetProjectChanges().SelectMany(p => p.GetChangedDocuments()); changedDocuments.AddRange(changedDocumentIds.Select(id => changedSolution.GetRequiredDocument(id))); } } return(changedDocuments.ToImmutable()); }, cancellationToken)); } // Wait for all that work to finish. await Task.WhenAll(tasks).ConfigureAwait(false); // Flatten the set of changed documents. These will naturally still be ordered by the diagnostic that // caused the change. using var _4 = ArrayBuilder <Document> .GetInstance(out var result); foreach (var task in tasks) { result.AddRange(await task.ConfigureAwait(false)); } return(result.ToImmutable()); }
public static List <DocumentId> GetDocumentIdsToOpen(this Solution newSolution, Solution oldSolution) { List <DocumentId> result; try { SolutionChanges changes = newSolution.GetChanges(oldSolution); IEnumerable <DocumentId> first = changes.GetProjectChanges().SelectMany((ProjectChanges p) => p.GetAddedDocuments()); IEnumerable <DocumentId> second = changes.GetProjectChanges().SelectMany((ProjectChanges p) => p.GetChangedDocuments()); result = first.Concat(second).ToList <DocumentId>(); } catch (Exception) { result = new List <DocumentId>(); } return(result); }
public virtual async Task <Solution> TryMergeFixesAsync(Solution oldSolution, IEnumerable <CodeAction> codeActions, CancellationToken cancellationToken) { var changedDocumentsMap = new Dictionary <DocumentId, Document>(); Dictionary <DocumentId, List <Document> > documentsToMergeMap = null; foreach (var codeAction in codeActions) { // TODO: Parallelize GetChangedSolutionInternalAsync for codeActions var changedSolution = await codeAction.GetChangedSolutionInternalAsync(cancellationToken).ConfigureAwait(false); var solutionChanges = new SolutionChanges(changedSolution, oldSolution); // TODO: Handle added/removed documents // TODO: Handle changed/added/removed additional documents var documentIdsWithChanges = solutionChanges .GetProjectChanges() .SelectMany(p => p.GetChangedDocuments()); foreach (var documentId in documentIdsWithChanges) { var document = changedSolution.GetDocument(documentId); Document existingDocument; if (changedDocumentsMap.TryGetValue(documentId, out existingDocument)) { if (existingDocument != null) { changedDocumentsMap[documentId] = null; var documentsToMerge = new List <Document>(); documentsToMerge.Add(existingDocument); documentsToMerge.Add(document); documentsToMergeMap = documentsToMergeMap ?? new Dictionary <DocumentId, List <Document> >(); documentsToMergeMap[documentId] = documentsToMerge; } else { documentsToMergeMap[documentId].Add(document); } } else { changedDocumentsMap[documentId] = document; } } } var currentSolution = oldSolution; foreach (var kvp in changedDocumentsMap) { var document = kvp.Value; if (document != null) { var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); currentSolution = currentSolution.WithDocumentText(kvp.Key, documentText); } } if (documentsToMergeMap != null) { var mergedDocuments = new ConcurrentDictionary <DocumentId, SourceText>(); var documentsToMergeArray = documentsToMergeMap.ToImmutableArray(); bool mergeFailed = false; var mergeTasks = new Task[documentsToMergeArray.Length]; for (int i = 0; i < documentsToMergeArray.Length; i++) { var kvp = documentsToMergeArray[i]; var documentId = kvp.Key; var documentsToMerge = kvp.Value; var oldDocument = oldSolution.GetDocument(documentId); mergeTasks[i] = Task.Run(async() => { var appliedChanges = (await documentsToMerge[0].GetTextChangesAsync(oldDocument, cancellationToken).ConfigureAwait(false)).ToList(); foreach (var document in documentsToMerge.Skip(1)) { appliedChanges = await TryAddDocumentMergeChangesAsync( oldDocument, document, appliedChanges, cancellationToken).ConfigureAwait(false); if (appliedChanges == null) { mergeFailed = true; break; } } if (!mergeFailed) { var oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); var newText = oldText.WithChanges(appliedChanges); mergedDocuments.TryAdd(documentId, newText); } }); } await Task.WhenAll(mergeTasks).ConfigureAwait(false); if (mergeFailed) { return(null); } foreach (var kvp in mergedDocuments) { currentSolution = currentSolution.WithDocumentText(kvp.Key, kvp.Value); } } return(currentSolution); }
public virtual async Task<Solution> TryMergeFixesAsync(Solution oldSolution, IEnumerable<CodeAction> codeActions, CancellationToken cancellationToken) { var changedDocumentsMap = new Dictionary<DocumentId, Document>(); Dictionary<DocumentId, List<Document>> documentsToMergeMap = null; foreach (var codeAction in codeActions) { cancellationToken.ThrowIfCancellationRequested(); // TODO: Parallelize GetChangedSolutionInternalAsync for codeActions var changedSolution = await codeAction.GetChangedSolutionInternalAsync(cancellationToken: cancellationToken).ConfigureAwait(false); var solutionChanges = new SolutionChanges(changedSolution, oldSolution); // TODO: Handle added/removed documents // TODO: Handle changed/added/removed additional documents var documentIdsWithChanges = solutionChanges .GetProjectChanges() .SelectMany(p => p.GetChangedDocuments()); foreach (var documentId in documentIdsWithChanges) { cancellationToken.ThrowIfCancellationRequested(); var document = changedSolution.GetDocument(documentId); Document existingDocument; if (changedDocumentsMap.TryGetValue(documentId, out existingDocument)) { if (existingDocument != null) { changedDocumentsMap[documentId] = null; var documentsToMerge = new List<Document>(); documentsToMerge.Add(existingDocument); documentsToMerge.Add(document); documentsToMergeMap = documentsToMergeMap ?? new Dictionary<DocumentId, List<Document>>(); documentsToMergeMap[documentId] = documentsToMerge; } else { documentsToMergeMap[documentId].Add(document); } } else { changedDocumentsMap[documentId] = document; } } } var currentSolution = oldSolution; foreach (var kvp in changedDocumentsMap) { cancellationToken.ThrowIfCancellationRequested(); var document = kvp.Value; if (document != null) { var documentText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); currentSolution = currentSolution.WithDocumentText(kvp.Key, documentText); } } if (documentsToMergeMap != null) { var mergedDocuments = new ConcurrentDictionary<DocumentId, SourceText>(); var documentsToMergeArray = documentsToMergeMap.ToImmutableArray(); var mergeTasks = new Task[documentsToMergeArray.Length]; for (int i = 0; i < documentsToMergeArray.Length; i++) { cancellationToken.ThrowIfCancellationRequested(); var kvp = documentsToMergeArray[i]; var documentId = kvp.Key; var documentsToMerge = kvp.Value; var oldDocument = oldSolution.GetDocument(documentId); mergeTasks[i] = Task.Run(async () => { var appliedChanges = (await documentsToMerge[0].GetTextChangesAsync(oldDocument, cancellationToken).ConfigureAwait(false)).ToList(); foreach (var document in documentsToMerge.Skip(1)) { cancellationToken.ThrowIfCancellationRequested(); appliedChanges = await TryAddDocumentMergeChangesAsync( oldDocument, document, appliedChanges, cancellationToken).ConfigureAwait(false); } var oldText = await oldDocument.GetTextAsync(cancellationToken).ConfigureAwait(false); var newText = oldText.WithChanges(appliedChanges); mergedDocuments.TryAdd(documentId, newText); }); } await Task.WhenAll(mergeTasks).ConfigureAwait(false); foreach (var kvp in mergedDocuments) { cancellationToken.ThrowIfCancellationRequested(); currentSolution = currentSolution.WithDocumentText(kvp.Key, kvp.Value); } } return currentSolution; }
public static bool Any(this SolutionChanges solutionChanges) => solutionChanges.GetProjectChanges().Any(x => x.GetChangedDocuments().Any());