Пример #1
0
        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;
        }
Пример #2
0
        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;
        }
Пример #3
0
        /// <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());
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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;
        }
Пример #7
0
 public static bool Any(this SolutionChanges solutionChanges)
 => solutionChanges.GetProjectChanges().Any(x => x.GetChangedDocuments().Any());