public ConflictResolution( Solution oldSolution, RenamedSpansTracker renamedSpansTracker, string replacementText, bool replacementTextValid) { _oldSolution = oldSolution; _newSolution = oldSolution; _intermediateSolutionContainingOnlyModifiedDocuments = oldSolution; _renamedSpansTracker = renamedSpansTracker; ReplacementText = replacementText; ReplacementTextValid = replacementTextValid; _relatedLocations = new List<RelatedLocation>(); }
public ConflictResolution( Solution oldSolution, RenamedSpansTracker renamedSpansTracker, string replacementText, bool replacementTextValid) { _oldSolution = oldSolution; _newSolution = oldSolution; _intermediateSolutionContainingOnlyModifiedDocuments = oldSolution; _renamedSpansTracker = renamedSpansTracker; ReplacementText = replacementText; ReplacementTextValid = replacementTextValid; _relatedLocations = new List <RelatedLocation>(); }
public RenameRewriterParameters( RenameAnnotation renamedSymbolDeclarationAnnotation, Document document, SemanticModel semanticModel, SyntaxNode syntaxRoot, string replacementText, string originalText, ICollection<string> possibleNameConflicts, Dictionary<TextSpan, RenameLocation> renameLocations, ISet<TextSpan> stringAndCommentTextSpans, ISet<TextSpan> conflictLocationSpans, Solution originalSolution, ISymbol renameSymbol, bool replacementTextValid, CancellationToken cancellationToken, RenamedSpansTracker renameSpansTracker, OptionSet optionSet, AnnotationTable<RenameAnnotation> renameAnnotations) { this.RenamedSymbolDeclarationAnnotation = renamedSymbolDeclarationAnnotation; this.Document = document; this.SemanticModel = semanticModel; this.SyntaxRoot = syntaxRoot; this.OriginalSyntaxTree = semanticModel.SyntaxTree; this.ReplacementText = replacementText; this.OriginalText = originalText; this.PossibleNameConflicts = possibleNameConflicts; this.RenameLocations = renameLocations; this.StringAndCommentTextSpans = stringAndCommentTextSpans; this.ConflictLocationSpans = conflictLocationSpans; this.OriginalSolution = originalSolution; this.RenameSymbol = renameSymbol; this.ReplacementTextValid = replacementTextValid; this.CancellationToken = cancellationToken; this.RenameSpansTracker = renameSpansTracker; this.OptionSet = optionSet; this.RenameAnnotations = renameAnnotations; }
// The rename process and annotation for the bookkeeping is performed in one-step private async Task <Solution> AnnotateAndRename_WorkerAsync( Solution originalSolution, Solution partiallyRenamedSolution, HashSet <DocumentId> documentIdsToRename, ISet <RenameLocation> renameLocations, RenamedSpansTracker renameSpansTracker, bool replacementTextValid) { try { foreach (var documentId in documentIdsToRename.ToList()) { _cancellationToken.ThrowIfCancellationRequested(); var document = originalSolution.GetDocument(documentId); var semanticModel = await document.GetSemanticModelAsync(_cancellationToken).ConfigureAwait(false); var originalSyntaxRoot = await semanticModel.SyntaxTree.GetRootAsync(_cancellationToken).ConfigureAwait(false); // Get all rename locations for the current document. var allTextSpansInSingleSourceTree = renameLocations .Where(l => l.DocumentId == documentId && ShouldIncludeLocation(renameLocations, l)) .ToDictionary(l => l.Location.SourceSpan); // All textspan in the document documentId, that requires rename in String or Comment var stringAndCommentTextSpansInSingleSourceTree = renameLocations .Where(l => l.DocumentId == documentId && l.IsRenameInStringOrComment) .GroupBy(l => l.ContainingLocationForStringOrComment) .Select(g => g.Key) .ToSet(); var conflictLocationSpans = _conflictLocations .Where(t => t.DocumentId == documentId) .Select(t => t.ComplexifiedSpan).ToSet(); // Annotate all nodes with a RenameLocation annotations to record old locations & old referenced symbols. // Also annotate nodes that should get complexified (nodes for rename locations + conflict locations) var parameters = new RenameRewriterParameters( _renamedSymbolDeclarationAnnotation, document, semanticModel, originalSyntaxRoot, _replacementText, _originalText, _possibleNameConflicts, allTextSpansInSingleSourceTree, stringAndCommentTextSpansInSingleSourceTree, conflictLocationSpans, originalSolution, _renameLocationSet.Symbol, replacementTextValid, renameSpansTracker, _optionSet, _renameAnnotations, _cancellationToken); var renameRewriterLanguageService = document.GetLanguageService <IRenameRewriterLanguageService>(); var newRoot = renameRewriterLanguageService.AnnotateAndRename(parameters); if (newRoot == originalSyntaxRoot) { // Update the list for the current phase, some files with strings containing the original or replacement // text may have been filtered out. documentIdsToRename.Remove(documentId); } else { partiallyRenamedSolution = partiallyRenamedSolution.WithDocumentSyntaxRoot(documentId, newRoot, PreservationMode.PreserveIdentity); } } return(partiallyRenamedSolution); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
// The method which performs rename, resolves the conflict locations and returns the result of the rename operation public async Task <ConflictResolution> ResolveConflictsAsync() { try { await FindDocumentsAndPossibleNameConflicts().ConfigureAwait(false); var baseSolution = _renameLocationSet.Solution; // Process rename one project at a time to improve caching and reduce syntax tree serialization. var documentsGroupedByTopologicallySortedProjectId = _documentsIdsToBeCheckedForConflict .GroupBy(d => d.ProjectId) .OrderBy(g => _topologicallySortedProjects.IndexOf(g.Key)); _replacementTextValid = IsIdentifierValid_Worker(baseSolution, _replacementText, documentsGroupedByTopologicallySortedProjectId.Select(g => g.Key), _cancellationToken); var renamedSpansTracker = new RenamedSpansTracker(); var conflictResolution = new ConflictResolution(baseSolution, renamedSpansTracker, _replacementText, _replacementTextValid); foreach (var documentsByProject in documentsGroupedByTopologicallySortedProjectId) { var documentIdsThatGetsAnnotatedAndRenamed = new HashSet <DocumentId>(documentsByProject); using (baseSolution.Services.CacheService?.EnableCaching(documentsByProject.Key)) { // Rename is going to be in 5 phases. // 1st phase - Does a simple token replacement // If the 1st phase results in conflict then we perform then: // 2nd phase is to expand and simplify only the reference locations with conflicts // 3rd phase is to expand and simplify all the conflict locations (both reference and non-reference) // If there are unresolved Conflicts after the 3rd phase then in 4th phase, // We complexify and resolve locations that were resolvable and for the other locations we perform the normal token replacement like the first the phase. // If the OptionSet has RenameFile to true, we rename files with the type declaration for (var phase = 0; phase < 4; phase++) { // Step 1: // The rename process and annotation for the bookkeeping is performed in one-step // The Process in short is, // 1. If renaming a token which is no conflict then replace the token and make a map of the oldspan to the newspan // 2. If we encounter a node that has to be expanded( because there was a conflict in previous phase), we expand it. // If the node happens to contain a token that needs to be renamed then we annotate it and rename it after expansion else just expand and proceed // 3. Through the whole process we maintain a map of the oldspan to newspan. In case of expansion & rename, we map the expanded node and the renamed token conflictResolution.UpdateCurrentSolution(await AnnotateAndRename_WorkerAsync( baseSolution, conflictResolution.NewSolution, documentIdsThatGetsAnnotatedAndRenamed, _renameLocationSet.Locations, renamedSpansTracker, _replacementTextValid).ConfigureAwait(false)); // Step 2: Check for conflicts in the renamed solution var foundResolvableConflicts = await IdentifyConflictsAsync( documentIdsForConflictResolution : documentIdsThatGetsAnnotatedAndRenamed, allDocumentIdsInProject : documentsByProject, projectId : documentsByProject.Key, conflictResolution : conflictResolution).ConfigureAwait(false); if (!foundResolvableConflicts || phase == 3) { break; } if (phase == 0) { _conflictLocations = conflictResolution.RelatedLocations .Where(loc => (documentIdsThatGetsAnnotatedAndRenamed.Contains(loc.DocumentId) && loc.Type == RelatedLocationType.PossiblyResolvableConflict && loc.IsReference)) .Select(loc => new ConflictLocationInfo(loc)) .ToSet(); // If there were no conflicting locations in references, then the first conflict phase has to be skipped. if (_conflictLocations.Count == 0) { phase++; } } if (phase == 1) { _conflictLocations = _conflictLocations.Concat(conflictResolution.RelatedLocations .Where(loc => documentIdsThatGetsAnnotatedAndRenamed.Contains(loc.DocumentId) && loc.Type == RelatedLocationType.PossiblyResolvableConflict) .Select(loc => new ConflictLocationInfo(loc))) .ToSet(); } // Set the documents with conflicts that need to be processed in the next phase. // Note that we need to get the conflictLocations here since we're going to remove some locations below if phase == 2 documentIdsThatGetsAnnotatedAndRenamed = new HashSet <DocumentId>(_conflictLocations.Select(l => l.DocumentId)); if (phase == 2) { // After phase 2, if there are still conflicts then remove the conflict locations from being expanded var unresolvedLocations = conflictResolution.RelatedLocations .Where(l => (l.Type & RelatedLocationType.UnresolvedConflict) != 0) .Select(l => Tuple.Create(l.ComplexifiedTargetSpan, l.DocumentId)).Distinct(); _conflictLocations = _conflictLocations.Where(l => !unresolvedLocations.Any(c => c.Item2 == l.DocumentId && c.Item1.Contains(l.OriginalIdentifierSpan))).ToSet(); } // Clean up side effects from rename before entering the next phase conflictResolution.ClearDocuments(documentIdsThatGetsAnnotatedAndRenamed); } // Step 3: Simplify the project conflictResolution.UpdateCurrentSolution(await renamedSpansTracker.SimplifyAsync(conflictResolution.NewSolution, documentsByProject, _replacementTextValid, _renameAnnotations, _cancellationToken).ConfigureAwait(false)); await conflictResolution.RemoveAllRenameAnnotationsAsync(documentsByProject, _renameAnnotations, _cancellationToken).ConfigureAwait(false); } } // This rename could break implicit references of this symbol (e.g. rename MoveNext on a collection like type in a // foreach/for each statement var renamedSymbolInNewSolution = await GetRenamedSymbolInCurrentSolutionAsync(conflictResolution).ConfigureAwait(false); if (IsRenameValid(conflictResolution, renamedSymbolInNewSolution)) { await AddImplicitConflictsAsync( renamedSymbolInNewSolution, _renameLocationSet.Symbol, _renameLocationSet.ImplicitLocations, await conflictResolution.NewSolution.GetDocument(_documentIdOfRenameSymbolDeclaration).GetSemanticModelAsync(_cancellationToken).ConfigureAwait(false), _renameSymbolDeclarationLocation, renamedSpansTracker.GetAdjustedPosition(_renameSymbolDeclarationLocation.SourceSpan.Start, _documentIdOfRenameSymbolDeclaration), conflictResolution, _cancellationToken).ConfigureAwait(false); } foreach (var relatedLocation in conflictResolution.RelatedLocations) { if (relatedLocation.Type == RelatedLocationType.PossiblyResolvableConflict) { relatedLocation.Type = RelatedLocationType.UnresolvedConflict; } } #if DEBUG await DebugVerifyNoErrorsAsync(conflictResolution, _documentsIdsToBeCheckedForConflict).ConfigureAwait(false); #endif // Step 5: Rename declaration files if (_optionSet.GetOption(RenameOptions.RenameFile)) { var definitionLocations = _renameLocationSet.Symbol.Locations; var definitionDocuments = definitionLocations .Select(l => conflictResolution.OldSolution.GetDocument(l.SourceTree)) .Distinct(); if (definitionDocuments.Count() == 1) { // At the moment, only single document renaming is allowed conflictResolution.RenameDocumentToMatchNewSymbol(definitionDocuments.Single()); } } return(conflictResolution); } catch (Exception e) when(FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
// The method which performs rename, resolves the conflict locations and returns the result of the rename operation public async Task<ConflictResolution> ResolveConflictsAsync() { try { await FindDocumentsAndPossibleNameConflicts().ConfigureAwait(false); var baseSolution = _renameLocationSet.Solution; // Process rename one project at a time to improve caching and reduce syntax tree serialization. var documentsGroupedByTopologicallySortedProjectId = _documentsIdsToBeCheckedForConflict .GroupBy(d => d.ProjectId) .OrderBy(g => _topologicallySortedProjects.IndexOf(g.Key)); _replacementTextValid = IsIdentifierValid_Worker(baseSolution, _replacementText, documentsGroupedByTopologicallySortedProjectId.Select(g => g.Key), _cancellationToken); var renamedSpansTracker = new RenamedSpansTracker(); var conflictResolution = new ConflictResolution(baseSolution, renamedSpansTracker, _replacementText, _replacementTextValid); foreach (var documentsByProject in documentsGroupedByTopologicallySortedProjectId) { var documentIdsThatGetsAnnotatedAndRenamed = new HashSet<DocumentId>(documentsByProject); using (baseSolution.Services.CacheService?.EnableCaching(documentsByProject.Key)) { // Rename is going to be in 4 phases. // 1st phase - Does a simple token replacement // If the 1st phase results in conflict then we perform then: // 2nd phase is to expand and simplify only the reference locations with conflicts // 3rd phase is to expand and simplify all the conflict locations (both reference and non-reference) // If there are unresolved Conflicts after the 3rd phase then in 4th phase, // We complexify and resolve locations that were resolvable and for the other locations we perform the normal token replacement like the first the phase. for (int phase = 0; phase < 4; phase++) { // Step 1: // The rename process and annotation for the bookkeeping is performed in one-step // The Process in short is, // 1. If renaming a token which is no conflict then replace the token and make a map of the oldspan to the newspan // 2. If we encounter a node that has to be expanded( because there was a conflict in previous phase), we expand it. // If the node happens to contain a token that needs to be renamed then we annotate it and rename it after expansion else just expand and proceed // 3. Through the whole process we maintain a map of the oldspan to newspan. In case of expansion & rename, we map the expanded node and the renamed token conflictResolution.UpdateCurrentSolution(await AnnotateAndRename_WorkerAsync( baseSolution, conflictResolution.NewSolution, documentIdsThatGetsAnnotatedAndRenamed, _renameLocationSet.Locations, renamedSpansTracker, _replacementTextValid).ConfigureAwait(false)); // Step 2: Check for conflicts in the renamed solution bool foundResolvableConflicts = await IdentifyConflictsAsync( documentIdsForConflictResolution: documentIdsThatGetsAnnotatedAndRenamed, allDocumentIdsInProject: documentsByProject, projectId: documentsByProject.Key, conflictResolution: conflictResolution).ConfigureAwait(false); if (!foundResolvableConflicts || phase == 3) { break; } if (phase == 0) { _conflictLocations = conflictResolution.RelatedLocations .Where(loc => (documentIdsThatGetsAnnotatedAndRenamed.Contains(loc.DocumentId) && loc.Type == RelatedLocationType.PossiblyResolvableConflict && loc.IsReference)) .Select(loc => new ConflictLocationInfo(loc)) .ToSet(); // If there were no conflicting locations in references, then the first conflict phase has to be skipped. if (_conflictLocations.Count == 0) { phase++; } } if (phase == 1) { _conflictLocations = _conflictLocations.Concat(conflictResolution.RelatedLocations .Where(loc => documentIdsThatGetsAnnotatedAndRenamed.Contains(loc.DocumentId) && loc.Type == RelatedLocationType.PossiblyResolvableConflict) .Select(loc => new ConflictLocationInfo(loc))) .ToSet(); } // Set the documents with conflicts that need to be processed in the next phase. // Note that we need to get the conflictLocations here since we're going to remove some locations below if phase == 2 documentIdsThatGetsAnnotatedAndRenamed = new HashSet<DocumentId>(_conflictLocations.Select(l => l.DocumentId)); if (phase == 2) { // After phase 2, if there are still conflicts then remove the conflict locations from being expanded var unresolvedLocations = conflictResolution.RelatedLocations .Where(l => (l.Type & RelatedLocationType.UnresolvedConflict) != 0) .Select(l => Tuple.Create(l.ComplexifiedTargetSpan, l.DocumentId)).Distinct(); _conflictLocations = _conflictLocations.Where(l => !unresolvedLocations.Any(c => c.Item2 == l.DocumentId && c.Item1.Contains(l.OriginalIdentifierSpan))).ToSet(); } // Clean up side effects from rename before entering the next phase conflictResolution.ClearDocuments(documentIdsThatGetsAnnotatedAndRenamed); } // Step 3: Simplify the project conflictResolution.UpdateCurrentSolution(await renamedSpansTracker.SimplifyAsync(conflictResolution.NewSolution, documentsByProject, _replacementTextValid, _renameAnnotations, _cancellationToken).ConfigureAwait(false)); conflictResolution.RemoveAllRenameAnnotations(documentsByProject, _renameAnnotations, _cancellationToken); } } // This rename could break implicit references of this symbol (e.g. rename MoveNext on a collection like type in a // foreach/for each statement ISymbol renamedSymbolInNewSolution = await GetRenamedSymbolInCurrentSolutionAsync(conflictResolution).ConfigureAwait(false); if (IsRenameValid(conflictResolution, renamedSymbolInNewSolution)) { AddImplicitConflicts( renamedSymbolInNewSolution, _renameLocationSet.Symbol, _renameLocationSet.ImplicitLocations, await conflictResolution.NewSolution.GetDocument(_documentIdOfRenameSymbolDeclaration).GetSemanticModelAsync(_cancellationToken).ConfigureAwait(false), _renameSymbolDeclarationLocation, renamedSpansTracker.GetAdjustedPosition(_renameSymbolDeclarationLocation.SourceSpan.Start, _documentIdOfRenameSymbolDeclaration), conflictResolution, _cancellationToken); } foreach (var relatedLocation in conflictResolution.RelatedLocations) { if (relatedLocation.Type == RelatedLocationType.PossiblyResolvableConflict) { relatedLocation.Type = RelatedLocationType.UnresolvedConflict; } } #if DEBUG DebugVerifyNoErrors(conflictResolution, _documentsIdsToBeCheckedForConflict); #endif return conflictResolution; } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
// The rename process and annotation for the bookkeeping is performed in one-step private async Task<Solution> AnnotateAndRename_WorkerAsync( Solution originalSolution, Solution partiallyRenamedSolution, HashSet<DocumentId> documentIdsToRename, IEnumerable<RenameLocation> renameLocations, RenamedSpansTracker renameSpansTracker, bool replacementTextValid) { try { foreach (var documentId in documentIdsToRename.ToList()) { _cancellationToken.ThrowIfCancellationRequested(); // We try to rewrite all locations that are not candidate locations. If there is only one location // it must be the correct one (the symbol is ambiguous to something else) and we always try to rewrite it. var document = originalSolution.GetDocument(documentId); var semanticModel = await document.GetSemanticModelAsync(_cancellationToken).ConfigureAwait(false); var originalSyntaxRoot = await semanticModel.SyntaxTree.GetRootAsync(_cancellationToken).ConfigureAwait(false); // Get all rename locations for the current document. var allTextSpansInSingleSourceTree = renameLocations .Where(l => l.DocumentId == documentId && !l.IsRenameInStringOrComment && (renameLocations.Count() == 1 || !l.IsCandidateLocation || l.IsMethodGroupReference)) .ToDictionary(l => l.Location.SourceSpan); // All textspan in the document documentId, that requires rename in String or Comment var stringAndCommentTextSpansInSingleSourceTree = renameLocations .Where(l => l.DocumentId == documentId && l.IsRenameInStringOrComment) .GroupBy(l => l.ContainingLocationForStringOrComment) .Select(g => g.Key) .ToSet(); var conflictLocationSpans = _conflictLocations .Where(t => t.DocumentId == documentId) .Select(t => t.ComplexifiedSpan).ToSet(); // Annotate all nodes with a RenameLocation annotations to record old locations & old referenced symbols. // Also annotate nodes that should get complexified (nodes for rename locations + conflict locations) var parameters = new RenameRewriterParameters( _renamedSymbolDeclarationAnnotation, document, semanticModel, originalSyntaxRoot, _replacementText, _originalText, _possibleNameConflicts, allTextSpansInSingleSourceTree, stringAndCommentTextSpansInSingleSourceTree, conflictLocationSpans, originalSolution, _renameLocationSet.Symbol, replacementTextValid, renameSpansTracker, _optionSet, _renameAnnotations, _cancellationToken); var renameRewriterLanguageService = document.Project.LanguageServices.GetService<IRenameRewriterLanguageService>(); var newRoot = renameRewriterLanguageService.AnnotateAndRename(parameters); if (newRoot == originalSyntaxRoot) { // Update the list for the current phase, some files with strings containing the original or replacement // text may have been filtered out. documentIdsToRename.Remove(documentId); } else { partiallyRenamedSolution = partiallyRenamedSolution.WithDocumentSyntaxRoot(documentId, newRoot, PreservationMode.PreserveIdentity); } } return partiallyRenamedSolution; } catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }
public RenameRewriter(RenameRewriterParameters parameters) : base(visitIntoStructuredTrivia: true) { _documentId = parameters.Document.Id; _renameRenamableSymbolDeclaration = parameters.RenamedSymbolDeclarationAnnotation; _solution = parameters.OriginalSolution; _replacementText = parameters.ReplacementText; _originalText = parameters.OriginalText; _possibleNameConflicts = parameters.PossibleNameConflicts; _renameLocations = parameters.RenameLocations; _conflictLocations = parameters.ConflictLocationSpans; _cancellationToken = parameters.CancellationToken; _semanticModel = parameters.SemanticModel; _renamedSymbol = parameters.RenameSymbol; _replacementTextValid = parameters.ReplacementTextValid; _renameSpansTracker = parameters.RenameSpansTracker; _isRenamingInStrings = parameters.OptionSet.GetOption(RenameOptions.RenameInStrings); _isRenamingInComments = parameters.OptionSet.GetOption(RenameOptions.RenameInComments); _stringAndCommentTextSpans = parameters.StringAndCommentTextSpans; _renameAnnotations = parameters.RenameAnnotations; _aliasSymbol = _renamedSymbol as IAliasSymbol; _renamableDeclarationLocation = _renamedSymbol.Locations.FirstOrDefault(loc => loc.IsInSource && loc.SourceTree == _semanticModel.SyntaxTree); _isVerbatim = _replacementText.StartsWith("@", StringComparison.Ordinal); _simplificationService = parameters.Document.Project.LanguageServices.GetService<ISimplificationService>(); _semanticFactsService = parameters.Document.Project.LanguageServices.GetService<ISemanticFactsService>(); }
public RenameRewriter(RenameRewriterParameters parameters) : base(visitIntoStructuredTrivia: true) { this.documentId = parameters.Document.Id; this.renameRenamableSymbolDeclaration = parameters.RenamedSymbolDeclarationAnnotation; this.solution = parameters.OriginalSolution; this.replacementText = parameters.ReplacementText; this.originalText = parameters.OriginalText; this.possibleNameConflicts = parameters.PossibleNameConflicts; this.renameLocations = parameters.RenameLocations; this.conflictLocations = parameters.ConflictLocationSpans; this.cancellationToken = parameters.CancellationToken; this.semanticModel = (SemanticModel)parameters.SemanticModel; this.renamedSymbol = parameters.RenameSymbol; this.replacementTextValid = parameters.ReplacementTextValid; this.renameSpansTracker = parameters.RenameSpansTracker; this.isRenamingInStrings = parameters.OptionSet.GetOption(RenameOptions.RenameInStrings); this.isRenamingInComments = parameters.OptionSet.GetOption(RenameOptions.RenameInComments); this.stringAndCommentTextSpans = parameters.StringAndCommentTextSpans; this.renameAnnotations = parameters.RenameAnnotations; this.aliasSymbol = this.renamedSymbol as IAliasSymbol; this.renamableDeclarationLocation = this.renamedSymbol.Locations.Where(loc => loc.IsInSource && loc.SourceTree == semanticModel.SyntaxTree).FirstOrDefault(); this.isVerbatim = this.replacementText.StartsWith("@"); this.simplificationService = LanguageService.GetService<ISimplificationService>(parameters.Document); }
// The rename process and annotation for the bookkeeping is performed in one-step private async Task <Solution> AnnotateAndRename_WorkerAsync( Solution originalSolution, Solution partiallyRenamedSolution, HashSet <DocumentId> documentIdsToRename, IEnumerable <RenameLocation> renameLocations, RenamedSpansTracker renameSpansTracker, bool replacementTextValid) { foreach (var documentId in documentIdsToRename.ToList()) { cancellationToken.ThrowIfCancellationRequested(); // We try to rewrite all locations that are not candidate locations. If there is only one location // it must be the correct one (the symbol is ambiguous to something else) and we always try to rewrite it. var document = originalSolution.GetDocument(documentId); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); var originalSyntaxRoot = await semanticModel.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); // Get all rename locations for the current document. var allTextSpansInSingleSourceTree = renameLocations .Where(l => l.DocumentId == documentId && !l.IsRenameInStringOrComment && (renameLocations.Count() == 1 || !l.IsCandidateLocation)) .ToDictionary(l => l.Location.SourceSpan); // All textspan in the document documentId, that requires rename in String or Comment var stringAndCommentTextSpansInSingleSourceTree = renameLocations .Where(l => l.DocumentId == documentId && l.IsRenameInStringOrComment) .GroupBy(l => l.ContainingLocationForStringOrComment) .Select(g => g.Key) .ToSet(); var conflictLocationSpans = this.conflictLocations .Where(t => t.DocumentId == documentId) .Select(t => t.ComplexifiedSpan).ToSet(); // Annotate all nodes with a RenameLocation annotations to record old locations & old referenced symbols. // Also annotate nodes that should get complexified (nodes for rename locations + conflict locations) var parameters = new RenameRewriterParameters( this.renamedSymbolDeclarationAnnotation, document, semanticModel, originalSyntaxRoot, replacementText, originalText, possibleNameConflicts, allTextSpansInSingleSourceTree, stringAndCommentTextSpansInSingleSourceTree, conflictLocationSpans, originalSolution, renameLocationSet.Symbol, replacementTextValid, cancellationToken, renameSpansTracker, optionSet, this.renameAnnotations); var renameRewriterLanguageService = LanguageService.GetService <IRenameRewriterLanguageService>(document); var newRoot = renameRewriterLanguageService.AnnotateAndRename(parameters); if (newRoot == originalSyntaxRoot) { // Update the list for the current phase, some files with strings containing the original or replacement // text may have been filtered out. documentIdsToRename.Remove(documentId); } else { partiallyRenamedSolution = partiallyRenamedSolution.WithDocumentSyntaxRoot(documentId, newRoot, PreservationMode.PreserveIdentity); } } return(partiallyRenamedSolution); }