示例#1
0
 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>();
 }
示例#2
0
 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;
 }
示例#4
0
            // 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;
                }
            }
示例#5
0
            // 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);
            }