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);
            }
        }
        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));
        }
예제 #3
0
        public static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType)
        {
            var logicalAndExpression = (BinaryExpressionSyntax)context.Node;

            if (!logicalAndExpression.ContainsDiagnostics)
            {
                ExpressionSyntax expression = SyntaxInfo.NullCheckExpressionInfo(logicalAndExpression.Left, allowedKinds: NullCheckKind.NotEqualsToNull).Expression;

                if (expression != null &&
                    context.SemanticModel
                    .GetTypeSymbol(expression, context.CancellationToken)?
                    .IsReferenceType == true)
                {
                    ExpressionSyntax right = logicalAndExpression.Right?.WalkDownParentheses();

                    if (right != null &&
                        ValidateRightExpression(right, context.SemanticModel, context.CancellationToken) &&
                        !RefactoringHelper.ContainsOutArgumentWithLocal(right, context.SemanticModel, context.CancellationToken))
                    {
                        ExpressionSyntax expression2 = FindExpressionThatCanBeConditionallyAccessed(expression, right);

                        if (expression2?.SpanContainsDirectives() == false &&
                            !logicalAndExpression.IsInExpressionTree(expressionType, context.SemanticModel, context.CancellationToken))
                        {
                            context.ReportDiagnostic(DiagnosticDescriptors.UseConditionalAccess, logicalAndExpression);
                        }
                    }
                }
            }
        }
예제 #4
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);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #8
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));
        }
예제 #9
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);
        }
예제 #12
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));
        }
예제 #13
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");
        }
예제 #14
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 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,
                    "!=");
            }
        }
예제 #16
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,
                    "==");
            }
        }
예제 #17
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);
                    }
                }
            }
        }
        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);
        }
        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));
        }
예제 #21
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 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);
        }
예제 #24
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));
            }
        }
예제 #25
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);
        }
예제 #26
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));
        }
        private static ExpressionSyntax CreateExpressionWithConditionalAccess(BinaryExpressionSyntax logicalAnd)
        {
            ExpressionSyntax expression = SyntaxInfo.NullCheckExpressionInfo(logicalAnd.Left, allowedStyles: NullCheckStyles.NotEqualsToNull).Expression;

            ExpressionSyntax right = logicalAnd.Right?.WalkDownParentheses();

            ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(
                expression,
                right);

            SyntaxKind kind = right.Kind();

            if (kind == SyntaxKind.LogicalNotExpression)
            {
                var logicalNot           = (PrefixUnaryExpressionSyntax)right;
                ExpressionSyntax operand = logicalNot.Operand;

                string s = operand.ToFullString();

                int length         = expression2.Span.End - operand.FullSpan.Start;
                int trailingLength = operand.GetTrailingTrivia().Span.Length;

                var sb = new StringBuilder();
                sb.Append(s, 0, length);
                sb.Append("?");
                sb.Append(s, length, s.Length - length - trailingLength);
                sb.Append(" == false");
                sb.Append(s, s.Length - trailingLength, trailingLength);

                return(SyntaxFactory.ParseExpression(sb.ToString()));
            }
            else
            {
                string s = right.ToFullString();

                int length         = expression2.Span.End - right.FullSpan.Start;
                int trailingLength = right.GetTrailingTrivia().Span.Length;

                var sb = new StringBuilder();
                sb.Append(s, 0, length);
                sb.Append("?");
                sb.Append(s, length, s.Length - length - trailingLength);

                switch (kind)
                {
                case SyntaxKind.LogicalOrExpression:
                case SyntaxKind.LogicalAndExpression:
                case SyntaxKind.BitwiseOrExpression:
                case SyntaxKind.BitwiseAndExpression:
                case SyntaxKind.ExclusiveOrExpression:
                case SyntaxKind.EqualsExpression:
                case SyntaxKind.NotEqualsExpression:
                case SyntaxKind.LessThanExpression:
                case SyntaxKind.LessThanOrEqualExpression:
                case SyntaxKind.GreaterThanExpression:
                case SyntaxKind.GreaterThanOrEqualExpression:
                case SyntaxKind.IsExpression:
                case SyntaxKind.AsExpression:
                case SyntaxKind.IsPatternExpression:
                    break;

                default:
                {
                    sb.Append(" == true");
                    break;
                }
                }

                sb.Append(s, s.Length - trailingLength, trailingLength);

                return(SyntaxFactory.ParseExpression(sb.ToString()));
            }
        }
예제 #28
0
        private static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context)
        {
            var asExpression = (BinaryExpressionSyntax)context.Node;

            AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression);

            if (!asExpressionInfo.Success)
            {
                return;
            }

            SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression);

            if (!localInfo.Success)
            {
                return;
            }

            if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives())
            {
                return;
            }

            if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement))
            {
                return;
            }

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

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

            StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault();

            if (statement == null)
            {
                return;
            }

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

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

            if (!nullCheck.Success)
            {
                return;
            }

            if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            if (!localInfo.Type.IsVar)
            {
                SemanticModel     semanticModel     = context.SemanticModel;
                CancellationToken cancellationToken = context.CancellationToken;

                ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(asExpressionInfo.Type, cancellationToken);

                if (typeSymbol.IsNullableType())
                {
                    return;
                }

                if (!SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken), typeSymbol))
                {
                    return;
                }
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement);
        }
        private static void AnalyzeLogicalAndExpression(SyntaxNodeAnalysisContext context)
        {
            var logicalAnd = (BinaryExpressionSyntax)context.Node;

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

            BinaryExpressionInfo logicalAndInfo = SyntaxInfo.BinaryExpressionInfo(logicalAnd);

            if (!logicalAndInfo.Success)
            {
                return;
            }

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

            if (!nullCheck.Success)
            {
                return;
            }

            ExpressionSyntax right = logicalAndInfo.Right;

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

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

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

                if (!binaryExpressionInfo.Success)
                {
                    break;
                }

                ExpressionSyntax left = binaryExpressionInfo.Left;

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

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

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

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

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

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

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

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

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

                        break;
                    }
                    }
                }

                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UnnecessaryNullCheck, logicalAnd);
            }
        }
        private static void Analyze(SyntaxNodeAnalysisContext context, SyntaxNode node, BlockSyntax body)
        {
            if (body == null)
            {
                return;
            }

            if (body.ContainsDiagnostics)
            {
                return;
            }

            SyntaxList <StatementSyntax> statements = body.Statements;

            if (statements.Count != 2)
            {
                return;
            }

            if (!(statements[0] is IfStatementSyntax ifStatement))
            {
                return;
            }

            if (!(statements[1] is ReturnStatementSyntax returnStatement))
            {
                return;
            }

            ExpressionSyntax returnExpression = returnStatement.Expression;

            if (returnExpression?.IsKind(SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression) != true)
            {
                return;
            }

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

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

            SimpleIfStatementInfo simpleIf = SyntaxInfo.SimpleIfStatementInfo(ifStatement);

            if (!simpleIf.Success)
            {
                return;
            }

            StatementSyntax statement = simpleIf.IfStatement.SingleNonBlockStatementOrDefault();

            if (statement == null)
            {
                return;
            }

            SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(statement);

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (!assignmentInfo.Left.IsKind(SyntaxKind.IdentifierName, SyntaxKind.SimpleMemberAccessExpression))
            {
                return;
            }

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

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(simpleIf.Condition, semanticModel: semanticModel, allowedStyles: NullCheckStyles.CheckingNull, cancellationToken: cancellationToken);

            if (!nullCheck.Success)
            {
                return;
            }

            ExpressionSyntax expression = nullCheck.Expression;

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

            if (!(semanticModel.GetSymbol(expression, cancellationToken) is IFieldSymbol fieldSymbol))
            {
                return;
            }

            if (!ExpressionEquals(expression, assignmentInfo.Left))
            {
                return;
            }

            if (fieldSymbol.Type.IsNullableType() &&
                returnExpression.Kind() == SyntaxKind.SimpleMemberAccessExpression)
            {
                var memberAccessExpression = (MemberAccessExpressionSyntax)returnExpression;

                if (memberAccessExpression.Name is IdentifierNameSyntax identifierName &&
                    string.Equals(identifierName.Identifier.ValueText, "Value", StringComparison.Ordinal))
                {
                    returnExpression = memberAccessExpression.Expression;
                }
            }

            if (!ExpressionEquals(expression, returnExpression))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.SimplifyLazyInitialization,
                                               Location.Create(node.SyntaxTree, TextSpan.FromBounds(ifStatement.SpanStart, returnStatement.Span.End)));
        }