Пример #1
0
            private IEnumerable <ISymbol> GetSymbolsInNewSolution(Document newDocument, SemanticModel newDocumentSemanticModel, RenameActionAnnotation conflictAnnotation, SyntaxNodeOrToken tokenOrNode)
            {
                IEnumerable <ISymbol> newReferencedSymbols = RenameUtilities.GetSymbolsTouchingPosition(tokenOrNode.Span.Start, newDocumentSemanticModel, newDocument.Project.Solution.Workspace, _cancellationToken);

                if (conflictAnnotation.IsInvocationExpression)
                {
                    IEnumerable <ISymbol> invocationReferencedSymbols = null;
                    if (tokenOrNode.IsNode)
                    {
                        invocationReferencedSymbols = SymbolsForEnclosingInvocationExpressionWorker((SyntaxNode)tokenOrNode, newDocumentSemanticModel, _cancellationToken);
                    }

                    if (invocationReferencedSymbols != null)
                    {
                        newReferencedSymbols = invocationReferencedSymbols;
                    }
                }

                // if there are more than one symbol, then remove the alias symbols.
                // When using (not declaring) an alias, the alias symbol and the target symbol are returned
                // by GetSymbolsTouchingPosition
                if (newReferencedSymbols.Skip(1).Any())
                {
                    newReferencedSymbols = newReferencedSymbols.Where(a => a.Kind != SymbolKind.Alias);
                }

                return(newReferencedSymbols);
            }
Пример #2
0
            /// <summary>
            /// The method determines the set of documents that need to be processed for Rename and also determines
            ///  the possible set of names that need to be checked for conflicts.
            /// </summary>
            private async Task FindDocumentsAndPossibleNameConflicts()
            {
                try
                {
                    var symbol          = _renameLocationSet.Symbol;
                    var solution        = _renameLocationSet.Solution;
                    var dependencyGraph = solution.GetProjectDependencyGraph();
                    _topologicallySortedProjects = dependencyGraph.GetTopologicallySortedProjects(_cancellationToken).ToList();

                    var allRenamedDocuments = _renameLocationSet.Locations.Select(loc => loc.Location.SourceTree).Distinct().Select(solution.GetDocument);
                    _documentsIdsToBeCheckedForConflict.AddRange(allRenamedDocuments.Select(d => d.Id));

                    var documentsFromAffectedProjects = RenameUtilities.GetDocumentsAffectedByRename(symbol, solution, _renameLocationSet.Locations);
                    foreach (var language in documentsFromAffectedProjects.Select(d => d.Project.Language).Distinct())
                    {
                        solution.Workspace.Services.GetLanguageServices(language).GetService <IRenameRewriterLanguageService>()
                        ?.TryAddPossibleNameConflicts(symbol, _replacementText, _possibleNameConflicts);
                    }

                    await AddDocumentsWithPotentialConflicts(documentsFromAffectedProjects).ConfigureAwait(false);
                }
                catch (Exception e) when(FatalError.ReportUnlessCanceled(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
            private async Task <ISymbol> TryGetSymbolAsync(
                Solution solutionWithOriginalName,
                DocumentId documentId,
                CancellationToken cancellationToken
                )
            {
                var documentWithOriginalName   = solutionWithOriginalName.GetDocument(documentId);
                var syntaxTreeWithOriginalName = await documentWithOriginalName
                                                 .GetSyntaxTreeAsync(cancellationToken)
                                                 .ConfigureAwait(false);

                var syntaxFacts =
                    documentWithOriginalName.GetLanguageService <ISyntaxFactsService>();
                var semanticFacts =
                    documentWithOriginalName.GetLanguageService <ISemanticFactsService>();
                var semanticModel = await documentWithOriginalName
                                    .GetSemanticModelAsync(cancellationToken)
                                    .ConfigureAwait(false);

                var token = await syntaxTreeWithOriginalName
                            .GetTouchingWordAsync(_snapshotSpan.Start, syntaxFacts, cancellationToken)
                            .ConfigureAwait(false);

                var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(
                    semanticFacts,
                    semanticModel,
                    token,
                    cancellationToken
                    );

                return(tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null);
            }
            public SymbolInlineRenameInfo(
                IEnumerable <IRefactorNotifyService> refactorNotifyServices,
                Document document,
                TextSpan triggerSpan,
                string triggerText,
                ISymbol renameSymbol,
                bool forceRenameOverloads,
                ImmutableArray <DocumentSpan> definitionLocations,
                CodeCleanupOptionsProvider fallbackOptions,
                CancellationToken cancellationToken)
            {
                this.CanRename = true;

                _refactorNotifyServices = refactorNotifyServices;
                _document         = document;
                _fallbackOptions  = fallbackOptions;
                this.RenameSymbol = renameSymbol;

                this.HasOverloads        = RenameUtilities.GetOverloadedSymbols(this.RenameSymbol).Any();
                this.MustRenameOverloads = forceRenameOverloads;

                _isRenamingAttributePrefix = CanRenameAttributePrefix(triggerText);
                this.TriggerSpan           = GetReferenceEditSpan(new InlineRenameLocation(document, triggerSpan), triggerText, cancellationToken);

                this.DefinitionLocations = definitionLocations;
            }
            private async Task <TriggerIdentifierKind> DetermineIfRenamableIdentifierAsync(SnapshotSpan snapshotSpan, bool initialCheck)
            {
                _threadingContext.ThrowIfNotOnBackgroundThread();
                var document = snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

                if (document != null)
                {
                    var syntaxFactsService = document.GetLanguageService <ISyntaxFactsService>();
                    var syntaxTree         = await document.GetSyntaxTreeAsync(_cancellationToken).ConfigureAwait(false);

                    var token = await syntaxTree.GetTouchingWordAsync(snapshotSpan.Start.Position, syntaxFactsService, _cancellationToken).ConfigureAwait(false);

                    // The OriginalName is determined with a simple textual check, so for a
                    // statement such as "Dim [x = 1" the textual check will return a name of "[x".
                    // The token found for "[x" is an identifier token, but only due to error
                    // recovery (the "[x" is actually in the trailing trivia). If the OriginalName
                    // found through the textual check has a different length than the span of the
                    // touching word, then we cannot perform a rename.
                    if (initialCheck && token.Span.Length != this.OriginalName.Length)
                    {
                        return(TriggerIdentifierKind.NotRenamable);
                    }

                    var languageHeuristicsService = document.GetLanguageService <IRenameTrackingLanguageHeuristicsService>();
                    if (syntaxFactsService.IsIdentifier(token) && languageHeuristicsService.IsIdentifierValidForRenameTracking(token.Text))
                    {
                        var semanticModel = await document.ReuseExistingSpeculativeModelAsync(token.Parent, _cancellationToken).ConfigureAwait(false);

                        var semanticFacts = document.GetLanguageService <ISemanticFactsService>();

                        var renameSymbolInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, token, _cancellationToken);
                        if (!renameSymbolInfo.HasSymbols)
                        {
                            return(TriggerIdentifierKind.NotRenamable);
                        }

                        if (renameSymbolInfo.IsMemberGroup)
                        {
                            // This is a reference from a nameof expression. Allow the rename but set the RenameOverloads option
                            _forceRenameOverloads = true;

                            return(await DetermineIfRenamableSymbolsAsync(renameSymbolInfo.Symbols, document).ConfigureAwait(false));
                        }
                        else
                        {
                            // We do not yet support renaming (inline rename or rename tracking) on
                            // named tuple elements.
                            if (renameSymbolInfo.Symbols.Single().ContainingType?.IsTupleType() == true)
                            {
                                return(TriggerIdentifierKind.NotRenamable);
                            }

                            return(await DetermineIfRenamableSymbolAsync(renameSymbolInfo.Symbols.Single(), document, token).ConfigureAwait(false));
                        }
                    }
                }

                return(TriggerIdentifierKind.NotRenamable);
            }
            private async Task <TriggerIdentifierKind> DetermineIfRenamableIdentifierAsync(SnapshotSpan snapshotSpan, bool initialCheck)
            {
                AssertIsBackground();
                var document = snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges();

                if (document != null)
                {
                    var syntaxFactsService = document.Project.LanguageServices.GetService <ISyntaxFactsService>();
                    var syntaxTree         = await document.GetSyntaxTreeAsync(_cancellationToken).ConfigureAwait(false);

                    var token = syntaxTree.GetTouchingWord(snapshotSpan.Start.Position, syntaxFactsService, _cancellationToken);

                    // The OriginalName is determined with a simple textual check, so for a
                    // statement such as "Dim [x = 1" the textual check will return a name of "[x".
                    // The token found for "[x" is an identifier token, but only due to error
                    // recovery (the "[x" is actually in the trailing trivia). If the OriginalName
                    // found through the textual check has a different length than the span of the
                    // touching word, then we cannot perform a rename.
                    if (initialCheck && token.Span.Length != this.OriginalName.Length)
                    {
                        return(TriggerIdentifierKind.NotRenamable);
                    }

                    if (syntaxFactsService.IsIdentifier(token))
                    {
                        var semanticModel = await document.GetSemanticModelForNodeAsync(token.Parent, _cancellationToken).ConfigureAwait(false);

                        var semanticFacts = document.GetLanguageService <ISemanticFactsService>();

                        var renameSymbolInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, token, _cancellationToken);
                        if (!renameSymbolInfo.HasSymbols)
                        {
                            return(TriggerIdentifierKind.NotRenamable);
                        }

                        if (renameSymbolInfo.IsMemberGroup)
                        {
                            // This is a reference from a nameof expression. Allow the rename but set the RenameOverloads option
                            _forceRenameOverloads = true;

                            return(await DetermineIfRenamableSymbolsAsync(renameSymbolInfo.Symbols, document, token).ConfigureAwait(false));
                        }
                        else
                        {
                            return(await DetermineIfRenamableSymbolAsync(renameSymbolInfo.Symbols.Single(), document, token).ConfigureAwait(false));
                        }
                    }
                }

                return(TriggerIdentifierKind.NotRenamable);
            }
            private bool TryGetSymbol(Solution solutionWithOriginalName, DocumentId documentId, CancellationToken cancellationToken, out ISymbol symbol)
            {
                var documentWithOriginalName   = solutionWithOriginalName.GetDocument(documentId);
                var syntaxTreeWithOriginalName = documentWithOriginalName.GetSyntaxTreeAsync(cancellationToken).WaitAndGetResult(cancellationToken);

                var syntaxFacts   = documentWithOriginalName.GetLanguageService <ISyntaxFactsService>();
                var semanticFacts = documentWithOriginalName.GetLanguageService <ISemanticFactsService>();
                var semanticModel = documentWithOriginalName.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);

                var token           = syntaxTreeWithOriginalName.GetTouchingWord(_snapshotSpan.Start, syntaxFacts, cancellationToken);
                var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, token, cancellationToken);

                symbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;
                return(symbol != null);
            }
Пример #8
0
            /// <summary>
            /// The method determines the set of documents that need to be processed for Rename and also determines
            ///  the possible set of names that need to be checked for conflicts.
            /// </summary>
            private async Task FindDocumentsAndPossibleNameConflicts()
            {
                var symbol          = renameLocationSet.Symbol;
                var solution        = renameLocationSet.Solution;
                var dependencyGraph = solution.GetProjectDependencyGraph();

                this.topologicallySortedProjects = dependencyGraph.GetTopologicallySortedProjects(cancellationToken).ToList();

                var allRenamedDocuments = renameLocationSet.Locations.Select(loc => loc.Location.SourceTree).Distinct().Select(solution.GetDocument);

                this.documentsIdsToBeCheckedForConflict.AddRange(allRenamedDocuments.Select(d => d.Id));

                var documentsFromAffectedProjects = RenameUtilities.GetDocumentsAffectedByRename(symbol, solution, renameLocationSet.Locations);

                foreach (var language in documentsFromAffectedProjects.Select(d => d.Project.Language).Distinct())
                {
                    solution.Workspace.Services.GetLanguageServices(language).GetService <IRenameRewriterLanguageService>()
                    .TryAddPossibleNameConflicts(symbol, replacementText, possibleNameConflicts);
                }

                await AddDocumentsWithPotentialConflicts(documentsFromAffectedProjects).ConfigureAwait(false);
            }
Пример #9
0
        public static async Task <ISymbol?> GetRenameSymbol(
            Document document, SyntaxToken triggerToken, CancellationToken cancellationToken)
        {
            var syntaxFactsService = document.Project.LanguageServices.GetRequiredService <ISyntaxFactsService>();

            if (syntaxFactsService.IsReservedOrContextualKeyword(triggerToken))
            {
                return(null);
            }

            var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var semanticFacts = document.GetLanguageService <ISemanticFactsService>();

            var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, triggerToken, cancellationToken);

            // Rename was invoked on a member group reference in a nameof expression.
            // Trigger the rename on any of the candidate symbols but force the
            // RenameOverloads option to be on.
            var triggerSymbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;

            if (triggerSymbol == null)
            {
                return(null);
            }

            // see https://github.com/dotnet/roslyn/issues/10898
            // we are disabling rename for tuple fields for now
            // 1) compiler does not return correct location information in these symbols
            // 2) renaming tuple fields seems a complex enough thing to require some design
            if (triggerSymbol.ContainingType?.IsTupleType == true)
            {
                return(null);
            }

            // If rename is invoked on a member group reference in a nameof expression, then the
            // RenameOverloads option should be forced on.
            var forceRenameOverloads = tokenRenameInfo.IsMemberGroup;

            if (syntaxFactsService.IsTypeNamedVarInVariableOrFieldDeclaration(triggerToken, triggerToken.Parent))
            {
                // To check if var in this context is a real type, or the keyword, we need to
                // speculatively bind the identifier "var". If it returns a symbol, it's a real type,
                // if not, it's the keyword.
                // see bugs 659683 (compiler API) and 659705 (rename/workspace api) for examples
                var symbolForVar = semanticModel.GetSpeculativeSymbolInfo(
                    triggerToken.SpanStart,
                    triggerToken.Parent,
                    SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol;

                if (symbolForVar == null)
                {
                    return(null);
                }
            }

            var symbolAndProjectId = await RenameLocations.ReferenceProcessing.GetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken : cancellationToken).ConfigureAwait(false);

            var symbol = symbolAndProjectId.Symbol;

            if (symbol == null)
            {
                return(null);
            }

            if (symbol.Kind == SymbolKind.Alias && symbol.IsExtern)
            {
                return(null);
            }

            // Cannot rename constructors in VB.  TODO: this logic should be in the VB subclass of this type.
            var workspace = document.Project.Solution.Workspace;

            if (symbol.Kind == SymbolKind.NamedType &&
                symbol.Language == LanguageNames.VisualBasic &&
                triggerToken.ToString().Equals("New", StringComparison.OrdinalIgnoreCase))
            {
                var originalSymbol = await SymbolFinder.FindSymbolAtPositionAsync(semanticModel, triggerToken.SpanStart, workspace, cancellationToken : cancellationToken);

                if (originalSymbol != null && originalSymbol.IsConstructor())
                {
                    return(null);
                }
            }

            if (syntaxFactsService.IsTypeNamedDynamic(triggerToken, triggerToken.Parent))
            {
                if (symbol.Kind == SymbolKind.DynamicType)
                {
                    return(null);
                }
            }

            // we allow implicit locals and parameters of Event handlers
            if (symbol.IsImplicitlyDeclared &&
                symbol.Kind != SymbolKind.Local &&
                !(symbol.Kind == SymbolKind.Parameter &&
                  symbol.ContainingSymbol.Kind == SymbolKind.Method &&
                  symbol.ContainingType != null &&
                  symbol.ContainingType.IsDelegateType() &&
                  symbol.ContainingType.AssociatedSymbol != null))
            {
                // We enable the parameter in RaiseEvent, if the Event is declared with a signature. If the Event is declared as a
                // delegate type, we do not have a connection between the delegate type and the event.
                // this prevents a rename in this case :(.
                return(null);
            }

            if (symbol.Kind == SymbolKind.Property && symbol.ContainingType.IsAnonymousType)
            {
                return(null);
            }

            if (symbol.IsErrorType())
            {
                return(null);
            }

            if (symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).MethodKind == MethodKind.UserDefinedOperator)
            {
                return(null);
            }

            var symbolLocations = symbol.Locations;

            // Does our symbol exist in an unchangeable location?
            foreach (var location in symbolLocations)
            {
                if (location.IsInMetadata)
                {
                    return(null);
                }
                if (location.IsInSource)
                {
                    if (document.Project.IsSubmission)
                    {
                        var solution            = document.Project.Solution;
                        var projectIdOfLocation = solution.GetDocument(location.SourceTree)?.Project.Id;

                        if (solution.Projects.Any(p => p.IsSubmission && p.ProjectReferences.Any(r => r.ProjectId == projectIdOfLocation)))
                        {
                            return(null);
                        }
                    }
                }
                else
                {
                    return(null);
                }
            }

            return(symbol);
        }
        internal static IInlineRenameInfo GetRenameInfo(
            IEnumerable <IRefactorNotifyService> refactorNotifyServices,
            Document document, SyntaxToken triggerToken, CancellationToken cancellationToken)
        {
            var syntaxFactsService = document.Project.LanguageServices.GetService <ISyntaxFactsService>();

            if (syntaxFactsService.IsKeyword(triggerToken))
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouMustRenameAnIdentifier));
            }

            var semanticModel = document.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
            var semanticFacts = document.GetLanguageService <ISemanticFactsService>();

            var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, triggerToken, cancellationToken);

            // Rename was invoked on a member group reference in a nameof expression.
            // Trigger the rename on any of the candidate symbols but force the
            // RenameOverloads option to be on.
            var triggerSymbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;

            if (triggerSymbol == null)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
            }

            // If rename is invoked on a member group reference in a nameof expression, then the
            // RenameOverloads option should be forced on.
            var forceRenameOverloads = tokenRenameInfo.IsMemberGroup;

            if (syntaxFactsService.IsTypeNamedVarInVariableOrFieldDeclaration(triggerToken, triggerToken.Parent))
            {
                // To check if va in this context is a real type, or the keyword, we need to
                // speculatively bind the identifier "var". If it returns a symbol, it's a real type,
                // if not, it's the keyword.
                // see bugs 659683 (compiler API) and 659705 (rename/workspace api) for examples
                var symbolForVar = semanticModel.GetSpeculativeSymbolInfo(
                    triggerToken.SpanStart,
                    triggerToken.Parent,
                    SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol;

                if (symbolForVar == null)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
                }
            }

            var symbol = RenameLocations.ReferenceProcessing.GetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken: cancellationToken).WaitAndGetResult(cancellationToken);

            if (symbol == null)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
            }

            if (symbol.Kind == SymbolKind.Alias && symbol.IsExtern)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
            }

            // Cannot rename constructors in VB.  TODO: this logic should be in the VB subclass of this type.
            var workspace = document.Project.Solution.Workspace;

            if (symbol != null &&
                symbol.Kind == SymbolKind.NamedType &&
                symbol.Language == LanguageNames.VisualBasic &&
                triggerToken.ToString().Equals("New", StringComparison.OrdinalIgnoreCase))
            {
                var originalSymbol = SymbolFinder.FindSymbolAtPosition(semanticModel, triggerToken.SpanStart, workspace, cancellationToken: cancellationToken);

                if (originalSymbol != null && originalSymbol.IsConstructor())
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
                }
            }

            if (syntaxFactsService.IsTypeNamedDynamic(triggerToken, triggerToken.Parent))
            {
                if (symbol.Kind == SymbolKind.DynamicType)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
                }
            }

            // we allow implicit locals and parameters of Event handlers
            if (symbol.IsImplicitlyDeclared &&
                symbol.Kind != SymbolKind.Local &&
                !(symbol.Kind == SymbolKind.Parameter &&
                  symbol.ContainingSymbol.Kind == SymbolKind.Method &&
                  symbol.ContainingType != null &&
                  symbol.ContainingType.IsDelegateType() &&
                  symbol.ContainingType.AssociatedSymbol != null))
            {
                // We enable the parameter in RaiseEvent, if the Event is declared with a signature. If the Event is declared as a
                // delegate type, we do not have a connection between the delegate type and the event.
                // this prevents a rename in this case :(.
                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
            }

            if (symbol.Kind == SymbolKind.Property && symbol.ContainingType.IsAnonymousType)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.RenamingAnonymousTypeMemberNotSupported));
            }

            if (symbol.IsErrorType())
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.PleaseResolveErrorsInYourCodeBeforeRenaming));
            }

            if (symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).MethodKind == MethodKind.UserDefinedOperator)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameOperators));
            }

            var symbolLocations = symbol.Locations;

            // Does our symbol exist in an unchangeable location?
            var navigationService = workspace.Services.GetService <IDocumentNavigationService>();

            foreach (var location in symbolLocations)
            {
                if (location.IsInMetadata)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameElementsInMetadata));
                }
                else if (location.IsInSource)
                {
                    if (document.Project.IsSubmission)
                    {
                        var solution            = document.Project.Solution;
                        var projectIdOfLocation = solution.GetDocument(location.SourceTree).Project.Id;

                        if (solution.Projects.Any(p => p.IsSubmission && p.ProjectReferences.Any(r => r.ProjectId == projectIdOfLocation)))
                        {
                            return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameElementsFromPrevSubmissions));
                        }
                    }
                    else
                    {
                        var sourceText   = location.SourceTree.GetTextAsync(cancellationToken).WaitAndGetResult(cancellationToken);
                        var textSnapshot = sourceText.FindCorrespondingEditorTextSnapshot();

                        if (textSnapshot != null)
                        {
                            var buffer       = textSnapshot.TextBuffer;
                            var originalSpan = location.SourceSpan.ToSnapshotSpan(textSnapshot).TranslateTo(buffer.CurrentSnapshot, SpanTrackingMode.EdgeInclusive);

                            if (buffer.IsReadOnly(originalSpan) || !navigationService.CanNavigateToSpan(workspace, document.Id, location.SourceSpan))
                            {
                                return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
                            }
                        }
                    }
                }
                else
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.YouCannotRenameThisElement));
                }
            }

            return(new SymbolInlineRenameInfo(refactorNotifyServices, document, triggerToken.Span, symbol, forceRenameOverloads, cancellationToken));
        }
        private async Task <IInlineRenameInfo> GetRenameInfoAsync(
            IEnumerable <IRefactorNotifyService> refactorNotifyServices,
            Document document, SyntaxToken triggerToken,
            CancellationToken cancellationToken)
        {
            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

            if (syntaxFacts.IsReservedOrContextualKeyword(triggerToken))
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_must_rename_an_identifier));
            }

            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var semanticFacts = document.GetRequiredLanguageService <ISemanticFactsService>();

            var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, triggerToken, cancellationToken);

            // Rename was invoked on a member group reference in a nameof expression.
            // Trigger the rename on any of the candidate symbols but force the
            // RenameOverloads option to be on.
            var triggerSymbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;

            if (triggerSymbol == null)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            // see https://github.com/dotnet/roslyn/issues/10898
            // we are disabling rename for tuple fields for now
            // 1) compiler does not return correct location information in these symbols
            // 2) renaming tuple fields seems a complex enough thing to require some design
            if (triggerSymbol.ContainingType?.IsTupleType == true)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            // If rename is invoked on a member group reference in a nameof expression, then the
            // RenameOverloads option should be forced on.
            var forceRenameOverloads = tokenRenameInfo.IsMemberGroup;
            var symbol = await RenameUtilities.TryGetRenamableSymbolAsync(document, triggerToken.SpanStart, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (symbol == null)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            if (symbol.Kind == SymbolKind.Alias && symbol.IsExtern)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            // Cannot rename constructors in VB.  TODO: this logic should be in the VB subclass of this type.
            var workspace = document.Project.Solution.Workspace;

            if (symbol.Kind == SymbolKind.NamedType &&
                symbol.Language == LanguageNames.VisualBasic &&
                triggerToken.ToString().Equals("New", StringComparison.OrdinalIgnoreCase))
            {
                var originalSymbol = await SymbolFinder.FindSymbolAtPositionAsync(
                    semanticModel, triggerToken.SpanStart, workspace, cancellationToken : cancellationToken).ConfigureAwait(false);

                if (originalSymbol != null && originalSymbol.IsConstructor())
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                }
            }

            if (CheckLanguageSpecificIssues(semanticModel, symbol, triggerToken, out var langError))
            {
                return(new FailureInlineRenameInfo(langError));
            }

            // we allow implicit locals and parameters of Event handlers
            if (symbol.IsImplicitlyDeclared &&
                symbol.Kind != SymbolKind.Local &&
                !(symbol.Kind == SymbolKind.Parameter &&
                  symbol.ContainingSymbol.Kind == SymbolKind.Method &&
                  symbol.ContainingType != null &&
                  symbol.ContainingType.IsDelegateType() &&
                  symbol.ContainingType.AssociatedSymbol != null))
            {
                // We enable the parameter in RaiseEvent, if the Event is declared with a signature. If the Event is declared as a
                // delegate type, we do not have a connection between the delegate type and the event.
                // this prevents a rename in this case :(.
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
            }

            if (symbol.Kind == SymbolKind.Property && symbol.ContainingType.IsAnonymousType)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.Renaming_anonymous_type_members_is_not_yet_supported));
            }

            if (symbol.IsErrorType())
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.Please_resolve_errors_in_your_code_before_renaming_this_element));
            }

            if (symbol.Kind == SymbolKind.Method && ((IMethodSymbol)symbol).MethodKind == MethodKind.UserDefinedOperator)
            {
                return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_operators));
            }

            var symbolLocations = symbol.Locations;

            // Does our symbol exist in an unchangeable location?
            var documentSpans = ArrayBuilder <DocumentSpan> .GetInstance();

            foreach (var location in symbolLocations)
            {
                if (location.IsInMetadata)
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_elements_that_are_defined_in_metadata));
                }
                else if (location.IsInSource)
                {
                    var solution       = document.Project.Solution;
                    var sourceDocument = solution.GetRequiredDocument(location.SourceTree);

                    if (sourceDocument is SourceGeneratedDocument)
                    {
                        // The file is generated so we can't go editing it (for now)
                        return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                    }

                    if (document.Project.IsSubmission)
                    {
                        var projectIdOfLocation = sourceDocument.Project.Id;

                        if (solution.Projects.Any(p => p.IsSubmission && p.ProjectReferences.Any(r => r.ProjectId == projectIdOfLocation)))
                        {
                            return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_elements_from_previous_submissions));
                        }
                    }
                    else
                    {
                        // We eventually need to return the symbol locations, so we must convert each location to a DocumentSpan since our return type is language-agnostic.
                        documentSpans.Add(new DocumentSpan(sourceDocument, location.SourceSpan));
                    }
                }
                else
                {
                    return(new FailureInlineRenameInfo(EditorFeaturesResources.You_cannot_rename_this_element));
                }
            }

            var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var triggerText     = sourceText.ToString(triggerToken.Span);
            var fallbackOptions = _globalOptions.CreateProvider();

            return(new SymbolInlineRenameInfo(
                       refactorNotifyServices, document, triggerToken.Span, triggerText,
                       symbol, forceRenameOverloads, documentSpans.ToImmutableAndFree(),
                       fallbackOptions, cancellationToken));
        }