Пример #1
0
        public static async Task <Document> RefactorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpressionSyntax,
            CancellationToken cancellationToken)
        {
            ConditionalExpressionInfo conditionalExpression;

            if (ConditionalExpressionInfo.TryCreate(conditionalExpressionSyntax, out conditionalExpression))
            {
                SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false);

                NullCheckExpression nullCheck;
                if (NullCheckExpression.TryCreate(conditionalExpression.Condition, semanticModel, out nullCheck, cancellationToken))
                {
                    ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull)
                        ? conditionalExpression.WhenTrue
                        : conditionalExpression.WhenFalse;

                    ExpressionSyntax whenNull = (nullCheck.IsCheckingNull)
                        ? conditionalExpression.WhenTrue
                        : conditionalExpression.WhenFalse;

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

                    ExpressionSyntax newNode;

                    if (expression.Parent == whenNotNull &&
                        whenNotNull.IsKind(SyntaxKind.SimpleMemberAccessExpression) &&
                        SemanticUtilities.IsPropertyOfNullableOfT(whenNotNull, "Value", semanticModel, cancellationToken))
                    {
                        newNode = expression;
                    }
                    else
                    {
                        newNode = SyntaxFactory.ParseExpression(whenNotNull.ToString().Insert(expression.Span.End - whenNotNull.SpanStart, "?"));
                    }

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

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

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

            Debug.Fail(conditionalExpressionSyntax.ToString());

            return(document);
        }
Пример #2
0
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context, INamedTypeSymbol expressionType)
        {
            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            ConditionalExpressionInfo conditionalExpression;

            if (ConditionalExpressionInfo.TryCreate((ConditionalExpressionSyntax)context.Node, out conditionalExpression))
            {
                SemanticModel     semanticModel     = context.SemanticModel;
                CancellationToken cancellationToken = context.CancellationToken;

                NullCheckExpression nullCheck;
                if (NullCheckExpression.TryCreate(conditionalExpression.Condition, semanticModel, out nullCheck, cancellationToken))
                {
                    ExpressionSyntax whenNotNull = (nullCheck.IsCheckingNotNull)
                        ? conditionalExpression.WhenTrue
                        : conditionalExpression.WhenFalse;

                    if (whenNotNull.IsKind(
                            SyntaxKind.SimpleMemberAccessExpression,
                            SyntaxKind.ElementAccessExpression,
                            SyntaxKind.ConditionalAccessExpression,
                            SyntaxKind.InvocationExpression) &&
                        semanticModel.GetTypeSymbol(nullCheck.Expression, cancellationToken)?.IsReferenceTypeOrNullableType() == true &&
                        !ContainsOutArgumentWithLocal(whenNotNull, semanticModel, cancellationToken))
                    {
                        ExpressionSyntax expression = FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull);

                        if (expression != null)
                        {
                            ExpressionSyntax whenNull = (nullCheck.IsCheckingNull)
                                ? conditionalExpression.WhenTrue
                                : conditionalExpression.WhenFalse;

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

                            if (semanticModel.IsDefaultValue(typeSymbol, whenNull, cancellationToken) &&
                                !conditionalExpression.Node.IsInExpressionTree(expressionType, semanticModel, cancellationToken))
                            {
                                context.ReportDiagnostic(
                                    DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression,
                                    conditionalExpression.Node);
                            }
                        }
                    }
                }
            }
        }
Пример #3
0
 public ConditionalExpressionInfo Parse()
 {
     var rslt = new ConditionalExpressionInfo(this);
     rslt.Logical_Or_Expression = this.Logical_or_expression.Parse();
     if (Second_expression != null)
     {
         rslt.Expression = this.Second_expression.Parse();
     }
     if (Third_expression != null)
     {
         rslt.ConditionalExpression = this.Third_expression.Parse();
     }
     return rslt;
 }
Пример #4
0
        public ConditionalExpressionInfo Parse()
        {
            var rslt = new ConditionalExpressionInfo(this);

            rslt.Logical_Or_Expression = this.Logical_or_expression.Parse();
            if (Second_expression != null)
            {
                rslt.Expression = this.Second_expression.Parse();
            }
            if (Third_expression != null)
            {
                rslt.ConditionalExpression = this.Third_expression.Parse();
            }
            return(rslt);
        }
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind trueKind = info.WhenTrue.Kind();

            if (trueKind == SyntaxKind.TrueLiteralExpression)
            {
                if (context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                }
            }
            else
            {
                SyntaxKind falseKind = info.WhenFalse.Kind();

                if (falseKind == SyntaxKind.FalseLiteralExpression)
                {
                    if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                    {
                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                    }
                }
                else if (trueKind == SyntaxKind.FalseLiteralExpression &&
                         falseKind == SyntaxKind.TrueLiteralExpression)
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                }
            }
        }
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!info.Success)
            {
                return;
            }

            switch (info.WhenTrue.Kind())
            {
            case SyntaxKind.TrueLiteralExpression:
            {
                if (info.WhenFalse.Kind() == SyntaxKind.FalseLiteralExpression)
                {
                    context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                }

                break;
            }

            case SyntaxKind.FalseLiteralExpression:
            {
                if (info.WhenFalse.Kind() == SyntaxKind.TrueLiteralExpression)
                {
                    context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                }

                break;
            }
            }
        }
Пример #7
0
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind trueKind = info.WhenTrue.Kind();

            if (trueKind == SyntaxKind.TrueLiteralExpression)
            {
                context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
            }
            else
            {
                SyntaxKind falseKind = info.WhenFalse.Kind();

                if (falseKind == SyntaxKind.FalseLiteralExpression)
                {
                    context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                }
                else if (trueKind == SyntaxKind.FalseLiteralExpression &&
                         falseKind == SyntaxKind.TrueLiteralExpression)
                {
                    context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                }
            }
        }
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            ConditionalExpressionInfo conditionalExpressionInfo,
            ExpressionSyntax whenNull,
            ExpressionSyntax whenNotNull,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(whenNotNull, cancellationToken);

            if (typeSymbol?.IsErrorType() == false &&
                semanticModel.IsDefaultValue(typeSymbol, whenNull, cancellationToken) &&
                !RefactoringHelper.ContainsOutArgumentWithLocal(whenNotNull, semanticModel, cancellationToken) &&
                !conditionalExpressionInfo.Node.IsInExpressionTree(semanticModel, cancellationToken))
            {
                context.ReportDiagnostic(
                    DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression,
                    conditionalExpressionInfo.Node);
            }
        }
        public static void Analyze(SyntaxNodeAnalysisContext context, ConditionalExpressionSyntax conditionalExpression)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            ConditionalExpressionInfo info;

            if (ConditionalExpressionInfo.TryCreate(conditionalExpression, out info))
            {
                switch (info.WhenTrue.Kind())
                {
                case SyntaxKind.TrueLiteralExpression:
                {
                    if (info.WhenFalse.IsKind(SyntaxKind.FalseLiteralExpression))
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                    }

                    break;
                }

                case SyntaxKind.FalseLiteralExpression:
                {
                    if (info.WhenFalse.IsKind(SyntaxKind.TrueLiteralExpression))
                    {
                        context.ReportDiagnostic(DiagnosticDescriptors.SimplifyConditionalExpression, conditionalExpression);
                    }

                    break;
                }
                }
            }
        }
Пример #10
0
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (conditionalExpression.ContainsDiagnostics)
            {
                return;
            }

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression, walkDownParentheses: false);

            if (!info.Success)
            {
                return;
            }

            if (info.Condition.Kind() == SyntaxKind.ParenthesizedExpression)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.ParenthesizeConditionInConditionalExpression, info.Condition);
        }
Пример #11
0
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind trueKind  = info.WhenTrue.Kind();
            SyntaxKind falseKind = info.WhenFalse.Kind();

            if (trueKind == SyntaxKind.TrueLiteralExpression)
            {
                // a ? true : false >>> a
                // a ? true : b >>> a || b
                if (falseKind == SyntaxKind.FalseLiteralExpression ||
                    context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    Report(DiagnosticDescriptors.SimplifyConditionalExpression);
                }
            }
            else if (trueKind == SyntaxKind.FalseLiteralExpression)
            {
                /// a ? false : true >>> !a
                if (falseKind == SyntaxKind.TrueLiteralExpression)
                {
                    Report(DiagnosticDescriptors.SimplifyConditionalExpression);
                }
                /// a ? false : b >>> !a && b
                else if (context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    Report(DiagnosticDescriptors.SimplifyConditionalExpression2);
                }
            }
            else if (falseKind == SyntaxKind.TrueLiteralExpression)
            {
                // a ? b : true >>> !a || b
                if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    Report(DiagnosticDescriptors.SimplifyConditionalExpression2);
                }
            }
            else if (falseKind == SyntaxKind.FalseLiteralExpression)
            {
                // a ? b : false >>> a && b
                if (context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    Report(DiagnosticDescriptors.SimplifyConditionalExpression);
                }
            }

            void Report(DiagnosticDescriptor descriptor)
            {
                DiagnosticHelpers.ReportDiagnosticIfNotSuppressed(context, descriptor, conditionalExpression);
            }
        }
        public static async Task <Document> RefactorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken)
        {
            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            ExpressionSyntax whenTrue  = info.WhenTrue;
            ExpressionSyntax whenFalse = info.WhenFalse;

            SyntaxKind trueKind  = whenTrue.Kind();
            SyntaxKind falseKind = whenFalse.Kind();

            ExpressionSyntax newNode = null;

            if (trueKind == SyntaxKind.TrueLiteralExpression)
            {
                if (falseKind == SyntaxKind.FalseLiteralExpression)
                {
                    newNode = CreateNewNode(conditionalExpression, info.Condition);
                }
                else
                {
                    SyntaxTriviaList trailingTrivia = info
                                                      .QuestionToken
                                                      .LeadingTrivia
                                                      .AddRange(info.QuestionToken.TrailingTrivia)
                                                      .AddRange(whenTrue.GetLeadingTrivia())
                                                      .EmptyIfWhitespace();

                    newNode = LogicalOrExpression(
                        conditionalExpression.Condition.Parenthesize().AppendToTrailingTrivia(trailingTrivia),
                        Token(info.ColonToken.LeadingTrivia, SyntaxKind.BarBarToken, info.ColonToken.TrailingTrivia),
                        whenFalse.Parenthesize());
                }
            }
            else if (falseKind == SyntaxKind.FalseLiteralExpression)
            {
                SyntaxTriviaList trailingTrivia = whenTrue
                                                  .GetTrailingTrivia()
                                                  .AddRange(info.ColonToken.LeadingTrivia)
                                                  .AddRange(info.ColonToken.TrailingTrivia)
                                                  .AddRange(whenFalse.GetLeadingTrivia())
                                                  .EmptyIfWhitespace()
                                                  .AddRange(whenFalse.GetTrailingTrivia());

                newNode = LogicalAndExpression(
                    conditionalExpression.Condition.Parenthesize(),
                    Token(info.QuestionToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, info.QuestionToken.TrailingTrivia),
                    whenTrue.WithTrailingTrivia(trailingTrivia).Parenthesize());
            }
            else if (trueKind == SyntaxKind.FalseLiteralExpression &&
                     falseKind == SyntaxKind.TrueLiteralExpression)
            {
                SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                newNode = CreateNewNode(conditionalExpression, Inverter.LogicallyNegate(info.Condition, semanticModel, cancellationToken));
            }

            newNode = newNode.Parenthesize();

            return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false));
        }
Пример #13
0
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!conditionalExpressionInfo.Success)
            {
                return;
            }

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

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

            if (!nullCheck.Success)
            {
                return;
            }

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

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

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

                if (expression == null)
                {
                    return;
                }

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

                if (typeSymbol == null)
                {
                    return;
                }

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

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

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

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

                        if (typeSymbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
                        {
                            DiagnosticHelpers.ReportDiagnostic(context,
                                                               DiagnosticDescriptors.UseConditionalAccessInsteadOfConditionalExpression,
                                                               conditionalExpression);
                        }
                    }
                }
            }
        }
Пример #14
0
        public static async Task <Document> RefactorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            ConditionalExpressionInfo conditionalExpressionInfo = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

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

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

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

            var castExpression = whenNotNull as CastExpressionSyntax;

            ExpressionSyntax expression = (castExpression != null)
                ? UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, castExpression.Expression, semanticModel, cancellationToken)
                : UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(nullCheck.Expression, whenNotNull, semanticModel, cancellationToken);

            var coalesce = false;

            ExpressionSyntax newNode = null;

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

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

                            if (castExpression != null)
                            {
                                newNode = castExpression
                                          .WithExpression(newNode.Parenthesize())
                                          .WithSimplifierAnnotation();
                            }
                        }
                    }
                }
            }

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

            if (coalesce ||
                (!semanticModel.GetTypeSymbol(whenNotNull, cancellationToken).IsReferenceTypeOrNullableType() &&
                 (whenNull as DefaultExpressionSyntax)?.Type.IsKind(SyntaxKind.NullableType) != true))
            {
                newNode = CoalesceExpression(newNode.Parenthesize(), whenNull.Parenthesize());
            }

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

            return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false));
        }
Пример #15
0
        private static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            ConditionalExpressionInfo info = SyntaxInfo.ConditionalExpressionInfo(conditionalExpression);

            if (!info.Success)
            {
                return;
            }

            SyntaxKind trueKind  = info.WhenTrue.Kind();
            SyntaxKind falseKind = info.WhenFalse.Kind();

            if (trueKind == SyntaxKind.TrueLiteralExpression)
            {
                // a ? true : false >>> a
                // a ? true : b >>> a || b
                if (falseKind == SyntaxKind.FalseLiteralExpression ||
                    (falseKind != SyntaxKind.ThrowExpression &&
                     context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean))
                {
                    ReportDiagnostic();
                }
            }
            else if (trueKind == SyntaxKind.FalseLiteralExpression)
            {
                /// a ? false : true >>> !a
                if (falseKind == SyntaxKind.TrueLiteralExpression)
                {
                    ReportDiagnostic();
                }
                /// a ? false : b >>> !a && b
                else if (falseKind != SyntaxKind.ThrowExpression &&
                         !AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted.IsEnabled(context) &&
                         context.SemanticModel.GetTypeInfo(info.WhenFalse, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.SimplifyConditionalExpression, conditionalExpression, AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted);
                }
            }
            else if (falseKind == SyntaxKind.TrueLiteralExpression)
            {
                // a ? b : true >>> !a || b
                if (trueKind != SyntaxKind.ThrowExpression &&
                    !AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted.IsEnabled(context) &&
                    context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.SimplifyConditionalExpression, conditionalExpression, AnalyzerOptions.DoNotSimplifyConditionalExpressionWhenConditionIsInverted);
                }
            }
            else if (falseKind == SyntaxKind.FalseLiteralExpression)
            {
                // a ? b : false >>> a && b
                if (trueKind != SyntaxKind.ThrowExpression &&
                    context.SemanticModel.GetTypeInfo(info.WhenTrue, context.CancellationToken).ConvertedType?.SpecialType == SpecialType.System_Boolean)
                {
                    ReportDiagnostic();
                }
            }

            void ReportDiagnostic()
            {
                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.SimplifyConditionalExpression, conditionalExpression);
            }
        }
Пример #16
0
        public static async Task <Document> RefactorAsync(
            Document document,
            ConditionalExpressionSyntax conditionalExpression,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync().ConfigureAwait(false);

            ConditionalExpressionInfo.TryCreate(conditionalExpression, out ConditionalExpressionInfo conditionalExpressionInfo);

            NullCheckExpression.TryCreate(conditionalExpressionInfo.Condition, semanticModel, out NullCheckExpression nullCheck, cancellationToken);

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

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

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

            bool coalesce = false;

            ExpressionSyntax newNode = null;

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

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

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

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

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

            return(await document.ReplaceNodeAsync(conditionalExpression, newNode, cancellationToken).ConfigureAwait(false));
        }
Пример #17
0
        public static void AnalyzeConditionalExpression(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.SpanContainsDirectives())
            {
                return;
            }

            var conditionalExpression = (ConditionalExpressionSyntax)context.Node;

            if (!ConditionalExpressionInfo.TryCreate(conditionalExpression, out ConditionalExpressionInfo conditionalExpressionInfo))
            {
                return;
            }

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

            if (!NullCheckExpression.TryCreate(conditionalExpressionInfo.Condition, semanticModel, out NullCheckExpression nullCheck, cancellationToken))
            {
                return;
            }

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

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

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

                if (expression == null)
                {
                    return;
                }

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

                if (typeSymbol == null)
                {
                    return;
                }

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

                        if (!memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) &&
                            (memberAccessExpression.Name as IdentifierNameSyntax)?.Identifier.ValueText == "Value")
                        {
                            if (memberAccessExpression == whenNotNull)
                            {
                                context.ReportDiagnostic(
                                    DiagnosticDescriptors.UseCoalesceExpressionInsteadOfConditionalExpression,
                                    conditionalExpression);
                            }
                            else
                            {
                                Analyze(context, conditionalExpressionInfo, whenNull, whenNotNull, semanticModel, cancellationToken);
                            }
                        }
                    }
                }
            }
        }
        private static (int, int) GetNearestConditionalExpressionIndexes(string source, out ConditionalExpressionInfo conditionalExpressionInfo)
        {
            conditionalExpressionInfo = null;
            int beginIndex = -1, endIndex = -1;

            // Находим первую конструкцию {ce.LeftSide}...значение...{ce.RightSide}
            foreach (var ce in conditionalExpressions)
            {
                int tempBeginIndex = source.IndexOf(ce.LeftSide);
                if (tempBeginIndex >= 0)
                {
                    int tempEndIndex = source.IndexOf(ce.RightSide, tempBeginIndex);
                    if (tempEndIndex >= 0)
                    {
                        // Если это первая итерация или найдена конструкция, находящаяся перед
                        // текущей конструкцией
                        if (beginIndex < 0 || tempBeginIndex < beginIndex)
                        {
                            beginIndex = tempBeginIndex;
                            endIndex   = tempEndIndex;
                            conditionalExpressionInfo = ce;
                        }
                    }
                }
            }
            if (beginIndex >= 0 && endIndex > 0)
            {
                // Ищем условные конструкции внутри нашей условной конструкции
                // Если таковые имеются и закрывающая стороная совпадает с нашей конструкцией,
                // то присваиваем endIndex следующую закрывающую сторону
                bool wasOffset          = false;
                int  lastTempBeginIndex = beginIndex + conditionalExpressionInfo.LeftSide.Length;
                do
                {
                    wasOffset = false;
                    // Ищем самую первую условную конструкцию в интервале от [lasTempBeginIndex; endIndex]
                    // Если таковая имеется, тогда присваиваем endIndex индекс следующей закрывающей стороны
                    int?tempBeginIndex = null;
                    foreach (var ce in conditionalExpressions)
                    {
                        int temp = source.IndexOf(ce.LeftSide, lastTempBeginIndex);
                        if (temp > 0)
                        {
                            temp += ce.LeftSide.Length;
                            if (!tempBeginIndex.HasValue && temp <= endIndex)
                            {
                                tempBeginIndex = temp;
                            }
                            else if (temp <= endIndex && temp < tempBeginIndex)
                            {
                                tempBeginIndex = temp;
                            }
                        }
                    }
                    if (tempBeginIndex.HasValue)
                    {
                        lastTempBeginIndex = tempBeginIndex.Value;
                        int tempEndIndex = source.IndexOf(conditionalExpressionInfo.RightSide, endIndex + conditionalExpressionInfo.RightSide.Length);
                        if (tempEndIndex > 0)
                        {
                            endIndex  = tempEndIndex;
                            wasOffset = true;
                        }
                    }
                } while (wasOffset);
            }
            return(beginIndex, endIndex);
        }