private static Task <Document> SplitLastElseIfAsync(
            Document document,
            IfStatementSyntax ifStatement,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax condition = ifStatement.Condition;
            StatementSyntax  statement = ifStatement.Statement.WithoutTrivia();

            IfStatementSyntax newIfStatement = ifStatement;

            ElseClauseSyntax elseClause = null;

            ExpressionChain.Reversed.Enumerator en = SyntaxInfo.BinaryExpressionInfo(condition).AsChain().Reverse().GetEnumerator();

            while (en.MoveNext())
            {
                newIfStatement = IfStatement(en.Current.TrimTrivia(), statement, elseClause);

                elseClause = ElseClause(newIfStatement);
            }

            newIfStatement = newIfStatement
                             .WithTriviaFrom(ifStatement)
                             .WithFormatterAnnotation();

            return(document.ReplaceNodeAsync(ifStatement, newIfStatement, cancellationToken));
        }
Пример #2
0
        private static Task <Document> CallAnyInsteadOfUsingCountAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (binaryExpressionInfo.Left is not MemberAccessExpressionSyntax memberAccessExpression)
            {
                memberAccessExpression = (MemberAccessExpressionSyntax)binaryExpressionInfo.Right;
            }

            SimpleNameSyntax name = memberAccessExpression.Name;

            ExpressionSyntax newExpression = SimpleMemberInvocationExpression(
                memberAccessExpression.Expression,
                IdentifierName("Any").WithLeadingTrivia(name.GetLeadingTrivia()),
                ArgumentList().WithTrailingTrivia(name.GetTrailingTrivia()));

            if (binaryExpression.IsKind(SyntaxKind.EqualsExpression))
            {
                newExpression = LogicalNotExpression(newExpression.WithoutLeadingTrivia().Parenthesize());
            }

            newExpression = newExpression
                            .WithTriviaFrom(binaryExpression)
                            .WithFormatterAnnotation();

            return(document.ReplaceNodeAsync(binaryExpression, newExpression, cancellationToken));
        }
        private static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context)
        {
            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            if (binaryExpression.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind leftKind = info.Left.Kind();

            if (leftKind == SyntaxKind.DefaultExpression || CSharpFacts.IsLiteralExpression(leftKind))
            {
                SyntaxKind rightKind = info.Right.Kind();

                if (rightKind != SyntaxKind.DefaultExpression && !CSharpFacts.IsLiteralExpression(rightKind))
                {
                    DiagnosticHelpers.ReportDiagnostic(
                        context,
                        DiagnosticDescriptors.ConstantValuesShouldBePlacedOnRightSideOfComparisons,
                        info.Left);
                }
            }
        }
        public static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context)
        {
            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!info.Success)
            {
                return;
            }

            if (CSharpUtility.IsStringConcatenation(binaryExpression, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            if (!info.Left.GetTrailingTrivia().All(f => f.IsWhitespaceTrivia()))
            {
                return;
            }

            if (!CheckOperatorTrailingTrivia(binaryExpression.OperatorToken.TrailingTrivia))
            {
                return;
            }

            if (!info.Right.GetLeadingTrivia().IsEmptyOrWhitespace())
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.FormatBinaryOperatorOnNextLine,
                                               binaryExpression.OperatorToken);
        }
        private static void AnalyzeEqualsExpression(SyntaxNodeAnalysisContext context)
        {
            var equalsExpression = (BinaryExpressionSyntax)context.Node;

            if (equalsExpression.ContainsDirectives)
            {
                return;
            }

            BinaryExpressionInfo equalsExpressionInfo = SyntaxInfo.BinaryExpressionInfo(equalsExpression);

            if (!equalsExpressionInfo.Success)
            {
                return;
            }

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

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            if (CSharpUtility.IsEmptyStringExpression(left, semanticModel, cancellationToken))
            {
                if (CSharpUtility.IsStringExpression(right, semanticModel, cancellationToken))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseStringIsNullOrEmptyMethod, equalsExpression);
                }
            }
            else if (CSharpUtility.IsEmptyStringExpression(right, semanticModel, cancellationToken) &&
                     CSharpUtility.IsStringExpression(left, semanticModel, cancellationToken))
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseStringIsNullOrEmptyMethod, equalsExpression);
            }
        }
Пример #6
0
        private static ExpressionPair GetExpressionPair(BinaryExpressionSyntax logicalAnd)
        {
            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(logicalAnd);

            if (info.Success)
            {
                ExpressionSyntax left  = info.Left;
                ExpressionSyntax right = info.Right;

                if (left.Kind() == SyntaxKind.LogicalNotExpression)
                {
                    if (right.Kind() != SyntaxKind.LogicalNotExpression)
                    {
                        var logicalNot = (PrefixUnaryExpressionSyntax)left;

                        return(new ExpressionPair(right, logicalNot.Operand.WalkDownParentheses()));
                    }
                }
                else if (right.Kind() == SyntaxKind.LogicalNotExpression)
                {
                    var logicalNot = (PrefixUnaryExpressionSyntax)right;

                    return(new ExpressionPair(left, logicalNot.Operand.WalkDownParentheses()));
                }
            }

            return(default(ExpressionPair));
        }
Пример #7
0
        private static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context)
        {
            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            if (binaryExpression.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!info.Success)
            {
                return;
            }

            if (info.Right.Kind() == SyntaxKind.NullLiteralExpression)
            {
                return;
            }

            if (info.Left.Kind() != SyntaxKind.NullLiteralExpression)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression,
                                               info.Left);
        }
Пример #8
0
        private static void AnalyzeCoalesceExpression(SyntaxNodeAnalysisContext context)
        {
            var coalesceExpression = (BinaryExpressionSyntax)context.Node;

            if (coalesceExpression.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(coalesceExpression);

            if (!info.Success)
            {
                return;
            }

            TextSpan span = GetRedundantSpan(coalesceExpression, info.Left, info.Right, context.SemanticModel, context.CancellationToken);

            if (span == default)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(
                context,
                DiagnosticRules.SimplifyCoalesceExpression,
                Location.Create(coalesceExpression.SyntaxTree, span));
        }
        private static Task <Document> SplitSimpleIfAsync(
            Document document,
            IfStatementSyntax ifStatement,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax condition = ifStatement.Condition;
            StatementSyntax  statement = ifStatement.Statement.WithoutTrivia();

            List <IfStatementSyntax> ifStatements = SyntaxInfo.BinaryExpressionInfo(condition)
                                                    .AsChain()
                                                    .Select(expression => IfStatement(expression.TrimTrivia(), statement).WithFormatterAnnotation())
                                                    .ToList();

            ifStatements[0] = ifStatements[0].WithLeadingTrivia(ifStatement.GetLeadingTrivia());
            ifStatements[ifStatements.Count - 1] = ifStatements[ifStatements.Count - 1].WithTrailingTrivia(ifStatement.GetTrailingTrivia());

            if (ifStatement.IsEmbedded())
            {
                BlockSyntax block = Block(ifStatements);

                return(document.ReplaceNodeAsync(ifStatement, block, cancellationToken));
            }
            else
            {
                return(document.ReplaceNodeAsync(ifStatement, ifStatements, cancellationToken));
            }
        }
Пример #10
0
        public static bool IsFixable(AssignmentExpressionSyntax assignmentExpression)
        {
            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression);

            if (!assignmentInfo.Success)
            {
                return(false);
            }

            if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression))
            {
                return(false);
            }

            if (!IsFixableBinaryExpression(assignmentInfo.Right.Kind()))
            {
                return(false);
            }

            BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)assignmentInfo.Right);

            if (!binaryInfo.Success)
            {
                return(false);
            }

            if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left))
            {
                return(false);
            }

            return(true);
        }
        public static void ComputeRefactoring(RefactoringContext context, BinaryExpressionSyntax binaryExpression)
        {
            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!info.Success)
            {
                return;
            }

            if (CanRefactor())
            {
                context.RegisterRefactoring(
                    "Swap operands",
                    cancellationToken => DocumentRefactorings.SwapBinaryOperandsAsync(context.Document, binaryExpression, cancellationToken),
                    RefactoringIdentifiers.SwapBinaryOperands);
            }

            bool CanRefactor()
            {
                SyntaxKind kind = binaryExpression.Kind();

                switch (kind)
                {
                case SyntaxKind.LogicalAndExpression:
                case SyntaxKind.LogicalOrExpression:
                case SyntaxKind.BitwiseAndExpression:
                case SyntaxKind.BitwiseOrExpression:
                case SyntaxKind.ExclusiveOrExpression:
                case SyntaxKind.AddExpression:
                case SyntaxKind.MultiplyExpression:
                {
                    return(!info.Left.IsKind(kind));
                }

                case SyntaxKind.EqualsExpression:
                case SyntaxKind.NotEqualsExpression:
                {
                    return(!info.Right.IsKind(
                               SyntaxKind.NullLiteralExpression,
                               SyntaxKind.TrueLiteralExpression,
                               SyntaxKind.FalseLiteralExpression));
                }

                case SyntaxKind.GreaterThanExpression:
                case SyntaxKind.GreaterThanOrEqualExpression:
                case SyntaxKind.LessThanExpression:
                case SyntaxKind.LessThanOrEqualExpression:
                {
                    return(true);
                }
                }

                return(false);
            }
        }
        internal static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context)
        {
            var logicalAnd = (BinaryExpressionSyntax)context.Node;

            if (logicalAnd.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo logicalAndInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd);

            if (!logicalAndInfo.Success)
            {
                return;
            }

            ExpressionSyntax left = logicalAndInfo.Left;

            if (!IsPropertyOfNullableOfT(left, "HasValue", context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            ExpressionSyntax right = logicalAndInfo.Right;

            switch (right.Kind())
            {
            case SyntaxKind.LogicalNotExpression:
            {
                var logicalNot = (PrefixUnaryExpressionSyntax)right;

                Analyze(context, logicalAnd, left, logicalNot.Operand?.WalkDownParentheses());
                break;
            }

            case SyntaxKind.EqualsExpression:
            {
                BinaryExpressionInfo equalsExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right);

                if (equalsExpressionInfo.Success &&
                    equalsExpressionInfo.Right.Kind() == SyntaxKind.FalseLiteralExpression)
                {
                    Analyze(context, logicalAnd, left, equalsExpressionInfo.Left);
                }

                break;
            }

            case SyntaxKind.SimpleMemberAccessExpression:
            {
                Analyze(context, logicalAnd, left, right);
                break;
            }
            }
        }
        private static async Task <Document> RemoveUnnecessaryNullCheckAsync(
            Document document,
            BinaryExpressionSyntax logicalAnd,
            CancellationToken cancellationToken)
        {
            BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd);

            ExpressionSyntax right = binaryExpressionInfo.Right;

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

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpressionInfo.Left, semanticModel, NullCheckStyles.HasValue | NullCheckStyles.NotEqualsToNull);

            var binaryExpression = right as BinaryExpressionSyntax;

            ExpressionSyntax newRight;

            switch (right.Kind())
            {
            case SyntaxKind.SimpleMemberAccessExpression:
            {
                newRight = TrueLiteralExpression().WithTriviaFrom(right);
                break;
            }

            case SyntaxKind.LogicalNotExpression:
            {
                newRight = FalseLiteralExpression().WithTriviaFrom(right);
                break;
            }

            default:
            {
                newRight = binaryExpression.Right;
                break;
            }
            }

            BinaryExpressionSyntax newBinaryExpression = BinaryExpression(
                (binaryExpression != null)
                    ? right.Kind()
                    : SyntaxKind.EqualsExpression,
                nullCheck.Expression.WithLeadingTrivia(logicalAnd.GetLeadingTrivia()),
                (binaryExpression != null)
                    ? ((BinaryExpressionSyntax)right).OperatorToken
                    : Token(SyntaxKind.EqualsEqualsToken).WithTriviaFrom(logicalAnd.OperatorToken),
                newRight)
                                                         .WithFormatterAnnotation();

            return(await document.ReplaceNodeAsync(logicalAnd, newBinaryExpression, cancellationToken).ConfigureAwait(false));
        }
        private static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context)
        {
            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            if (binaryExpression.ContainsDiagnostics)
            {
                return;
            }

            if (binaryExpression.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind kind = binaryExpression.Kind();

            if (kind == SyntaxKind.LogicalOrExpression)
            {
                if (info.Left.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.IsPatternExpression) &&
                    info.Right.IsKind(SyntaxKind.EqualsExpression) &&
                    IsFixable(
                        info.Left,
                        (BinaryExpressionSyntax)info.Right,
                        context.SemanticModel,
                        context.CancellationToken))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseStringIsNullOrEmptyMethod, binaryExpression);
                }
            }
            else if (kind == SyntaxKind.LogicalAndExpression)
            {
                if (info.Left.IsKind(SyntaxKind.NotEqualsExpression, SyntaxKind.LogicalNotExpression) &&
                    info.Right.IsKind(SyntaxKind.NotEqualsExpression, SyntaxKind.GreaterThanExpression) &&
                    IsFixable(
                        info.Left,
                        (BinaryExpressionSyntax)info.Right,
                        context.SemanticModel,
                        context.CancellationToken))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseStringIsNullOrEmptyMethod, binaryExpression);
                }
            }
        }
Пример #15
0
        private static async Task <Document> UseStringIsNullOrEmptyMethodAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            if (binaryExpression.IsKind(SyntaxKind.EqualsExpression))
            {
                SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

                ExpressionSyntax expression = (CSharpUtility.IsEmptyStringExpression(binaryExpressionInfo.Left, semanticModel, cancellationToken))
                    ? binaryExpressionInfo.Right
                    : binaryExpressionInfo.Left;

                ExpressionSyntax newNode = SimpleMemberInvocationExpression(
                    CSharpTypeFactory.StringType(),
                    IdentifierName("IsNullOrEmpty"),
                    Argument(expression));

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

                return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left);

                ExpressionSyntax newNode = SimpleMemberInvocationExpression(
                    CSharpTypeFactory.StringType(),
                    IdentifierName("IsNullOrEmpty"),
                    Argument(nullCheck.Expression));

                if (nullCheck.IsCheckingNotNull)
                {
                    newNode = LogicalNotExpression(newNode);
                }

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

                return(await document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken).ConfigureAwait(false));
            }
        }
        private static void AnalyzeCoalesceExpression(SyntaxNodeAnalysisContext context)
        {
            var coalesceExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(coalesceExpression, walkDownParentheses: false);

            if (!binaryExpressionInfo.Success)
            {
                return;
            }

            ExpressionSyntax right = binaryExpressionInfo.Right;

            if (!right.IsKind(SyntaxKind.ParenthesizedExpression))
            {
                return;
            }

            var parenthesizedExpression = (ParenthesizedExpressionSyntax)right;

            ExpressionSyntax expression = parenthesizedExpression.Expression;

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

            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo((AssignmentExpressionSyntax)expression);

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(binaryExpressionInfo.Left, assignmentInfo.Left))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCompoundAssignment, coalesceExpression);

            DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, parenthesizedExpression.OpenParenToken);
            DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, assignmentInfo.Left);
            DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, parenthesizedExpression.CloseParenToken);
        }
Пример #17
0
        // 0 > x >>> false
        private static void AnalyzeGreaterThanExpression(SyntaxNodeAnalysisContext context)
        {
            var greaterThanExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(greaterThanExpression);

            if (!info.Success)
            {
                return;
            }

            if (!IsAlwaysEqualToTrueOrFalse(greaterThanExpression, info.Right, info.Left, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            ReportExpressionAlwaysEqualToTrueOrFalse(context, "false");
        }
Пример #18
0
        // x > 0 (x > 0) true/false
        // 0 > x (x < 0) false
        public static void GreaterThanExpression(SyntaxNodeAnalysisContext context)
        {
            var greaterThanExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(greaterThanExpression);

            if (!info.Success)
            {
                return;
            }

            if (!IsFixable(greaterThanExpression, info.Right, info.Left, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            ReportDiagnostic(context, "false");
        }
Пример #19
0
        // x <= 0 (x <= 0) true/false
        // 0 <= x (x >= 0) true
        public static void AnalyzeLessThanOrEqualExpression(SyntaxNodeAnalysisContext context)
        {
            var lessThanOrEqualExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(lessThanOrEqualExpression);

            if (!info.Success)
            {
                return;
            }

            if (!IsFixable(lessThanOrEqualExpression, info.Right, info.Left, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            ReportDiagnostic(context, "true");
        }
        private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context)
        {
            var assignmentExpression = (AssignmentExpressionSyntax)context.Node;

            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression);

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression))
            {
                return;
            }

            ExpressionSyntax right = assignmentInfo.Right;

            if (!CanBeReplacedWithCompoundAssignment(right.Kind()))
            {
                return;
            }

            BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right);

            if (!binaryInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left))
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)right;

            context.ReportDiagnostic(DiagnosticDescriptors.UseCompoundAssignment, assignmentExpression, GetCompoundAssignmentOperatorText(binaryExpression));
            context.ReportNode(DiagnosticDescriptors.UseCompoundAssignmentFadeOut, binaryExpression.Left);
        }
Пример #21
0
        // x:
        // byte
        // ushort
        // uint
        // ulong
        // Array.Length
        // string.Length
        // ICollection<T>.Count
        // IReadOnlyCollection<T>.Count

        // x >= 0 >>> true
        // 0 >= x >>> 0 == x
        private static void AnalyzeGreaterThanOrEqualExpression(SyntaxNodeAnalysisContext context)
        {
            var greaterThanOrEqualExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(greaterThanOrEqualExpression);

            if (!info.Success)
            {
                return;
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.ExpressionIsAlwaysEqualToTrueOrFalse) &&
                IsAlwaysEqualToTrueOrFalse(greaterThanOrEqualExpression, info.Left, info.Right, context.SemanticModel, context.CancellationToken))
            {
                ReportExpressionAlwaysEqualToTrueOrFalse(context, "true");
            }
            else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnnecessaryOperator) &&
                     IsUnnecessaryRelationalOperator(info.Right, info.Left, context.SemanticModel, context.CancellationToken))
            {
                ReportUnnecessaryRelationalOperator(context, info.OperatorToken);
            }
        }
Пример #22
0
        // 0 <= x >>> true
        // x <= 0 >>> x == 0
        private static void AnalyzeLessThanOrEqualExpression(SyntaxNodeAnalysisContext context)
        {
            var lessThanOrEqualExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo(lessThanOrEqualExpression);

            if (!info.Success)
            {
                return;
            }

            if (DiagnosticRules.ExpressionIsAlwaysEqualToTrueOrFalse.IsEffective(context) &&
                IsAlwaysEqualToTrueOrFalse(lessThanOrEqualExpression, info.Right, info.Left, context.SemanticModel, context.CancellationToken))
            {
                ReportExpressionAlwaysEqualToTrueOrFalse(context, "true");
            }
            else if (DiagnosticRules.UnnecessaryOperator.IsEffective(context) &&
                     IsUnnecessaryRelationalOperator(info.Left, info.Right, context.SemanticModel, context.CancellationToken))
            {
                ReportUnnecessaryRelationalOperator(context, info.OperatorToken);
            }
        }
        private static void AnalyzeEqualsExpression(SyntaxNodeAnalysisContext context)
        {
            var equalsExpression = (BinaryExpressionSyntax)context.Node;

            if (equalsExpression.ContainsDirectives)
            {
                return;
            }

            BinaryExpressionInfo equalsExpressionInfo = SyntaxInfo.BinaryExpressionInfo(equalsExpression);

            if (!equalsExpressionInfo.Success)
            {
                return;
            }

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

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            if (CSharpUtility.IsEmptyStringExpression(left, semanticModel, cancellationToken))
            {
                if (CSharpUtility.IsStringExpression(right, semanticModel, cancellationToken) &&
                    !equalsExpression.IsInExpressionTree(semanticModel, cancellationToken))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseStringLengthInsteadOfComparisonWithEmptyString, equalsExpression);
                }
            }
            else if (CSharpUtility.IsEmptyStringExpression(right, semanticModel, cancellationToken) &&
                     CSharpUtility.IsStringExpression(left, semanticModel, cancellationToken) &&
                     !equalsExpression.IsInExpressionTree(semanticModel, cancellationToken))
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UseStringLengthInsteadOfComparisonWithEmptyString, equalsExpression);
            }
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo)
        {
            INamedTypeSymbol stringBuilderSymbol = context.GetTypeByMetadataName(MetadataNames.System_Text_StringBuilder);

            if (stringBuilderSymbol == null)
            {
                return;
            }

            InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression;

            IMethodSymbol methodSymbol = context.SemanticModel.GetMethodSymbol(invocationExpression, context.CancellationToken);

            if (methodSymbol == null)
            {
                return;
            }

            if (methodSymbol.IsExtensionMethod)
            {
                return;
            }

            if (methodSymbol.ContainingType?.Equals(stringBuilderSymbol) != true)
            {
                return;
            }

            ImmutableArray <IParameterSymbol> parameters = methodSymbol.Parameters;

            int parameterCount = parameters.Length;

            if (parameterCount == 0)
            {
                if (methodSymbol.IsName("AppendLine"))
                {
                    SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationInfo.Expression);

                    if (invocationInfo2.Success &&
                        invocationInfo2.NameText == "Append" &&
                        invocationInfo2.Arguments.Count == 1)
                    {
                        IMethodSymbol methodInfo2 = context.SemanticModel.GetMethodSymbol(invocationInfo2.InvocationExpression, context.CancellationToken);

                        if (methodInfo2?.IsStatic == false &&
                            methodInfo2.ContainingType?.Equals(stringBuilderSymbol) == true &&
                            methodInfo2.HasSingleParameter(SpecialType.System_String))
                        {
                            context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, invocationInfo.Name, methodSymbol.Name);
                        }
                    }
                }
            }
            else if (parameterCount == 1)
            {
                if (methodSymbol.IsName("Append", "AppendLine"))
                {
                    ArgumentSyntax argument = invocationInfo.Arguments.SingleOrDefault(shouldThrow: false);

                    if (argument != null)
                    {
                        ExpressionSyntax expression = argument.Expression;

                        SyntaxKind expressionKind = expression.Kind();

                        switch (expressionKind)
                        {
                        case SyntaxKind.InterpolatedStringExpression:
                        {
                            context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodSymbol.Name);
                            return;
                        }

                        case SyntaxKind.AddExpression:
                        {
                            BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)expression);

                            if (binaryExpressionInfo.Success &&
                                binaryExpressionInfo.IsStringConcatenation(context.SemanticModel, context.CancellationToken))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodSymbol.Name);
                                return;
                            }

                            break;
                        }

                        default:
                        {
                            if (expressionKind == SyntaxKind.InvocationExpression &&
                                IsFixable((InvocationExpressionSyntax)expression, context.SemanticModel, context.CancellationToken))
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.OptimizeStringBuilderAppendCall, argument, methodSymbol.Name);
                                return;
                            }

                            if (methodSymbol.IsName("Append") &&
                                parameterCount == 1 &&
                                parameters[0].Type.IsObject() &&
                                context.SemanticModel.GetTypeSymbol(argument.Expression, context.CancellationToken).IsValueType)
                            {
                                context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, argument);
                                return;
                            }

                            break;
                        }
                        }
                    }
                }
            }
            else if (parameterCount == 2)
            {
                if (methodSymbol.IsName("Insert") &&
                    parameters[0].Type.SpecialType == SpecialType.System_Int32 &&
                    parameters[1].Type.SpecialType == SpecialType.System_Object)
                {
                    SeparatedSyntaxList <ArgumentSyntax> arguments = invocationInfo.Arguments;

                    if (arguments.Count == 2 &&
                        context.SemanticModel
                        .GetTypeSymbol(arguments[1].Expression, context.CancellationToken)
                        .IsValueType)
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.AvoidBoxingOfValueType, arguments[1]);
                    }
                }
            }
        }
        private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context)
        {
            var assignmentExpression = (AssignmentExpressionSyntax)context.Node;

            SimpleAssignmentExpressionInfo assignmentInfo = SyntaxInfo.SimpleAssignmentExpressionInfo(assignmentExpression);

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (assignmentExpression.IsParentKind(SyntaxKind.ObjectInitializerExpression))
            {
                return;
            }

            ExpressionSyntax right = assignmentInfo.Right;

            if (!CanBeReplacedWithCompoundAssignment(right.Kind()))
            {
                return;
            }

            BinaryExpressionInfo binaryInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right);

            if (!binaryInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(assignmentInfo.Left, binaryInfo.Left))
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)right;

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCompoundAssignment, assignmentExpression, GetCompoundAssignmentOperatorText(binaryExpression));
            DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseCompoundAssignmentFadeOut, binaryExpression.Left);

            bool CanBeReplacedWithCompoundAssignment(SyntaxKind kind)
            {
                switch (kind)
                {
                case SyntaxKind.AddExpression:
                case SyntaxKind.SubtractExpression:
                case SyntaxKind.MultiplyExpression:
                case SyntaxKind.DivideExpression:
                case SyntaxKind.ModuloExpression:
                case SyntaxKind.BitwiseAndExpression:
                case SyntaxKind.ExclusiveOrExpression:
                case SyntaxKind.BitwiseOrExpression:
                case SyntaxKind.LeftShiftExpression:
                case SyntaxKind.RightShiftExpression:
                    return(true);

                case SyntaxKind.CoalesceExpression:
                    return(((CSharpCompilation)context.Compilation).LanguageVersion >= LanguageVersion.CSharp8);

                default:
                    return(false);
                }
            }
        }
Пример #26
0
        public static void AnalyzeLogicalOrExpression(SyntaxNodeAnalysisContext context)
        {
            SyntaxNode node = context.Node;

            if (node.ContainsDiagnostics)
            {
                return;
            }

            if (node.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo info = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)context.Node);

            if (!info.Success)
            {
                return;
            }

            if (!info.Left.IsKind(SyntaxKind.LogicalAndExpression))
            {
                return;
            }

            if (!info.Right.IsKind(SyntaxKind.LogicalAndExpression))
            {
                return;
            }

            ExpressionPair expressions = GetExpressionPair((BinaryExpressionSyntax)info.Left);

            if (!expressions.IsValid)
            {
                return;
            }

            ExpressionPair expressions2 = GetExpressionPair((BinaryExpressionSyntax)info.Right);

            if (!expressions2.IsValid)
            {
                return;
            }

            if (expressions.Expression.Kind() != expressions2.NegatedExpression.Kind())
            {
                return;
            }

            if (expressions.NegatedExpression.Kind() != expressions2.Expression.Kind())
            {
                return;
            }

            if (!AreEquivalent(expressions.Expression, expressions2.NegatedExpression))
            {
                return;
            }

            if (!AreEquivalent(expressions.NegatedExpression, expressions2.Expression))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.UseExclusiveOrOperator, context.Node);
        }
Пример #27
0
        private static void AnalyzeBinaryExpression(SyntaxNodeAnalysisContext context)
        {
            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo(binaryExpression);

            if (!binaryExpressionInfo.Success)
            {
                return;
            }

            if (binaryExpressionInfo.Right.Kind() != SyntaxKind.TrueLiteralExpression)
            {
                return;
            }

            ExpressionSyntax left = binaryExpressionInfo.Left;

            if (left.Kind() != SyntaxKind.ConditionalAccessExpression)
            {
                return;
            }

            var conditionalAccess = (ConditionalAccessExpressionSyntax)left;

            ExpressionSyntax whenNotNull = conditionalAccess.WhenNotNull;

            if (whenNotNull.Kind() != SyntaxKind.InvocationExpression)
            {
                return;
            }

            var invocationExpression = (InvocationExpressionSyntax)whenNotNull;

            if (invocationExpression.ArgumentList.Arguments.Count != 1)
            {
                return;
            }

            ExpressionSyntax expression = invocationExpression.Expression;

            if (expression.Kind() != SyntaxKind.MemberBindingExpression)
            {
                return;
            }

            var memberBindingExpression = (MemberBindingExpressionSyntax)expression;

            SimpleNameSyntax name = memberBindingExpression.Name;

            if (name.Kind() != SyntaxKind.IdentifierName)
            {
                return;
            }

            var identifierName = (IdentifierNameSyntax)name;

            if (!string.Equals(identifierName.Identifier.ValueText, "IsKind", StringComparison.Ordinal))
            {
                return;
            }

            ISymbol symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);

            if (symbol?.Kind != SymbolKind.Method)
            {
                return;
            }

            var methodSymbol = (IMethodSymbol)symbol;

            if (methodSymbol.MethodKind != MethodKind.ReducedExtension)
            {
                return;
            }

            if (methodSymbol.ReturnType.SpecialType != SpecialType.System_Boolean)
            {
                return;
            }

            if (methodSymbol.ContainingType?.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_CSharpExtensions) != true)
            {
                return;
            }

            ImmutableArray <IParameterSymbol> parameters = methodSymbol
                                                           .ReducedFrom
                                                           .Parameters;

            if (parameters.Length != 2)
            {
                return;
            }

            if (!parameters[0].Type.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxNode))
            {
                return;
            }

            if (!parameters[1].Type.HasMetadataName(CSharpMetadataNames.Microsoft_CodeAnalysis_CSharp_SyntaxKind))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UnnecessaryConditionalAccess, conditionalAccess.OperatorToken);
            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UnnecessaryConditionalAccessFadeOut, binaryExpression.Right);
        }
        private static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context)
        {
            var logicalAnd = (BinaryExpressionSyntax)context.Node;

            if (logicalAnd.SpanContainsDirectives())
            {
                return;
            }

            BinaryExpressionInfo logicalAndInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd);

            if (!logicalAndInfo.Success)
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(
                logicalAndInfo.Left,
                context.SemanticModel,
                NullCheckStyles.NotEqualsToNull | NullCheckStyles.HasValue,
                cancellationToken: context.CancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            ExpressionSyntax right = logicalAndInfo.Right;

            switch (right.Kind())
            {
            case SyntaxKind.LogicalNotExpression:
            {
                var logicalNot = (PrefixUnaryExpressionSyntax)right;

                Analyze(nullCheck.Expression, logicalNot.Operand?.WalkDownParentheses(), null);
                break;
            }

            case SyntaxKind.EqualsExpression:
            case SyntaxKind.LessThanExpression:
            case SyntaxKind.LessThanOrEqualExpression:
            case SyntaxKind.GreaterThanExpression:
            case SyntaxKind.GreaterThanOrEqualExpression:
            {
                BinaryExpressionInfo binaryExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)right);

                if (!binaryExpressionInfo.Success)
                {
                    break;
                }

                ExpressionSyntax left = binaryExpressionInfo.Left;

                Analyze(nullCheck.Expression, left, binaryExpressionInfo.Right);
                break;
            }

            case SyntaxKind.SimpleMemberAccessExpression:
            {
                AnalyzeSimpleMemberAccessExpression(nullCheck.Expression, (MemberAccessExpressionSyntax)right, null);
                break;
            }
            }

            void Analyze(ExpressionSyntax expression1, ExpressionSyntax expression2, ExpressionSyntax expression3)
            {
                if (expression2.IsKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    AnalyzeSimpleMemberAccessExpression(expression1, (MemberAccessExpressionSyntax)expression2, expression3);
                }
            }

            void AnalyzeSimpleMemberAccessExpression(ExpressionSyntax expression, MemberAccessExpressionSyntax memberAccessExpression, ExpressionSyntax expression3)
            {
                if (memberAccessExpression.Name is not IdentifierNameSyntax identifierName ||
                    !string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal))
                {
                    return;
                }

                if (!SyntaxUtility.IsPropertyOfNullableOfT(memberAccessExpression, "Value", context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                if (!AreEquivalent(expression, memberAccessExpression.Expression))
                {
                    return;
                }

                if (expression3 != null)
                {
                    switch (expression3.Kind())
                    {
                    case SyntaxKind.NumericLiteralExpression:
                    case SyntaxKind.StringLiteralExpression:
                    case SyntaxKind.CharacterLiteralExpression:
                    case SyntaxKind.TrueLiteralExpression:
                    case SyntaxKind.FalseLiteralExpression:
                    {
                        break;
                    }

                    case SyntaxKind.NullLiteralExpression:
                    case SyntaxKind.DefaultLiteralExpression:
                    {
                        return;
                    }

                    default:
                    {
                        if (context.SemanticModel.GetTypeSymbol(expression3, context.CancellationToken).IsNullableType())
                        {
                            return;
                        }

                        break;
                    }
                    }
                }

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryNullCheck, logicalAnd);
            }
        }
Пример #29
0
        public 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, SyntaxKind.ArrowExpressionClause))
                    {
                        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;
                }
                }
            }
        }
Пример #30
0
        private static void AnalyzeElementAccessExpression(SyntaxNodeAnalysisContext context)
        {
            var elementAccessExpression = (ElementAccessExpressionSyntax)context.Node;

            ExpressionSyntax expression = elementAccessExpression
                                          .ArgumentList
                                          .Arguments
                                          .SingleOrDefault(shouldThrow: false)?
                                          .Expression
                                          .WalkDownParentheses();

            if (expression == null)
            {
                return;
            }

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

            BinaryExpressionInfo subtractExpressionInfo = SyntaxInfo.BinaryExpressionInfo((BinaryExpressionSyntax)expression);

            if (!subtractExpressionInfo.Right.IsNumericLiteralExpression("1"))
            {
                return;
            }

            if (!subtractExpressionInfo.Left.IsKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                return;
            }

            var memberAccessExpression = (MemberAccessExpressionSyntax)subtractExpressionInfo.Left;

            if (!(memberAccessExpression.Name is IdentifierNameSyntax identifierName))
            {
                return;
            }

            if (identifierName.Identifier.ValueText != "Count")
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(elementAccessExpression.Expression, memberAccessExpression.Expression))
            {
                return;
            }

            ISymbol symbol = context.SemanticModel.GetSymbol(elementAccessExpression, context.CancellationToken);

            if (symbol?.Kind != SymbolKind.Property ||
                symbol.IsStatic ||
                symbol.DeclaredAccessibility != Accessibility.Public ||
                !RoslynSymbolUtility.IsList(symbol.ContainingType.OriginalDefinition))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.CallLastInsteadOfUsingElementAccess, elementAccessExpression.ArgumentList);
        }