-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update features to fork solution once instead of forking once per changed document. #73396
Changes from all commits
2161fd2
1c3bbe2
385732f
de2d16c
877cd52
40e0a1c
d83aace
293671a
f0cae2c
c07e1c7
f8b5f15
1ef30bd
26231b9
3f86104
d1260da
efc2a15
47f4a96
cbc0df0
a870326
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
using Microsoft.CodeAnalysis.PooledObjects; | ||
using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; | ||
using Microsoft.CodeAnalysis.Shared.Extensions; | ||
using Microsoft.CodeAnalysis.Shared.Utilities; | ||
using Microsoft.CodeAnalysis.Simplification; | ||
using Microsoft.CodeAnalysis.Text; | ||
using Roslyn.Utilities; | ||
|
@@ -487,32 +488,25 @@ private static SyntaxNode CreateImport(SyntaxGenerator syntaxGenerator, string n | |
|
||
var refLocationGroups = refLocationsInSolution.GroupBy(loc => loc.Document.Id); | ||
|
||
var fixedDocuments = await Task.WhenAll( | ||
refLocationGroups.Select(refInOneDocument => | ||
FixReferencingDocumentAsync( | ||
solutionWithChangedNamespace.GetRequiredDocument(refInOneDocument.Key), | ||
var fixedDocuments = await ProducerConsumer<(DocumentId documentId, SyntaxNode newRoot)>.RunParallelAsync( | ||
source: refLocationGroups, | ||
produceItems: static async (refInOneDocument, callback, args, cancellationToken) => | ||
{ | ||
var result = await FixReferencingDocumentAsync( | ||
args.solutionWithChangedNamespace.GetRequiredDocument(refInOneDocument.Key), | ||
refInOneDocument, | ||
newNamespace, | ||
fallbackOptions, | ||
cancellationToken))).ConfigureAwait(false); | ||
|
||
var solutionWithFixedReferences = await MergeDocumentChangesAsync(solutionWithChangedNamespace, fixedDocuments, cancellationToken).ConfigureAwait(false); | ||
args.newNamespace, | ||
args.fallbackOptions, | ||
cancellationToken).ConfigureAwait(false); | ||
callback((result.Id, await result.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false))); | ||
}, | ||
args: (solutionWithChangedNamespace, newNamespace, fallbackOptions), | ||
cancellationToken).ConfigureAwait(false); | ||
|
||
var solutionWithFixedReferences = solutionWithChangedNamespace.WithDocumentSyntaxRoots(fixedDocuments); | ||
return (solutionWithFixedReferences, refLocationGroups.SelectAsArray(g => g.Key)); | ||
} | ||
|
||
private static async Task<Solution> MergeDocumentChangesAsync(Solution originalSolution, Document[] changedDocuments, CancellationToken cancellationToken) | ||
{ | ||
foreach (var document in changedDocuments) | ||
{ | ||
originalSolution = originalSolution.WithDocumentSyntaxRoot( | ||
document.Id, | ||
await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false)); | ||
} | ||
|
||
return originalSolution; | ||
} | ||
|
||
private readonly struct LocationForAffectedSymbol(ReferenceLocation location, bool isReferenceToExtensionMethod) | ||
{ | ||
public ReferenceLocation ReferenceLocation { get; } = location; | ||
|
@@ -773,40 +767,39 @@ private static async Task<Solution> RemoveUnnecessaryImportsAsync( | |
CodeCleanupOptionsProvider fallbackOptions, | ||
CancellationToken cancellationToken) | ||
{ | ||
using var _ = PooledHashSet<DocumentId>.GetInstance(out var linkedDocumentsToSkip); | ||
var documentsToProcessBuilder = ArrayBuilder<Document>.GetInstance(); | ||
using var _1 = PooledHashSet<DocumentId>.GetInstance(out var linkedDocumentsToSkip); | ||
using var _2 = ArrayBuilder<Document>.GetInstance(out var documentsToProcess); | ||
|
||
foreach (var id in ids) | ||
{ | ||
if (linkedDocumentsToSkip.Contains(id)) | ||
{ | ||
continue; | ||
} | ||
|
||
var document = solution.GetRequiredDocument(id); | ||
linkedDocumentsToSkip.AddRange(document.GetLinkedDocumentIds()); | ||
documentsToProcessBuilder.Add(document); | ||
|
||
document = await RemoveUnnecessaryImportsWorkerAsync( | ||
document, | ||
CreateImports(document, names, withFormatterAnnotation: false), | ||
cancellationToken).ConfigureAwait(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this was wacky. we were updating the documents serially, and then doing a parallel processing of it below. |
||
solution = document.Project.Solution; | ||
documentsToProcess.Add(document); | ||
} | ||
|
||
var documentsToProcess = documentsToProcessBuilder.ToImmutableAndFree(); | ||
|
||
var changeDocuments = await Task.WhenAll(documentsToProcess.Select( | ||
doc => RemoveUnnecessaryImportsWorkerAsync( | ||
var changedDocuments = await ProducerConsumer<(DocumentId documentId, SyntaxNode newRoot)>.RunParallelAsync( | ||
source: documentsToProcess, | ||
produceItems: static async (doc, callback, args, cancellationToken) => | ||
{ | ||
var result = await RemoveUnnecessaryImportsWorkerAsync( | ||
doc, | ||
CreateImports(doc, names, withFormatterAnnotation: false), | ||
cancellationToken))).ConfigureAwait(false); | ||
CreateImports(doc, args.names, withFormatterAnnotation: false), | ||
args.fallbackOptions, | ||
cancellationToken).ConfigureAwait(false); | ||
callback((result.Id, await result.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false))); | ||
}, | ||
args: (names, fallbackOptions), | ||
cancellationToken).ConfigureAwait(false); | ||
|
||
return await MergeDocumentChangesAsync(solution, changeDocuments, cancellationToken).ConfigureAwait(false); | ||
return solution.WithDocumentSyntaxRoots(changedDocuments); | ||
|
||
async Task<Document> RemoveUnnecessaryImportsWorkerAsync( | ||
async static Task<Document> RemoveUnnecessaryImportsWorkerAsync( | ||
Document doc, | ||
IEnumerable<SyntaxNode> importsToRemove, | ||
CodeCleanupOptionsProvider fallbackOptions, | ||
CancellationToken token) | ||
{ | ||
var removeImportService = doc.GetRequiredLanguageService<IRemoveUnnecessaryImportsService>(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
using Microsoft.CodeAnalysis.Operations; | ||
using Microsoft.CodeAnalysis.Shared.Collections; | ||
using Microsoft.CodeAnalysis.Shared.Extensions; | ||
using Microsoft.CodeAnalysis.Shared.Utilities; | ||
using Roslyn.Utilities; | ||
|
||
namespace Microsoft.CodeAnalysis.IntroduceParameter; | ||
|
@@ -241,17 +242,26 @@ private async Task<Solution> IntroduceParameterAsync(Document originalDocument, | |
var rewriter = new IntroduceParameterDocumentRewriter(this, originalDocument, | ||
expression, methodSymbol, containingMethod, selectedCodeAction, fallbackOptions, allOccurrences); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i checked, and rewriter should be safe to use concurrently from within produceItems below. |
||
|
||
foreach (var (project, projectCallSites) in methodCallSites.GroupBy(kvp => kvp.Key.Project)) | ||
{ | ||
var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); | ||
foreach (var (document, invocations) in projectCallSites) | ||
var changedRoots = await ProducerConsumer<(DocumentId documentId, SyntaxNode newRoot)>.RunParallelAsync( | ||
source: methodCallSites.GroupBy(kvp => kvp.Key.Project), | ||
produceItems: static async (tuple, callback, rewriter, cancellationToken) => | ||
{ | ||
var newRoot = await rewriter.RewriteDocumentAsync(compilation, document, invocations, cancellationToken).ConfigureAwait(false); | ||
modifiedSolution = modifiedSolution.WithDocumentSyntaxRoot(document.Id, newRoot); | ||
} | ||
} | ||
|
||
return modifiedSolution; | ||
var (project, projectCallSites) = tuple; | ||
var compilation = await project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false); | ||
await RoslynParallel.ForEachAsync( | ||
projectCallSites, | ||
cancellationToken, | ||
async (tuple, cancellationToken) => | ||
{ | ||
var (document, invocations) = tuple; | ||
var newRoot = await rewriter.RewriteDocumentAsync(compilation, document, invocations, cancellationToken).ConfigureAwait(false); | ||
callback((document.Id, newRoot)); | ||
}).ConfigureAwait(false); | ||
}, | ||
args: rewriter, | ||
cancellationToken).ConfigureAwait(false); | ||
|
||
return modifiedSolution.WithDocumentSyntaxRoots(changedRoots); | ||
} | ||
|
||
/// <summary> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
view with whitespace off.