public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            // Don't bother if there isn't a selection
            var textSpan = context.Span;
            if (textSpan.IsEmpty)
            {
                return;
            }

            var document = context.Document;
            var cancellationToken = context.CancellationToken;

            var workspace = document.Project.Solution.Workspace;
            if (workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            var activeInlineRenameSession = workspace.Services.GetService<ICodeRefactoringHelpersService>().ActiveInlineRenameSession;
            if (activeInlineRenameSession)
            {
                return;
            }

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            var action = await GetCodeActionAsync(document, textSpan, cancellationToken: cancellationToken).ConfigureAwait(false);
            if (action == null)
            {
                return;
            }

            context.RegisterRefactoring(action.Item1);
        }
        private static void RenameIdentifierNameAccordingToTypeName(
            CodeRefactoringContext context,
            SemanticModel semanticModel,
            ForEachStatementSyntax forEachStatement)
        {
            if (forEachStatement.Type == null)
            {
                return;
            }

            if (!forEachStatement.Identifier.Span.Contains(context.Span))
            {
                return;
            }

            string newName = NamingHelper.CreateIdentifierName(
                forEachStatement.Type,
                semanticModel,
                firstCharToLower: true);

            if (string.IsNullOrEmpty(newName))
            {
                return;
            }

            if (string.Equals(newName, forEachStatement.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            ISymbol symbol = semanticModel.GetDeclaredSymbol(forEachStatement, context.CancellationToken);

            context.RegisterRefactoring(
                $"Rename foreach variable to '{newName}'",
                cancellationToken => symbol.RenameAsync(newName, context.Document, cancellationToken));
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var textSpan          = context.Span;
            var cancellationToken = context.CancellationToken;

            var root = (SyntaxNode)await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var token = root.FindToken(textSpan.Start);

            // Only trigger if the text span is within the 'if' keyword token of an if-else statement.

            if (token.Kind() != SyntaxKind.IfKeyword ||
                !token.Span.IntersectsWith(textSpan.Start) ||
                !token.Span.IntersectsWith(textSpan.End))
            {
                return;
            }

            var ifStatement = token.Parent as IfStatementSyntax;

            if (ifStatement == null || ifStatement.Else == null)
            {
                return;
            }

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

            ReturnStatementSyntax returnStatement;

            if (ReturnConditionalAnalyzer.TryGetNewReturnStatement(ifStatement, semanticModel, out returnStatement))
            {
                var action = new ConvertToConditionalCodeAction("Convert to conditional expression", (c) => Task.FromResult(ConvertToConditional(document, semanticModel, ifStatement, returnStatement, c)));
                context.RegisterRefactoring(action);
            }
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var expressionStatement = await GetExpressionStatementAsync(context)
                                      .ConfigureAwait(false);

            if (expressionStatement == null)
            {
                return;
            }

            var(document, _, cancellationToken) = context;
            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();
            var expression  = syntaxFacts.GetExpressionOfExpressionStatement(expressionStatement);

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

            var type = semanticModel.GetTypeInfo(expression).Type;

            if (type == null || type.SpecialType == SpecialType.System_Void)
            {
                return;
            }

            var singleLineExpression = syntaxFacts.ConvertToSingleLine(expression);
            var nodeString           = singleLineExpression.ToString();

            context.RegisterRefactoring(
                new MyCodeAction(
                    string.Format(FeaturesResources.Introduce_local_for_0, nodeString),
                    c => IntroduceLocalAsync(document, expressionStatement, c)
                    ),
                expressionStatement.Span
                );
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            if (document.Project.Solution.WorkspaceKind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            if (textSpan.Length > 0)
            {
                return;
            }

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            if (root.SyntaxTree.Options.LanguageVersion() < LanguageVersion.CSharp9)
            {
                return;
            }

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

            var node            = root.FindToken(textSpan.Start).Parent;
            var replacementFunc = GetReplacementFunc(node, model);

            if (replacementFunc is null)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeAction.Create(
                    CSharpFeaturesResources.Use_recursive_patterns,
                    _ => Task.FromResult(document.WithSyntaxRoot(replacementFunc(root))),
                    nameof(CSharpFeaturesResources.Use_recursive_patterns)));
        }
        ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var root = await context.Document.GetSyntaxRootAsync(context.
                                                                 CancellationToken).
                       ConfigureAwait(false);

            // Find the node at the selection.
            var node = root.FindNode(context.Span);
            // Only offer a refactoring if the selected node is
            // a class statement node.
            var classDecl = node as ClassDeclarationSyntax;

            if (classDecl == null)
            {
                return;
            }
            var action = CodeAction.Create(title: Title,
                                           createChangedDocument: c =>
                                           MakeRelayCommandAsync(context.Document,
                                                                 classDecl, c), equivalenceKey: Title);

            // Register this code action.
            context.RegisterRefactoring(action);
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            Document          document          = context.Document;
            TextSpan          textSpan          = context.Span;
            CancellationToken cancellationToken = context.CancellationToken;

            // shouldn't have selection
            if (!textSpan.IsEmpty)
            {
                return;
            }

            // get applicable actions
            ApplicableActionFinder finder = new ApplicableActionFinder(document, textSpan.Start, cancellationToken);

            (TextSpan span, CodeAction action) = await finder.GetSpanAndActionAsync().ConfigureAwait(false);

            if (action == null || !span.IntersectsWith(textSpan.Start))
            {
                return;
            }

            context.RegisterRefactoring(action);
        }
        private static void CreateField(CodeRefactoringContext context, Document document, TextSpan span, SemanticModel model, SyntaxNode root, LiteralExpressionSyntax constantLiteral, SyntaxNode parentBlock, MemberDeclarationSyntax parentTypeMember)
        {
            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Create constant field"),
                    t2 =>
            {
                TypeInfo constType  = model.GetTypeInfo(constantLiteral);
                string newConstName = CreateName(context, root, parentBlock, constType.ConvertedType.Name);

                var newConstDecl = SyntaxFactory.FieldDeclaration(SyntaxFactory.List <AttributeListSyntax>(),
                                                                  CreateConst(),
                                                                  CreateVariableDecl(constantLiteral.Token, model, constType, newConstName)
                                                                  ).WithAdditionalAnnotations(Formatter.Annotation);

                var trackedRoot = root.TrackNodes(constantLiteral, parentTypeMember);
                var newRoot     = trackedRoot.InsertNodesBefore(trackedRoot.GetCurrentNode(parentTypeMember), new[] { newConstDecl });
                newRoot         = ReplaceWithConst(newRoot.GetCurrentNode(constantLiteral), newConstName, newRoot);
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            })
                );
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            // TODO: Replace the following code with your own analysis, generating a CodeAction for each refactoring to offer

            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            // Find the node at the selection.
            var node = root.FindNode(context.Span);

            // Only offer a refactoring if the selected node is a type declaration node.
            if (!(node is ParameterSyntax parameterSyntax))
            {
                return;
            }

            var parameterNode  = (ParameterSyntax)node;
            var underscoreName = $"_{parameterNode.Identifier}";

            // For any type declaration node, create a code action to reverse the identifier text.
            var action = CodeAction.Create($"Create and initialize field {underscoreName}", c => CreateInitilizeFieldAsync(context.Document, parameterSyntax, underscoreName, c));

            // Register this code action.
            context.RegisterRefactoring(action);
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token = root.FindToken(span.Start);

            if (!token.IsKind(SyntaxKind.IdentifierToken))
            {
                return;
            }

            var node = token.Parent as VariableDeclaratorSyntax;

            if (node == null)
            {
                return;
            }
            var declaredSymbol = model.GetDeclaredSymbol(node, cancellationToken);

            if (declaredSymbol == null || !declaredSymbol.IsKind(SymbolKind.Event))
            {
                return;
            }
            if (declaredSymbol.ContainingSymbol.IsInterfaceType())
            {
                return;
            }
            var invokeMethod = declaredSymbol.GetReturnType().GetDelegateInvokeMethod();

            if (invokeMethod == null)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.CreateInsertion(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Create event invocator"),
                    t2 =>
            {
                SyntaxNode eventInvocator = CreateEventInvocator(document, declaredSymbol);
                return(Task.FromResult(new InsertionResult(context, eventInvocator, declaredSymbol.ContainingType, declaredSymbol.Locations.First())));
            }
                    )
                );
        }
示例#11
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var node = root.FindNode(span) as IdentifierNameSyntax;

            if (node == null || !node.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                return;
            }
            var memberAccess = node.Parent as MemberAccessExpressionSyntax;
            var invocation   = node.Parent.Parent as InvocationExpressionSyntax;

            if (invocation == null)
            {
                return;
            }

            var invocationRR = model.GetSymbolInfo(invocation);

            if (invocationRR.Symbol == null)
            {
                return;
            }

            var method = invocationRR.Symbol as IMethodSymbol;

            if (method == null || !method.IsExtensionMethod)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("To static invocation"),
                    t2 =>
            {
                var newRoot = root.ReplaceNode((SyntaxNode)invocation, ToStaticMethodInvocation(model, invocation, memberAccess, invocationRR).WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia(invocation.GetLeadingTrivia()));
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
示例#12
0
        private async Task HandleNonSelectionAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var textSpan          = context.Span;
            var cancellationToken = context.CancellationToken;

            var syntaxFacts = document.GetLanguageService <ISyntaxFactsService>();
            var sourceText  = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            // We offer the refactoring when the user is either on the header of a class/struct,
            // or if they're between any members of a class/struct and are on a blank line.
            if (!syntaxFacts.IsOnTypeHeader(root, textSpan.Start) &&
                !syntaxFacts.IsBetweenTypeMembers(sourceText, root, textSpan.Start))
            {
                return;
            }

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

            // Only supported on classes/structs.
            var containingType = GetEnclosingNamedType(semanticModel, root, textSpan.Start, cancellationToken);

            if (containingType?.TypeKind != TypeKind.Class && containingType?.TypeKind != TypeKind.Struct)
            {
                return;
            }

            // No constructors for static classes.
            if (containingType.IsStatic)
            {
                return;
            }

            // Find all the possible writable instance fields/properties.  If there are any, then
            // show a dialog to the user to select the ones they want.  Otherwise, if there are none
            // don't offer to generate anything.
            var viableMembers = containingType.GetMembers().WhereAsArray(IsWritableInstanceFieldOrProperty);

            if (viableMembers.Length == 0)
            {
                return;
            }

            var pickMemberOptions = ArrayBuilder <PickMembersOption> .GetInstance();

            var canAddNullCheck = viableMembers.Any(
                m => m.GetSymbolType().CanAddNullCheck());

            if (canAddNullCheck)
            {
                var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);

                var optionValue = options.GetOption(GenerateConstructorFromMembersOptions.AddNullChecks);

                pickMemberOptions.Add(new PickMembersOption(
                                          AddNullChecksId,
                                          FeaturesResources.Add_null_checks,
                                          optionValue));
            }

            context.RegisterRefactoring(
                new GenerateConstructorWithDialogCodeAction(
                    this, document, textSpan, containingType, viableMembers,
                    pickMemberOptions.ToImmutableAndFree()));
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token = root.FindToken(span.Start);

            ExpressionSyntax identifier = token.Parent as IdentifierNameSyntax;

            if (identifier == null)
            {
                return;
            }

            // If identifier is a type name, this might be a static member access or similar, don't suggest null checks on it
            var identifierSymbol = model.GetSymbolInfo(identifier).Symbol;

            if ((identifierSymbol == null) || (identifierSymbol.IsType()))
            {
                return;
            }

            // Identifier might be part of a MemberAccessExpression and we need to check it for null as a whole
            identifier = GetOuterMemberAccessExpression(identifier) ?? identifier;

            if ((identifier.Parent is ExpressionSyntax) && ConditionContainsNullCheck((ExpressionSyntax)identifier.Parent, identifier))
            {
                return;
            }

            var identifierAncestors = identifier.Ancestors();

            // Don't surround Return statements with checks
            if (identifierAncestors.OfType <ReturnStatementSyntax>().Any())
            {
                return;
            }

            // If identifier is in a conditional ternary expression, skip refactoring is case of present null check in its condition
            var conditionalExprParent = identifierAncestors.OfType <TernaryConditionalExpressionSyntax>().FirstOrDefault();

            if ((conditionalExprParent != null) && ConditionContainsNullCheck(conditionalExprParent.Condition, identifier))
            {
                return;
            }

            // Check identifier type, don't suggest null checks for value types!
            var identifierType = model.GetTypeInfo(identifier).Type;

            if ((identifierType == null) || (identifierType.IsValueType && !identifierType.IsNullableType()))
            {
                return;
            }

            SyntaxNode statementToWrap = identifierAncestors.OfType <ExecutableStatementSyntax>().FirstOrDefault();

            if (statementToWrap == null)
            {
                return;
            }

            // No refactoring if statement is inside of a local variable declaration
            if (statementToWrap is LocalDeclarationStatementSyntax)
            {
                return;
            }

            bool       wrapWithSingleLineIfStatement = false;
            SyntaxNode newWrappedStatement           = null;

            var wrappedStatementAncestors = statementToWrap.Ancestors();

            if (wrappedStatementAncestors.OfType <SingleLineLambdaExpressionSyntax>().Any())
            {
                // Inside of a single-line lambda => wrap with single line If statement
                wrapWithSingleLineIfStatement = true;
            }

            // Check surrounding block
            var surroundingElseIfBlock = wrappedStatementAncestors.FirstOrDefault() as ElseIfBlockSyntax;

            if (surroundingElseIfBlock != null)
            {
                // Special handling for extension of Else If blocks
                if (StatementWithConditionContainsNullCheck(surroundingElseIfBlock, identifier))
                {
                    return;
                }
                statementToWrap     = surroundingElseIfBlock;
                newWrappedStatement = ExtendIfConditionWithNullCheck(surroundingElseIfBlock, identifier);
            }
            else
            {
                var surroundingStatement = wrappedStatementAncestors.OfType <ExecutableStatementSyntax>().FirstOrDefault();
                if (surroundingStatement != null)
                {
                    if (StatementWithConditionContainsNullCheck(surroundingStatement, identifier))
                    {
                        return;
                    }
                    if ((surroundingStatement is MultiLineIfBlockSyntax) || (surroundingStatement is SingleLineIfStatementSyntax))
                    {
                        statementToWrap     = surroundingStatement;
                        newWrappedStatement = ExtendIfConditionWithNullCheck(surroundingStatement, identifier);
                    }
                }
                else
                {
                    if (StatementWithConditionContainsNullCheck(statementToWrap, identifier))
                    {
                        return;
                    }
                    if ((statementToWrap is MultiLineIfBlockSyntax) || (statementToWrap is SingleLineIfStatementSyntax))
                    {
                        newWrappedStatement = ExtendIfConditionWithNullCheck(statementToWrap, identifier);
                    }
                }
            }

            if (newWrappedStatement == null)
            {
                if (wrapWithSingleLineIfStatement)
                {
                    newWrappedStatement = SyntaxFactory.SingleLineIfStatement(
                        SyntaxFactory.Token(SyntaxKind.IfKeyword),
                        CreateIsNotNothingBinaryExpression(identifier),
                        SyntaxFactory.Token(SyntaxKind.ThenKeyword),
                        SyntaxFactory.List <StatementSyntax>(new[] { ((StatementSyntax)statementToWrap).WithoutLeadingTrivia().WithoutTrailingTrivia() }),
                        null
                        ).WithLeadingTrivia(statementToWrap.GetLeadingTrivia()).WithTrailingTrivia(statementToWrap.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation);
                }
                else
                {
                    newWrappedStatement = SyntaxFactory.MultiLineIfBlock(
                        SyntaxFactory.IfStatement(
                            SyntaxFactory.Token(SyntaxKind.IfKeyword),
                            CreateIsNotNothingBinaryExpression(identifier),
                            SyntaxFactory.Token(SyntaxKind.ThenKeyword)),
                        SyntaxFactory.List <StatementSyntax>(new[] { ((StatementSyntax)statementToWrap).WithoutLeadingTrivia().WithoutTrailingTrivia() }),
                        SyntaxFactory.List <ElseIfBlockSyntax>(),
                        null
                        ).WithLeadingTrivia(statementToWrap.GetLeadingTrivia()).WithTrailingTrivia(statementToWrap.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation);
                }
            }

            context.RegisterRefactoring(CodeActionFactory.Create(token.Span, DiagnosticSeverity.Info, GettextCatalog.GetString("Add check for Nothing"), t2 =>
            {
                var newRoot = root.ReplaceNode <SyntaxNode>(statementToWrap, newWrappedStatement);
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }));
        }
示例#14
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token = root.FindToken(span.Start);

            if (token.Parent == null)
            {
                return;
            }

            var bracketedList = token.Parent.AncestorsAndSelf().OfType <BracketedArgumentListSyntax>().FirstOrDefault();

            if (bracketedList == null)
            {
                return;
            }
            var elementAccess = bracketedList.AncestorsAndSelf().OfType <ElementAccessExpressionSyntax>().FirstOrDefault();

            if (elementAccess == null)
            {
                return;
            }
            var elementType = model.GetTypeInfo(elementAccess.Expression);
            var type        = elementType.Type;

            if (type == null)
            {
                return;
            }
            if (!IsDictionary(type as INamedTypeSymbol) && !type.AllInterfaces.Any(IsDictionary))
            {
                return;
            }
            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    string.Format(GettextCatalog.GetString("Use 'if ({0}.TryGetValue({1}, out val))'"), elementAccess.Expression, elementAccess.ArgumentList.Arguments.First()),
                    t2 =>
            {
                var reservedNames        = model.LookupSymbols(elementAccess.SpanStart).Select(s => s.Name);
                string localVariableName = NameGenerator.EnsureUniqueness("val", reservedNames, true);

                var parentStatement = elementAccess.Parent.AncestorsAndSelf().OfType <StatementSyntax>().FirstOrDefault();
                var newParent       = SyntaxFactory.IfStatement(
                    SyntaxFactory.InvocationExpression(
                        SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, elementAccess.Expression, SyntaxFactory.IdentifierName("TryGetValue")),
                        SyntaxFactory.ArgumentList(elementAccess.ArgumentList.Arguments.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(localVariableName)).WithRefOrOutKeyword(SyntaxFactory.Token(SyntaxKind.OutKeyword))))
                        ),
                    parentStatement.ReplaceNode(elementAccess, SyntaxFactory.IdentifierName(localVariableName))
                    ).WithAdditionalAnnotations(Formatter.Annotation);
                var dict = IsDictionary(elementType.Type as INamedTypeSymbol) ? elementType.Type : elementType.Type.AllInterfaces.First(IsDictionary);

                var varDecl = SyntaxFactory.LocalDeclarationStatement(
                    SyntaxFactory.VariableDeclaration(
                        dict.GetTypeArguments()[1].GenerateTypeSyntax(),
                        SyntaxFactory.SeparatedList(new[] { SyntaxFactory.VariableDeclarator(localVariableName) })
                        )
                    ).WithAdditionalAnnotations(Formatter.Annotation);

                SyntaxNode newRoot;

                if (parentStatement.Parent.IsKind(SyntaxKind.Block))
                {
                    newRoot = root.ReplaceNode(parentStatement, new SyntaxNode[] { varDecl, newParent });
                }
                else
                {
                    newRoot = root.ReplaceNode(parentStatement, SyntaxFactory.Block(varDecl, newParent).WithAdditionalAnnotations(Formatter.Annotation));
                }

                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
示例#15
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token = root.FindToken(span.Start);

            if (token.Parent == null)
            {
                return;
            }

            var bracketedList = token.Parent.AncestorsAndSelf().OfType <BracketedArgumentListSyntax>().FirstOrDefault();

            if (bracketedList == null)
            {
                return;
            }
            var elementAccess = bracketedList.AncestorsAndSelf().OfType <ElementAccessExpressionSyntax>().FirstOrDefault();

            if (elementAccess == null)
            {
                return;
            }
            var elementType = model.GetTypeInfo(elementAccess.Expression);
            var type        = elementType.Type;

            if (type == null)
            {
                return;
            }
            if (!IsCollection(type as INamedTypeSymbol) && !type.AllInterfaces.Any(IsCollection))
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    string.Format(GettextCatalog.GetString("Check 'if ({0}.Count > {1})'"), elementAccess.Expression, elementAccess.ArgumentList.Arguments.First()),
                    t2 =>
            {
                var parentStatement = elementAccess.Parent.AncestorsAndSelf().OfType <StatementSyntax>().FirstOrDefault();

                var newParent = SyntaxFactory.IfStatement(
                    SyntaxFactory.BinaryExpression(
                        SyntaxKind.GreaterThanExpression,
                        SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, elementAccess.Expression, SyntaxFactory.IdentifierName("Count")),
                        elementAccess.ArgumentList.Arguments.First().Expression
                        ),
                    parentStatement
                    );

                return(Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode((SyntaxNode)parentStatement, newParent.WithAdditionalAnnotations(Formatter.Annotation)))));
            }
                    )
                );
        }
示例#16
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxToken token = root.FindToken(span.Start);

            if (!token.IsKind(SyntaxKind.IdentifierToken))
            {
                return;
            }
            var property = token.Parent as PropertyDeclarationSyntax;

            if (property == null || !property.Identifier.Span.Contains(span))
            {
                return;
            }
            if (IsEmptyComputedProperty(property))
            {
                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        token.Span,
                        DiagnosticSeverity.Info,
                        GettextCatalog.GetString("Convert to auto-property"),
                        t2 =>
                {
                    var newRoot = root.ReplaceNode(property, CreateNewProperty(property).WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia(property.GetLeadingTrivia()));
                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }
                        )
                    );
                return;
            }
            var field = GetBackingField(model, property);

            if (!IsValidField(field, property.Parent as TypeDeclarationSyntax))
            {
                return;
            }

            //variable declarator->declaration->field declaration
            var backingFieldNode = root.FindNode(field.Locations.First().SourceSpan).Ancestors().OfType <FieldDeclarationSyntax>().First();


            var propertyAnnotation = new SyntaxAnnotation();
            var fieldAnnotation    = new SyntaxAnnotation();

            //annotate our property node and our field node
            root = root.ReplaceNode((SyntaxNode)property, property.WithAdditionalAnnotations(propertyAnnotation));
            root = root.ReplaceNode((SyntaxNode)root.FindNode(backingFieldNode.Span), backingFieldNode.WithAdditionalAnnotations(fieldAnnotation));

            context.RegisterRefactoring(
                CodeActionFactory.Create(token.Span, DiagnosticSeverity.Info, GettextCatalog.GetString("Convert to auto-property"),
                                         PerformAction(document, model, root, field.Name, CreateNewProperty(property), propertyAnnotation, fieldAnnotation))
                );
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(container, explicitName, name) = await GetContainerAsync(context).ConfigureAwait(false);

            if (container == null)
            {
                return;
            }

            if (!CheckExplicitNameAllowsConversion(explicitName))
            {
                return;
            }

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

            var member = semanticModel.GetDeclaredSymbol(container, cancellationToken);

            Contract.ThrowIfNull(member);

            if (!CheckMemberCanBeConverted(member))
            {
                return;
            }

            var project = document.Project;

            var directlyImplementedMembers = new MemberImplementationMap();

            // Grab the name off of the *interface* member being implemented, not the implementation
            // member.  Interface member names are the expected names that people expect to see
            // (like "GetEnumerator"), instead of the auto-generated names that the compiler makes
            // like: "System.IEnumerable.GetEnumerator"
            directlyImplementedMembers.AddRange(member, member.ExplicitOrImplicitInterfaceImplementations());

            var codeAction = new MyCodeAction(
                string.Format(Implement_0, member.ExplicitOrImplicitInterfaceImplementations().First().Name),
                c => ChangeImplementationAsync(project, directlyImplementedMembers, c));

            var containingType = member.ContainingType;
            var interfaceTypes = directlyImplementedMembers.SelectMany(kvp => kvp.Value).Select(
                s => s.ContainingType).Distinct().ToImmutableArray();

            var implementedMembersFromSameInterfaces = GetImplementedMembers(containingType, interfaceTypes);
            var implementedMembersFromAllInterfaces  = GetImplementedMembers(containingType, containingType.AllInterfaces);

            var offerForSameInterface = TotalCount(implementedMembersFromSameInterfaces) > TotalCount(directlyImplementedMembers);
            var offerForAllInterfaces = TotalCount(implementedMembersFromAllInterfaces) > TotalCount(implementedMembersFromSameInterfaces);

            // If there's only one member in the interface we implement, and there are no other
            // interfaces, then just offer to switch the implementation for this single member
            if (!offerForSameInterface && !offerForAllInterfaces)
            {
                context.RegisterRefactoring(codeAction);
                return;
            }

            // Otherwise, create a top level action to change the implementation, and offer this
            // action, along with either/both of the other two.

            var nestedActions = ArrayBuilder <CodeAction> .GetInstance();

            nestedActions.Add(codeAction);

            if (offerForSameInterface)
            {
                var interfaceNames = interfaceTypes.Select(i => i.ToDisplayString(NameAndTypeParametersFormat));
                nestedActions.Add(new MyCodeAction(
                                      string.Format(Implement_0, string.Join(", ", interfaceNames)),
                                      c => ChangeImplementationAsync(project, implementedMembersFromSameInterfaces, c)));
            }

            if (offerForAllInterfaces)
            {
                nestedActions.Add(new MyCodeAction(
                                      Implement_all_interfaces,
                                      c => ChangeImplementationAsync(project, implementedMembersFromAllInterfaces, c)));
            }

            context.RegisterRefactoring(new CodeAction.CodeActionWithNestedActions(
                                            Implement, nestedActions.ToImmutableAndFree(), isInlinable: true));
        }
		public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
		{
			var actions = await service.GetEncapsulateFieldCodeActionsAsync(context.Document, context.Span, context.CancellationToken).ConfigureAwait(false);
			foreach (var action in actions)
				context.RegisterRefactoring(action);
		}
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var cancellationToken = context.CancellationToken;

            var(tupleExprOrTypeNode, tupleType) = await TryGetTupleInfoAsync(
                document, context.Span, cancellationToken).ConfigureAwait(false);

            if (tupleExprOrTypeNode == null || tupleType == null)
            {
                return;
            }

            // Check if the tuple type actually references another anonymous type inside of it.
            // If it does, we can't convert this.  There is no way to describe this anonymous type
            // in the concrete type we create.
            var fields = tupleType.TupleElements;
            var containsAnonymousType = fields.Any(p => p.Type.ContainsAnonymousType());

            if (containsAnonymousType)
            {
                return;
            }

            var capturedTypeParameters =
                fields.Select(p => p.Type)
                .SelectMany(t => t.GetReferencedTypeParameters())
                .Distinct()
                .ToImmutableArray();

            var scopes = ArrayBuilder <CodeAction> .GetInstance();

            scopes.Add(CreateAction(context, Scope.ContainingMember));

            // If we captured any Method type-parameters, we can only replace the tuple types we
            // find in the containing method.  No other tuple types in other members would be able
            // to reference this type parameter.
            if (!capturedTypeParameters.Any(tp => tp.TypeParameterKind == TypeParameterKind.Method))
            {
                var containingType = tupleExprOrTypeNode.GetAncestor <TTypeBlockSyntax>();
                if (containingType != null)
                {
                    scopes.Add(CreateAction(context, Scope.ContainingType));
                }

                // If we captured any Type type-parameters, we can only replace the tuple
                // types we find in the containing type.  No other tuple types in other
                // types would be able to reference this type parameter.
                if (!capturedTypeParameters.Any(tp => tp.TypeParameterKind == TypeParameterKind.Type))
                {
                    // To do a global find/replace of matching tuples, we need to search for documents
                    // containing tuples *and* which have the names of the tuple fields in them.  That means
                    // the tuple field name must exist in the document.
                    //
                    // this means we can only find tuples like ```(x: 1, ...)``` but not ```(1, 2)```.  The
                    // latter has members called Item1 and Item2, but those names don't show up in source.
                    if (fields.All(f => f.CorrespondingTupleField != f))
                    {
                        scopes.Add(CreateAction(context, Scope.ContainingProject));
                        scopes.Add(CreateAction(context, Scope.DependentProjects));
                    }
                }
            }

            context.RegisterRefactoring(new CodeAction.CodeActionWithNestedActions(
                                            FeaturesResources.Convert_to_struct,
                                            scopes.ToImmutableAndFree(),
                                            isInlinable: false));
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);

            MemberDeclarationSyntax memberDeclaration = root
                                                        .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                        .FirstAncestorOrSelf <MemberDeclarationSyntax>();

            if (memberDeclaration == null)
            {
                return;
            }

            SplitAttributesRefactoring.Refactor(context, memberDeclaration);
            MergeAttributesRefactoring.Refactor(context, memberDeclaration);

            switch (memberDeclaration.Kind())
            {
            case SyntaxKind.MethodDeclaration:
            case SyntaxKind.IndexerDeclaration:
            case SyntaxKind.PropertyDeclaration:
            case SyntaxKind.OperatorDeclaration:
            case SyntaxKind.ConversionOperatorDeclaration:
            case SyntaxKind.ConstructorDeclaration:
            case SyntaxKind.EventDeclaration:
            case SyntaxKind.NamespaceDeclaration:
            case SyntaxKind.ClassDeclaration:
            case SyntaxKind.StructDeclaration:
            case SyntaxKind.InterfaceDeclaration:
            {
                if (MemberDeclarationRefactoring.CanBeRemoved(context, memberDeclaration))
                {
                    context.RegisterRefactoring(
                        "Remove " + SyntaxHelper.GetSyntaxNodeName(memberDeclaration),
                        cancellationToken => MemberDeclarationRefactoring.RemoveMemberAsync(context.Document, memberDeclaration, cancellationToken));
                }

                if (MemberDeclarationRefactoring.CanBeDuplicated(context, memberDeclaration))
                {
                    context.RegisterRefactoring(
                        "Duplicate " + SyntaxHelper.GetSyntaxNodeName(memberDeclaration),
                        cancellationToken => MemberDeclarationRefactoring.DuplicateMemberAsync(context.Document, memberDeclaration, cancellationToken));
                }

                break;
            }
            }

            if (root.FindTrivia(context.Span.Start).IsWhitespaceOrEndOfLine())
            {
                SwapMembersRefactoring.Refactor(context, memberDeclaration);
            }

            switch (memberDeclaration.Kind())
            {
            case SyntaxKind.MethodDeclaration:
            {
                await ComputeRefactoringsAsync(context, (MethodDeclarationSyntax)memberDeclaration);

                break;
            }

            case SyntaxKind.IndexerDeclaration:
            {
                ComputeRefactorings(context, (IndexerDeclarationSyntax)memberDeclaration);
                break;
            }

            case SyntaxKind.PropertyDeclaration:
            {
                await ComputeRefactoringsAsync(context, (PropertyDeclarationSyntax)memberDeclaration);

                break;
            }

            case SyntaxKind.EventFieldDeclaration:
            {
                await ComputeRefactoringsAsync(context, (EventFieldDeclarationSyntax)memberDeclaration);

                break;
            }
            }
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, _, cancellationToken) = context;
            var numericToken = await GetNumericTokenAsync(context).ConfigureAwait(false);

            if (numericToken == default || numericToken.ContainsDiagnostics)
            {
                return;
            }

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

            var symbol = semanticModel.GetTypeInfo(syntaxNode, cancellationToken).Type;

            if (symbol == null)
            {
                return;
            }

            if (!IsIntegral(symbol.SpecialType))
            {
                return;
            }

            var valueOpt = semanticModel.GetConstantValue(syntaxNode);

            if (!valueOpt.HasValue)
            {
                return;
            }

            var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var value       = IntegerUtilities.ToInt64(valueOpt.Value);
            var numericText = numericToken.ToString();

            var(hexPrefix, binaryPrefix) = GetNumericLiteralPrefixes();
            var(prefix, number, suffix)  = GetNumericLiteralParts(numericText, hexPrefix, binaryPrefix);
            var kind = string.IsNullOrEmpty(prefix) ? NumericKind.Decimal
                : prefix.Equals(hexPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Hexadecimal
                : prefix.Equals(binaryPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Binary
                : NumericKind.Unknown;

            if (kind == NumericKind.Unknown)
            {
                return;
            }

            if (kind != NumericKind.Decimal)
            {
                RegisterRefactoringWithResult(value.ToString(), FeaturesResources.Convert_to_decimal);
            }

            if (kind != NumericKind.Binary)
            {
                RegisterRefactoringWithResult(binaryPrefix + Convert.ToString(value, toBase: 2), FeaturesResources.Convert_to_binary);
            }

            if (kind != NumericKind.Hexadecimal)
            {
                RegisterRefactoringWithResult(hexPrefix + value.ToString("X"), FeaturesResources.Convert_to_hex);
            }

            const string DigitSeparator = "_";

            if (numericText.Contains(DigitSeparator))
            {
                RegisterRefactoringWithResult(prefix + number.Replace(DigitSeparator, string.Empty), FeaturesResources.Remove_separators);
            }
            else
            {
                switch (kind)
                {
                case NumericKind.Decimal when number.Length > 3:
                    RegisterRefactoringWithResult(AddSeparators(number, interval: 3), FeaturesResources.Separate_thousands);
                    break;

                case NumericKind.Hexadecimal when number.Length > 4:
                    RegisterRefactoringWithResult(hexPrefix + AddSeparators(number, interval: 4), FeaturesResources.Separate_words);
                    break;

                case NumericKind.Binary when number.Length > 4:
                    RegisterRefactoringWithResult(binaryPrefix + AddSeparators(number, interval: 4), FeaturesResources.Separate_nibbles);
                    break;
                }
            }

            void RegisterRefactoringWithResult(string text, string title)
            {
                context.RegisterRefactoring(
                    new MyCodeAction(title, c => ReplaceTokenAsync(document, root, numericToken, value, text, suffix)),
                    numericToken.Span);
            }
        }
示例#22
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var textSpan          = context.Span;
            var cancellationToken = context.CancellationToken;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles ||
                document.IsGeneratedCode(cancellationToken))
            {
                return;
            }

            var state = await State.CreateAsync(this, document, textSpan, cancellationToken).ConfigureAwait(false);

            if (state == null)
            {
                return;
            }

            // No move file action if rootnamespace isn't a prefix of current declared namespace
            if (state.RelativeDeclaredNamespace != null)
            {
                // These code actions try to move file to a new location based on declared namespace
                // and the default namespace of the project. The new location is a list of folders
                // determined by the relateive part of the declared namespace compare to the default namespace.
                //
                // For example, if he default namespace is `A.B.C`, file path is
                // "[project root dir]\Class1.cs" and declared namespace in the file is
                // `A.B.C.D.E`, then this action will move the file to [project root dir]\D\E\Class1.cs". .
                //
                // We also try to use existing folders as target if possible, using the same example above,
                // if folder "[project root dir]\D.E\" already exist, we will also offer to move file to
                // "[project root dir]\D.E\Class1.cs".
                context.RegisterRefactorings(MoveFileCodeAction.Create(state));
            }

            // No change namespace action if we can't construct a valid namespace from rootnamespace and folder names.
            if (state.TargetNamespace != null)
            {
                // This code action tries to change the name of the namespace declaration to
                // match the folder hierarchy of the document. The new namespace is constructed
                // by concatenating the default namespace of the project and all the folders in
                // the file path up to the project root.
                //
                // For example, if he default namespace is `A.B.C`, file path is
                // "[project root dir]\D\E\F\Class1.cs" and declared namespace in the file is
                // `Foo.Bar.Baz`, then this action will change the namespace declaration
                // to `A.B.C.D.E.F`.
                //
                // Note that it also handles the case where the target namespace or declared namespace
                // is global namespace, i.e. default namespace is "" and the file is located at project
                // root directory, and no namespace declaration in the document, respectively.

                var service = document.GetLanguageService <IChangeNamespaceService>();

                var solutionChangeAction = new ChangeNamespaceCodeAction(
                    state.TargetNamespace.Length == 0
                        ? FeaturesResources.Change_to_global_namespace
                        : string.Format(FeaturesResources.Change_namespace_to_0, state.TargetNamespace),
                    token => service.ChangeNamespaceAsync(document, state.Container, state.TargetNamespace, token));

                context.RegisterRefactoring(solutionChangeAction);
            }
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            SyntaxNode root = await context.Document.GetSyntaxRootAsync(context.CancellationToken);

            InvocationExpressionSyntax invocationExpression = root
                                                              .FindNode(context.Span, getInnermostNodeForTie: true)?
                                                              .FirstAncestorOrSelf <InvocationExpressionSyntax>();

            if (invocationExpression != null &&
                invocationExpression.Expression != null &&
                invocationExpression.ArgumentList != null &&
                invocationExpression.Expression.IsKind(SyntaxKind.SimpleMemberAccessExpression) &&
                ((MemberAccessExpressionSyntax)invocationExpression.Expression).Name?.Span.Contains(context.Span) == true &&
                context.Document.SupportsSemanticModel)
            {
                SemanticModel semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken);

                ConvertEnumerableMethodToElementAccessRefactoring.Refactor(context, invocationExpression, semanticModel);

                var methodSymbol = semanticModel.GetSymbolInfo(invocationExpression, context.CancellationToken).Symbol as IMethodSymbol;

                if (methodSymbol == null)
                {
                    return;
                }

                INamedTypeSymbol enumerable = semanticModel.Compilation.GetTypeByMetadataName("System.Linq.Enumerable");

                if (enumerable == null)
                {
                    return;
                }

                int argumentIndex = (methodSymbol.ReducedFrom != null) ? 0 : 1;

                methodSymbol = methodSymbol.ReducedFrom ?? methodSymbol.ConstructedFrom;

                if (methodSymbol.Equals(GetMethod(enumerable, "Any")))
                {
                    ExpressionSyntax expression = GetExpression(invocationExpression, argumentIndex);

                    if (expression != null)
                    {
                        context.RegisterRefactoring(
                            "Change 'Any' to 'All'",
                            cancellationToken =>
                        {
                            return(CreateChangedDocumentAsync(
                                       context.Document,
                                       invocationExpression,
                                       "All",
                                       expression,
                                       cancellationToken));
                        });
                    }
                }
                else if (methodSymbol.Equals(GetMethod(enumerable, "All")))
                {
                    ExpressionSyntax expression = GetExpression(invocationExpression, argumentIndex);

                    if (expression != null)
                    {
                        context.RegisterRefactoring(
                            "Change 'All' to 'Any'",
                            cancellationToken =>
                        {
                            return(CreateChangedDocumentAsync(
                                       context.Document,
                                       invocationExpression,
                                       "Any",
                                       expression,
                                       cancellationToken));
                        });
                    }
                }
            }
        }
示例#24
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;
            var service  = document.GetLanguageService <IReplaceMethodWithPropertyService>();

            if (service == null)
            {
                return;
            }

            var cancellationToken = context.CancellationToken;

            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var position = context.Span.Start;
            var token    = root.FindToken(position);

            if (!token.Span.Contains(context.Span))
            {
                return;
            }

            var methodDeclaration = service.GetMethodDeclaration(token);

            if (methodDeclaration == null)
            {
                return;
            }

            // Ok, we're in the signature of the method.  Now see if the method is viable to be
            // replaced with a property.
            var methodName = service.GetMethodName(methodDeclaration);

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

            var methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration) as IMethodSymbol;

            if (!IsValidGetMethod(methodSymbol))
            {
                return;
            }

            var hasGetPrefix = HasGetPrefix(methodName);
            var propertyName = hasGetPrefix
                ? methodName.Substring(GetPrefix.Length)
                : methodName;
            var nameChanged = hasGetPrefix;

            // Looks good!
            context.RegisterRefactoring(new ReplaceMethodWithPropertyCodeAction(
                                            string.Format(FeaturesResources.Replace0WithProperty, methodName),
                                            c => ReplaceMethodsWithProperty(context.Document, propertyName, nameChanged, methodSymbol, setMethod: null, cancellationToken: c),
                                            methodName));

            // If this method starts with 'Get' see if there's an associated 'Set' method we could
            // replace as well.
            if (hasGetPrefix)
            {
                var setMethod = FindSetMethod(methodSymbol);
                if (setMethod != null)
                {
                    context.RegisterRefactoring(new ReplaceMethodWithPropertyCodeAction(
                                                    string.Format(FeaturesResources.Replace0and1WithProperty, methodName, setMethod.Name),
                                                    c => ReplaceMethodsWithProperty(context.Document, propertyName, nameChanged, methodSymbol, setMethod, cancellationToken: c),
                                                    methodName + "-get/set"));
                }
            }
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, textSpan, cancellationToken) = context;
            var forStatement = await context.TryGetRelevantNodeAsync <TForStatementSyntax>().ConfigureAwait(false);

            if (forStatement == null)
            {
                return;
            }

            if (!TryGetForStatementComponents(forStatement,
                                              out var iterationVariable, out var initializer,
                                              out var memberAccess, out var stepValueExpressionOpt, cancellationToken))
            {
                return;
            }

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();

            syntaxFacts.GetPartsOfMemberAccessExpression(memberAccess,
                                                         out var collectionExpressionNode, out var memberAccessNameNode);

            var collectionExpression = (TExpressionSyntax)collectionExpressionNode;

            syntaxFacts.GetNameAndArityOfSimpleName(memberAccessNameNode, out var memberAccessName, out _);
            if (memberAccessName is not nameof(Array.Length) and not nameof(IList.Count))
            {
                return;
            }

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

            // Make sure it's a single-variable for loop and that we're not a loop where we're
            // referencing some previously declared symbol.  i.e
            // VB allows:
            //
            //      dim i as integer
            //      for i = 0 to ...
            //
            // We can't convert this as it would change important semantics.
            // NOTE: we could potentially update this if we saw that the variable was not used
            // after the for-loop.  But, for now, we'll just be conservative and assume this means
            // the user wanted the 'i' for some other purpose and we should keep things as is.
            if (semanticModel.GetOperation(forStatement, cancellationToken) is not ILoopOperation operation || operation.Locals.Length != 1)
            {
                return;
            }

            // Make sure we're starting at 0.
            var initializerValue = semanticModel.GetConstantValue(initializer, cancellationToken);

            if (!(initializerValue.HasValue && initializerValue.Value is 0))
            {
                return;
            }

            // Make sure we're incrementing by 1.
            if (stepValueExpressionOpt != null)
            {
                var stepValue = semanticModel.GetConstantValue(stepValueExpressionOpt);
                if (!(stepValue.HasValue && stepValue.Value is 1))
                {
                    return;
                }
            }

            var collectionType = semanticModel.GetTypeInfo(collectionExpression, cancellationToken);

            if (collectionType.Type == null || collectionType.Type.TypeKind == TypeKind.Error)
            {
                return;
            }

            var containingType = semanticModel.GetEnclosingNamedType(textSpan.Start, cancellationToken);

            if (containingType == null)
            {
                return;
            }

            var ienumerableType = semanticModel.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T);
            var ienumeratorType = semanticModel.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T);

            // make sure the collection can be iterated.
            if (!TryGetIterationElementType(
                    containingType, collectionType.Type,
                    ienumerableType, ienumeratorType,
                    out var iterationType))
            {
                return;
            }

            // If the user uses the iteration variable for any other reason, we can't convert this.
            var bodyStatements = GetBodyStatements(forStatement);

            foreach (var statement in bodyStatements)
            {
                if (IterationVariableIsUsedForMoreThanCollectionIndex(statement))
                {
                    return;
                }
            }

            // Looks good.  We can convert this.
            var title = GetTitle();

            context.RegisterRefactoring(
                CodeAction.Create(
                    title,
                    c => ConvertForToForEachAsync(
                        document, forStatement, iterationVariable, collectionExpression,
                        containingType, collectionType.Type, iterationType, c),
                    title),
                forStatement.Span);

            return;

            // local functions
            bool IterationVariableIsUsedForMoreThanCollectionIndex(SyntaxNode current)
            {
                if (syntaxFacts.IsIdentifierName(current))
                {
                    syntaxFacts.GetNameAndArityOfSimpleName(current, out var name, out _);
                    if (name == iterationVariable.ValueText)
                    {
                        // found a reference.  make sure it's only used inside something like
                        // list[i]

                        if (!syntaxFacts.IsSimpleArgument(current.Parent) ||
                            !syntaxFacts.IsElementAccessExpression(current.Parent?.Parent?.Parent))
                        {
                            // used in something other than accessing into a collection.
                            // can't convert this for-loop.
                            return(true);
                        }

                        var arguments = syntaxFacts.GetArgumentsOfArgumentList(current.Parent.Parent);
                        if (arguments.Count != 1)
                        {
                            // was used in a multi-dimensional indexing.  Can't conver this.
                            return(true);
                        }

                        var expr = syntaxFacts.GetExpressionOfElementAccessExpression(current.Parent.Parent.Parent);
                        if (!syntaxFacts.AreEquivalent(expr, collectionExpression))
                        {
                            // was indexing into something other than the collection.
                            // can't convert this for-loop.
                            return(true);
                        }

                        // this usage of the for-variable is fine.
                    }
                }

                foreach (var child in current.ChildNodesAndTokens())
                {
                    if (child.IsNode)
                    {
                        if (IterationVariableIsUsedForMoreThanCollectionIndex(child.AsNode() !))
                        {
                            return(true);
                        }
                    }
                }

                return(false);
            }
        }
示例#26
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token     = root.FindToken(span.Start);
            var parameter = token.Parent as ParameterSyntax;

            if (parameter != null)
            {
                var ctor = parameter.Parent.Parent as ConstructorDeclarationSyntax;
                if (ctor == null)
                {
                    return;
                }

                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        parameter.Span,
                        DiagnosticSeverity.Info,
                        GettextCatalog.GetString("Initialize field from parameter"),
                        t2 =>
                {
                    var newFieldName = NameProposalService.GetNameProposal(parameter.Identifier.ValueText, SyntaxKind.FieldDeclaration, Accessibility.Private, false, context.Document, ctor.SpanStart);
                    var newField     = SyntaxFactory.FieldDeclaration(
                        SyntaxFactory.VariableDeclaration(
                            parameter.Type,
                            SyntaxFactory.SingletonSeparatedList <VariableDeclaratorSyntax>(SyntaxFactory.VariableDeclarator(newFieldName)))
                        ).WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)))
                                       .WithAdditionalAnnotations(Formatter.Annotation);

                    var assignmentStatement = SyntaxFactory.ExpressionStatement(
                        SyntaxFactory.AssignmentExpression(
                            SyntaxKind.SimpleAssignmentExpression,
                            SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(newFieldName)),
                            SyntaxFactory.IdentifierName(newFieldName)
                            )
                        ).WithAdditionalAnnotations(Formatter.Annotation);

                    var trackedRoot = root.TrackNodes(ctor);
                    var newRoot     = trackedRoot.InsertNodesBefore(trackedRoot.GetCurrentNode(ctor), new List <SyntaxNode>()
                    {
                        newField
                    });
                    newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(ctor), ctor.WithBody(
                                                      ctor.Body.WithStatements(SyntaxFactory.List <StatementSyntax>(new[] { assignmentStatement }.Concat(ctor.Body.Statements)))
                                                      ));

                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                })
                    );
            }
        }
示例#27
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token = root.FindToken(span.Start);

            if (!token.IsKind(SyntaxKind.IdentifierToken))
            {
                return;
            }

            var node = token.Parent as MemberDeclarationSyntax;

            if (node == null)
            {
                return;
            }
            var declaredSymbol = model.GetDeclaredSymbol(node, cancellationToken);

            if (declaredSymbol == null || !string.IsNullOrEmpty(declaredSymbol.GetDocumentationCommentXml(null, false, cancellationToken)))
            {
                return;
            }

            string documentation;
            var    baseMember = GetBaseMember(declaredSymbol, out documentation, cancellationToken);

            if (baseMember == null || string.IsNullOrEmpty(documentation))
            {
                return;
            }
            XDocument doc         = XDocument.Parse(documentation);
            var       rootElement = doc.Elements().First();
            var       inner       = string.Join(System.Environment.NewLine, rootElement.Nodes().Select(n => n.ToString())).Trim();

            if (string.IsNullOrEmpty(inner))
            {
                return;
            }

            // "Copy comments from interface"
            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    baseMember.ContainingType != null && baseMember.ContainingType.TypeKind == TypeKind.Interface ? GettextCatalog.GetString("Copy comments from interface") : GettextCatalog.GetString("Copy comments from base"),
                    t2 =>
            {
                var triva = node.GetLeadingTrivia();

                var indentTrivia = triva.FirstOrDefault(t => t.IsKind(SyntaxKind.WhitespaceTrivia));
                var indent       = indentTrivia.ToString();

                string[] lines = NewLine.SplitLines(inner);
                for (int i = 0; i < lines.Length; i++)
                {
                    lines[i] = indent + "/// " + lines[i].Trim();
                }


                var eol = "\r\n";
                int idx = 0;
                while (idx < triva.Count && triva[idx].IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    idx++;
                }
                triva       = triva.Insert(idx, SyntaxFactory.SyntaxTrivia(SyntaxKind.SingleLineCommentTrivia, string.Join(eol, lines) + eol));
                var newRoot = root.ReplaceNode(node, node.WithLeadingTrivia(triva));
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
示例#28
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;

            if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }
            var span = context.Span;

            if (!span.IsEmpty)
            {
                return;
            }
            var cancellationToken = context.CancellationToken;

            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            var model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var root = await model.SyntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            var token     = root.FindToken(span.Start);
            var parameter = token.Parent as ParameterSyntax;

            if (parameter != null)
            {
                var ctor = parameter.Parent.Parent as ConstructorDeclarationSyntax;
                if (ctor == null)
                {
                    return;
                }

                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        parameter.Span,
                        DiagnosticSeverity.Info,
                        GettextCatalog.GetString("Initialize auto-property from parameter"),
                        t2 =>
                {
                    var propertyName     = GetPropertyName(parameter.Identifier.ToString());
                    var accessorDeclList = new SyntaxList <AccessorDeclarationSyntax>().Add(SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))).Add(SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
                    var newProperty      = SyntaxFactory.PropertyDeclaration(parameter.Type, propertyName)
                                           .WithAccessorList(SyntaxFactory.AccessorList(accessorDeclList))
                                           .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
                                           .WithAdditionalAnnotations(Formatter.Annotation);

                    var assignmentStatement = SyntaxFactory.ExpressionStatement(
                        SyntaxFactory.AssignmentExpression(
                            SyntaxKind.SimpleAssignmentExpression,
                            propertyName != parameter.Identifier.ToString() ? (ExpressionSyntax)SyntaxFactory.IdentifierName(propertyName) : SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(parameter.Identifier)),
                            SyntaxFactory.IdentifierName(parameter.Identifier)
                            )
                        ).WithAdditionalAnnotations(Formatter.Annotation);

                    root        = root.TrackNodes(ctor);
                    var newRoot = root.InsertNodesBefore(root.GetCurrentNode(ctor), new List <SyntaxNode>()
                    {
                        newProperty
                    });
                    newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(ctor), ctor.WithBody(
                                                      ctor.Body.WithStatements(SyntaxFactory.List <StatementSyntax>(new[] { assignmentStatement }.Concat(ctor.Body.Statements)))
                                                      ));

                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                })
                    );
            }
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            if (!options.IsFeatureEnabled(FeatureIdentifiers.AddInitializedFieldRefactoring))
            {
                return;
            }

            if (context.Document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles)
            {
                return;
            }

            if (!context.Span.IsEmpty)
            {
                return;
            }

            var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);

            var node = root.FindNode(context.Span);

            var parameter = node as ParameterSyntax;

            if (parameter == null && context.Span.Start > 0)
            {
                var span = new TextSpan(context.Span.Start - 1, 0);
                node = root.FindNode(span);

                parameter = node as ParameterSyntax;
                if (parameter == null)
                {
                    return;
                }
            }

            if (parameter == null)
            {
                return;
            }

            var constructor = parameter.Ancestors().OfType <ConstructorDeclarationSyntax>().FirstOrDefault();

            if (constructor == null)
            {
                return;
            }

            var model = await context.Document.GetSemanticModelAsync(context.CancellationToken);

            var constructorSymbol = model.GetDeclaredSymbol(constructor, context.CancellationToken);

            if (constructorSymbol != null && constructorSymbol.IsStatic)
            {
                return;
            }

            if (CheckIfAlreadyInitialized(model, parameter, constructor, context.CancellationToken))
            {
                return;
            }

            var existingField = FindExistingField(model, parameter, parameter.GetParentTypeDeclaration(), context.CancellationToken);

            var action = CodeAction.Create(existingField != null ? Resources.InitializeExistingField : Resources.AddInitializedField,
                                           cancellationToken => InitializeFieldAsync(context.Document, root, parameter, constructor, cancellationToken));

            context.RegisterRefactoring(action);
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(document, span, cancellationToken) = context;
            if (!span.IsEmpty)
            {
                return;
            }

            var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

            var root = await tree.GetRootAsync(cancellationToken).ConfigureAwait(false);

            if (document.Project.AnalyzerOptions.TryGetEditorConfigOption(CodeStyleOptions2.FileHeaderTemplate, tree, out string fileHeaderTemplate) &&
                !string.IsNullOrEmpty(fileHeaderTemplate))
            {
                // If we have a defined file header template, allow the analyzer and code fix to handle it
                return;
            }

            var position   = span.Start;
            var firstToken = root.GetFirstToken();

            if (!firstToken.FullSpan.IntersectsWith(position))
            {
                return;
            }

            var syntaxFacts = document.GetRequiredLanguageService <ISyntaxFactsService>();
            var banner      = syntaxFacts.GetFileBanner(root);

            if (banner.Length > 0)
            {
                // Already has a banner.
                return;
            }

            // Process the other documents in this document's project.  Look at the
            // ones that we can get a root from (without having to parse).  Then
            // look at the ones we'd need to parse.
            var siblingDocumentsAndRoots =
                document.Project.Documents
                .Where(d => d != document)
                .Select(d =>
            {
                d.TryGetSyntaxRoot(out var siblingRoot);
                return(document: d, root: siblingRoot);
            })
                .OrderBy((t1, t2) => (t1.root != null) == (t2.root != null) ? 0 : t1.root != null ? -1 : 1);

            foreach (var(siblingDocument, siblingRoot) in siblingDocumentsAndRoots)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var siblingBanner = await TryGetBannerAsync(siblingDocument, siblingRoot, cancellationToken).ConfigureAwait(false);

                if (siblingBanner.Length > 0 && !siblingDocument.IsGeneratedCode(cancellationToken))
                {
                    context.RegisterRefactoring(
                        new MyCodeAction(_ => AddBannerAsync(document, root, siblingDocument, siblingBanner)),
                        new Text.TextSpan(position, length: 0));
                    return;
                }
            }
        }
示例#31
0
            public async Task ComputeRefactoringsAsync(
                CodeRefactoringContext context, SyntaxNode root, CancellationToken cancellationToken)
            {
                if (context.Span.Length > 0)
                {
                    return;
                }

                var position = context.Span.Start;
                var token    = root.FindToken(position);

                if (token.Span.Start == position &&
                    IsCloseParenOrComma(token))
                {
                    token = token.GetPreviousToken();
                    if (token.Span.End != position)
                    {
                        return;
                    }
                }

                var argument = root.FindNode(token.Span).FirstAncestorOrSelfUntil <TBaseArgumentSyntax>(node => node is TArgumentListSyntax) as TSimpleArgumentSyntax;

                if (argument == null)
                {
                    return;
                }

                if (!IsPositionalArgument(argument))
                {
                    return;
                }

                // Arguments can be arbitrarily large.  Only offer this feature if the caret is on hte
                // line that the argument starts on.

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

                var argumentStartLine = sourceText.Lines.GetLineFromPosition(argument.Span.Start).LineNumber;
                var caretLine         = sourceText.Lines.GetLineFromPosition(position).LineNumber;

                if (argumentStartLine != caretLine)
                {
                    return;
                }

                var receiver = GetReceiver(argument);

                if (receiver == null)
                {
                    return;
                }

                if (receiver.ContainsDiagnostics)
                {
                    return;
                }

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

                var symbol = semanticModel.GetSymbolInfo(receiver, cancellationToken).Symbol;

                if (symbol == null)
                {
                    return;
                }

                var parameters = symbol.GetParameters();

                if (parameters.IsDefaultOrEmpty)
                {
                    return;
                }

                var argumentList = argument.Parent as TArgumentListSyntax;

                if (argumentList == null)
                {
                    return;
                }

                var arguments     = GetArguments(argumentList);
                var argumentCount = arguments.Count;
                var argumentIndex = arguments.IndexOf(argument);

                if (argumentIndex >= parameters.Length)
                {
                    return;
                }

                if (!IsLegalToAddNamedArguments(parameters, argumentCount))
                {
                    return;
                }

                for (var i = argumentIndex; i < argumentCount; i++)
                {
                    if (!(arguments[i] is TSimpleArgumentSyntax))
                    {
                        return;
                    }
                }

                var argumentName = parameters[argumentIndex].Name;

                if (this.SupportsNonTrailingNamedArguments(root.SyntaxTree.Options) &&
                    argumentIndex < argumentCount - 1)
                {
                    context.RegisterRefactoring(
                        new MyCodeAction(
                            string.Format(FeaturesResources.Add_argument_name_0, argumentName),
                            c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: false)));

                    context.RegisterRefactoring(
                        new MyCodeAction(
                            string.Format(FeaturesResources.Add_argument_name_0_including_trailing_arguments, argumentName),
                            c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: true)));
                }
                else
                {
                    context.RegisterRefactoring(
                        new MyCodeAction(
                            string.Format(FeaturesResources.Add_argument_name_0, argumentName),
                            c => AddNamedArgumentsAsync(root, document, argument, parameters, argumentIndex, includingTrailingArguments: true)));
                }
            }
示例#32
0
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var cancellationToken = context.CancellationToken;
            var syntaxFacts       = document.GetLanguageService <ISyntaxFactsService>();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var numericToken = await root.SyntaxTree.GetTouchingTokenAsync(context.Span.Start,
                                                                           token => syntaxFacts.IsNumericLiteralExpression(token.Parent), cancellationToken).ConfigureAwait(false);

            if (numericToken == default)
            {
                return;
            }

            if (numericToken.ContainsDiagnostics)
            {
                return;
            }

            if (context.Span.Length > 0 &&
                context.Span != numericToken.Span)
            {
                return;
            }

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

            var symbol = semanticModel.GetTypeInfo(syntaxNode, cancellationToken).Type;

            if (symbol == null)
            {
                return;
            }

            if (!IsIntegral(symbol.SpecialType))
            {
                return;
            }

            var valueOpt = semanticModel.GetConstantValue(syntaxNode);

            if (!valueOpt.HasValue)
            {
                return;
            }

            var value       = IntegerUtilities.ToInt64(valueOpt.Value);
            var numericText = numericToken.ToString();

            var(hexPrefix, binaryPrefix) = GetNumericLiteralPrefixes();
            var(prefix, number, suffix)  = GetNumericLiteralParts(numericText, hexPrefix, binaryPrefix);
            var kind = string.IsNullOrEmpty(prefix) ? NumericKind.Decimal
                : prefix.Equals(hexPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Hexadecimal
                : prefix.Equals(binaryPrefix, StringComparison.OrdinalIgnoreCase) ? NumericKind.Binary
                : NumericKind.Unknown;

            if (kind == NumericKind.Unknown)
            {
                return;
            }

            if (kind != NumericKind.Decimal)
            {
                RegisterRefactoringWithResult(value.ToString(), FeaturesResources.Convert_to_decimal);
            }

            if (kind != NumericKind.Binary)
            {
                RegisterRefactoringWithResult(binaryPrefix + Convert.ToString(value, 2), FeaturesResources.Convert_to_binary);
            }

            if (kind != NumericKind.Hexadecimal)
            {
                RegisterRefactoringWithResult(hexPrefix + value.ToString("X"), FeaturesResources.Convert_to_hex);
            }

            const string DigitSeparator = "_";

            if (numericText.Contains(DigitSeparator))
            {
                RegisterRefactoringWithResult(prefix + number.Replace(DigitSeparator, string.Empty), FeaturesResources.Remove_separators);
            }
            else
            {
                switch (kind)
                {
                case NumericKind.Decimal when number.Length > 3:
                    RegisterRefactoringWithResult(AddSeparators(number, 3), FeaturesResources.Separate_thousands);
                    break;

                case NumericKind.Hexadecimal when number.Length > 4:
                    RegisterRefactoringWithResult(hexPrefix + AddSeparators(number, 4), FeaturesResources.Separate_words);
                    break;

                case NumericKind.Binary when number.Length > 4:
                    RegisterRefactoringWithResult(binaryPrefix + AddSeparators(number, 4), FeaturesResources.Separate_nibbles);
                    break;
                }
            }

            void RegisterRefactoringWithResult(string text, string title)
            {
                context.RegisterRefactoring(new MyCodeAction(title, c =>
                {
                    var generator    = SyntaxGenerator.GetGenerator(document);
                    var updatedToken = generator.NumericLiteralToken(text + suffix, (ulong)value)
                                       .WithTriviaFrom(numericToken);
                    var updatedRoot = root.ReplaceToken(numericToken, updatedToken);
                    return(Task.FromResult(document.WithSyntaxRoot(updatedRoot)));
                }));
            }
        }