Exemplo n.º 1
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))
                );
        }
Exemplo n.º 2
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);

            string          keyword;
            StatementSyntax embeddedStatement;
            BlockSyntax     block = null;

            if (IsSpecialNode(token, out keyword, out embeddedStatement))
            {
                block = embeddedStatement as BlockSyntax;
                if (block == null || block.Statements.Count != 1 || block.Statements.First() is LabeledStatementSyntax || block.Statements.First() is LocalDeclarationStatementSyntax)
                {
                    return;
                }
            }

            if (block == null)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    token.Span,
                    DiagnosticSeverity.Info,
                    string.Format(GettextCatalog.GetString("Remove braces from '{0}'"), keyword),
                    t2 =>
            {
                var parent = block.Parent.ReplaceNode((SyntaxNode)block, block.Statements.First())
                             .WithAdditionalAnnotations(Formatter.Annotation);

                var newRoot = root.ReplaceNode((SyntaxNode)block.Parent, parent);
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
Exemplo n.º 3
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 property = root.FindNode(span) as PropertyStatementSyntax;

            if (property == null || !property.Identifier.Span.Contains(span))
            {
                return;
            }

            var propertyBlock = property.Parent as PropertyBlockSyntax;

            if (propertyBlock == null)
            {
                return;
            }

            var field = GetBackingField(model, propertyBlock);

            if (field == null)
            {
                return;
            }
            var type = propertyBlock.Parent as TypeBlockSyntax;

            if (type == null)
            {
                return;
            }

            var resolvedType = model.Compilation.GetTypeSymbol("System", "EventHandler", 0, cancellationToken);

            if (resolvedType == null)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Create changed event"),
                    t2 =>
            {
                var eventDeclaration  = CreateChangedEventDeclaration(propertyBlock);
                var methodDeclaration = CreateEventInvocator(
                    type.BlockStatement.Identifier.ToString(),
                    type.BlockStatement.Modifiers.Any(m => m.IsKind(SyntaxKind.NotInheritableKeyword)),
                    eventDeclaration.Modifiers.Any(m => m.IsKind(SyntaxKind.SharedKeyword)),
                    eventDeclaration.Identifier.ToString(),
                    resolvedType.GetDelegateInvokeMethod(),
                    false
                    );
                var invocation = SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(
                                                                       SyntaxFactory.IdentifierName(methodDeclaration.SubOrFunctionStatement.Identifier.ToString()),
                                                                       SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList <ArgumentSyntax>(new[] {
                    SyntaxFactory.SimpleArgument(SyntaxFactory.ParseExpression("System.EventArgs.Empty").WithAdditionalAnnotations(Simplifier.Annotation))
                }))
                                                                       ));

                var marker = new SyntaxAnnotation();

                var newPropertyBlockSetterAccessor = propertyBlock.Accessors.First(a => a.IsKind(SyntaxKind.SetAccessorBlock));
                newPropertyBlockSetterAccessor     =
                    newPropertyBlockSetterAccessor.WithStatements(
                        newPropertyBlockSetterAccessor.Statements.Add(invocation.WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation)));

                var newPropertyBlock = propertyBlock.WithAccessors(
                    SyntaxFactory.List <AccessorBlockSyntax>(new[] {
                    propertyBlock.Accessors.First(a => a.IsKind(SyntaxKind.GetAccessorBlock)),
                    newPropertyBlockSetterAccessor
                }));

                var newRoot = root.ReplaceNode(propertyBlock, new SyntaxNode[] {
                    newPropertyBlock,
                    methodDeclaration.WithAdditionalAnnotations(Formatter.Annotation),
                    eventDeclaration.WithTrailingTrivia(propertyBlock.GetTrailingTrivia()).WithAdditionalAnnotations(Formatter.Annotation)
                });

                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            })
                );
        }
        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.IsIdentifierOrAccessorOrAccessibilityModifier())
            {
                return;
            }
            var node = token.Parent;

            while (node != null && !(node is MemberDeclarationSyntax || node is AccessorDeclarationSyntax))
            {
                node = node.Parent;
            }
            if (node == null || node.IsKind(SyntaxKind.InterfaceDeclaration, SyntaxKind.EnumMemberDeclaration))
            {
                return;
            }

            ISymbol symbol = null;
            var     field  = node as FieldDeclarationSyntax;

            if (field != null)
            {
                symbol = model.GetDeclaredSymbol(field.Declaration.Variables.First(), cancellationToken);
            }
            else
            {
                var member = node as MemberDeclarationSyntax;
                if (member != null)
                {
                    symbol = model.GetDeclaredSymbol(member, cancellationToken);
                }
                else
                {
                    var accessor = node as AccessorDeclarationSyntax;
                    if (accessor != null)
                    {
                        symbol = model.GetDeclaredSymbol(accessor, cancellationToken);
                    }
                }
            }
            if (!symbol.AccessibilityChangeable())
            {
                return;
            }

            foreach (var accessibility in GetPossibleAccessibilities(model, symbol, node, cancellationToken))
            {
                var modifiers = GetAccessibilityModifiers(accessibility);
                context.RegisterRefactoring(CodeActionFactory.Create(
                                                token.Span,
                                                DiagnosticSeverity.Info,
                                                GettextCatalog.GetString("To " + String.Join(" ", modifiers)),
                                                t =>
                {
                    var newRoot = root.ReplaceNode(
                        node,
                        node.WithoutLeadingTrivia().WithModifiers(modifiers).WithLeadingTrivia(node.GetLeadingTrivia()));

                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }));
            }
        }
        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 node = token.Parent as AssignmentExpressionSyntax;

            if (node == null || !node.OperatorToken.Span.Contains(span))
            {
                return;
            }

            var updatedNode = ReplaceWithOperatorAssignmentCodeRefactoringProvider.CreateAssignment(node) ?? node;

            if ((!updatedNode.IsKind(SyntaxKind.AddAssignmentExpression) && !updatedNode.IsKind(SyntaxKind.SubtractAssignmentExpression)))
            {
                return;
            }

            var rightLiteral = updatedNode.Right as LiteralExpressionSyntax;

            if (rightLiteral == null || ((int)rightLiteral.Token.Value) != 1)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    token.Span,
                    DiagnosticSeverity.Info,
                    updatedNode.IsKind(SyntaxKind.AddAssignmentExpression) ? GettextCatalog.GetString("To '{0}++'") : GettextCatalog.GetString("To '{0}--'"),
                    t2 =>
            {
                var newNode = SyntaxFactory.PostfixUnaryExpression(updatedNode.IsKind(SyntaxKind.AddAssignmentExpression) ? SyntaxKind.PostIncrementExpression : SyntaxKind.PostDecrementExpression, updatedNode.Left);
                var newRoot = root.ReplaceNode((SyntaxNode)node, newNode.WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia(node.GetLeadingTrivia()));
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
        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 root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

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

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var node = root.FindNode(span) as IfStatementSyntax;

            if (node == null)
            {
                return;
            }

            var switchExpr = ConvertIfStatementToSwitchStatementAnalyzer.GetSwitchExpression(model, node.Condition);

            if (switchExpr == null)
            {
                return;
            }

            var switchSections = new List <SwitchSectionSyntax>();

            if (!ConvertIfStatementToSwitchStatementAnalyzer.CollectSwitchSections(switchSections, model, node, switchExpr))
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("To 'switch'"),
                    ct =>
            {
                var switchStatement = SyntaxFactory.SwitchStatement(switchExpr, new SyntaxList <SwitchSectionSyntax>().AddRange(switchSections));
                return(Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(
                                                                   (SyntaxNode)node, switchStatement
                                                                   .WithLeadingTrivia(node.GetLeadingTrivia())
                                                                   .WithAdditionalAnnotations(Formatter.Annotation)))));
            })
                );
        }
Exemplo n.º 7
0
        protected override IEnumerable <CodeAction> GetActions(Document document, SemanticModel semanticModel, SyntaxNode root, TextSpan span, ParameterSyntax node, CancellationToken cancellationToken)
        {
            if (!node.Identifier.Span.Contains(span))
            {
                return(Enumerable.Empty <CodeAction>());
            }
            var parameter     = node;
            var bodyStatement = parameter.Parent.Parent.Parent as MethodBlockBaseSyntax;
            var lambdaBody    = parameter.Parent.Parent.Parent as MultiLineLambdaExpressionSyntax;

            if (bodyStatement == null && lambdaBody == null)
            {
                return(Enumerable.Empty <CodeAction>());
            }

            var parameterSymbol = semanticModel.GetDeclaredSymbol(node);
            var type            = parameterSymbol.Type;

            if (type == null || type.IsValueType || HasNullCheck(semanticModel, parameterSymbol, (SyntaxNode)bodyStatement ?? lambdaBody))
            {
                return(Enumerable.Empty <CodeAction>());
            }
            return(new[] { CodeActionFactory.Create(
                               node.Identifier.Span,
                               DiagnosticSeverity.Info,
                               GettextCatalog.GetString("Add 'Is Nothing' check for parameter"),
                               t2 => {
                    var paramName = node.Identifier.ToString();

                    ExpressionSyntax parameterExpr;

                    var parseOptions = root.SyntaxTree.Options as VisualBasicParseOptions;
                    if (parseOptions != null && parseOptions.LanguageVersion < LanguageVersion.VisualBasic14)
                    {
                        parameterExpr = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(paramName));
                    }
                    else
                    {
                        parameterExpr = SyntaxFactory.ParseExpression("NameOf(" + paramName + ")");
                    }

                    var ifStatement = SyntaxFactory.IfStatement(SyntaxFactory.IsExpression(SyntaxFactory.IdentifierName(paramName), SyntaxFactory.Token(SyntaxKind.IsKeyword), SyntaxFactory.NothingLiteralExpression(SyntaxFactory.Token(SyntaxKind.NothingKeyword))))
                                      .WithThenKeyword(SyntaxFactory.Token(SyntaxKind.ThenKeyword));

                    var statements = SyntaxFactory.SingletonList <StatementSyntax>(SyntaxFactory.ThrowStatement(
                                                                                       SyntaxFactory.ObjectCreationExpression(
                                                                                           SyntaxFactory.ParseTypeName("System.ArgumentNullException")
                                                                                           )
                                                                                       .WithArgumentList(SyntaxFactory.ArgumentList(
                                                                                                             SyntaxFactory.SingletonSeparatedList <ArgumentSyntax>(
                                                                                                                 SyntaxFactory.SimpleArgument(
                                                                                                                     parameterExpr
                                                                                                                     )
                                                                                                                 )
                                                                                                             ))
                                                                                       ));

                    var ifBlock = SyntaxFactory.MultiLineIfBlock(ifStatement, statements, default(SyntaxList <ElseIfBlockSyntax>), null)
                                  .WithAdditionalAnnotations(Formatter.Annotation, Simplifier.Annotation);

                    SyntaxNode newRoot;
                    if (bodyStatement != null)
                    {
                        var newStatements = bodyStatement.Statements.Insert(0, ifBlock);
                        var newBody = bodyStatement.WithStatements(newStatements);
                        newRoot = root.ReplaceNode(bodyStatement, newBody);
                    }
                    else
                    {
                        var newStatements = lambdaBody.Statements.Insert(0, ifBlock);
                        var newBody = lambdaBody.WithStatements(newStatements);
                        newRoot = root.ReplaceNode(lambdaBody, newBody);
                    }
                    return Task.FromResult(document.WithSyntaxRoot(newRoot));
                }
                               ) });
        }
Exemplo n.º 8
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 node = token.Parent;

            if (node.IsKind(SyntaxKind.IdentifierName) && node.SpanStart == span.Start)
            {
                node = node.Parent;
                if (node.Parent is ConditionalExpressionSyntax && node.Parent.SpanStart == span.Start && ((ConditionalExpressionSyntax)node.Parent).Condition == node)
                {
                    node = node.Parent;
                }
            }

            var condExpr = node as ConditionalExpressionSyntax;

            if (condExpr == null)
            {
                return;
            }
            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    token.Span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Invert '?:'"),
                    t2 =>
            {
                var newRoot = root.ReplaceNode((SyntaxNode)
                                               condExpr,
                                               condExpr
                                               .WithCondition(CSharpUtil.InvertCondition(condExpr.Condition))
                                               .WithWhenTrue(condExpr.WhenFalse)
                                               .WithWhenFalse(condExpr.WhenTrue)
                                               .WithAdditionalAnnotations(Formatter.Annotation)
                                               );
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
        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 is VariableDeclaratorSyntax))
            {
                return;
            }
            var declarator       = (VariableDeclaratorSyntax)token.Parent;
            var fieldDeclaration = declarator.Parent?.Parent as FieldDeclarationSyntax;

            if (fieldDeclaration == null)
            {
                return;
            }
            var enclosingType = fieldDeclaration.Parent as TypeDeclarationSyntax;

            if (enclosingType == null)
            {
                return;
            }
            foreach (var member in enclosingType.Members)
            {
                if (member is PropertyDeclarationSyntax && ContainsGetter(model, (PropertyDeclarationSyntax)member, declarator))
                {
                    return;
                }
            }
            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    token.Span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Generate getter"),
                    t2 => {
                var newRoot = root.InsertNodesAfter(fieldDeclaration, new[] { GeneratePropertyDeclaration(fieldDeclaration, declarator) });
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
Exemplo n.º 10
0
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document          = context.Document;
            var span              = context.Span;
            var cancellationToken = context.CancellationToken;
            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, SyntaxKind.AbstractKeyword, SyntaxKind.VirtualKeyword, SyntaxKind.ThisKeyword))
            {
                return;
            }
            MemberDeclarationSyntax declaration;
            ISymbol symbol = null;

            if (token.IsKind(SyntaxKind.IdentifierToken))
            {
                if (token.Parent?.Parent?.IsKind(SyntaxKind.VariableDeclaration) == true)
                {
                    declaration = token.Parent?.Parent?.Parent as MemberDeclarationSyntax;
                    symbol      = model.GetDeclaredSymbol(token.Parent);
                }
                else
                {
                    declaration = token.Parent as MemberDeclarationSyntax;
                    if (declaration != null)
                    {
                        symbol = model.GetDeclaredSymbol(declaration);
                    }
                }
            }
            else
            {
                declaration = token.Parent as MemberDeclarationSyntax;
                if (declaration != null)
                {
                    symbol = model.GetDeclaredSymbol(declaration);
                }
            }
            if (declaration == null || symbol == null ||
                declaration is BaseTypeDeclarationSyntax ||
                declaration is ConstructorDeclarationSyntax ||
                declaration is DestructorDeclarationSyntax)
            {
                return;
            }
            var modifiers = declaration.GetModifiers();

            if (modifiers.Any(m => m.IsKind(SyntaxKind.OverrideKeyword, SyntaxKind.ExternKeyword)))
            {
                return;
            }

            var containingType = symbol.ContainingType;

            if (symbol.DeclaredAccessibility == Accessibility.Private || containingType.IsInterfaceType())
            {
                return;
            }

            var explicitInterface = declaration.GetExplicitInterfaceSpecifierSyntax();

            if (explicitInterface != null)
            {
                return;
            }

            if (containingType.IsAbstract)
            {
                if (modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword)))
                {
                    context.RegisterRefactoring(CodeActionFactory.Create(
                                                    token.Span,
                                                    DiagnosticSeverity.Info,
                                                    GettextCatalog.GetString("To non-abstract"),
                                                    t2 =>
                    {
                        var newRoot = root.ReplaceNode((SyntaxNode)declaration, ImplementAbstractDeclaration(declaration).WithAdditionalAnnotations(Formatter.Annotation));
                        return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                    }
                                                    )
                                                );
                }
                else
                {
                    if (CheckBody(declaration))
                    {
                        context.RegisterRefactoring(CodeActionFactory.Create(
                                                        token.Span,
                                                        DiagnosticSeverity.Info,
                                                        GettextCatalog.GetString("To abstract"),
                                                        t2 =>
                        {
                            var newRoot = root.ReplaceNode((SyntaxNode)declaration, MakeAbstractDeclaration(declaration).WithAdditionalAnnotations(Formatter.Annotation));
                            return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                        }
                                                        )
                                                    );
                    }
                }
            }

            if (modifiers.Any(m => m.IsKind(SyntaxKind.VirtualKeyword)))
            {
                context.RegisterRefactoring(CodeActionFactory.Create(
                                                token.Span,
                                                DiagnosticSeverity.Info,
                                                GettextCatalog.GetString("To non-virtual"),
                                                t2 =>
                {
                    var newRoot = root.ReplaceNode((SyntaxNode)declaration, RemoveVirtualModifier(declaration));
                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }
                                                )
                                            );
            }
            else
            {
                if (modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword)))
                {
                    context.RegisterRefactoring(CodeActionFactory.Create(
                                                    token.Span,
                                                    DiagnosticSeverity.Info,
                                                    GettextCatalog.GetString("To virtual"),
                                                    t2 =>
                    {
                        var newRoot = root.ReplaceNode((SyntaxNode)declaration, ImplementAbstractDeclaration(declaration, true).WithAdditionalAnnotations(Formatter.Annotation));
                        return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                    }
                                                    )
                                                );
                }
                else if (!containingType.IsStatic)
                {
                    context.RegisterRefactoring(CodeActionFactory.Create(
                                                    token.Span,
                                                    DiagnosticSeverity.Info,
                                                    GettextCatalog.GetString("To virtual"),
                                                    t2 =>
                    {
                        var newRoot = root.ReplaceNode((SyntaxNode)declaration, AddModifier(declaration, SyntaxKind.VirtualKeyword).WithAdditionalAnnotations(Formatter.Annotation));
                        return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                    }
                                                    )
                                                );
                }
            }
        }
        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 BinaryExpressionSyntax;

            //ignore nodes except string concat.
            if (node == null || !node.OperatorToken.IsKind(SyntaxKind.PlusToken))
            {
                return;
            }

            LiteralExpressionSyntax left;
            var leftBinaryExpr = node.Left as BinaryExpressionSyntax;

            //if there is something other than a string literal on the left, then just take the right node (e.g. a+b+c => a+(b+c))
            if (leftBinaryExpr != null && leftBinaryExpr.OperatorToken.IsKind(SyntaxKind.PlusToken))
            {
                left = leftBinaryExpr.Right as LiteralExpressionSyntax;
            }
            else
            {
                left = node.Left as LiteralExpressionSyntax;
            }

            var right = node.Right as LiteralExpressionSyntax;

            //ignore non-string literals
            if (left == null || right == null || !left.IsKind(SyntaxKind.StringLiteralExpression) || !right.IsKind(SyntaxKind.StringLiteralExpression))
            {
                return;
            }

            bool isLeftVerbatim  = left.Token.IsVerbatimStringLiteral();
            bool isRightVerbatim = right.Token.IsVerbatimStringLiteral();

            if (isLeftVerbatim != isRightVerbatim)
            {
                return;
            }

            String newString = left.Token.ValueText + right.Token.ValueText;
            LiteralExpressionSyntax stringLit;

            if (isLeftVerbatim)
            {
                stringLit = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal("@\"" + newString + "\"", newString));
            }
            else
            {
                stringLit = SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(newString));
            }

            ExpressionSyntax exprNode;

            if (leftBinaryExpr == null)
            {
                exprNode = stringLit;
            }
            else
            {
                exprNode = leftBinaryExpr.WithRight(stringLit);
            }
            context.RegisterRefactoring(
                CodeActionFactory.Create(span, DiagnosticSeverity.Info, GettextCatalog.GetString("Join strings"), document.WithSyntaxRoot(root.ReplaceNode((SyntaxNode)node, exprNode as ExpressionSyntax)))
                );
        }
Exemplo n.º 12
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 options = document.Project.ParseOptions as CSharpParseOptions;

            if (options != null && options.LanguageVersion < LanguageVersion.CSharp6)
            {
                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.FindToken(span.Start).Parent;
            var memberAccessExpr = node.Parent as MemberAccessExpressionSyntax;

            if (memberAccessExpr == null)
            {
                return;
            }
            var info = model.GetSymbolInfo(node, cancellationToken);

            if (info.Symbol == null || info.Symbol.Kind != SymbolKind.NamedType || !info.Symbol.IsStatic)
            {
                return;
            }

            var parentMemberAccessExpr = memberAccessExpr.Parent as MemberAccessExpressionSyntax;

            if (parentMemberAccessExpr != null)
            {
                var memberInfoSymbol = model.GetSymbolInfo(parentMemberAccessExpr).Symbol;
                if ((memberInfoSymbol == null) || memberInfoSymbol.IsExtensionMethod())
                {
                    return;
                }
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    node.Span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Import static class with using"),
                    t2 =>
            {
                return(ImportStaticClassWithUsing(document, model, root, node, info, t2));
            }
                    )
                );
        }
        public async override Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document          = context.Document;
            var cancellationToken = context.CancellationToken;
            var span        = context.Span;
            var diagnostics = context.Diagnostics;
            var root        = await document.GetSyntaxRootAsync(cancellationToken);

            var diagnostic = diagnostics.First();
            var node       = root.FindNode(context.Span, getInnermostNodeForTie: true) as ConditionalExpressionSyntax;
            var newRoot    = root;

            bool?trueBranch  = GetBool(node.WhenTrue.SkipParens());
            bool?falseBranch = GetBool(node.WhenFalse.SkipParens());

            if (trueBranch == false && falseBranch == true)
            {
                newRoot = newRoot.ReplaceNode(node, CSharpUtil.InvertCondition(node.Condition).WithAdditionalAnnotations(Formatter.Annotation));
            }
            else if (trueBranch == true)
            {
                newRoot = newRoot.ReplaceNode(
                    (SyntaxNode)node,
                    SyntaxFactory.BinaryExpression(
                        SyntaxKind.LogicalOrExpression,
                        node.Condition,
                        SyntaxFactory.ParseToken(" || "),
                        node.WhenFalse
                        ).WithAdditionalAnnotations(Formatter.Annotation)
                    );
            }
            else if (trueBranch == false)
            {
                newRoot = newRoot.ReplaceNode(
                    (SyntaxNode)node,
                    SyntaxFactory.BinaryExpression(
                        SyntaxKind.LogicalAndExpression,
                        CSharpUtil.InvertCondition(node.Condition),
                        SyntaxFactory.ParseToken(" && "),
                        node.WhenFalse
                        ).WithAdditionalAnnotations(Formatter.Annotation)
                    );
            }
            else if (falseBranch == true)
            {
                newRoot = newRoot.ReplaceNode(
                    (SyntaxNode)node,
                    SyntaxFactory.BinaryExpression(
                        SyntaxKind.LogicalOrExpression,
                        CSharpUtil.InvertCondition(node.Condition),
                        SyntaxFactory.ParseToken(" || "),
                        node.WhenTrue
                        ).WithAdditionalAnnotations(Formatter.Annotation)
                    );
            }
            else if (falseBranch == false)
            {
                newRoot = newRoot.ReplaceNode(
                    (SyntaxNode)node,
                    SyntaxFactory.BinaryExpression(
                        SyntaxKind.LogicalAndExpression,
                        node.Condition,
                        SyntaxFactory.ParseToken(" && "),
                        node.WhenTrue
                        ).WithAdditionalAnnotations(Formatter.Annotation)
                    );
            }

            context.RegisterCodeFix(CodeActionFactory.Create(node.Span, diagnostic.Severity, "Simplify conditional expression", document.WithSyntaxRoot(newRoot)), diagnostic);
        }
        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 is ParameterSyntax parameter))
            {
                return;
            }

            if (!(parameter.Parent.Parent is ConstructorDeclarationSyntax ctor))
            {
                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(parameter.Identifier)
                        )
                    ).WithAdditionalAnnotations(Formatter.Annotation);

                var trackedRoot = root.TrackNodes(ctor);
                var newRoot     = trackedRoot.InsertNodesBefore(trackedRoot.GetCurrentNode(ctor), new [] { newField });

                IEnumerable <StatementSyntax> statements = new[] { assignmentStatement };

                if (ctor.Body != null)
                {
                    statements = statements.Concat(ctor.Body.Statements);
                }
                else if (ctor.ExpressionBody != null)
                {
                    var expressionStatement = SyntaxFactory.ExpressionStatement(ctor.ExpressionBody.Expression, SyntaxFactory.Token(SyntaxKind.SemicolonToken));
                    statements = statements.Concat(new[] { expressionStatement });
                }

                var ctorBody = SyntaxFactory.Block(statements);        //.WithLeadingTrivia(ctor.GetLeadingTrivia());
                ConstructorDeclarationSyntax newCtor = ctor.WithBody(ctorBody)
                                                       .WithExpressionBody(null)
                                                       .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.None))
                                                       .WithAdditionalAnnotations(Formatter.Annotation)
                                                       .WithTrailingTrivia(ctor.GetTrailingTrivia());

                newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(ctor), newCtor);

                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            })
                );
        }
        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 complexIfElseStatement = GetIfElseStatement(root, span);

            if (complexIfElseStatement != null)
            {
                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        span,
                        DiagnosticSeverity.Info,
                        invertIfFixMessage,
                        t2 =>
                {
                    var statements = GenerateReplacementStatements(complexIfElseStatement);
                    var newRoot    = statements.Count == 1 ?  root.ReplaceNode(complexIfElseStatement, statements[0]) : root.ReplaceNode(complexIfElseStatement, statements);
                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }
                        )
                    );
                return;
            }

            var simpleIfElseStatement = GetIfElseStatementSimple(root, span);

            if (simpleIfElseStatement != null)
            {
                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        span,
                        DiagnosticSeverity.Info,
                        invertIfFixMessage,
                        t2 =>
                {
                    var newRoot = root.ReplaceNode((SyntaxNode)
                                                   simpleIfElseStatement,
                                                   simpleIfElseStatement
                                                   .WithCondition(CSharpUtil.InvertCondition(simpleIfElseStatement.Condition))
                                                   .WithStatement(simpleIfElseStatement.Else.Statement)
                                                   .WithElse(simpleIfElseStatement.Else.WithStatement(simpleIfElseStatement.Statement))
                                                   .WithAdditionalAnnotations(Formatter.Annotation)
                                                   );
                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }
                        )
                    );
                return;
            }

            var ifStatement = GetIfStatement(root, span);

            if (ifStatement != null)
            {
                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        ifStatement.Span,
                        DiagnosticSeverity.Info,
                        invertIfFixMessage,
                        t2 =>
                {
                    var mergedIfStatement = SyntaxFactory.IfStatement(CSharpUtil.InvertCondition(ifStatement.Condition), SyntaxFactory.ReturnStatement())
                                            .WithAdditionalAnnotations(Formatter.Annotation);
                    var newRoot = root.ReplaceNode((SyntaxNode)ifStatement, new SyntaxNode[] { mergedIfStatement }.Concat(GetStatements(ifStatement.Statement)));
                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }
                        )
                    );
            }


            var ifStatementInLoop = GetIfElseStatementInLoop(root, span);

            if (ifStatementInLoop != null)
            {
                context.RegisterRefactoring(
                    CodeActionFactory.Create(
                        ifStatementInLoop.Span,
                        DiagnosticSeverity.Info,
                        invertIfFixMessage,
                        t2 =>
                {
                    var mergedIfStatement = SyntaxFactory.IfStatement(CSharpUtil.InvertCondition(ifStatementInLoop.Condition), SyntaxFactory.ContinueStatement())
                                            .WithAdditionalAnnotations(Formatter.Annotation);
                    var newRoot = root.ReplaceNode((SyntaxNode)ifStatementInLoop, new SyntaxNode[] { mergedIfStatement }.Concat(GetStatements(ifStatementInLoop.Statement)));
                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                }
                        )
                    );
                return;
            }
        }
Exemplo n.º 16
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                {
                    CodeAction codeAction = CodeActionFactory.RemoveMemberDeclaration(context.Document, memberDeclaration, equivalenceKey: GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.AddAccessibilityModifiers:
                {
                    var accessibility = (Accessibility)Enum.Parse(
                        typeof(Accessibility),
                        diagnostic.Properties[nameof(Accessibility)]);

                    CodeAction codeAction = CodeAction.Create(
                        "Add accessibility modifiers",
                        cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantSealedModifier:
                {
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword);
                    break;
                }

                case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary semicolon",
                        cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.OrderModifiers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Order modifiers",
                        ct => OrderModifiersAsync(context.Document, memberDeclaration, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.MakeFieldReadOnly:
                {
                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables;

                    string title = (declarators.Count == 1)
                                ? $"Make '{declarators[0].Identifier.ValueText}' read-only"
                                : "Make fields read-only";

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title);
                    break;
                }

                case DiagnosticIdentifiers.UseConstantInsteadOfField:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use constant instead of field",
                        cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseReadOnlyAutoProperty:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use read-only auto-property",
                        cancellationToken => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ConvertCommentToDocumentationComment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        ConvertCommentToDocumentationCommentRefactoring.Title,
                        cancellationToken => ConvertCommentToDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.MakeMethodExtensionMethod:
                {
                    var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration;

                    CodeAction codeAction = CodeAction.Create(
                        "Make method an extension method",
                        cancellationToken =>
                        {
                            ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0];

                            ParameterSyntax newParameter = ModifierList.Insert(parameter, SyntaxKind.ThisKeyword);

                            return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, LocalFunctionStatementSyntax localFunctionStatement)
        {
            if (localFunctionStatement.IsParentKind(SyntaxKind.Block))
            {
                BlockSyntax body = localFunctionStatement.Body;

                if (body != null)
                {
                    if (body.OpenBraceToken.Span.Contains(context.Span) ||
                        body.CloseBraceToken.Span.Contains(context.Span))
                    {
                        if (context.IsRefactoringEnabled(RefactoringDescriptors.RemoveMemberDeclaration))
                        {
                            context.RegisterRefactoring(CodeActionFactory.RemoveStatement(context.Document, localFunctionStatement, equivalenceKey: EquivalenceKey.Create(RefactoringDescriptors.RemoveMemberDeclaration)));
                        }

                        if (context.IsRefactoringEnabled(RefactoringDescriptors.CopyMemberDeclaration))
                        {
                            context.RegisterRefactoring(
                                "Copy local function",
                                ct => CopyMemberDeclarationRefactoring.RefactorAsync(
                                    context.Document,
                                    localFunctionStatement,
                                    copyAfter: body.CloseBraceToken.Span.Contains(context.Span),
                                    ct),
                                RefactoringDescriptors.CopyMemberDeclaration);
                        }

                        if (context.IsRefactoringEnabled(RefactoringDescriptors.CommentOutMemberDeclaration))
                        {
                            CommentOutRefactoring.RegisterRefactoring(context, localFunctionStatement);
                        }
                    }
                }
            }

            if (context.IsRefactoringEnabled(RefactoringDescriptors.ChangeMethodReturnTypeToVoid) &&
                context.Span.IsEmptyAndContainedInSpan(localFunctionStatement))
            {
                await ChangeMethodReturnTypeToVoidRefactoring.ComputeRefactoringAsync(context, localFunctionStatement).ConfigureAwait(false);
            }

            if (context.IsRefactoringEnabled(RefactoringDescriptors.AddGenericParameterToDeclaration))
            {
                AddGenericParameterToDeclarationRefactoring.ComputeRefactoring(context, localFunctionStatement);
            }

            if (context.IsRefactoringEnabled(RefactoringDescriptors.ConvertBlockBodyToExpressionBody) &&
                ConvertBlockBodyToExpressionBodyRefactoring.CanRefactor(localFunctionStatement, context.Span))
            {
                context.RegisterRefactoring(
                    ConvertBlockBodyToExpressionBodyRefactoring.Title,
                    ct => ConvertBlockBodyToExpressionBodyRefactoring.RefactorAsync(context.Document, localFunctionStatement, ct),
                    RefactoringDescriptors.ConvertBlockBodyToExpressionBody);
            }

            if (context.IsRefactoringEnabled(RefactoringDescriptors.MoveUnsafeContextToContainingDeclaration))
            {
                MoveUnsafeContextToContainingDeclarationRefactoring.ComputeRefactoring(context, localFunctionStatement);
            }
        }
        /*
         *  This sample code refactoring shows some basics of refactoring implementations
         *  and can serve as a simple template for own refactorings in RefactoringEssentials project.
         *
         *  This example operates on interface declarations: It checks whether interface name begins with an "I"
         *  and if not, suggests to add an "I" prefix.
         */

        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            // Some general variables we need for further processing and some basic checks to exit as early as possible.
            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);

            // This is the initial code element on which the refactoring is to be offered.
            // Example: In code "public class SomeClass { ..." user presses Ctrl+. on the "class" keyword.
            // Then token will point to the "class" keyword token.
            var token = root.FindToken(span.Start);

            // Now we need to find out whether "token" is inside of a code element we need to refactor.
            // We want to refactor an interface name. Then we need to check if "token" is
            // a type name identifier and is inside of an interface declaration.
            var interfaceDeclaration = token.Parent as InterfaceDeclarationSyntax;

            if (interfaceDeclaration == null)
            {
                // Not cast-able to interface declaration -> exit, we are wrong here
                return;
            }

            // Is "token" itself the interface's name identifier? We want to offer the refactoring exactly on the name.
            // Note: Checking the syntax element's Kind is another way to detect a specific type, and often is even more detailed.
            if (!token.IsKind(SyntaxKind.IdentifierToken))
            {
                // Not the name identifier -> don't offer a refactoring here
                return;
            }

            // Get interface's name identifier and check its name
            var interfaceName = interfaceDeclaration.Identifier.ValueText;

            // Does interface name start with an "I"?
            // And if so: Is 2nd character a capital, too?
            // Then our refactoring is not needed anymore, name already has the desired format.
            if (interfaceName.StartsWith("I"))
            {
                if ((interfaceName.Length > 1) && char.IsUpper(interfaceName[1]))
                {
                    return;
                }
            }

            context.RegisterRefactoring(CodeActionFactory.Create(token.Span, DiagnosticSeverity.Info, GettextCatalog.GetString("Sample: Prepend with 'I'"), t2 =>
            {
                return(Task.FromResult(PerformAction(document, model, root, interfaceDeclaration, interfaceName)));
            }));
        }
Exemplo n.º 19
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);

            if (!node.IsKind(SyntaxKind.IdentifierName))
            {
                return;
            }

            var nodeGrandparent = node.Parent?.Parent;

            if ((nodeGrandparent is EventDeclarationSyntax) || (nodeGrandparent is EventFieldDeclarationSyntax))
            {
                return;
            }

            if (node.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                node = node.Parent;
            }

            var info = model.GetTypeInfo(node, cancellationToken);
            var type = info.ConvertedType ?? info.Type;

            if (type == null)
            {
                return;
            }

            var invocationMethod = type.GetDelegateInvokeMethod();

            if (invocationMethod == null)
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    node.Span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("To lambda expression"),
                    t2 =>
            {
                var expr = SyntaxFactory.InvocationExpression(
                    (ExpressionSyntax)node,
                    SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(invocationMethod.Parameters.Select(p => SyntaxFactory.Argument(SyntaxFactory.IdentifierName(p.Name)))))
                    );
                var parameters = invocationMethod.Parameters.Select(p => CreateParameterSyntax(model, node, p)).ToList();
                var ame        = SyntaxFactory.ParenthesizedLambdaExpression(
                    SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)),
                    expr
                    );
                var newRoot = root.ReplaceNode((SyntaxNode)node, ame.WithAdditionalAnnotations(Formatter.Annotation));
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
Exemplo n.º 20
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyEnabled(
                    CodeFixIdentifiers.UseExplicitTypeInsteadOfVar,
                    CodeFixIdentifiers.ReplaceVariableDeclarationWithAssignment))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(
                                                SyntaxKind.VariableDeclaration,
                                                SyntaxKind.ForEachStatement,
                                                SyntaxKind.Parameter,
                                                SyntaxKind.DeclarationPattern,
                                                SyntaxKind.DeclarationExpression)))
            {
                return;
            }

            if (node.IsKind(SyntaxKind.ForEachStatement, SyntaxKind.Parameter, SyntaxKind.DeclarationPattern, SyntaxKind.DeclarationExpression))
            {
                return;
            }

            var variableDeclaration = (VariableDeclarationSyntax)node;

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ImplicitlyTypedVariablesCannotHaveMultipleDeclarators:
                case CompilerDiagnosticIdentifiers.ImplicitlyTypedVariablesCannotBeConstant:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.UseExplicitTypeInsteadOfVar))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeSyntax type = variableDeclaration.Type;

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, context.CancellationToken);

                    if (typeSymbol?.SupportsExplicitDeclaration() == true)
                    {
                        CodeAction codeAction = CodeActionFactory.ChangeType(context.Document, type, typeSymbol, semanticModel, equivalenceKey: GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.LocalVariableOrFunctionIsAlreadyDefinedInThisScope:
                case CompilerDiagnosticIdentifiers.LocalOrParameterCannotBeDeclaredInThisScopeBecauseThatNameIsUsedInEnclosingScopeToDefineLocalOrParameter:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.ReplaceVariableDeclarationWithAssignment))
                    {
                        return;
                    }

                    if (!(variableDeclaration.Parent is LocalDeclarationStatementSyntax localDeclaration))
                    {
                        return;
                    }

                    VariableDeclaratorSyntax variableDeclarator = variableDeclaration.Variables.SingleOrDefault(shouldThrow: false);

                    if (variableDeclarator == null)
                    {
                        break;
                    }

                    ExpressionSyntax value = variableDeclarator.Initializer?.Value;

                    if (value == null)
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    VariableDeclaratorSyntax variableDeclarator2 = FindVariableDeclarator(
                        variableDeclarator.Identifier.ValueText,
                        semanticModel.GetEnclosingSymbolSyntax(localDeclaration.SpanStart, context.CancellationToken));

                    if (variableDeclarator2?.SpanStart < localDeclaration.SpanStart)
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Replace variable declaration with assignment",
                            cancellationToken =>
                            {
                                ExpressionStatementSyntax newNode = CSharpFactory.SimpleAssignmentStatement(
                                    SyntaxFactory.IdentifierName(variableDeclarator.Identifier),
                                    value);

                                newNode = newNode
                                          .WithTriviaFrom(localDeclaration)
                                          .WithFormatterAnnotation();

                                return(context.Document.ReplaceNodeAsync(localDeclaration, newNode, cancellationToken));
                            },
                            GetEquivalenceKey(diagnostic));
                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }
                }
            }
        }
Exemplo n.º 21
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 DeclarationStatementSyntax;

            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 trivia = node.GetLeadingTrivia();

                var indentTrivia = trivia.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 < trivia.Count && trivia[idx].IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    idx++;
                }
                trivia      = trivia.Insert(idx, SyntaxFactory.SyntaxTrivia(SyntaxKind.DocumentationCommentExteriorTrivia, string.Join(eol, lines) + eol));
                var newRoot = root.ReplaceNode(node, node.WithLeadingTrivia(trivia));
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
        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);

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

                    return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
                })
                    );
            }
        }
Exemplo n.º 23
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 root = await document.GetSyntaxRootAsync(cancellationToken);

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

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }
            var node = root.FindNode(span) as IfStatementSyntax;

            if (node == null || !(node.Parent is MultiLineIfBlockSyntax))
            {
                return;
            }

            var ifBlock = node.Parent as MultiLineIfBlockSyntax;

            var selectCaseExpression = GetSelectCaseExpression(model, node.Condition);

            if (selectCaseExpression == null)
            {
                return;
            }

            var caseBlocks = new List <CaseBlockSyntax>();

            if (!CollectCaseBlocks(caseBlocks, model, ifBlock, selectCaseExpression))
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("To 'Select Case'"),
                    ct =>
            {
                var selectCaseStatement = SyntaxFactory.SelectBlock(SyntaxFactory.SelectStatement(selectCaseExpression).WithCaseKeyword(SyntaxFactory.Token(SyntaxKind.CaseKeyword)),
                                                                    new SyntaxList <CaseBlockSyntax>().AddRange(caseBlocks))
                                          .NormalizeWhitespace();
                return(Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(
                                                                   ifBlock, selectCaseStatement
                                                                   .WithLeadingTrivia(ifBlock.GetLeadingTrivia())
                                                                   .WithTrailingTrivia(ifBlock.GetTrailingTrivia())
                                                                   .WithAdditionalAnnotations(Formatter.Annotation)))));
            })
                );
        }
Exemplo n.º 24
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindNode(root, context.Span, out ExpressionSyntax expression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertTypeExplicitConversionExists:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken);

                    ITypeSymbol type          = typeInfo.Type;
                    ITypeSymbol convertedType = typeInfo.ConvertedType;

                    if ((type is INamedTypeSymbol namedType) &&
                        namedType.IsNullableType())
                    {
                        if (convertedType?.SpecialType == SpecialType.System_Boolean ||
                            AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression))
                        {
                            if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddComparisonWithBooleanLiteral))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    AddComparisonWithBooleanLiteralRefactoring.GetTitle(expression),
                                    cancellationToken => AddComparisonWithBooleanLiteralRefactoring.RefactorAsync(context.Document, expression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddComparisonWithBooleanLiteral));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                        else if (SymbolEqualityComparer.Default.Equals(namedType.TypeArguments[0], convertedType))
                        {
                            if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseCoalesceExpression))
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Use coalesce expression",
                                    cancellationToken =>
                                    {
                                        ExpressionSyntax defaultValue = convertedType.GetDefaultValueSyntax(context.Document.GetDefaultSyntaxOptions());

                                        ExpressionSyntax newNode = CoalesceExpression(expression.WithoutTrivia(), defaultValue)
                                                                   .WithTriviaFrom(expression)
                                                                   .Parenthesize()
                                                                   .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseCoalesceExpression));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement))
                    {
                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddCastExpression))
                    {
                        CodeFixRegistrator.AddCastExpression(context, diagnostic, expression, convertedType, semanticModel);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeTypeAccordingToInitializer))
                    {
                        ChangeTypeAccordingToInitializerRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.CreateSingletonArray) &&
                        type?.IsErrorType() == false &&
                        !SymbolEqualityComparer.Default.Equals(type, convertedType) &&
                        (convertedType is IArrayTypeSymbol arrayType) &&
                        semanticModel.IsImplicitConversion(expression, arrayType.ElementType))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Create singleton array",
                            cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken),
                            GetEquivalenceKey(diagnostic, CodeFixIdentifiers.CreateSingletonArray));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ConstantValueCannotBeConverted:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseUncheckedExpression))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Use 'unchecked'",
                        cancellationToken =>
                        {
                            CheckedExpressionSyntax newNode = CSharpFactory.UncheckedExpression(expression.WithoutTrivia());

                            newNode = newNode.WithTriviaFrom(expression);

                            return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ExpressionBeingAssignedMustBeConstant:
                {
                    SyntaxNode parent = expression.Parent;

                    if (parent?.IsKind(SyntaxKind.EqualsValueClause) != true)
                    {
                        break;
                    }

                    parent = parent.Parent;

                    if (parent?.IsKind(SyntaxKind.VariableDeclarator) != true)
                    {
                        break;
                    }

                    parent = parent.Parent;

                    if (!(parent is VariableDeclarationSyntax variableDeclaration))
                    {
                        break;
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstModifier) &&
                        variableDeclaration.Parent is LocalDeclarationStatementSyntax localDeclarationStatement)
                    {
                        SyntaxTokenList modifiers = localDeclarationStatement.Modifiers;

                        if (!modifiers.Contains(SyntaxKind.ConstKeyword))
                        {
                            break;
                        }

                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, localDeclarationStatement, SyntaxKind.ConstKeyword);
                    }
                    else if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceConstantWithField) &&
                             variableDeclaration.Variables.Count == 1 &&
                             (variableDeclaration.Parent is FieldDeclarationSyntax fieldDeclaration) &&
                             fieldDeclaration.Modifiers.Contains(SyntaxKind.ConstKeyword))
                    {
                        CodeAction codeAction = CodeAction.Create(
                            ReplaceConstantWithFieldRefactoring.Title,
                            cancellationToken => ReplaceConstantWithFieldRefactoring.RefactorAsync(context.Document, fieldDeclaration, cancellationToken),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType:
                case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeParameterBecauseItCouldBeNonNullableValueType:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue))
                    {
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    CodeFixRegistrator.ReplaceNullWithDefaultValue(context, diagnostic, expression, semanticModel);
                    break;
                }

                case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse))
                    {
                        break;
                    }

                    NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(expression, allowedStyles: NullCheckStyles.ComparisonToNull);

                    if (!nullCheck.Success)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Remove condition",
                        cancellationToken =>
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            SyntaxNode newRoot = RemoveCondition(root, expression, nullCheck.Style == NullCheckStyles.NotEqualsToNull);

                            cancellationToken.ThrowIfCancellationRequested();

                            return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot)));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveParentheses) &&
                        expression is ParenthesizedExpressionSyntax parenthesizedExpression &&
                        parenthesizedExpression?.IsMissing == false)
                    {
                        CodeAction codeAction = CodeActionFactory.RemoveParentheses(context.Document, parenthesizedExpression, equivalenceKey: GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    if (expression.Parent is ArrowExpressionClauseSyntax arrowExpresssionClause)
                    {
                        if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression))
                        {
                            break;
                        }

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                    }
                    else if (expression.Parent is ExpressionStatementSyntax expressionStatement)
                    {
                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.AddArgumentList) &&
                            expression.IsKind(
                                SyntaxKind.IdentifierName,
                                SyntaxKind.SimpleMemberAccessExpression))
                        {
                            SyntaxNode invocationExpression = InvocationExpression(expression);

                            if (semanticModel.GetSpeculativeMethodSymbol(expression.SpanStart, invocationExpression) != null)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Add argument list",
                                    cancellationToken => context.Document.ReplaceNodeAsync(expression, invocationExpression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddArgumentList));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }

                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceComparisonWithAssignment) &&
                            expression.IsKind(SyntaxKind.EqualsExpression))
                        {
                            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(expression);

                            if (!info.Success)
                            {
                                break;
                            }

                            ITypeSymbol leftTypeSymbol = semanticModel.GetTypeSymbol(info.Left, context.CancellationToken);

                            if (leftTypeSymbol?.IsErrorType() != false)
                            {
                                break;
                            }

                            if (!semanticModel.IsImplicitConversion(info.Right, leftTypeSymbol))
                            {
                                break;
                            }

                            CodeAction codeAction = CodeAction.Create(
                                "Replace comparison with assignment",
                                cancellationToken =>
                                {
                                    AssignmentExpressionSyntax simpleAssignment = SimpleAssignmentExpression(info.Left, info.Right).WithTriviaFrom(expression);
                                    return(context.Document.ReplaceNodeAsync(expression, simpleAssignment, cancellationToken));
                                },
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceComparisonWithAssignment));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }

                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse) &&
                            (expression is ConditionalExpressionSyntax conditionalExpression) &&
                            conditionalExpression.Condition != null)
                        {
                            ExpressionSyntax whenTrue  = conditionalExpression.WhenTrue;
                            ExpressionSyntax whenFalse = conditionalExpression.WhenFalse;

                            if (whenTrue != null &&
                                whenFalse != null &&
                                semanticModel.GetTypeSymbol(whenTrue, context.CancellationToken)?.SpecialType == SpecialType.System_Void &&
                                semanticModel.GetTypeSymbol(whenFalse, context.CancellationToken)?.SpecialType == SpecialType.System_Void)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace ?: with if-else",
                                    cancellationToken =>
                                    {
                                        IfStatementSyntax newNode = IfStatement(
                                            conditionalExpression.Condition.WalkDownParentheses(),
                                            Block(ExpressionStatement(whenTrue)),
                                            ElseClause(Block(ExpressionStatement(whenFalse))));

                                        newNode = newNode
                                                  .WithTriviaFrom(expressionStatement)
                                                  .WithFormatterAnnotation();

                                        return(context.Document.ReplaceNodeAsync(expressionStatement, newNode, cancellationToken));
                                    },
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceConditionalExpressionWithIfElse));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }

                        if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() != false)
                        {
                            break;
                        }

                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() != false)
                        {
                            break;
                        }

                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.IntroduceLocalVariable) &&
                            !expressionStatement.IsEmbedded())
                        {
                            bool addAwait = typeSymbol.OriginalDefinition.EqualsOrInheritsFromTaskOfT() &&
                                            semanticModel.GetEnclosingSymbol(expressionStatement.SpanStart, context.CancellationToken).IsAsyncMethod();

                            CodeAction codeAction = CodeAction.Create(
                                IntroduceLocalVariableRefactoring.GetTitle(expression),
                                cancellationToken => IntroduceLocalVariableRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, addAwait, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceLocalVariable));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }

                        if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.IntroduceField))
                        {
                            CodeAction codeAction = CodeAction.Create(
                                $"Introduce field for '{expression}'",
                                cancellationToken => IntroduceFieldRefactoring.RefactorAsync(context.Document, expressionStatement, typeSymbol, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.IntroduceField));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertType:
                {
                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceYieldReturnWithForEach) &&
                        expression.IsParentKind(SyntaxKind.YieldReturnStatement))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ReplaceYieldReturnWithForEachRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                        break;
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeMemberTypeAccordingToReturnExpression) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement, SyntaxKind.YieldReturnStatement))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ChangeMemberTypeRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);
                        break;
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeTypeAccordingToInitializer))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        CodeFixRegistrationResult result = ChangeTypeAccordingToInitializerRefactoring.ComputeCodeFix(context, diagnostic, expression, semanticModel);

                        if (!result.Success)
                        {
                            RemoveAssignmentOfVoidExpression(context, diagnostic, expression, semanticModel);
                        }

                        break;
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral) &&
                        expression?.Kind() == SyntaxKind.StringLiteralExpression)
                    {
                        var literalExpression = (LiteralExpressionSyntax)expression;

                        if (literalExpression.Token.ValueText.Length == 1)
                        {
                            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                            if (semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Char)
                            {
                                CodeAction codeAction = CodeAction.Create(
                                    "Replace string literal with character literal",
                                    cancellationToken => ReplaceStringLiteralWithCharacterLiteralRefactoring.RefactorAsync(context.Document, literalExpression, cancellationToken),
                                    GetEquivalenceKey(diagnostic, CodeFixIdentifiers.ReplaceStringLiteralWithCharacterLiteral));

                                context.RegisterCodeFix(codeAction, diagnostic);
                            }
                        }
                    }

                    if (Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn) &&
                        expression.IsParentKind(SyntaxKind.ReturnStatement))
                    {
                        var returnStatement = (ReturnStatementSyntax)expression.Parent;

                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        ISymbol containingSymbol = semanticModel.GetEnclosingSymbol(returnStatement.SpanStart, context.CancellationToken);

                        if (containingSymbol?.Kind == SymbolKind.Method &&
                            ((IMethodSymbol)containingSymbol).ReturnType.OriginalDefinition.IsIEnumerableOrIEnumerableOfT())
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Use yield return instead of return",
                                cancellationToken => UseYieldReturnInsteadOfReturnRefactoring.RefactorAsync(context.Document, returnStatement, SyntaxKind.YieldReturnStatement, semanticModel, cancellationToken),
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseYieldReturnInsteadOfReturn));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.LeftHandSideOfAssignmentMustBeVariablePropertyOrIndexer:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.RemoveConstModifier))
                    {
                        return;
                    }

                    if (!expression.IsKind(SyntaxKind.IdentifierName))
                    {
                        return;
                    }

                    if (!expression.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(expression, context.CancellationToken);

                    if (symbolInfo.CandidateReason != CandidateReason.NotAVariable)
                    {
                        return;
                    }

                    if (!(symbolInfo.CandidateSymbols.SingleOrDefault(shouldThrow: false) is ILocalSymbol localSymbol))
                    {
                        return;
                    }

                    if (!localSymbol.IsConst)
                    {
                        return;
                    }

                    SyntaxNode node = localSymbol.GetSyntaxOrDefault(context.CancellationToken);

                    if (!node.IsKind(SyntaxKind.VariableDeclarator))
                    {
                        return;
                    }

                    node = node.Parent;

                    if (!node.IsKind(SyntaxKind.VariableDeclaration))
                    {
                        return;
                    }

                    node = node.Parent;

                    if (!(node is LocalDeclarationStatementSyntax localDeclaration))
                    {
                        return;
                    }

                    SyntaxToken constModifier = localDeclaration.Modifiers.Find(SyntaxKind.ConstKeyword);

                    if (!constModifier.IsKind(SyntaxKind.ConstKeyword))
                    {
                        return;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, localDeclaration, constModifier);

                    break;
                }

                case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBeAssignedTo:
                {
                    if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MakeFieldWritable))
                    {
                        break;
                    }

                    SimpleAssignmentExpressionInfo simpleAssignment = SyntaxInfo.SimpleAssignmentExpressionInfo(expression.Parent);

                    if (!simpleAssignment.Success)
                    {
                        return;
                    }

                    if (simpleAssignment.Left != expression)
                    {
                        return;
                    }

                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(expression, context.CancellationToken);

                    if (symbolInfo.CandidateReason != CandidateReason.NotAVariable)
                    {
                        return;
                    }

                    if (!(symbolInfo.CandidateSymbols.SingleOrDefault(shouldThrow: false) is IFieldSymbol fieldSymbol))
                    {
                        return;
                    }

                    if (fieldSymbol.DeclaredAccessibility != Accessibility.Private)
                    {
                        return;
                    }

                    if (!(fieldSymbol.GetSyntax().Parent.Parent is FieldDeclarationSyntax fieldDeclaration))
                    {
                        return;
                    }

                    TypeDeclarationSyntax containingTypeDeclaration = fieldDeclaration.FirstAncestor <TypeDeclarationSyntax>();

                    if (!expression.Ancestors().Any(f => f == containingTypeDeclaration))
                    {
                        return;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(
                        context,
                        diagnostic,
                        fieldDeclaration,
                        SyntaxKind.ReadOnlyKeyword,
                        title: $"Make '{fieldSymbol.Name}' writable");

                    break;
                }
                }
            }
        }
        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);

            while (node != null && !(node is MemberDeclarationSyntax))
            {
                node = node.Parent;
            }
            if (node == null)
            {
                return;
            }

            if (!node.IsKind(SyntaxKind.MethodDeclaration) &&
                !node.IsKind(SyntaxKind.PropertyDeclaration) &&
                !node.IsKind(SyntaxKind.IndexerDeclaration) &&
                !node.IsKind(SyntaxKind.EventDeclaration))
            {
                return;
            }

            var memberDeclaration = node as MemberDeclarationSyntax;
            var explicitSyntax    = memberDeclaration.GetExplicitInterfaceSpecifierSyntax();

            if (explicitSyntax == null || !explicitSyntax.Span.Contains(span))
            {
                return;
            }

            var enclosingSymbol = model.GetDeclaredSymbol(memberDeclaration, cancellationToken);

            if (enclosingSymbol == null)
            {
                return;
            }
            var containingType = enclosingSymbol.ContainingType;


            foreach (var member in containingType.GetMembers())
            {
                if (member == enclosingSymbol ||
                    member.Kind != enclosingSymbol.Kind)
                {
                    continue;
                }

                switch (member.Kind)
                {
                case SymbolKind.Property:
                    var property1 = (IPropertySymbol)enclosingSymbol;
                    var property2 = (IPropertySymbol)member;

                    foreach (var explictProperty in property1.ExplicitInterfaceImplementations)
                    {
                        if (explictProperty.Name == property2.Name)
                        {
                            if (SignatureComparer.HaveSameSignature(property1.Parameters, property2.Parameters))
                            {
                                return;
                            }
                        }
                    }
                    break;

                case SymbolKind.Method:
                    var method1 = (IMethodSymbol)enclosingSymbol;
                    var method2 = (IMethodSymbol)member;
                    foreach (var explictMethod in method1.ExplicitInterfaceImplementations)
                    {
                        if (explictMethod.Name == method2.Name)
                        {
                            if (SignatureComparer.HaveSameSignature(method1.Parameters, method2.Parameters))
                            {
                                return;
                            }
                        }
                    }
                    break;

                case SymbolKind.Event:
                    var evt1 = (IEventSymbol)enclosingSymbol;
                    var evt2 = (IEventSymbol)member;
                    foreach (var explictProperty in evt1.ExplicitInterfaceImplementations)
                    {
                        if (explictProperty.Name == evt2.Name)
                        {
                            return;
                        }
                    }
                    break;
                }
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("To implicit implementation"),
                    t2 =>
            {
                var newNode = memberDeclaration;
                switch (newNode.Kind())
                {
                case SyntaxKind.MethodDeclaration:
                    var method = (MethodDeclarationSyntax)memberDeclaration.WithoutLeadingTrivia();
                    newNode    = method
                                 .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
                                 .WithExplicitInterfaceSpecifier(null);
                    break;

                case SyntaxKind.PropertyDeclaration:
                    var property = (PropertyDeclarationSyntax)memberDeclaration.WithoutLeadingTrivia();
                    newNode      = property
                                   .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
                                   .WithExplicitInterfaceSpecifier(null);
                    break;

                case SyntaxKind.IndexerDeclaration:
                    var indexer = (IndexerDeclarationSyntax)memberDeclaration.WithoutLeadingTrivia();
                    newNode     = indexer
                                  .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
                                  .WithExplicitInterfaceSpecifier(null);
                    break;

                case SyntaxKind.EventDeclaration:
                    var evt = (EventDeclarationSyntax)memberDeclaration.WithoutLeadingTrivia();
                    newNode = evt
                              .WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
                              .WithExplicitInterfaceSpecifier(null);
                    break;
                }
                var newRoot = root.ReplaceNode((SyntaxNode)
                                               memberDeclaration,
                                               newNode.WithAdditionalAnnotations(Formatter.Annotation).WithLeadingTrivia(memberDeclaration.GetLeadingTrivia())
                                               );
                return(Task.FromResult(document.WithSyntaxRoot(newRoot)));
            }
                    )
                );
        }
Exemplo n.º 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 root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

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

            if (model.IsFromGeneratedCode(cancellationToken))
            {
                return;
            }

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

            if (node == null || !node.OperatorToken.IsKind(SyntaxKind.QuestionQuestionToken))
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Replace '??' operator with '?:' expression"), t2 =>
            {
                var left = node.Left;
                var info = model.GetTypeInfo(left, t2);
                if (info.ConvertedType.IsNullableType())
                {
                    left = SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, CSharpUtil.AddParensIfRequired(left), SyntaxFactory.IdentifierName("Value"));
                }
                var ternary = SyntaxFactory.ConditionalExpression(
                    SyntaxFactory.BinaryExpression(
                        SyntaxKind.NotEqualsExpression,
                        node.Left,
                        SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)
                        ),
                    left,
                    node.Right
                    ).WithAdditionalAnnotations(Formatter.Annotation);
                return(Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(node, ternary))));
            }
                    )
                );
        }
        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 <ArgumentListSyntax>().FirstOrDefault();

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

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

            if (elementType.Type == null)
            {
                return;
            }

            if (!IsDictionary(elementType.Type as INamedTypeSymbol) && !elementType.Type.AllInterfaces.Any(IsDictionary))
            {
                return;
            }

            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    string.Format(GettextCatalog.GetString("Check 'If {0}.TryGetValue({1}, 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 dict            = IsDictionary(elementType.Type as INamedTypeSymbol) ? elementType.Type : elementType.Type.AllInterfaces.First(IsDictionary);

                var tempVariableDeclaration = SyntaxFactory.LocalDeclarationStatement(
                    SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.DimKeyword)),
                    SyntaxFactory.SeparatedList(new[] {
                    SyntaxFactory.VariableDeclarator(SyntaxFactory.SeparatedList(new[]
                    {
                        SyntaxFactory.ModifiedIdentifier(localVariableName)
                    }),
                                                     SyntaxFactory.SimpleAsClause(SyntaxFactory.ParseTypeName(dict.GetTypeArguments()[1].GetFullName())),
                                                     null)
                })).WithTrailingTrivia(parentStatement.GetTrailingTrivia());

                var newParent = SyntaxFactory.MultiLineIfBlock(
                    SyntaxFactory.IfStatement(
                        SyntaxFactory.Token(SyntaxKind.IfKeyword),
                        SyntaxFactory.InvocationExpression(
                            SyntaxFactory.MemberAccessExpression(
                                SyntaxKind.SimpleMemberAccessExpression,
                                elementAccess.Expression,
                                SyntaxFactory.Token(SyntaxKind.DotToken),
                                SyntaxFactory.IdentifierName("TryGetValue")),
                            SyntaxFactory.ArgumentList(elementAccess.ArgumentList.Arguments)
                            .AddArguments(SyntaxFactory.SimpleArgument(SyntaxFactory.IdentifierName(localVariableName)))
                            ),
                        SyntaxFactory.Token(SyntaxKind.ThenKeyword)),
                    SyntaxFactory.List(new[] { parentStatement.ReplaceNode(elementAccess, SyntaxFactory.IdentifierName(localVariableName)) }),
                    SyntaxFactory.List <ElseIfBlockSyntax>(), null
                    ).WithLeadingTrivia(parentStatement.GetLeadingTrivia());

                return(Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode(parentStatement,
                                                                                new SyntaxNode[] { tempVariableDeclaration.WithAdditionalAnnotations(Formatter.Annotation), newParent.WithAdditionalAnnotations(Formatter.Annotation) }))));
            }
                    )
                );
        }
        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;
            }
            var argument = elementAccess.ArgumentList?.Arguments.FirstOrDefault();

            if (argument == null)
            {
                return;
            }
            context.RegisterRefactoring(
                CodeActionFactory.Create(
                    span,
                    DiagnosticSeverity.Info,
                    string.Format(GettextCatalog.GetString("Check 'if ({0}.Count > {1})'"), elementAccess.Expression, argument),
                    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")),
                        argument.Expression
                        ),
                    parentStatement
                    );

                return(Task.FromResult(document.WithSyntaxRoot(root.ReplaceNode((SyntaxNode)parentStatement, newParent.WithAdditionalAnnotations(Formatter.Annotation)))));
            }
                    )
                );
        }
        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<ConditionalExpressionSyntax>().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;

            var statementToWrap = identifierAncestors.OfType<StatementSyntax>().FirstOrDefault();
            if (statementToWrap == null)
                return;

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

            SyntaxNode newWrappedStatement = null;

            // Check surrounding block
            var surroundingStatement = statementToWrap.Ancestors().OfType<StatementSyntax>().FirstOrDefault();
            if (surroundingStatement is BlockSyntax)
                surroundingStatement = surroundingStatement.Parent as StatementSyntax;
            if (surroundingStatement != null)
            {
                if (StatementWithConditionContainsNullCheck(surroundingStatement, identifier))
                    return;

                if (surroundingStatement is IfStatementSyntax surroundingIfStatement
                    && surroundingIfStatement.Else == null)
                {
                    statementToWrap = surroundingIfStatement;
                }
            }

            if (statementToWrap is IfStatementSyntax)
            {
                newWrappedStatement = ExtendIfConditionWithNullCheck((IfStatementSyntax)statementToWrap, identifier);
            }
            else
            {
                newWrappedStatement = SyntaxFactory.IfStatement(
                        SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, identifier, SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)),
                        SyntaxFactory.Block(statementToWrap).WithLeadingTrivia(statementToWrap.GetLeadingTrivia()).WithTrailingTrivia(statementToWrap.GetTrailingTrivia())
                    ).WithAdditionalAnnotations(Formatter.Annotation);
            }

            context.RegisterRefactoring(CodeActionFactory.Create(token.Span, DiagnosticSeverity.Info, GettextCatalog.GetString("Add null check"), t2 =>
            {
                var newRoot = root.ReplaceNode(statementToWrap, newWrappedStatement);
                return Task.FromResult(document.WithSyntaxRoot(newRoot));
            }));
        }
Exemplo n.º 30
0
        protected override IEnumerable <CodeAction> GetActions(Document document, SemanticModel semanticModel, SyntaxNode root, TextSpan span, VariableDeclaratorSyntax node, CancellationToken cancellationToken)
        {
            var variableDeclaration = node.GetAncestor <VariableDeclarationSyntax>();
            var localDeclaration    = node.GetAncestor <LocalDeclarationStatementSyntax>();

            if (node.Initializer == null || node.Parent.Parent != null && node.Parent.Parent.IsKind(SyntaxKind.UsingStatement))
            {
                yield break;
            }

            var symbol = semanticModel.GetDeclaredSymbol(node) as ILocalSymbol;

            if (symbol == null)
            {
                yield break;
            }

            if (!symbol.Type.ImplementsSpecialTypeInterface(SpecialType.System_IDisposable))
            {
                yield break;
            }

            var containingBlock = node.GetAncestor <BlockSyntax>();

            yield return(CodeActionFactory.Create(span, DiagnosticSeverity.Info, "Put inside 'using'", ct =>
            {
                var insideUsing = containingBlock.Statements.SkipWhile(x => x != localDeclaration).Skip(1).ToList();

                ReduceUsingBlock(semanticModel, insideUsing, symbol);

                var nodesToRemove = new List <SyntaxNode>(insideUsing);

                var beforeUsing = new List <StatementSyntax>();

                if (insideUsing.Any())
                {
                    ExtractVariableDeclarationsBeforeUsing(semanticModel, beforeUsing, insideUsing, nodesToRemove, ct);
                }

                if (IsEndingWithDispose(semanticModel, insideUsing, symbol))
                {
                    nodesToRemove.Add(insideUsing.Last());
                    insideUsing.RemoveAt(insideUsing.Count - 1);
                }

                var usingVariableDeclaration = SyntaxFactory.VariableDeclaration(variableDeclaration.Type.WithoutTrivia(), SyntaxFactory.SingletonSeparatedList(node));

                var usingNode = SyntaxFactory.UsingStatement(usingVariableDeclaration, null, SyntaxFactory.Block(insideUsing))
                                .WithAdditionalAnnotations(Formatter.Annotation)
                                .WithPrependedLeadingTrivia(variableDeclaration.GetLeadingTrivia());

                var newRoot = root.TrackNodes(nodesToRemove.Concat(localDeclaration));

                newRoot = newRoot.RemoveNodes(newRoot.GetCurrentNodes <SyntaxNode>(nodesToRemove), SyntaxRemoveOptions.AddElasticMarker);

                newRoot = newRoot.InsertNodesAfter(newRoot.GetCurrentNode(localDeclaration), beforeUsing.Concat(usingNode));

                if (localDeclaration.Declaration.Variables.Count > 1)
                {
                    var remainingVariables = localDeclaration.Declaration.Variables.Except(new[] { node });
                    newRoot = newRoot.ReplaceNode(newRoot.GetCurrentNode(localDeclaration),
                                                  localDeclaration.WithDeclaration(localDeclaration.Declaration.WithVariables(SyntaxFactory.SeparatedList(remainingVariables)))
                                                  .WithAdditionalAnnotations(Formatter.Annotation));
                }
                else
                {
                    newRoot = newRoot.RemoveNode(newRoot.GetCurrentNode(localDeclaration), SyntaxRemoveOptions.AddElasticMarker);
                }

                return Task.FromResult(document.WithSyntaxRoot(newRoot));
            }));
        }