Exemple #1
0
        private static StatementContainer GetStatementContainer(SyntaxNode node)
        {
            SyntaxNode parent = node.Parent;

            if (parent != null)
            {
                StatementContainer container;

                if (StatementContainer.TryCreate(parent, out container))
                {
                    return(container);
                }
            }

            return(null);
        }
        private StatementContainer GetStatementContainer(BinaryExpressionSyntax binaryExpression)
        {
            SyntaxNode node = binaryExpression.Parent.Parent;

            if (node != null)
            {
                StatementContainer container;

                if (StatementContainer.TryCreate(node, out container))
                {
                    return(container);
                }
            }

            return(null);
        }
        private static async Task<Document> RefactorAsync(
            Document document,
            ExpressionSyntax expression,
            StatementSyntax statement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (EmbeddedStatement.IsEmbeddedStatement(statement))
            {
                return await document.ReplaceNodeAsync(statement, Block(statement, CreateNullCheck(expression)), cancellationToken).ConfigureAwait(false);
            }
            else
            {
                IStatementContainer container;
                if (StatementContainer.TryCreate(statement, out container))
                {
                    SyntaxList<StatementSyntax> statements = container.Statements;

                    int statementIndex = statements.IndexOf(statement);

                    ISymbol symbol = (statement.IsKind(SyntaxKind.LocalDeclarationStatement))
                        ? semanticModel.GetDeclaredSymbol(((LocalDeclarationStatementSyntax)statement).Declaration.Variables.First(), cancellationToken)
                        : semanticModel.GetSymbol(expression, cancellationToken);

                    int lastStatementIndex = IncludeAllReferencesOfSymbol(symbol, expression.Kind(), statements, statementIndex + 1, semanticModel, cancellationToken);

                    if (lastStatementIndex != -1)
                    {
                        if (lastStatementIndex < statements.Count - 1)
                            lastStatementIndex = IncludeAllReferencesOfVariablesDeclared(statements, statementIndex + 1, lastStatementIndex, semanticModel, cancellationToken);

                        return await RefactorAsync(
                            document,
                            expression,
                            statements,
                            container,
                            statementIndex,
                            lastStatementIndex,
                            cancellationToken).ConfigureAwait(false);
                    }
                }
            }

            return await document.InsertNodeAfterAsync(statement, CreateNullCheck(expression), cancellationToken).ConfigureAwait(false);
        }
        private static bool NullCheckExists(ExpressionSyntax expression, StatementSyntax statement)
        {
            if (!EmbeddedStatement.IsEmbeddedStatement(statement))
            {
                StatementContainer container;

                if (StatementContainer.TryCreate(statement, out container))
                {
                    SyntaxList <StatementSyntax> statements = container.Statements;

                    int index = statements.IndexOf(statement);

                    if (index < statements.Count - 1)
                    {
                        StatementSyntax nextStatement = statements[index + 1];

                        if (nextStatement.IsKind(SyntaxKind.IfStatement))
                        {
                            var ifStatement = (IfStatementSyntax)nextStatement;

                            ExpressionSyntax condition = ifStatement.Condition;

                            if (condition?.IsKind(SyntaxKind.NotEqualsExpression) == true)
                            {
                                var notEqualsExpression = (BinaryExpressionSyntax)condition;

                                ExpressionSyntax left = notEqualsExpression.Left;

                                if (left?.IsEquivalentTo(expression, topLevel: false) == true)
                                {
                                    ExpressionSyntax right = notEqualsExpression.Right;

                                    if (right?.IsKind(SyntaxKind.NullLiteralExpression) == true)
                                    {
                                        return(true);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
Exemple #5
0
        public async Task <Solution> InlineAndRemoveMethodAsync(
            ExpressionStatementSyntax expressionStatement,
            SyntaxList <StatementSyntax> statements)
        {
            if (expressionStatement.SyntaxTree == MethodDeclaration.SyntaxTree)
            {
                DocumentEditor editor = await DocumentEditor.CreateAsync(Document, CancellationToken).ConfigureAwait(false);

                StatementSyntax[] newStatements = RewriteStatements(statements);

                int count = statements.Count;

                newStatements[0]         = newStatements[0].WithLeadingTrivia(expressionStatement.GetLeadingTrivia());
                newStatements[count - 1] = newStatements[count - 1].WithTrailingTrivia(expressionStatement.GetTrailingTrivia());

                StatementContainer container;
                if (StatementContainer.TryCreate(expressionStatement, out container))
                {
                    SyntaxNode newNode = container.NodeWithStatements(container.Statements.ReplaceRange(expressionStatement, newStatements));

                    editor.ReplaceNode(container.Node, newNode);
                }
                else
                {
                    editor.ReplaceNode(expressionStatement, Block(newStatements));
                }

                editor.RemoveNode(MethodDeclaration);

                return(editor.GetChangedDocument().Solution());
            }
            else
            {
                Document newDocument = await InlineMethodAsync(expressionStatement, statements).ConfigureAwait(false);

                DocumentId documentId = Document.Solution().GetDocumentId(MethodDeclaration.SyntaxTree);

                newDocument = await newDocument.Solution().GetDocument(documentId).RemoveMemberAsync(MethodDeclaration, CancellationToken).ConfigureAwait(false);

                return(newDocument.Solution());
            }
        }
        public static void ComputeRefactoring(RefactoringContext context, ReturnStatementSyntax returnStatement)
        {
            ExpressionSyntax expression = returnStatement.Expression;

            if (expression != null)
            {
                IStatementContainer container;
                if (StatementContainer.TryCreate(returnStatement, out container))
                {
                    SyntaxList <StatementSyntax> statements = container.Statements;

                    if (statements.Count > 1)
                    {
                        int index = statements.IndexOf(returnStatement);

                        if (index == statements.Count - 1)
                        {
                            StatementSyntax prevStatement = statements[index - 1];

                            if (prevStatement.IsKind(SyntaxKind.IfStatement))
                            {
                                var ifStatement = (IfStatementSyntax)prevStatement;

                                IfStatement ifElse = IfStatement.Create(ifStatement);

                                if (ifElse.EndsWithIf &&
                                    ifElse
                                    .Nodes
                                    .Where(f => f.IsIf)
                                    .All(f => IsLastStatementReturnStatement(f)))
                                {
                                    context.RegisterRefactoring(
                                        "Wrap in else",
                                        cancellationToken => RefactorAsync(context.Document, ifStatement, returnStatement, container, cancellationToken));
                                }
                            }
                        }
                    }
                }
            }
        }
        public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            var ifStatement = (IfStatementSyntax)context.Node;

            if (!ifStatement.IsSimpleIf())
            {
                StatementContainer container;
                if (StatementContainer.TryCreate(ifStatement, out container))
                {
                    int index = container.Statements.IndexOf(ifStatement);

                    ReturnStatementSyntax returnStatement = FindReturnStatementBelow(container.Statements, index);
                    if (returnStatement?.ContainsDiagnostics == false)
                    {
                        ExpressionSyntax expression = returnStatement.Expression;
                        if (expression != null &&
                            !ifStatement.SpanOrTrailingTriviaContainsDirectives() &&
                            !returnStatement.SpanOrLeadingTriviaContainsDirectives())
                        {
                            SemanticModel     semanticModel     = context.SemanticModel;
                            CancellationToken cancellationToken = context.CancellationToken;

                            ISymbol symbol = semanticModel.GetSymbol(expression, cancellationToken);

                            if (IsLocalDeclaredInScopeOrNonRefOrOutParameterOfEnclosingSymbol(symbol, container.Node, semanticModel, cancellationToken) &&
                                ifStatement
                                .GetChain()
                                .All(ifOrElse => IsSymbolAssignedInLastStatement(ifOrElse, symbol, semanticModel, cancellationToken)))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.UseReturnInsteadOfAssignment, ifStatement);
                            }
                        }
                    }
                }
            }
        }
        private static void RegisterRefactoring(
            RefactoringContext context,
            StatementSyntax statement,
            InitializerExpressionSyntax initializer,
            ExpressionSyntax expression)
        {
            StatementContainer container;

            if (StatementContainer.TryCreate(statement, out container))
            {
                context.RegisterRefactoring(
                    Title,
                    cancellationToken => RefactorAsync(
                        context.Document,
                        container,
                        statement,
                        initializer,
                        expression.WithoutTrivia(),
                        cancellationToken));
            }
        }
        public Task <Document> InlineMethodAsync(
            ExpressionStatementSyntax expressionStatement,
            SyntaxList <StatementSyntax> statements)
        {
            int count = statements.Count;

            StatementSyntax[] newStatements = RewriteStatements(statements);

            newStatements[0]         = newStatements[0].WithLeadingTrivia(expressionStatement.GetLeadingTrivia());
            newStatements[count - 1] = newStatements[count - 1].WithTrailingTrivia(expressionStatement.GetTrailingTrivia());

            if (StatementContainer.TryCreate(expressionStatement, out StatementContainer container))
            {
                SyntaxNode newNode = container.NodeWithStatements(container.Statements.ReplaceRange(expressionStatement, newStatements));

                return(Document.ReplaceNodeAsync(container.Node, newNode, CancellationToken));
            }
            else
            {
                return(Document.ReplaceNodeAsync(expressionStatement, Block(newStatements), CancellationToken));
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveUnreachableCode))
            {
                return;
            }

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

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UnreachableCodeDetected:
                {
                    Debug.Assert(context.Span.Start == statement.SpanStart, statement.ToString());

                    if (context.Span.Start != statement.SpanStart)
                    {
                        break;
                    }

                    CodeAction codeAction = CreateCodeActionForIfElse(context.Document, diagnostic, statement.Parent);

                    if (codeAction != null)
                    {
                        context.RegisterCodeFix(codeAction, diagnostic);
                        break;
                    }

                    if (StatementContainer.TryCreate(statement, out StatementContainer container))
                    {
                        codeAction = CodeAction.Create(
                            Title,
                            cancellationToken =>
                            {
                                SyntaxList <StatementSyntax> statements = container.Statements;

                                int index = statements.IndexOf(statement);

                                if (index == statements.Count - 1)
                                {
                                    return(context.Document.RemoveStatementAsync(statement, cancellationToken));
                                }
                                else
                                {
                                    SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

                                    if (statement.GetLeadingTrivia().IsEmptyOrWhitespace())
                                    {
                                        removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
                                    }

                                    if (statements.Last().GetTrailingTrivia().IsEmptyOrWhitespace())
                                    {
                                        removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                    }

                                    return(context.Document.RemoveNodesAsync(statements.Skip(index), removeOptions, cancellationToken));
                                }
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }
                }
            }
        }
Exemple #11
0
        public static async Task <Document> RefactorAsync(
            Document document,
            VariableDeclaratorSyntax declarator,
            CancellationToken cancellationToken)
        {
            var declaration = (VariableDeclarationSyntax)declarator.Parent;

            var localDeclaration = (LocalDeclarationStatementSyntax)declaration.Parent;

            StatementContainer container;

            if (StatementContainer.TryCreate(localDeclaration, out container))
            {
                SyntaxList <StatementSyntax> statements = container.Statements;

                int index = statements.IndexOf(localDeclaration);

                StatementSyntax nextStatement = statements[index + 1];

                var expressionStatement = (ExpressionStatementSyntax)nextStatement;

                var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;

                ExpressionSyntax right = assignment.Right;

                EqualsValueClauseSyntax initializer = declarator.Initializer;

                ExpressionSyntax value = initializer?.Value;

                VariableDeclaratorSyntax newDeclarator = (value != null)
                    ? declarator.ReplaceNode(value, right)
                    : declarator.WithInitializer(EqualsValueClause(right));

                LocalDeclarationStatementSyntax newLocalDeclaration = localDeclaration.ReplaceNode(declarator, newDeclarator);

                SyntaxTriviaList trailingTrivia = nextStatement.GetTrailingTrivia();

                IEnumerable <SyntaxTrivia> trivia = container
                                                    .Node
                                                    .DescendantTrivia(TextSpan.FromBounds(localDeclaration.Span.End, right.SpanStart));

                if (!trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                {
                    newLocalDeclaration = newLocalDeclaration.WithTrailingTrivia(trivia.Concat(trailingTrivia));
                }
                else
                {
                    newLocalDeclaration = newLocalDeclaration.WithTrailingTrivia(trailingTrivia);
                }

                SyntaxList <StatementSyntax> newStatements = statements
                                                             .Replace(localDeclaration, newLocalDeclaration)
                                                             .RemoveAt(index + 1);

                return(await document.ReplaceNodeAsync(container.Node, container.NodeWithStatements(newStatements), cancellationToken).ConfigureAwait(false));
            }

            Debug.Assert(false, "");

            return(document);
        }
Exemple #12
0
        public static void ComputeRefactoring(RefactoringContext context, ExpressionSyntax expression)
        {
            SyntaxNode parent = expression.Parent;

            if (parent != null)
            {
                SyntaxKind kind = parent.Kind();

                if (kind == SyntaxKind.LogicalAndExpression ||
                    kind == SyntaxKind.LogicalOrExpression)
                {
                    BinaryExpressionSyntax binaryExpression = GetCondition((BinaryExpressionSyntax)parent);

                    if (binaryExpression != null)
                    {
                        parent = binaryExpression.Parent;

                        switch (parent?.Kind())
                        {
                        case SyntaxKind.IfStatement:
                        {
                            if (kind == SyntaxKind.LogicalAndExpression)
                            {
                                var refactoring = new ExtractConditionFromIfToNestedIfRefactoring();
                                context.RegisterRefactoring(
                                    refactoring.Title,
                                    cancellationToken => refactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken));
                            }
                            else if (kind == SyntaxKind.LogicalOrExpression)
                            {
                                StatementContainer container;
                                if (StatementContainer.TryCreate((StatementSyntax)parent, out container))
                                {
                                    var refactoring = new ExtractConditionFromIfToIfRefactoring();
                                    context.RegisterRefactoring(
                                        refactoring.Title,
                                        cancellationToken => refactoring.RefactorAsync(context.Document, container, binaryExpression, expression, cancellationToken));
                                }
                            }

                            break;
                        }

                        case SyntaxKind.WhileStatement:
                        {
                            if (kind == SyntaxKind.LogicalAndExpression)
                            {
                                StatementContainer container;
                                if (StatementContainer.TryCreate((StatementSyntax)parent, out container))
                                {
                                    var refactoring = new ExtractConditionFromWhileToNestedIfRefactoring();
                                    context.RegisterRefactoring(
                                        refactoring.Title,
                                        cancellationToken => refactoring.RefactorAsync(context.Document, (WhileStatementSyntax)parent, binaryExpression, expression, cancellationToken));
                                }
                            }

                            break;
                        }
                        }
                    }
                }
            }
        }
        public static async Task <Document> RefactorAsync(
            Document document,
            StatementSyntax statement,
            CancellationToken cancellationToken)
        {
            StatementContainer container;

            if (StatementContainer.TryCreate(statement, out container))
            {
                SyntaxList <StatementSyntax> statements = container.Statements;

                int index = statements.IndexOf(statement);

                StatementSyntax nextStatemnt = statements[index + 1];

                switch (statement.Kind())
                {
                case SyntaxKind.IfStatement:
                {
                    var ifStatement = (IfStatementSyntax)statement;

                    var expressionStatement = (ExpressionStatementSyntax)GetSingleStatementOrDefault(ifStatement.Statement);

                    var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;

                    ExpressionSyntax left  = assignment.Left;
                    ExpressionSyntax right = assignment.Right;

                    BinaryExpressionSyntax coalesceExpression = CoalesceExpression(
                        left.WithoutLeadingTrivia().WithTrailingTrivia(Space),
                        right.WithLeadingTrivia(Space));

                    AssignmentExpressionSyntax newAssignment = assignment.WithRight(coalesceExpression.WithTriviaFrom(right));

                    ExpressionStatementSyntax newNode = expressionStatement.WithExpression(newAssignment);

                    IEnumerable <SyntaxTrivia> trivia = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, expressionStatement.SpanStart));

                    if (trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                    {
                        newNode = newNode.WithLeadingTrivia(ifStatement.GetLeadingTrivia());
                    }
                    else
                    {
                        newNode = newNode
                                  .WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(trivia))
                                  .WithFormatterAnnotation();
                    }

                    return(await document.ReplaceNodeAsync(ifStatement, newNode, cancellationToken).ConfigureAwait(false));
                }

                case SyntaxKind.ExpressionStatement:
                {
                    var expressionStatement = (ExpressionStatementSyntax)statement;

                    var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;

                    return(await RefactorAsync(document, expressionStatement, (IfStatementSyntax)nextStatemnt, index, container, assignment.Right, cancellationToken).ConfigureAwait(false));
                }

                case SyntaxKind.LocalDeclarationStatement:
                {
                    var localDeclaration = (LocalDeclarationStatementSyntax)statement;

                    ExpressionSyntax value = localDeclaration
                                             .Declaration
                                             .Variables
                                             .First()
                                             .Initializer
                                             .Value;

                    return(await RefactorAsync(document, localDeclaration, (IfStatementSyntax)nextStatemnt, index, container, value, cancellationToken).ConfigureAwait(false));
                }
                }
            }

            Debug.Assert(false, statement.Kind().ToString());

            return(document);
        }
Exemple #14
0
        private static ReduceIfNestingAnalysis AnalyzeCore(
            IfStatementSyntax ifStatement,
            SemanticModel semanticModel,
            SyntaxKind jumpKind,
            ReduceIfNestingOptions options,
            INamedTypeSymbol taskSymbol         = null,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!StatementContainer.TryCreate(ifStatement, out StatementContainer container))
            {
                return(Fail(ifStatement));
            }

            CSharpSyntaxNode node       = container.Node;
            SyntaxNode       parent     = node.Parent;
            SyntaxKind       parentKind = parent.Kind();

            SyntaxList <StatementSyntax> statements = container.Statements;

            if (container.IsSwitchSection ||
                parentKind == SyntaxKind.SwitchSection)
            {
                SyntaxNode switchSection = (container.IsSwitchSection) ? node : parent;

                if (!options.AllowSwitchSection())
                {
                    return(Fail(switchSection));
                }

                if (ifStatement != statements.LastButOneOrDefault())
                {
                    return(Fail(switchSection));
                }

                if (!IsFixableJumpStatement(statements.Last(), ref jumpKind))
                {
                    return(Fail(switchSection));
                }

                if (!options.AllowNestedFix() &&
                    IsNestedFix(switchSection.Parent, semanticModel, options, taskSymbol, cancellationToken))
                {
                    return(Fail(switchSection));
                }

                return(Success(jumpKind, switchSection));
            }

            if (parentKind.Is(
                    SyntaxKind.ForStatement,
                    SyntaxKind.ForEachStatement,
                    SyntaxKind.DoStatement,
                    SyntaxKind.WhileStatement))
            {
                if (!options.AllowLoop())
                {
                    return(Fail(parent));
                }

                StatementSyntax lastStatement = statements.Last();

                if (ifStatement == lastStatement)
                {
                    jumpKind = SyntaxKind.ContinueStatement;
                }
                else
                {
                    if (ifStatement != statements.LastButOneOrDefault())
                    {
                        return(Fail(parent));
                    }

                    if (!IsFixableJumpStatement(lastStatement, ref jumpKind))
                    {
                        return(Fail(parent));
                    }
                }

                if (!options.AllowNestedFix() &&
                    IsNestedFix(parent.Parent, semanticModel, options, taskSymbol, cancellationToken))
                {
                    return(Fail(parent));
                }

                return(Success(jumpKind, parent));
            }

            if (!IsFixable(ifStatement, statements, ref jumpKind))
            {
                return(Fail(node));
            }

            switch (parentKind)
            {
            case SyntaxKind.ConstructorDeclaration:
            case SyntaxKind.DestructorDeclaration:
            case SyntaxKind.SetAccessorDeclaration:
            case SyntaxKind.AddAccessorDeclaration:
            case SyntaxKind.RemoveAccessorDeclaration:
            {
                if (jumpKind == SyntaxKind.None)
                {
                    jumpKind = SyntaxKind.ReturnStatement;
                }
                else if (jumpKind != SyntaxKind.ReturnStatement)
                {
                    return(Fail(parent));
                }

                return(Success(jumpKind, parent));
            }

            case SyntaxKind.OperatorDeclaration:
            case SyntaxKind.ConversionOperatorDeclaration:
            case SyntaxKind.GetAccessorDeclaration:
            {
                if (jumpKind == SyntaxKind.None)
                {
                    return(Fail(parent));
                }

                return(Success(jumpKind, parent));
            }

            case SyntaxKind.MethodDeclaration:
            {
                var methodDeclaration = (MethodDeclarationSyntax)parent;

                if (jumpKind != SyntaxKind.None)
                {
                    return(Success(jumpKind, parent));
                }

                if (methodDeclaration.ReturnsVoid())
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (methodDeclaration.Modifiers.Contains(SyntaxKind.AsyncKeyword) &&
                    taskSymbol != null &&
                    semanticModel
                    .GetDeclaredSymbol(methodDeclaration, cancellationToken)?
                    .ReturnType
                    .Equals(taskSymbol) == true)
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (semanticModel
                    .GetDeclaredSymbol(methodDeclaration, cancellationToken)?
                    .ReturnType
                    .IsIEnumerableOrConstructedFromIEnumerableOfT() == true &&
                    methodDeclaration.ContainsYield())
                {
                    return(Success(SyntaxKind.YieldBreakStatement, parent));
                }

                break;
            }

            case SyntaxKind.LocalFunctionStatement:
            {
                var localFunction = (LocalFunctionStatementSyntax)parent;

                if (jumpKind != SyntaxKind.None)
                {
                    return(Success(jumpKind, parent));
                }

                if (localFunction.ReturnsVoid())
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (localFunction.Modifiers.Contains(SyntaxKind.AsyncKeyword) &&
                    taskSymbol != null &&
                    ((IMethodSymbol)semanticModel.GetDeclaredSymbol(localFunction, cancellationToken))?
                    .ReturnType
                    .Equals(taskSymbol) == true)
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (((IMethodSymbol)semanticModel.GetDeclaredSymbol(localFunction, cancellationToken))?
                    .ReturnType
                    .IsIEnumerableOrConstructedFromIEnumerableOfT() == true &&
                    localFunction.ContainsYield())
                {
                    return(Success(SyntaxKind.YieldBreakStatement, parent));
                }

                break;
            }

            case SyntaxKind.AnonymousMethodExpression:
            case SyntaxKind.SimpleLambdaExpression:
            case SyntaxKind.ParenthesizedLambdaExpression:
            {
                var anonymousFunction = (AnonymousFunctionExpressionSyntax)parent;

                if (jumpKind != SyntaxKind.None)
                {
                    return(Success(jumpKind, parent));
                }

                var methodSymbol = semanticModel.GetSymbol(anonymousFunction, cancellationToken) as IMethodSymbol;

                if (methodSymbol == null)
                {
                    return(Fail(parent));
                }

                if (methodSymbol.ReturnsVoid)
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                if (anonymousFunction.AsyncKeyword.IsKind(SyntaxKind.AsyncKeyword) &&
                    methodSymbol.ReturnType.Equals(taskSymbol))
                {
                    return(Success(SyntaxKind.ReturnStatement, parent));
                }

                break;
            }

            case SyntaxKind.IfStatement:
            {
                ifStatement = (IfStatementSyntax)parent;

                if (ifStatement.Parent is ElseClauseSyntax elseClause)
                {
                    if (ifStatement.Else != null)
                    {
                        return(Fail(parent));
                    }

                    if (!options.AllowIfInsideIfElse())
                    {
                        return(Fail(parent));
                    }

                    return(AnalyzeCore(ifStatement.GetTopmostIf(), semanticModel, jumpKind, options, taskSymbol, cancellationToken));
                }
                else
                {
                    if (!IsFixable(ifStatement))
                    {
                        return(Fail(parent));
                    }

                    if (!options.AllowNestedFix())
                    {
                        return(Fail(parent));
                    }

                    return(AnalyzeCore(ifStatement, semanticModel, jumpKind, options, taskSymbol, cancellationToken));
                }
            }

            case SyntaxKind.ElseClause:
            {
                if (!options.AllowIfInsideIfElse())
                {
                    return(Fail(parent));
                }

                var elseClause = (ElseClauseSyntax)parent;

                return(AnalyzeCore(elseClause.GetTopmostIf(), semanticModel, jumpKind, options, taskSymbol, cancellationToken));
            }
            }

            return(Fail(parent));
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, IfStatementSyntax ifStatement)
        {
            if (!StatementContainer.TryCreate(ifStatement, out StatementContainer container))
            {
                return;
            }

            ReturnStatementSyntax   returnStatement = GetReturnStatement(ifStatement.Statement);
            LiteralExpressionSyntax booleanLiteral  = GetBooleanLiteral(returnStatement);

            if (booleanLiteral == null)
            {
                return;
            }

            ReturnStatementSyntax   returnStatement2 = null;
            LiteralExpressionSyntax booleanLiteral2  = null;

            TextSpan         span       = ifStatement.Span;
            ElseClauseSyntax elseClause = ifStatement.Else;

            if (elseClause != null)
            {
                returnStatement2 = GetReturnStatement(elseClause.Statement);
                booleanLiteral2  = GetBooleanLiteral(returnStatement2);

                if (booleanLiteral2 == null)
                {
                    return;
                }
            }
            else
            {
                SyntaxList <StatementSyntax> statements = container.Statements;

                int index = statements.IndexOf(ifStatement);

                if (index == statements.Count - 1)
                {
                    return;
                }

                if (index > 0 &&
                    ((statements[index - 1] is IfStatementSyntax ifStatement2) &&
                     ifStatement2.Else == null &&
                     GetBooleanLiteral(ifStatement2.Statement) != null))
                {
                    return;
                }

                StatementSyntax nextStatement = statements[index + 1];

                if (nextStatement.Kind() != SyntaxKind.ReturnStatement)
                {
                    return;
                }

                returnStatement2 = (ReturnStatementSyntax)nextStatement;
                booleanLiteral2  = GetBooleanLiteral(returnStatement2);

                if (booleanLiteral2 == null)
                {
                    return;
                }

                span = TextSpan.FromBounds(ifStatement.SpanStart, returnStatement2.Span.End);
            }

            if (booleanLiteral.Kind() == booleanLiteral2.Kind())
            {
                return;
            }

            if (!container.Node
                .DescendantTrivia(span)
                .All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatement, ifStatement.IfKeyword);

            context.ReportToken(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatementFadeOut, ifStatement.IfKeyword);
            context.ReportToken(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatementFadeOut, ifStatement.OpenParenToken);
            context.ReportToken(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatementFadeOut, ifStatement.CloseParenToken);
            context.ReportNode(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatementFadeOut, ifStatement.Statement);

            if (elseClause != null)
            {
                context.ReportNode(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatementFadeOut, elseClause);
            }
            else
            {
                context.ReportNode(DiagnosticDescriptors.ReplaceIfStatementWithReturnStatementFadeOut, returnStatement2);
            }
        }
Exemple #16
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.RemoveUnreachableCode,
                    CodeFixIdentifiers.RemoveEmptySwitchStatement,
                    CodeFixIdentifiers.IntroduceLocalVariable,
                    CodeFixIdentifiers.RemoveJumpStatement))
            {
                return;
            }

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

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.UnreachableCodeDetected:
                {
                    if (context.Span.Start == statement.SpanStart)
                    {
                        StatementContainer container;
                        if (StatementContainer.TryCreate(statement, out container))
                        {
                            CodeAction codeAction = CodeAction.Create(
                                "Remove unreachable code",
                                cancellationToken =>
                                {
                                    SyntaxList <StatementSyntax> statements = container.Statements;

                                    int index = statements.IndexOf(statement);

                                    if (index == statements.Count - 1)
                                    {
                                        return(context.Document.RemoveStatementAsync(statement, context.CancellationToken));
                                    }
                                    else
                                    {
                                        SyntaxRemoveOptions removeOptions = RemoveHelper.DefaultRemoveOptions;

                                        if (statement.GetLeadingTrivia().IsEmptyOrWhitespace())
                                        {
                                            removeOptions &= ~SyntaxRemoveOptions.KeepLeadingTrivia;
                                        }

                                        if (statements.Last().GetTrailingTrivia().IsEmptyOrWhitespace())
                                        {
                                            removeOptions &= ~SyntaxRemoveOptions.KeepTrailingTrivia;
                                        }

                                        return(context.Document.RemoveNodesAsync(statements.Skip(index), removeOptions, context.CancellationToken));
                                    }
                                },
                                GetEquivalenceKey(diagnostic));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.EmptySwitchBlock:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveEmptySwitchStatement))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.SwitchStatement))
                    {
                        break;
                    }

                    var switchStatement = (SwitchStatementSyntax)statement;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove switch statement",
                        cancellationToken => context.Document.RemoveStatementAsync(switchStatement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.OnlyAssignmentCallIncrementDecrementAndNewObjectExpressionsCanBeUsedAsStatement:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.IntroduceLocalVariable))
                    {
                        break;
                    }

                    if (!statement.IsKind(SyntaxKind.ExpressionStatement))
                    {
                        break;
                    }

                    var expressionStatement = (ExpressionStatementSyntax)statement;

                    ExpressionSyntax expression = expressionStatement.Expression;

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

                    if (semanticModel.GetSymbol(expression, context.CancellationToken)?.IsErrorType() == false)
                    {
                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken);

                        if (typeSymbol?.IsErrorType() == false)
                        {
                            bool addAwait = typeSymbol.IsConstructedFromTaskOfT(semanticModel) &&
                                            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));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoEnclosingLoopOutOfWhichToBreakOrContinue:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveJumpStatement))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {statement.GetTitle()}",
                        cancellationToken => context.Document.RemoveStatementAsync(statement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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