public static async Task ComputeRefactoringsAsync(RefactoringContext context, BinaryExpressionSyntax binaryExpression)
        {
            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, NullCheckStyles.ComparisonToNull);

            if (!nullCheck.Success)
            {
                return;
            }

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

            if (semanticModel
                .GetTypeInfo(nullCheck.Expression, context.CancellationToken)
                .ConvertedType?
                .SpecialType != SpecialType.System_String)
            {
                return;
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrEmpty))
            {
                ReplaceEqualsExpressionWithStringIsNullOrEmptyRefactoring.Instance.RegisterRefactoring(context, nullCheck);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrWhiteSpace))
            {
                ReplaceEqualsExpressionWithStringIsNullOrWhiteSpaceRefactoring.Instance.RegisterRefactoring(context, nullCheck);
            }
        }
Пример #2
0
        private static IfRefactoring CreateIfToAssignment(
            IfStatementSyntax ifStatement,
            ExpressionSyntax left,
            ExpressionSyntax expression1,
            ExpressionSyntax expression2,
            NullCheckExpressionInfo nullCheck,
            IfAnalysisOptions options,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if ((nullCheck.Kind & NullCheckKind.ComparisonToNull) != 0 &&
                SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1))
            {
                return(CreateIfToAssignment(ifStatement, left, expression1, expression2, options, isNullable: false));
            }

            expression1 = GetNullableOfTValueProperty(expression1, semanticModel, cancellationToken);

            if (SyntaxComparer.AreEquivalent(nullCheck.Expression, expression1))
            {
                return(CreateIfToAssignment(ifStatement, left, expression1, expression2, options, isNullable: true));
            }

            return(null);
        }
        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));
        }
        private void RegisterRefactoring(RefactoringContext context, NullCheckExpressionInfo nullCheck)
        {
            string title = (nullCheck.Style == NullCheckStyles.EqualsToNull)
                ? $"Replace '{nullCheck.NullCheckExpression}' with 'string.{MethodName}({nullCheck.Expression})'"
                : $"Replace '{nullCheck.NullCheckExpression}' with '!string.{MethodName}({nullCheck.Expression})'";

            context.RegisterRefactoring(
                title,
                cancellationToken => RefactorAsync(context.Document, nullCheck, cancellationToken));
        }
Пример #5
0
        private static void Analyze(SyntaxNodeAnalysisContext context, BinaryExpressionSyntax binaryExpression, NullCheckStyles allowedStyles)
        {
            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: allowedStyles);

            if (nullCheck.Success &&
                IsUnconstrainedTypeParameter(context.SemanticModel.GetTypeSymbol(nullCheck.Expression, context.CancellationToken)) &&
                !binaryExpression.SpanContainsDirectives())
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UnconstrainedTypeParameterCheckedForNull, binaryExpression);
            }
        }
        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 bool IsFixable(
            ExpressionSyntax left,
            ExpressionSyntax right,
            SyntaxKind binaryExpressionKind,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            NullCheckStyles allowedStyles = (binaryExpressionKind == SyntaxKind.LogicalAndExpression)
                ? NullCheckStyles.NotEqualsToNull
                : NullCheckStyles.EqualsToNull;

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(left, allowedStyles: allowedStyles);

            ExpressionSyntax expression = nullCheck.Expression;

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

            ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression, cancellationToken);

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

            if (!typeSymbol.IsReferenceTypeOrNullableType())
            {
                return(false);
            }

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

            if (!ValidateRightExpression(right, binaryExpressionKind, semanticModel, cancellationToken))
            {
                return(false);
            }

            if (RefactoringUtility.ContainsOutArgumentWithLocal(right, semanticModel, cancellationToken))
            {
                return(false);
            }

            ExpressionSyntax expression2 = FindExpressionThatCanBeConditionallyAccessed(expression, right, isNullable: !typeSymbol.IsReferenceType);

            return(expression2?.SpanContainsDirectives() == false);
        }
        public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (ifStatement.IsSimpleIf() &&
                !ifStatement.ContainsDiagnostics &&
                ifStatement.TryGetContainingList(out SyntaxList <StatementSyntax> statements) &&
                !IsPartOfLazyInitialization(ifStatement, statements))
            {
                NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, semanticModel: context.SemanticModel, cancellationToken: context.CancellationToken);
                if (nullCheck.Success)
                {
                    SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(ifStatement.GetSingleStatementOrDefault());
                    if (assignmentInfo.Success &&
                        SyntaxComparer.AreEquivalent(assignmentInfo.Left, nullCheck.Expression) &&
                        assignmentInfo.Right.IsSingleLine() &&
                        !ifStatement.SpanContainsDirectives())
                    {
                        int index = statements.IndexOf(ifStatement);

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

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

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

                            if (!nextStatement.ContainsDiagnostics)
                            {
                                MemberInvocationStatementInfo invocationInfo = SyntaxInfo.MemberInvocationStatementInfo(nextStatement);
                                if (invocationInfo.Success &&
                                    SyntaxComparer.AreEquivalent(nullCheck.Expression, invocationInfo.Expression) &&
                                    !ifStatement.Parent.ContainsDirectives(TextSpan.FromBounds(ifStatement.SpanStart, nextStatement.Span.End)))
                                {
                                    context.ReportDiagnostic(DiagnosticDescriptors.InlineLazyInitialization, ifStatement);
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #9
0
        private static Task <Document> UseIsNullPatternInsteadOfComparisonAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, NullCheckStyles.ComparisonToNull, walkDownParentheses: false);

            ExpressionSyntax expression = nullCheck.Expression;
            ExpressionSyntax nullLiteral;

            if (object.ReferenceEquals(expression, binaryExpression.Left))
            {
                nullLiteral = binaryExpression.Right;
            }
            else
            {
                expression = expression.WithTrailingTrivia(binaryExpression.Left.GetTrailingTrivia());

                nullLiteral = binaryExpression.Left.WithLeadingTrivia(expression.GetLeadingTrivia());
            }

            bool useIsNotNull = !AnalyzerOptions.UseLogicalNegationAndPatternMatchingToCheckForNull.IsEnabled(document, binaryExpression);

            PatternSyntax pattern = ConstantPattern(nullLiteral);

            if (binaryExpression.IsKind(SyntaxKind.NotEqualsExpression) &&
                useIsNotNull)
            {
                pattern = NotPattern(pattern);
            }

            ExpressionSyntax newExpression = IsPatternExpression(
                expression,
                Token(binaryExpression.OperatorToken.LeadingTrivia, SyntaxKind.IsKeyword, binaryExpression.OperatorToken.TrailingTrivia),
                pattern);

            if (binaryExpression.IsKind(SyntaxKind.NotEqualsExpression) &&
                !useIsNotNull)
            {
                newExpression = LogicalNotExpression(ParenthesizedExpression(newExpression.WithoutTrivia()));
            }

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

            return(document.ReplaceNodeAsync(binaryExpression, newExpression, cancellationToken));
        }
Пример #10
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));
            }
        }
        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);
        }
        public static void AnalyzeFirstOrDefault(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo)
        {
            InvocationExpressionSyntax invocation = invocationInfo.InvocationExpression;

            SyntaxNode parent = invocation.WalkUpParentheses().Parent;

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(parent, NullCheckStyles.ComparisonToNull | NullCheckStyles.IsNull);

            if (!nullCheck.Success)
            {
                return;
            }

            SyntaxNode node = nullCheck.NullCheckExpression;

            if (node.ContainsDirectives)
            {
                return;
            }

            ExtensionMethodSymbolInfo extensionMethodSymbolInfo = context.SemanticModel.GetReducedExtensionMethodInfo(invocation, context.CancellationToken);

            IMethodSymbol methodSymbol = extensionMethodSymbolInfo.Symbol;

            if (methodSymbol == null)
            {
                return;
            }

            if (!SymbolUtility.IsLinqExtensionOfIEnumerableOfTWithPredicate(methodSymbol, context.SemanticModel, name: invocationInfo.NameText, allowImmutableArrayExtension: true))
            {
                return;
            }

            if (!extensionMethodSymbolInfo
                .ReducedSymbol
                .ReturnType
                .IsReferenceTypeOrNullableType())
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.SimplifyLinqMethodChain, node);
        }
Пример #13
0
        public static async Task <Document> RefactorAsync(
            Document document,
            IfStatementSyntax ifStatement,
            CancellationToken cancellationToken)
        {
            var statement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault();

            StatementSyntax newStatement = statement;

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

            SimpleMemberInvocationStatementInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationStatementInfo(statement);

            ExpressionSyntax expression = invocationInfo.Expression;

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

            if (semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken).IsNullableType())
            {
                var memberAccess = (MemberAccessExpressionSyntax)invocationInfo.Expression;

                newStatement = statement.ReplaceNode(memberAccess, memberAccess.Expression.WithTrailingTrivia(memberAccess.GetTrailingTrivia()));

                expression = memberAccess.Expression;
            }

            int insertIndex = expression.Span.End - statement.FullSpan.Start;

            newStatement = SyntaxFactory.ParseStatement(newStatement.ToFullString().Insert(insertIndex, "?"));

            IEnumerable <SyntaxTrivia> leading = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, statement.SpanStart));

            newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                ? newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia())
                : newStatement.WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(leading));

            IEnumerable <SyntaxTrivia> trailing = ifStatement.DescendantTrivia(TextSpan.FromBounds(statement.Span.End, ifStatement.Span.End));

            newStatement = (leading.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                ? newStatement.WithTrailingTrivia(ifStatement.GetTrailingTrivia())
                : newStatement.WithTrailingTrivia(trailing.Concat(ifStatement.GetTrailingTrivia()));

            return(await document.ReplaceNodeAsync(ifStatement, newStatement, cancellationToken).ConfigureAwait(false));
        }
Пример #14
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");
        }
Пример #15
0
        private static IfAnalysis CreateIfToAssignment(
            IfStatementSyntax ifStatement,
            ExpressionSyntax left,
            ExpressionSyntax expression1,
            ExpressionSyntax expression2,
            NullCheckExpressionInfo nullCheck,
            IfAnalysisOptions options,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if ((nullCheck.Style & NullCheckStyles.ComparisonToNull) != 0 &&
                AreEquivalent(nullCheck.Expression, expression1))
            {
                return(CreateIfToAssignment(isNullable: false));
            }

            expression1 = GetNullableOfTValueProperty(expression1, semanticModel, cancellationToken);

            if (AreEquivalent(nullCheck.Expression, expression1))
            {
                return(CreateIfToAssignment(isNullable: true));
            }

            return(null);

            IfAnalysis CreateIfToAssignment(bool isNullable)
            {
                if (!isNullable &&
                    expression2.Kind() == SyntaxKind.NullLiteralExpression)
                {
                    if (options.UseExpression)
                    {
                        return(new IfElseToAssignmentWithExpressionAnalysis(ifStatement, expression1.FirstAncestor <ExpressionStatementSyntax>(), semanticModel));
                    }
                }
                else if (options.UseCoalesceExpression)
                {
                    return(new IfElseToAssignmentWithCoalesceExpressionAnalysis(ifStatement, left, expression1, expression2, semanticModel));
                }

                return(null);
            }
        }
        private static void AnalyzeNotEqualsExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)context.Node;

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

            if (nullCheck.Success)
            {
                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticDescriptors.UseIsNullPatternInsteadOfComparisonOrViceVersa,
                    binaryExpression,
                    "!=");
            }
        }
Пример #17
0
        private static Task <Document> SimplifyNullChckWithFirstOrDefault(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            NullCheckExpressionInfo nullCheck = NullCheckExpressionInfo(node, NullCheckStyles.ComparisonToNull | NullCheckStyles.IsNull);

            var invocation = (InvocationExpressionSyntax)nullCheck.Expression;

            ExpressionSyntax newNode = RefactoringUtility.ChangeInvokedMethodName(invocation, "Any");

            if (node.IsKind(SyntaxKind.EqualsExpression, SyntaxKind.IsPatternExpression))
            {
                newNode = LogicalNotExpression(newNode.TrimTrivia().Parenthesize());
            }

            newNode = newNode.WithTriviaFrom(node);

            return(document.ReplaceNodeAsync(node, newNode, cancellationToken));
        }
Пример #18
0
        private static void AnalyzeNotEqualsExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)context.Node;

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

            if (nullCheck.Success)
            {
                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticRules.UsePatternMatchingToCheckForNullOrViceVersa,
                    binaryExpression,
                    "!=");
            }
        }
        private Task <Document> RefactorAsync(
            Document document,
            NullCheckExpressionInfo nullCheck,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax newNode = SimpleMemberInvocationExpression(
                StringType(),
                IdentifierName(MethodName),
                Argument(nullCheck.Expression));

            if (nullCheck.Style == NullCheckStyles.NotEqualsToNull)
            {
                newNode = LogicalNotExpression(newNode);
            }

            newNode = newNode
                      .WithTriviaFrom(nullCheck.NullCheckExpression)
                      .WithFormatterAnnotation();

            return(document.ReplaceNodeAsync(nullCheck.NullCheckExpression, newNode, cancellationToken));
        }
Пример #20
0
        public static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (ifStatement.IsSimpleIf() &&
                !ifStatement.ContainsDiagnostics)
            {
                NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, allowedKinds: NullCheckKind.NotEqualsToNull);
                if (nullCheck.Success)
                {
                    MemberInvocationStatementInfo invocationInfo = SyntaxInfo.MemberInvocationStatementInfo(ifStatement.GetSingleStatementOrDefault());
                    if (invocationInfo.Success &&
                        SyntaxComparer.AreEquivalent(nullCheck.Expression, invocationInfo.Expression) &&
                        !ifStatement.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken) &&
                        !ifStatement.SpanContainsDirectives())
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, ifStatement);
                    }
                }
            }
        }
Пример #21
0
        private static void AnalyzeEqualsExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)context.Node;

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(binaryExpression, allowedStyles: NullCheckStyles.EqualsToNull, walkDownParentheses: false);

            if (nullCheck.Success)
            {
                DiagnosticHelpers.ReportDiagnostic(
                    context,
                    DiagnosticRules.UsePatternMatchingToCheckForNullOrViceVersa,
                    binaryExpression,
                    AnalyzerOptions.UseComparisonInsteadPatternMatchingToCheckForNull,
                    "==");
            }
        }
        public static Task <Document> RefactorAsync(
            Document document,
            SyntaxNode node,
            CancellationToken cancellationToken)
        {
            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(node);

            AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(nullCheck.Expression);

            ExpressionSyntax newNode = IsExpression(asExpressionInfo.Expression, asExpressionInfo.Type);

            if (nullCheck.IsCheckingNull)
            {
                newNode = LogicalNotExpression(newNode.WithoutTrivia().Parenthesize()).WithTriviaFrom(newNode);
            }

            newNode = newNode
                      .Parenthesize()
                      .WithFormatterAnnotation();

            return(document.ReplaceNodeAsync(node, newNode, cancellationToken));
        }
        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);
        }
Пример #24
0
        public static bool CanRefactor(
            ParameterSyntax parameter,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default)
        {
            BlockSyntax body = GetBody(parameter);

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

            IParameterSymbol parameterSymbol = semanticModel.GetDeclaredSymbol(parameter, cancellationToken);

            if (parameterSymbol?.Type.IsReferenceTypeOrNullableType() != true)
            {
                return(false);
            }

            foreach (StatementSyntax statement in body.Statements)
            {
                NullCheckExpressionInfo nullCheck = GetNullCheckExpressionInfo(statement, semanticModel, cancellationToken);

                if (nullCheck.Success)
                {
                    if (string.Equals(((IdentifierNameSyntax)nullCheck.Expression).Identifier.ValueText, parameter.Identifier.ValueText, StringComparison.Ordinal))
                    {
                        return(false);
                    }
                }
                else
                {
                    break;
                }
            }

            return(true);
        }
Пример #25
0
        private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxNode node)
        {
            if (node.SpanContainsDirectives())
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(node);

            if (!nullCheck.Success)
            {
                return;
            }

            AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(nullCheck.Expression);

            if (!asExpressionInfo.Success)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UseIsOperatorInsteadOfAsOperator, node);
        }
        private static void AnalyzeNotEqualsExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            var binaryExpression = (BinaryExpressionSyntax)context.Node;

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

            if (!nullCheck.Success)
            {
                return;
            }

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

            ReportDiagnostic(context, binaryExpression, "pattern matching");
        }
        private static Task <Document> UseStringIsNullOrEmptyMethodAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            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(document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken));
        }
        private static bool IsNullCheck(
            StatementSyntax statement,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!(statement is IfStatementSyntax ifStatement))
            {
                return(false);
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull);

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

            if (nullCheck.Expression.Kind() != SyntaxKind.IdentifierName)
            {
                return(false);
            }

            var throwStatement = ifStatement.SingleNonBlockStatementOrDefault() as ThrowStatementSyntax;

            if (throwStatement?.Expression?.Kind() != SyntaxKind.ObjectCreationExpression)
            {
                return(false);
            }

            var objectCreation = (ObjectCreationExpressionSyntax)throwStatement.Expression;

            INamedTypeSymbol exceptionType = semanticModel.GetTypeByMetadataName(MetadataNames.System_ArgumentNullException);

            ISymbol type = semanticModel.GetSymbol(objectCreation.Type, cancellationToken);

            return(type?.Equals(exceptionType) == true);
        }
Пример #29
0
        private static ImmutableArray <IfRefactoring> Analyze(
            IfStatementSyntax ifStatement,
            ExpressionSyntax condition,
            ExpressionSyntax expression1,
            ExpressionSyntax expression2,
            IfAnalysisOptions options,
            bool isYield,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            if (expression1?.IsMissing != false)
            {
                return(Empty);
            }

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

            if (options.UseCoalesceExpression ||
                options.UseExpression)
            {
                SyntaxKind kind1 = expression1.Kind();
                SyntaxKind kind2 = expression2.Kind();

                if (kind1.IsBooleanLiteralExpression() &&
                    kind2.IsBooleanLiteralExpression() &&
                    kind1 != kind2)
                {
                    if (options.UseExpression)
                    {
                        if (ifStatement.IsSimpleIf() &&
                            (ifStatement.PreviousStatementOrDefault() is IfStatementSyntax previousIf) &&
                            previousIf.IsSimpleIf() &&
                            (previousIf.GetSingleStatementOrDefault() is ReturnStatementSyntax returnStatement) &&
                            returnStatement.Expression?.WalkDownParentheses().Kind() == kind1)
                        {
                            return(Empty);
                        }

                        return(new IfToReturnWithExpression(ifStatement, condition, isYield, negate: kind1 == SyntaxKind.FalseLiteralExpression).ToImmutableArray());
                    }

                    return(Empty);
                }

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

                if (nullCheck.Success)
                {
                    IfRefactoring refactoring = CreateIfToReturnStatement(
                        ifStatement,
                        (nullCheck.IsCheckingNull) ? expression2 : expression1,
                        (nullCheck.IsCheckingNull) ? expression1 : expression2,
                        nullCheck,
                        options,
                        isYield,
                        semanticModel,
                        cancellationToken);

                    if (refactoring != null)
                    {
                        return(refactoring.ToImmutableArray());
                    }
                }
            }

            IfToReturnWithBooleanExpression ifToReturnWithBooleanExpression = null;

            if (options.UseBooleanExpression &&
                (expression1.Kind().IsBooleanLiteralExpression() || expression2.Kind().IsBooleanLiteralExpression()) &&
                semanticModel.GetTypeSymbol(expression1, cancellationToken)?.IsBoolean() == true &&
                semanticModel.GetTypeSymbol(expression2, cancellationToken)?.IsBoolean() == true)
            {
                ifToReturnWithBooleanExpression = IfToReturnWithBooleanExpression.Create(ifStatement, expression1, expression2, isYield);
            }

            IfToReturnWithConditionalExpression ifToReturnWithConditionalExpression = null;

            if (options.UseConditionalExpression &&
                (!expression1.Kind().IsBooleanLiteralExpression() || !expression2.Kind().IsBooleanLiteralExpression()))
            {
                ifToReturnWithConditionalExpression = IfToReturnWithConditionalExpression.Create(ifStatement, expression1, expression2, isYield);
            }

            return(ToImmutableArray(ifToReturnWithBooleanExpression, ifToReturnWithConditionalExpression));
        }
Пример #30
0
        private static ImmutableArray <IfRefactoring> Analyze(
            IfStatementSyntax ifStatement,
            ExpressionSyntax condition,
            ExpressionStatementSyntax expressionStatement1,
            ExpressionStatementSyntax expressionStatement2,
            IfAnalysisOptions options,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            SimpleAssignmentStatementInfo assignment1 = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement1);

            if (!assignment1.Success)
            {
                return(Empty);
            }

            SimpleAssignmentStatementInfo assignment2 = SyntaxInfo.SimpleAssignmentStatementInfo(expressionStatement2);

            if (!assignment2.Success)
            {
                return(Empty);
            }

            ExpressionSyntax left1  = assignment1.Left;
            ExpressionSyntax left2  = assignment2.Left;
            ExpressionSyntax right1 = assignment1.Right;
            ExpressionSyntax right2 = assignment2.Right;

            if (!SyntaxComparer.AreEquivalent(left1, left2))
            {
                return(Empty);
            }

            if (options.UseCoalesceExpression ||
                options.UseExpression)
            {
                SyntaxKind kind1 = right1.Kind();
                SyntaxKind kind2 = right2.Kind();

                if (kind1.IsBooleanLiteralExpression() &&
                    kind2.IsBooleanLiteralExpression() &&
                    kind1 != kind2)
                {
                    if (options.UseExpression)
                    {
                        return(new IfElseToAssignmentWithCondition(ifStatement, left1, condition, negate: kind1 == SyntaxKind.FalseLiteralExpression).ToImmutableArray());
                    }

                    return(Empty);
                }

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

                if (nullCheck.Success)
                {
                    IfRefactoring refactoring = CreateIfToAssignment(
                        ifStatement,
                        left1,
                        (nullCheck.IsCheckingNull) ? right2 : right1,
                        (nullCheck.IsCheckingNull) ? right1 : right2,
                        nullCheck,
                        options,
                        semanticModel,
                        cancellationToken);

                    if (refactoring != null)
                    {
                        return(refactoring.ToImmutableArray());
                    }
                }
            }

            if (options.UseConditionalExpression)
            {
                return(new IfElseToAssignmentWithConditionalExpression(ifStatement, left1, right1, right2).ToImmutableArray());
            }

            return(Empty);
        }