Example #1
0
        private static async Task AddImplicitConflictsAsync(
            ISymbol renamedSymbol,
            ISymbol originalSymbol,
            IEnumerable <ReferenceLocation> implicitReferenceLocations,
            SemanticModel semanticModel,
            Location originalDeclarationLocation,
            int newDeclarationLocationStartingPosition,
            ConflictResolution conflictResolution,
            CancellationToken cancellationToken)
        {
            {
                var renameRewriterService  = conflictResolution.NewSolution.Workspace.Services.GetLanguageServices(renamedSymbol.Language).GetService <IRenameRewriterLanguageService>();
                var implicitUsageConflicts = renameRewriterService.ComputePossibleImplicitUsageConflicts(renamedSymbol, semanticModel, originalDeclarationLocation, newDeclarationLocationStartingPosition, cancellationToken);
                foreach (var implicitUsageConflict in implicitUsageConflicts)
                {
                    conflictResolution.AddOrReplaceRelatedLocation(new RelatedLocation(implicitUsageConflict.SourceSpan, conflictResolution.OldSolution.GetDocument(implicitUsageConflict.SourceTree).Id, RelatedLocationType.UnresolvableConflict));
                }
            }

            if (implicitReferenceLocations.IsEmpty())
            {
                return;
            }

            foreach (var implicitReferenceLocationsPerLanguage in implicitReferenceLocations.GroupBy(loc => loc.Document.Project.Language))
            {
                // the location of the implicit reference defines the language rules to check.
                // E.g. foreach in C# using a MoveNext in VB that is renamed to MOVENEXT (within VB)
                var renameRewriterService = implicitReferenceLocationsPerLanguage.First().Document.Project.LanguageServices.GetService <IRenameRewriterLanguageService>();
                var implicitConflicts     = await renameRewriterService.ComputeImplicitReferenceConflictsAsync(
                    originalSymbol,
                    renamedSymbol,
                    implicitReferenceLocationsPerLanguage,
                    cancellationToken).ConfigureAwait(false);

                foreach (var implicitConflict in implicitConflicts)
                {
                    conflictResolution.AddRelatedLocation(new RelatedLocation(implicitConflict.SourceSpan, conflictResolution.OldSolution.GetDocument(implicitConflict.SourceTree).Id, RelatedLocationType.UnresolvableConflict));
                }
            }
        }
Example #2
0
            /// <summary>
            /// Find conflicts in the new solution
            /// </summary>
            private async Task <bool> IdentifyConflictsAsync(
                HashSet <DocumentId> documentIdsForConflictResolution,
                IEnumerable <DocumentId> allDocumentIdsInProject,
                ProjectId projectId,
                ConflictResolution conflictResolution)
            {
                try
                {
                    _documentOfRenameSymbolHasBeenRenamed |= documentIdsForConflictResolution.Contains(_documentIdOfRenameSymbolDeclaration);

                    // Get the renamed symbol in complexified new solution
                    ISymbol renamedSymbolInNewSolution = await GetRenamedSymbolInCurrentSolutionAsync(conflictResolution).ConfigureAwait(false);

                    // if the text replacement is invalid, we just did a simple token replacement.
                    // Therefore we don't need more mapping information and can skip the rest of
                    // the loop body.
                    if (!IsRenameValid(conflictResolution, renamedSymbolInNewSolution))
                    {
                        foreach (var documentId in documentIdsForConflictResolution)
                        {
                            var newDocument = conflictResolution.NewSolution.GetDocument(documentId);
                            var syntaxRoot  = await newDocument.GetSyntaxRootAsync(_cancellationToken).ConfigureAwait(false);

                            var nodesOrTokensWithConflictCheckAnnotations = GetNodesOrTokensToCheckForConflicts(documentId, syntaxRoot);
                            foreach (var nodeOrToken in nodesOrTokensWithConflictCheckAnnotations)
                            {
                                if (nodeOrToken.annotation.IsRenameLocation)
                                {
                                    conflictResolution.AddRelatedLocation(new RelatedLocation(
                                                                              nodeOrToken.annotation.OriginalSpan, documentId, RelatedLocationType.UnresolvedConflict));
                                }
                            }
                        }

                        return(false);
                    }

                    Dictionary <Location, Location> reverseMappedLocations = new Dictionary <Location, Location>();

                    foreach (var documentId in documentIdsForConflictResolution)
                    {
                        var newDocument = conflictResolution.NewSolution.GetDocument(documentId);
                        var syntaxRoot  = await newDocument.GetSyntaxRootAsync(_cancellationToken).ConfigureAwait(false);

                        var baseDocument   = conflictResolution.OldSolution.GetDocument(documentId);
                        var baseSyntaxTree = await baseDocument.GetSyntaxTreeAsync(_cancellationToken).ConfigureAwait(false);

                        var baseRoot = await baseDocument.GetSyntaxRootAsync(_cancellationToken).ConfigureAwait(false);

                        SemanticModel newDocumentSemanticModel = null;
                        var           syntaxFactsService       = newDocument.Project.LanguageServices.GetService <ISyntaxFactsService>();

                        // Get all tokens that need conflict check
                        var nodesOrTokensWithConflictCheckAnnotations = GetNodesOrTokensToCheckForConflicts(documentId, syntaxRoot);

                        var complexifiedLocationSpanForThisDocument =
                            _conflictLocations
                            .Where(t => t.DocumentId == documentId)
                            .Select(t => t.OriginalIdentifierSpan).ToSet();

                        foreach (var nodeAndAnnotation in nodesOrTokensWithConflictCheckAnnotations)
                        {
                            var tokenOrNode        = nodeAndAnnotation.syntax;
                            var conflictAnnotation = nodeAndAnnotation.annotation;
                            reverseMappedLocations[tokenOrNode.GetLocation()] = baseSyntaxTree.GetLocation(conflictAnnotation.OriginalSpan);
                            var originalLocation = conflictAnnotation.OriginalSpan;
                            IEnumerable <ISymbol> newReferencedSymbols = null;

                            var hasConflict = _renameAnnotations.HasAnnotation(tokenOrNode, RenameInvalidIdentifierAnnotation.Instance);
                            if (!hasConflict)
                            {
                                newDocumentSemanticModel = newDocumentSemanticModel ?? await newDocument.GetSemanticModelAsync(_cancellationToken).ConfigureAwait(false);

                                newReferencedSymbols = GetSymbolsInNewSolution(newDocument, newDocumentSemanticModel, conflictAnnotation, tokenOrNode);

                                // The semantic correctness, after rename, for each token of interest in the
                                // rename context is performed by getting the symbol pointed by each token
                                // and obtain the Symbol's First Ordered Location's  Span-Start and check to
                                // see if it is the same as before from the base solution. During rename,
                                // the spans would have been modified and so we need to adjust the old position
                                // to the new position for which we use the renameSpanTracker, which was tracking
                                // & mapping the old span -> new span during rename
                                hasConflict = _hasConflictCallback?.Invoke(newReferencedSymbols) ??
                                              await CheckForConflictAsync(conflictResolution, renamedSymbolInNewSolution, newDocument, conflictAnnotation, newReferencedSymbols).ConfigureAwait(false);
                            }

                            if (!hasConflict && !conflictAnnotation.IsInvocationExpression)
                            {
                                hasConflict = LocalVariableConflictPerLanguage((SyntaxToken)tokenOrNode, newDocument, newReferencedSymbols);
                            }

                            if (!hasConflict)
                            {
                                if (conflictAnnotation.IsRenameLocation)
                                {
                                    conflictResolution.AddRelatedLocation(
                                        new RelatedLocation(originalLocation,
                                                            documentId,
                                                            complexifiedLocationSpanForThisDocument.Contains(originalLocation) ? RelatedLocationType.ResolvedReferenceConflict : RelatedLocationType.NoConflict,
                                                            isReference: true));
                                }
                                else
                                {
                                    // if a complexified location was not a reference location, then it was a resolved conflict of a non reference location
                                    if (!conflictAnnotation.IsOriginalTextLocation && complexifiedLocationSpanForThisDocument.Contains(originalLocation))
                                    {
                                        conflictResolution.AddRelatedLocation(
                                            new RelatedLocation(originalLocation,
                                                                documentId,
                                                                RelatedLocationType.ResolvedNonReferenceConflict,
                                                                isReference: false));
                                    }
                                }
                            }
                            else
                            {
                                var baseToken          = baseRoot.FindToken(conflictAnnotation.OriginalSpan.Start, true);
                                var complexifiedTarget = GetExpansionTargetForLocationPerLanguage(baseToken, baseDocument);
                                conflictResolution.AddRelatedLocation(new RelatedLocation(
                                                                          originalLocation,
                                                                          documentId,
                                                                          complexifiedTarget != null ? RelatedLocationType.PossiblyResolvableConflict : RelatedLocationType.UnresolvableConflict,
                                                                          isReference: conflictAnnotation.IsRenameLocation,
                                                                          complexifiedTargetSpan: complexifiedTarget != null ? complexifiedTarget.Span : default));
                            }
                        }
                    }

                    // there are more conflicts that cannot be identified by checking if the tokens still reference the same
                    // symbol. These conflicts are mostly language specific. A good example is a member with the same name
                    // as the parent (yes I know, this is a simplification).
                    if (_documentIdOfRenameSymbolDeclaration.ProjectId == projectId)
                    {
                        // Calculating declaration conflicts may require location mapping in documents
                        // that were not otherwise being processed in the current rename phase, so add
                        // the annotated spans in these documents to reverseMappedLocations.
                        foreach (var unprocessedDocumentIdWithPotentialDeclarationConflicts in allDocumentIdsInProject.Where(d => !documentIdsForConflictResolution.Contains(d)))
                        {
                            var newDocument = conflictResolution.NewSolution.GetDocument(unprocessedDocumentIdWithPotentialDeclarationConflicts);
                            var syntaxRoot  = await newDocument.GetSyntaxRootAsync(_cancellationToken).ConfigureAwait(false);

                            var baseDocument   = conflictResolution.OldSolution.GetDocument(unprocessedDocumentIdWithPotentialDeclarationConflicts);
                            var baseSyntaxTree = await baseDocument.GetSyntaxTreeAsync(_cancellationToken).ConfigureAwait(false);

                            var nodesOrTokensWithConflictCheckAnnotations = GetNodesOrTokensToCheckForConflicts(unprocessedDocumentIdWithPotentialDeclarationConflicts, syntaxRoot);
                            foreach (var nodeAndAnnotation in nodesOrTokensWithConflictCheckAnnotations)
                            {
                                var tokenOrNode        = nodeAndAnnotation.syntax;
                                var conflictAnnotation = nodeAndAnnotation.annotation;
                                reverseMappedLocations[tokenOrNode.GetLocation()] = baseSyntaxTree.GetLocation(conflictAnnotation.OriginalSpan);
                            }
                        }

                        var referencedSymbols = _renameLocationSet.ReferencedSymbols;
                        var renameSymbol      = _renameLocationSet.Symbol;
                        await AddDeclarationConflictsAsync(
                            renamedSymbolInNewSolution, renameSymbol, referencedSymbols, conflictResolution, reverseMappedLocations, _cancellationToken).ConfigureAwait(false);
                    }

                    return(conflictResolution.RelatedLocations.Any(r => r.Type == RelatedLocationType.PossiblyResolvableConflict));
                }
                catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }