private static bool CanUseCoalesceExpression(StatementSyntax statement, ExpressionSyntax expression)
        {
            SyntaxKind kind = statement.Kind();

            if (kind == SyntaxKind.LocalDeclarationStatement)
            {
                SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo((LocalDeclarationStatementSyntax)statement);

                return(localInfo.Success &&
                       !localInfo.Type.IsKind(SyntaxKind.RefType) &&
                       expression.IsKind(SyntaxKind.IdentifierName) &&
                       string.Equals(localInfo.IdentifierText, ((IdentifierNameSyntax)expression).Identifier.ValueText, StringComparison.Ordinal) &&
                       !localInfo.Value.GetTrailingTrivia().Any(f => f.IsDirective) &&
                       !localInfo.SemicolonToken.ContainsDirectives);
            }
            else if (kind == SyntaxKind.ExpressionStatement)
            {
                var expressionStatement = (ExpressionStatementSyntax)statement;

                SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement);

                return(assignmentInfo.Success &&
                       CSharpFactory.AreEquivalent(expression, assignmentInfo.Left) &&
                       !assignmentInfo.Right.GetTrailingTrivia().Any(f => f.IsDirective) &&
                       !expressionStatement.SemicolonToken.ContainsDirectives);
            }

            return(false);
        }
Exemple #2
0
 private static bool AreEquivalent(StatementSyntax statement1, StatementSyntax statement2)
 {
     return(statement1.Kind() == statement2.Kind() &&
            CSharpFactory.AreEquivalent(statement1, statement2) &&
            statement1.DescendantTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()) &&
            statement2.DescendantTrivia().All(f => f.IsWhitespaceOrEndOfLineTrivia()));
 }
Exemple #3
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);
        }
        private static bool AreEquivalent(StatementSyntax statement1, StatementSyntax statement2)
        {
            if (statement1 == null)
            {
                return(false);
            }

            if (statement2 == null)
            {
                return(false);
            }

            if (statement1 is not BlockSyntax block1)
            {
                return(CSharpFactory.AreEquivalent(statement1, statement2.SingleNonBlockStatementOrDefault()));
            }

            SyntaxList <StatementSyntax> statements1 = block1.Statements;

            if (statement2 is not BlockSyntax block2)
            {
                return(CSharpFactory.AreEquivalent(statement2, statement1.SingleNonBlockStatementOrDefault()));
            }

            SyntaxList <StatementSyntax> statements2 = block2.Statements;

            return(SyntaxFactory.AreEquivalent(statements1, statements2, topLevel: false));
        }
Exemple #5
0
        private static bool NullCheckExists(ExpressionSyntax expression, StatementSyntax statement)
        {
            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement);

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

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            int index = statements.IndexOf(statement);

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

            StatementSyntax nextStatement = statements[index + 1];

            if (!(nextStatement is IfStatementSyntax ifStatement))
            {
                return(false);
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.NotEqualsToNull);

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

            return(CSharpFactory.AreEquivalent(expression, nullCheck.Expression));
        }
        internal static ExpressionSyntax FindExpressionThatCanBeConditionallyAccessed(ExpressionSyntax expressionToFind, ExpressionSyntax expression)
        {
            if (expression.IsKind(SyntaxKind.LogicalNotExpression))
            {
                expression = ((PrefixUnaryExpressionSyntax)expression).Operand;
            }

            SyntaxKind kind = expressionToFind.Kind();

            SyntaxToken firstToken = expression.GetFirstToken();

            int start = firstToken.SpanStart;

            SyntaxNode node = firstToken.Parent;

            while (node?.SpanStart == start)
            {
                if (kind == node.Kind() &&
                    node.IsParentKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression) &&
                    CSharpFactory.AreEquivalent(expressionToFind, node))
                {
                    return((ExpressionSyntax)node);
                }

                node = node.Parent;
            }

            return(null);
        }
Exemple #7
0
        internal static SimplifyCodeBranchingKind?GetKind(IfStatementSyntax ifStatement, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            ExpressionSyntax condition = ifStatement.Condition?.WalkDownParentheses();

            if (condition?.IsMissing != false)
            {
                return(null);
            }

            StatementSyntax ifStatementStatement = ifStatement.Statement;

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

            ElseClauseSyntax elseClause = ifStatement.Else;

            if (elseClause != null)
            {
                if (IsFixableIfElseInsideWhile(ifStatement, elseClause))
                {
                    return(SimplifyCodeBranchingKind.IfElseInsideWhile);
                }
                else
                {
                    var ifStatementBlock = ifStatementStatement as BlockSyntax;

                    if (ifStatementBlock?.Statements.Any() == false &&
                        ifStatementBlock.OpenBraceToken.TrailingTrivia.IsEmptyOrWhitespace() &&
                        ifStatementBlock.CloseBraceToken.LeadingTrivia.IsEmptyOrWhitespace() &&
                        IsFixableIfElseWithEmptyIf(ifStatement, elseClause))
                    {
                        return(SimplifyCodeBranchingKind.IfElseWithEmptyIf);
                    }
                    else if (IsFixableIfElseWithReturnOrContinueInsideIf(ifStatement, elseClause))
                    {
                        return(SimplifyCodeBranchingKind.LastIfElseWithReturnOrContinueInsideIf);
                    }
                }
            }
            else if (IsFixableSimpleIfInsideWhileOrDo(ifStatement, semanticModel, cancellationToken))
            {
                return(SimplifyCodeBranchingKind.SimplifyIfInsideWhileOrDo);
            }
            else if (!ifStatement.IsParentKind(SyntaxKind.ElseClause) &&
                     (ifStatement.SingleNonBlockStatementOrDefault() is DoStatementSyntax doStatement) &&
                     CSharpFactory.AreEquivalent(condition, doStatement.Condition?.WalkDownParentheses()))
            {
                return(SimplifyCodeBranchingKind.SimpleIfContainingOnlyDo);
            }

            return(null);
        }
        internal static ExpressionSyntax FindExpressionThatCanBeConditionallyAccessed(
            ExpressionSyntax expressionToFind,
            ExpressionSyntax expression,
            bool isNullable,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default)
        {
            if (expression.IsKind(SyntaxKind.LogicalNotExpression))
            {
                expression = ((PrefixUnaryExpressionSyntax)expression).Operand;
            }

            SyntaxKind kind = expressionToFind.Kind();

            SyntaxToken firstToken = expression.GetFirstToken();

            int start = firstToken.SpanStart;

            SyntaxNode node = firstToken.Parent;

            while (node?.SpanStart == start)
            {
                if (kind == node.Kind() &&
                    node.IsParentKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression) &&
                    semanticModel.GetTypeSymbol(node.Parent, cancellationToken)?.Kind != SymbolKind.PointerType &&
                    CSharpFactory.AreEquivalent(expressionToFind, node))
                {
                    if (!isNullable)
                    {
                        return((ExpressionSyntax)node);
                    }

                    if (node.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) &&
                        (((MemberAccessExpressionSyntax)node.Parent).Name is IdentifierNameSyntax identifierName) &&
                        string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal) &&
                        node.Parent.IsParentKind(SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression))
                    {
                        return((ExpressionSyntax)node.Parent);
                    }

                    return(null);
                }

                node = node.Parent;
            }

            return(null);
        }
        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);
        }
        public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (!ifStatement.IsSimpleIf())
            {
                return;
            }

            if (ifStatement.ContainsDiagnostics)
            {
                return;
            }

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

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedStyles: NullCheckStyles.NotEqualsToNull);

            if (!nullCheck.Success)
            {
                return;
            }

            SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(ifStatement.SingleNonBlockStatementOrDefault());

            if (!invocationInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression))
            {
                return;
            }

            if (ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement);
        }
Exemple #11
0
        private static void AnalyzeLogicalOrExpression(SyntaxNodeAnalysisContext context)
        {
            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            if (binaryExpression.ContainsDiagnostics)
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left, context.SemanticModel, allowedStyles: NullCheckStyles.CheckingNull);

            ExpressionSyntax expression = nullCheck.Expression;

            if (expression == null)
            {
                return;
            }

            ExpressionSyntax right = binaryExpression.Right.WalkDownParentheses();

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

            var logicalAndExpression = (BinaryExpressionSyntax)right;

            ExpressionChain.Enumerator en = logicalAndExpression.AsChain().GetEnumerator();

            if (!en.MoveNext())
            {
                return;
            }

            NullCheckExpressionInfo nullCheck2 = SyntaxInfo.NullCheckExpressionInfo(en.Current, context.SemanticModel, allowedStyles: NullCheckStyles.CheckingNotNull);

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

            ReportExpressionAlwaysEqualToTrueOrFalse(context, nullCheck2.NullCheckExpression, "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);
        }
        private static bool IsFixable(
            ExpressionSyntax left,
            BinaryExpressionSyntax right,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default)
        {
            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left);

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

            ExpressionSyntax expression = nullCheck.Expression;

            if (CSharpFactory.AreEquivalent(expression, right.Left))
            {
                return(right.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression) &&
                       SymbolEquals(expression, right.Left, semanticModel, cancellationToken) &&
                       CSharpUtility.IsEmptyStringExpression(right.Right, semanticModel, cancellationToken));
            }

            if (right.Left.IsKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                var memberAccess = (MemberAccessExpressionSyntax)right.Left;

                return(string.Equals(memberAccess.Name.Identifier.ValueText, "Length", StringComparison.Ordinal) &&
                       right.Right.IsNumericLiteralExpression("0") &&
                       semanticModel.GetSymbol(memberAccess, cancellationToken) is IPropertySymbol propertySymbol &&
                       !propertySymbol.IsIndexer &&
                       SymbolUtility.IsPublicInstance(propertySymbol, "Length") &&
                       propertySymbol.Type.SpecialType == SpecialType.System_Int32 &&
                       propertySymbol.ContainingType?.SpecialType == SpecialType.System_String &&
                       CSharpFactory.AreEquivalent(expression, memberAccess.Expression) &&
                       SymbolEquals(expression, memberAccess.Expression, semanticModel, cancellationToken));
            }

            return(false);
        }
        private static bool IsFixableEqualsExpression(
            BinaryExpressionSyntax equalsExpression,
            ExpressionSyntax switchExpression,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax left = equalsExpression.Left?.WalkDownParentheses();

            if (IsFixableSwitchExpression(left, semanticModel, cancellationToken))
            {
                ExpressionSyntax right = equalsExpression.Right?.WalkDownParentheses();

                if (IsFixableSwitchExpression(right, semanticModel, cancellationToken) &&
                    semanticModel.HasConstantValue(right))
                {
                    return(switchExpression == null ||
                           CSharpFactory.AreEquivalent(left, switchExpression));
                }
            }

            return(false);
        }
Exemple #15
0
        private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (ifStatement.ContainsDiagnostics)
            {
                return;
            }

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

            if (!ifStatement.IsSimpleIf())
            {
                return;
            }

            SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(ifStatement).Statements;

            if (!statements.Any())
            {
                return;
            }

            if (IsPartOfLazyInitialization())
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(
                ifStatement.Condition,
                semanticModel: context.SemanticModel,
                allowedStyles: NullCheckStyles.CheckingNull,
                cancellationToken: context.CancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.SingleNonBlockStatementOrDefault());

            if (!assignmentInfo.Success)
            {
                return;
            }

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

            if (!assignmentInfo.Right.IsSingleLine())
            {
                return;
            }

            int index = statements.IndexOf(ifStatement);

            if (index > 0 &&
                !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpression))
            {
                StatementSyntax previousStatement = statements[index - 1];

                if (!previousStatement.ContainsDiagnostics &&
                    !previousStatement.GetTrailingTrivia().Any(f => f.IsDirective) &&
                    !ifStatement.GetLeadingTrivia().Any(f => f.IsDirective) &&
                    CanUseCoalesceExpression(previousStatement, nullCheck.Expression))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseCoalesceExpression, previousStatement);
                }
            }

            if (context.IsAnalyzerSuppressed(DiagnosticDescriptors.InlineLazyInitialization))
            {
                return;
            }

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

            StatementSyntax nextStatement = statements[index + 1];

            if (nextStatement.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(nextStatement);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression))
            {
                return;
            }

            if (ifStatement.GetTrailingTrivia().Any(f => f.IsDirective))
            {
                return;
            }

            if (nextStatement.SpanOrLeadingTriviaContainsDirectives())
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.InlineLazyInitialization, ifStatement);

            bool IsPartOfLazyInitialization()
            {
                return(statements.Count == 2 &&
                       statements.IndexOf(ifStatement) == 0 &&
                       statements[1].IsKind(SyntaxKind.ReturnStatement));
            }
        }
Exemple #16
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);
        }
        public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionOfTSymbol)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (!ifStatement.IsSimpleIf())
            {
                return;
            }

            if (ifStatement.ContainsDiagnostics)
            {
                return;
            }

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

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedStyles: NullCheckStyles.NotEqualsToNull);

            ExpressionSyntax expression = nullCheck.Expression;

            if (expression == null)
            {
                return;
            }

            SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(ifStatement.SingleNonBlockStatementOrDefault());

            ExpressionSyntax expression2 = invocationInfo.Expression;

            if (expression2 == null)
            {
                return;
            }

            ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(expression);

            if (typeSymbol == null)
            {
                return;
            }

            if (typeSymbol.IsNullableType())
            {
                if (!expression2.IsKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    return;
                }

                var memberAccess = (MemberAccessExpressionSyntax)expression2;

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

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

                expression2 = memberAccess.Expression;
            }

            if (!CSharpFactory.AreEquivalent(expression, expression2))
            {
                return;
            }

            if (ifStatement.IsInExpressionTree(expressionOfTSymbol, context.SemanticModel, context.CancellationToken))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement);
        }
        internal static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            ExpressionSyntax condition = ifStatement.Condition?.WalkDownParentheses();

            if (condition?.IsMissing != false)
            {
                return;
            }

            StatementSyntax statement = ifStatement.Statement;

            if (statement == null)
            {
                return;
            }

            var block = statement as BlockSyntax;

            if (block?.Statements.Any() == false &&
                block.OpenBraceToken.TrailingTrivia.IsEmptyOrWhitespace() &&
                block.CloseBraceToken.LeadingTrivia.IsEmptyOrWhitespace())
            {
                if (IsFixableIfElse(ifStatement))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyCodeBranching, ifStatement);
                }
            }
            else
            {
                ElseClauseSyntax elseClause = ifStatement.Else;

                if (elseClause != null)
                {
                    if (IsFixableIfElseInsideWhile(ifStatement, elseClause))
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyCodeBranching, ifStatement);
                    }
                }
                else if (IsFixableSimpleIfInsideWhileOrDo(ifStatement, context.SemanticModel, context.CancellationToken))
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyCodeBranching, ifStatement);
                }
                else
                {
                    if (ifStatement.IsParentKind(SyntaxKind.ElseClause))
                    {
                        return;
                    }

                    if (!(ifStatement.SingleNonBlockStatementOrDefault() is DoStatementSyntax doStatement))
                    {
                        return;
                    }

                    if (!CSharpFactory.AreEquivalent(condition, doStatement.Condition?.WalkDownParentheses()))
                    {
                        return;
                    }

                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyCodeBranching, ifStatement);
                }
            }
        }
Exemple #19
0
        private static BinaryExpressionPart GetRedundantPart(
            ExpressionSyntax left,
            ExpressionSyntax right,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            SyntaxKind leftKind  = left.Kind();
            SyntaxKind rightKind = right.Kind();

            switch (leftKind)
            {
            case SyntaxKind.ObjectCreationExpression:
            case SyntaxKind.AnonymousObjectCreationExpression:
            case SyntaxKind.ArrayCreationExpression:
            case SyntaxKind.ImplicitArrayCreationExpression:
            case SyntaxKind.InterpolatedStringExpression:
            case SyntaxKind.ThisExpression:
            case SyntaxKind.StringLiteralExpression:
            case SyntaxKind.TypeOfExpression:
                return(BinaryExpressionPart.Right);

            case SyntaxKind.NullLiteralExpression:
                return(BinaryExpressionPart.Left);

            case SyntaxKind.DefaultExpression:
            {
                if (IsDefaultOfReferenceOrNullableType((DefaultExpressionSyntax)left, semanticModel, cancellationToken))
                {
                    return(BinaryExpressionPart.Left);
                }

                break;
            }
            }

            Optional <object> optional = semanticModel.GetConstantValue(left, cancellationToken);

            if (optional.HasValue)
            {
                object value = optional.Value;

                if (value != null)
                {
                    return(BinaryExpressionPart.Right);
                }
                else
                {
                    return(BinaryExpressionPart.Left);
                }
            }

            ITypeSymbol leftSymbol = semanticModel.GetTypeSymbol(left, cancellationToken);

            if (leftSymbol?.IsErrorType() == false &&
                leftSymbol.IsValueType &&
                !leftSymbol.IsNullableType())
            {
                return(BinaryExpressionPart.Right);
            }

            switch (rightKind)
            {
            case SyntaxKind.NullLiteralExpression:
            {
                return(BinaryExpressionPart.Right);
            }

            case SyntaxKind.DefaultExpression:
            {
                if (IsDefaultOfReferenceOrNullableType((DefaultExpressionSyntax)right, semanticModel, cancellationToken))
                {
                    return(BinaryExpressionPart.Right);
                }

                break;
            }
            }

            if (leftKind == rightKind &&
                CSharpFactory.AreEquivalent(left, right))
            {
                return(BinaryExpressionPart.Right);
            }

            return(BinaryExpressionPart.None);
        }
        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);
                }
            }
        }
        public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (!ifStatement.IsSimpleIf())
            {
                return;
            }

            if (ifStatement.ContainsDiagnostics)
            {
                return;
            }

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

            SyntaxList <StatementSyntax> statements = SyntaxInfo.StatementListInfo(ifStatement).Statements;

            if (!statements.Any())
            {
                return;
            }

            if (IsPartOfLazyInitialization(ifStatement, statements))
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, semanticModel: context.SemanticModel, cancellationToken: context.CancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            SimpleAssignmentStatementInfo simpleAssignment = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.SingleNonBlockStatementOrDefault());

            if (!simpleAssignment.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(simpleAssignment.Left, nullCheck.Expression))
            {
                return;
            }

            if (!simpleAssignment.Right.IsSingleLine())
            {
                return;
            }

            int index = statements.IndexOf(ifStatement);

            if (index > 0)
            {
                StatementSyntax previousStatement = statements[index - 1];

                if (!previousStatement.ContainsDiagnostics &&
                    IsFixable(previousStatement, ifStatement, nullCheck.Expression, ifStatement.Parent))
                {
                    context.ReportDiagnostic(DiagnosticDescriptors.UseCoalesceExpression, previousStatement);
                }
            }

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

            StatementSyntax nextStatement = statements[index + 1];

            if (nextStatement.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(nextStatement);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(nullCheck.Expression, invocationInfo.Expression))
            {
                return;
            }

            if (ifStatement.Parent.ContainsDirectives(TextSpan.FromBounds(ifStatement.SpanStart, nextStatement.Span.End)))
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.InlineLazyInitialization, ifStatement);
        }
        private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

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

            IsKindExpressionInfo isKindExpression = IsKindExpressionInfo.Create(ifStatement.Condition, semanticModel, cancellationToken: cancellationToken);

            if (!isKindExpression.Success)
            {
                return;
            }

            Optional <object> optionalConstantValue = semanticModel.GetConstantValue(isKindExpression.KindExpression, cancellationToken);

            if (!optionalConstantValue.HasValue)
            {
                return;
            }

            if (!(optionalConstantValue.Value is ushort value))
            {
                return;
            }

            if (!_syntaxKindValuesToNames.TryGetValue(value, out string name))
            {
                return;
            }

            if (!_syntaxKindNames.Contains(name))
            {
                return;
            }

            switch (isKindExpression.Style)
            {
            case IsKindExpressionStyle.IsKind:
            case IsKindExpressionStyle.IsKindConditional:
            case IsKindExpressionStyle.Kind:
            case IsKindExpressionStyle.KindConditional:
            {
                if (!(ifStatement.Statement is BlockSyntax block))
                {
                    return;
                }

                Analyze(block.Statements.FirstOrDefault());
                break;
            }

            case IsKindExpressionStyle.NotIsKind:
            case IsKindExpressionStyle.NotIsKindConditional:
            case IsKindExpressionStyle.NotKind:
            case IsKindExpressionStyle.NotKindConditional:
            {
                if (ifStatement.Else != null)
                {
                    return;
                }

                StatementSyntax statement = ifStatement.Statement.SingleNonBlockStatementOrDefault();

                if (statement == null)
                {
                    return;
                }

                if (!CSharpFacts.IsJumpStatement(statement.Kind()))
                {
                    return;
                }

                Analyze(ifStatement.NextStatement());
                break;
            }
            }

            void Analyze(StatementSyntax statement)
            {
                SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(statement);

                if (!localInfo.Success)
                {
                    return;
                }

                if (!(localInfo.Value is CastExpressionSyntax castExpression))
                {
                    return;
                }

                if (!IsFixableSyntaxSymbol(castExpression.Type, name, semanticModel, cancellationToken))
                {
                    return;
                }

                if (!CSharpFactory.AreEquivalent(isKindExpression.Expression, castExpression.Expression))
                {
                    return;
                }

                context.ReportDiagnostic(DiagnosticDescriptors.UsePatternMatching, ifStatement.IfKeyword);
            }
        }
Exemple #23
0
        private static void AnalyzeBitwiseAndExpression(SyntaxNodeAnalysisContext context)
        {
            var bitwiseAnd = (BinaryExpressionSyntax)context.Node;

            ExpressionSyntax expression = bitwiseAnd.WalkUpParentheses();

            if (!expression.IsParentKind(SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression))
            {
                return;
            }

            var equalsOrNotEquals = (BinaryExpressionSyntax)expression.Parent;

            ExpressionSyntax otherExpression = (ReferenceEquals(equalsOrNotEquals.Left, expression))
                ? equalsOrNotEquals.Right
                : equalsOrNotEquals.Left;

            otherExpression = otherExpression.WalkDownParentheses();

            ExpressionSyntax right = bitwiseAnd.Right.WalkDownParentheses();

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

            if (otherExpression.IsNumericLiteralExpression("0"))
            {
                if (SyntaxUtility.IsCompositeEnumValue(right, semanticModel, cancellationToken))
                {
                    return;
                }
            }
            else if (!CSharpFactory.AreEquivalent(right, otherExpression))
            {
                return;
            }

            IMethodSymbol methodSymbol = semanticModel.GetMethodSymbol(bitwiseAnd, cancellationToken);

            if (methodSymbol?.MethodKind != MethodKind.BuiltinOperator ||
                methodSymbol.Name != WellKnownMemberNames.BitwiseAndOperatorName ||
                methodSymbol.ContainingType?.TypeKind != TypeKind.Enum)
            {
                return;
            }

            ExpressionSyntax left = bitwiseAnd.Left.WalkDownParentheses();

            if (!IsSuitableAsExpressionOfHasFlag(left))
            {
                return;
            }

            if (!IsSuitableAsArgumentOfHasFlag(right))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(
                context,
                DiagnosticRules.ReportOnly.ConvertBitwiseOperationToHasFlagCall,
                equalsOrNotEquals);

            bool IsSuitableAsExpressionOfHasFlag(ExpressionSyntax expression)
            {
                if (expression.IsKind(
                        SyntaxKind.IdentifierName,
                        SyntaxKind.SimpleMemberAccessExpression,
                        SyntaxKind.InvocationExpression,
                        SyntaxKind.ElementAccessExpression))
                {
                    return(semanticModel.GetTypeSymbol(expression, cancellationToken)?.TypeKind == TypeKind.Enum);
                }

                return(false);
            }

            bool IsSuitableAsArgumentOfHasFlag(ExpressionSyntax expression)
            {
                expression = expression.WalkDownParentheses();

                if (expression.IsKind(
                        SyntaxKind.BitwiseAndExpression,
                        SyntaxKind.BitwiseOrExpression,
                        SyntaxKind.SimpleMemberAccessExpression,
                        SyntaxKind.IdentifierName))
                {
                    return(semanticModel.GetTypeSymbol(expression, cancellationToken)?.TypeKind == TypeKind.Enum);
                }

                return(false);
            }
        }
        public static async Task <Document> RefactorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false);

            ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(conditionalExpressionInfo.Condition, semanticModel: semanticModel, cancellationToken: cancellationToken);

            ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse;

            ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue;

            ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull);

            bool coalesce = false;

            ExpressionSyntax newNode = null;

            if (CSharpFactory.AreEquivalent(nullCheck.Expression, whenNotNull))
            {
                newNode  = nullCheck.Expression;
                coalesce = true;
            }
            else if (semanticModel
                     .GetTypeSymbol(nullCheck.Expression, cancellationToken)
                     .IsNullableType())
            {
                if (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    var memberAccessExpression = (MemberAccessExpressionSyntax)expression.Parent;

                    if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) &&
                        (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value")
                    {
                        if (memberAccessExpression == whenNotNull)
                        {
                            newNode  = nullCheck.Expression;
                            coalesce = true;
                        }
                        else
                        {
                            newNode = ParseExpression($"{expression}?{whenNotNull.ToString().Substring(memberAccessExpression.Span.End - whenNotNull.SpanStart)}");
                        }
                    }
                }
            }

            if (newNode == null)
            {
                newNode = ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?"));
            }

            if (coalesce || !semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceType)
            {
                newNode = CoalesceExpression(newNode.Parenthesize(), whenNull.Parenthesize());
            }

            newNode = newNode
                      .WithTriviaFrom(conditionalExpression)
                      .Parenthesize();

            return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false));
        }
        private static void AnalyzeSimpleAssignmentExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var assignment = (AssignmentExpressionSyntax)context.Node;

            if (assignment.IsParentKind(
                    SyntaxKind.ObjectInitializerExpression,
                    SyntaxKind.WithInitializerExpression))
            {
                return;
            }

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

            if (left?.IsMissing != false)
            {
                return;
            }

            if (right?.IsKind(SyntaxKind.AddExpression, SyntaxKind.SubtractExpression) != true)
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)right;

            ExpressionSyntax binaryLeft  = binaryExpression.Left;
            ExpressionSyntax binaryRight = binaryExpression.Right;

            if (binaryLeft?.IsMissing != false)
            {
                return;
            }

            if (binaryRight?.IsNumericLiteralExpression("1") != true)
            {
                return;
            }

            ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(left, context.CancellationToken);

            if (typeSymbol?.SupportsPrefixOrPostfixUnaryOperator() != true)
            {
                return;
            }

            if (!CSharpFactory.AreEquivalent(left, binaryLeft))
            {
                return;
            }

            string operatorText = GetOperatorText(assignment);

            ReportDiagnostic(context, assignment, operatorText);

            DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.UseUnaryOperatorInsteadOfAssignmentFadeOut, assignment.OperatorToken, operatorText);
            DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseUnaryOperatorInsteadOfAssignmentFadeOut, binaryLeft, operatorText);
            DiagnosticHelpers.ReportNode(context, DiagnosticDescriptors.UseUnaryOperatorInsteadOfAssignmentFadeOut, binaryRight, operatorText);
        }
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!conditionalExpressionInfo.Success)
            {
                return;
            }

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

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(conditionalExpressionInfo.Condition, semanticModel: semanticModel, cancellationToken: cancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenTrue : conditionalExpressionInfo.WhenFalse;

            ExpressionSyntax whenNull = (nullCheck.IsCheckingNotNull) ? conditionalExpressionInfo.WhenFalse : conditionalExpressionInfo.WhenTrue;

            if (CSharpFactory.AreEquivalent(nullCheck.Expression, whenNotNull))
            {
                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression) &&
                    semanticModel
                    .GetTypeSymbol(nullCheck.Expression, cancellationToken)?
                    .IsReferenceTypeOrNullableType() == true)
                {
                    DiagnosticHelpers.ReportDiagnostic(context,
                                                       DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression,
                                                       conditionalExpression);
                }
            }
            else if (whenNotNull.IsKind(
                         SyntaxKind.SimpleMemberAccessExpression,
                         SyntaxKind.ElementAccessExpression,
                         SyntaxKind.ConditionalAccessExpression,
                         SyntaxKind.InvocationExpression))
            {
                ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(
                    nullCheck.Expression,
                    whenNotNull,
                    semanticModel,
                    cancellationToken);

                if (expression == null)
                {
                    return;
                }

                ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken);

                if (typeSymbol == null)
                {
                    return;
                }

                if (typeSymbol.IsReferenceType)
                {
                    Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken);
                }
                else if (typeSymbol.IsNullableType())
                {
                    if (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
                    {
                        var memberAccessExpression = (MemberAccessExpressionSyntax)expression.Parent;

                        if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) &&
                            (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value")
                        {
                            if (memberAccessExpression == whenNotNull)
                            {
                                if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression))
                                {
                                    DiagnosticHelpers.ReportDiagnostic(
                                        context,
                                        DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression,
                                        conditionalExpression);
                                }
                            }
                            else
                            {
                                Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken);
                            }
                        }
                    }
                }
            }
            else if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression) &&
                     whenNotNull.IsKind(SyntaxKind.CastExpression) &&
                     whenNull.IsKind(SyntaxKind.NullLiteralExpression, SyntaxKind.DefaultLiteralExpression))
            {
                var castExpression = (CastExpressionSyntax)whenNotNull;

                if (castExpression.Type.IsKind(SyntaxKind.NullableType) &&
                    castExpression.Expression.IsKind(SyntaxKind.InvocationExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.ElementAccessExpression))
                {
                    ExpressionSyntax expression = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(
                        nullCheck.Expression,
                        castExpression.Expression,
                        isNullable: true,
                        semanticModel,
                        cancellationToken);

                    if (expression != null)
                    {
                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken);

                        if (typeSymbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                        {
                            DiagnosticHelpers.ReportDiagnostic(context,
                                                               DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression,
                                                               conditionalExpression);
                        }
                    }
                }
            }
        }
        private static void AnalyzeUsingStatement(SyntaxNodeAnalysisContext context)
        {
            var usingStatement = (UsingStatementSyntax)context.Node;

            StatementSyntax statement = usingStatement.Statement;

            if (statement?.Kind() != SyntaxKind.Block)
            {
                return;
            }

            var block = (BlockSyntax)statement;

            StatementSyntax lastStatement = block.Statements.LastOrDefault();

            if (lastStatement == null)
            {
                return;
            }

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

            SimpleMemberInvocationStatementInfo info = SyntaxInfo.SimpleMemberInvocationStatementInfo(lastStatement);

            if (!info.Success)
            {
                return;
            }

            if (info.Arguments.Any())
            {
                return;
            }

            string methodName = info.NameText;

            if (methodName != "Dispose" && methodName != "Close")
            {
                return;
            }

            ExpressionSyntax usingExpression = usingStatement.Expression;

            if (usingExpression != null)
            {
                if (CSharpFactory.AreEquivalent(info.Expression, usingExpression))
                {
                    ReportDiagnostic(context, info.Statement, methodName);
                }
            }
            else
            {
                VariableDeclarationSyntax usingDeclaration = usingStatement.Declaration;

                if (usingDeclaration != null &&
                    info.Expression.Kind() == SyntaxKind.IdentifierName)
                {
                    var identifierName = (IdentifierNameSyntax)info.Expression;

                    VariableDeclaratorSyntax declarator = usingDeclaration.Variables.LastOrDefault();

                    if (declarator != null &&
                        declarator.Identifier.ValueText == identifierName.Identifier.ValueText)
                    {
                        ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(declarator, context.CancellationToken);

                        if (symbol?.Equals(context.SemanticModel.GetSymbol(identifierName, context.CancellationToken)) == true)
                        {
                            ReportDiagnostic(context, info.Statement, methodName);
                        }
                    }
                }
            }
        }
        private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
        {
            var invocationExpression = (InvocationExpressionSyntax)context.Node;

            if (invocationExpression.ContainsDiagnostics)
            {
                return;
            }

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationExpression);

            if (!invocationInfo.Success)
            {
                return;
            }

            ISymbol symbol = null;

            string methodName = invocationInfo.NameText;

            switch (invocationInfo.Arguments.Count)
            {
            case 0:
            {
                switch (methodName)
                {
                case "First":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingFirst();
                    }

                    break;
                }
                }

                break;
            }

            case 1:
            {
                switch (methodName)
                {
                case "ElementAt":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseElementAccess))
                    {
                        UseElementAccessInsteadOfCallingElementAt();
                    }

                    break;
                }

                case "IsKind":
                {
                    if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnnecessaryNullCheck))
                    {
                        AnalyzeUnnecessaryNullCheck();
                    }

                    break;
                }
                }

                break;
            }
            }

            if (!context.IsAnalyzerSuppressed(DiagnosticDescriptors.UseReturnValue) &&
                invocationExpression.IsParentKind(SyntaxKind.ExpressionStatement))
            {
                UseReturnValue();
            }

            void AnalyzeUnnecessaryNullCheck()
            {
                ExpressionSyntax expression = invocationInfo.InvocationExpression.WalkUpParentheses();

                SyntaxNode parent = expression.Parent;

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

                var binaryExpression = (BinaryExpressionSyntax)parent;

                if (expression != binaryExpression.Right)
                {
                    return;
                }

                if (binaryExpression.Left.ContainsDirectives)
                {
                    return;
                }

                if (binaryExpression.OperatorToken.ContainsDirectives)
                {
                    return;
                }

                NullCheckExpressionInfo nullCheckInfo = SyntaxInfo.NullCheckExpressionInfo(binaryExpression.Left, NullCheckStyles.CheckingNotNull & ~NullCheckStyles.HasValue);

                if (!nullCheckInfo.Success)
                {
                    return;
                }

                if (!CSharpFactory.AreEquivalent(invocationInfo.Expression, nullCheckInfo.Expression))
                {
                    return;
                }

                if (!CSharpSymbolUtility.IsIsKindExtensionMethod(invocationExpression, context.SemanticModel, context.CancellationToken))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(binaryExpression.Left.SpanStart, binaryExpression.OperatorToken.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UnnecessaryNullCheck,
                    Location.Create(invocationInfo.InvocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingFirst()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

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

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

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseElementAccessInsteadOfCallingElementAt()
            {
                if (!invocationInfo.Expression.GetTrailingTrivia().IsEmptyOrWhitespace())
                {
                    return;
                }

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

                if (symbol?.Kind != SymbolKind.Method ||
                    symbol.IsStatic ||
                    symbol.DeclaredAccessibility != Accessibility.Public ||
                    !symbol.ContainingType.OriginalDefinition.HasMetadataName(RoslynMetadataNames.Microsoft_CodeAnalysis_SyntaxTriviaList))
                {
                    return;
                }

                TextSpan span = TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End);

                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseElementAccess,
                    Location.Create(invocationExpression.SyntaxTree, span));
            }

            void UseReturnValue()
            {
                if (symbol == null)
                {
                    symbol = context.SemanticModel.GetSymbol(invocationExpression, context.CancellationToken);
                }

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

                if (!RoslynSymbolUtility.IsRoslynType(symbol.ContainingType))
                {
                    return;
                }

                var methodSymbol = (IMethodSymbol)symbol;

                if (!RoslynSymbolUtility.IsRoslynType(methodSymbol.ReturnType))
                {
                    return;
                }

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseReturnValue, invocationExpression);
            }
        }