static CodeAction AddIsNaNIssue(Document document, SemanticModel semanticModel, SyntaxNode root, BinaryExpressionSyntax node, ExpressionSyntax argExpr, string floatType)
 {
     return CodeActionFactory.Create(node.Span, DiagnosticSeverity.Warning, string.Format(node.IsKind(SyntaxKind.EqualsExpression) ? "Replace with '{0}.IsNaN(...)' call" : "Replace with '!{0}.IsNaN(...)' call", floatType), token =>
     {
         SyntaxNode newRoot;
         ExpressionSyntax expr;
         var arguments = new SeparatedSyntaxList<ArgumentSyntax>();
         arguments = arguments.Add(SyntaxFactory.Argument(argExpr));
         expr = SyntaxFactory.InvocationExpression(
             SyntaxFactory.MemberAccessExpression(
                 SyntaxKind.SimpleMemberAccessExpression,
                 SyntaxFactory.ParseExpression(floatType),
                 SyntaxFactory.IdentifierName("IsNaN")
             ),
             SyntaxFactory.ArgumentList(
                 arguments
             )
         );
         if (node.IsKind(SyntaxKind.NotEqualsExpression))
             expr = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, expr);
         expr = expr.WithAdditionalAnnotations(Formatter.Annotation);
         newRoot = root.ReplaceNode((SyntaxNode)node, expr);
         return Task.FromResult(document.WithSyntaxRoot(newRoot));
     });
 }
Example #2
0
        protected override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            var nameSyntax = FindIdentifierName (node.Left);
            if (nameSyntax == null)
                return base.VisitBinaryExpression (node);

            switch (node.Kind)
            {
                case SyntaxKind.AddAssignExpression:
                case SyntaxKind.OrAssignExpression:
                case SyntaxKind.SubtractAssignExpression:
                case SyntaxKind.MultiplyAssignExpression:
                case SyntaxKind.DivideAssignExpression:
                case SyntaxKind.ModuloAssignExpression:
                case SyntaxKind.RightShiftAssignExpression:
                case SyntaxKind.LeftShiftAssignExpression:
                case SyntaxKind.AndAssignExpression:
                case SyntaxKind.ExclusiveOrAssignExpression:
                    var token = Syntax.Token (GetComplexAssignOperator (node.Kind));

                    ExpressionSyntax expr = Syntax.ParseExpression (nameSyntax.PlainName + token + node.Right);

                    return node.Update (node.Left, AssignToken, GetLogExpression (nameSyntax.PlainName, expr));

                case SyntaxKind.AssignExpression:
                    return node.Update (node.Left, node.OperatorToken, GetLogExpression (nameSyntax.PlainName, node.Right));

                default:
                    return base.VisitBinaryExpression (node);
            }
        }
 static bool TryFlip(BinaryExpressionSyntax expr, out SyntaxKind flippedKind, out string operatorText)
 {
     switch (expr.Kind())
     {
         case SyntaxKind.LessThanExpression:
             flippedKind = SyntaxKind.GreaterThanExpression;
             operatorText = ">";
             return true;
         case SyntaxKind.LessThanOrEqualExpression:
             flippedKind = SyntaxKind.GreaterThanOrEqualExpression;
             operatorText = ">=";
             return true;
         case SyntaxKind.GreaterThanExpression:
             flippedKind = SyntaxKind.LessThanExpression;
             operatorText = "<";
             return true;
         case SyntaxKind.GreaterThanOrEqualExpression:
             flippedKind = SyntaxKind.LessThanOrEqualExpression;
             operatorText = "<=";
             return true;
     }
     flippedKind = SyntaxKind.None;
     operatorText = null;
     return false;
 }
Example #4
0
        public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            var based = base.VisitBinaryExpression (node);

            if (node.Left.FindIdentifierName() == null)
                return node;

            switch (node.Kind)
            {
                case SyntaxKind.AddAssignExpression:
                case SyntaxKind.OrAssignExpression:
                case SyntaxKind.SubtractAssignExpression:
                case SyntaxKind.MultiplyAssignExpression:
                case SyntaxKind.DivideAssignExpression:
                case SyntaxKind.ModuloAssignExpression:
                case SyntaxKind.RightShiftAssignExpression:
                case SyntaxKind.LeftShiftAssignExpression:
                case SyntaxKind.AndAssignExpression:
                case SyntaxKind.ExclusiveOrAssignExpression:
                case SyntaxKind.AssignExpression:
                    return based.WithTrailingTrivia (based.GetTrailingTrivia().Prepend (GetIdComment()));

                default:
                    return node;
            }
        }
 internal static ExpressionSyntax GetOuterLeft(BinaryExpressionSyntax bop)
 {
     var leftBop = bop.Left as BinaryExpressionSyntax;
     if (leftBop != null && bop.OperatorToken.IsKind(leftBop.OperatorToken.Kind()))
         return GetOuterLeft(leftBop);
     return bop.Left;
 }
Example #6
0
 public BoundBinaryExpression(BoundExpression left, BoundExpression right, BinaryOperators @operator, BinaryExpressionSyntax binaryExpressionSyntax, IType type)
     : base(binaryExpressionSyntax, type)
 {
     Left = left;
     Right = right;
     Operator = @operator;
 }
 private static SyntaxNode CalculateNewRoot(SyntaxNode root, BinaryExpressionSyntax currentAsBinary)
 {
     return root.ReplaceNode(currentAsBinary,
         SyntaxFactory.ConcatenateExpression(
             currentAsBinary.Left,
             SyntaxFactory.Token(SyntaxKind.AmpersandToken).WithTriviaFrom(currentAsBinary.OperatorToken),
             currentAsBinary.Right));
 }
 ExpressionSyntax GenerateTarget(SemanticModel model, BinaryExpressionSyntax node)
 {
     var symbols = model.LookupSymbols(node.SpanStart).OfType<IMethodSymbol>();
     if (!symbols.Any() || HasDifferentEqualsMethod(symbols))
         return SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParseExpression("object"), SyntaxFactory.IdentifierName("Equals"));
     else
         return SyntaxFactory.IdentifierName("Equals");
 }
        static Document PerformAction(Document document, SyntaxNode root, BinaryExpressionSyntax bop)
        {
            var nodeToReplace = bop.IsParentKind(SyntaxKind.ParenthesizedExpression) ? bop.Parent : bop;
            var castExpr = (ExpressionSyntax)SyntaxFactory.CastExpression(bop.Right as TypeSyntax, CSharpUtil.AddParensIfRequired(bop.Left.WithoutLeadingTrivia().WithoutTrailingTrivia())).WithLeadingTrivia(bop.GetLeadingTrivia()).WithTrailingTrivia(bop.GetTrailingTrivia());

            var newRoot = root.ReplaceNode((SyntaxNode)nodeToReplace, castExpr);
            return document.WithSyntaxRoot(newRoot);
        }
 internal static SyntaxNode ComputeExpression(SyntaxNode nodeToReplace, BinaryExpressionSyntax expression, SyntaxNode root, SemanticModel semanticModel)
 {
     var result = semanticModel.GetConstantValue(expression);
     if (!result.HasValue) return null;
     var newExpression = SyntaxFactory.ParseExpression(System.Convert.ToString(result.Value, System.Globalization.CultureInfo.InvariantCulture));
     var newRoot = root.ReplaceNode(nodeToReplace, newExpression);
     return newRoot;
 }
 public BoundBinaryExpression(BinaryExpressionSyntax syntax, BinaryOperatorKind operatorKind, BoundExpression left, BoundExpression right, TypeSymbol type)
     : base(BoundNodeKind.BinaryExpression, syntax)
 {
     OperatorKind = operatorKind;
     Left = left;
     Right = right;
     Type = type;
 }
Example #12
0
		/// <summary>
		///   Normalizes the <paramref name="binaryExpression" />.
		/// </summary>
		public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax binaryExpression)
		{
			if (!IsFormulaType(binaryExpression))
				return base.VisitBinaryExpression(binaryExpression);

			var left = ReplaceImplicitConversion(binaryExpression.Left);
			var right = ReplaceImplicitConversion(binaryExpression.Right);
			return binaryExpression.Update(left, binaryExpression.OperatorToken, right);
		}
 private static BinaryExpressionSyntax ChangeOperator(BinaryExpressionSyntax binary)
 {
     return
         SyntaxFactory.BinaryExpression(
             OppositeExpressionKinds[binary.Kind()],
             binary.Left,
             binary.Right)
         .WithTriviaFrom(binary);
 }
 private static void AnalyzeBinaryExpression(BinaryExpressionSyntax node, SemanticModel model, Action<Diagnostic> addDiagnostic)
 {
     var leftType = model.GetTypeInfo(node.Left).Type;
     var rightType = model.GetTypeInfo(node.Right).Type;
     if (leftType != null && rightType != null && leftType.SpecialType == SpecialType.System_String && rightType.SpecialType == SpecialType.System_String)
     {
         addDiagnostic(node.OperatorToken.GetLocation().CreateDiagnostic(Rule));
     }
 }
        public static void Go(OutputWriter writer, BinaryExpressionSyntax expression)
        {
            var leftExpression = expression.Left;
            var rightExpression = expression.Right;

            var operatorToken = expression.OperatorToken;
             
            WriteIt(writer, operatorToken, rightExpression, leftExpression);
        }
        public static IEnumerable<ReplaceAction> GetSimplifications(BinaryExpressionSyntax b, ISemanticModel model, Assumptions assume, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!b.Left.DefinitelyHasBooleanType(model)) yield break;
            if (!b.Right.DefinitelyHasBooleanType(model)) yield break;

            // prep basic analysis
            var leftEffects = b.Left.HasSideEffects(model, assume) != false;
            var rightEffects = b.Right.HasSideEffects(model, assume) != false;
            var lv = b.Left.TryGetConstBoolValue();
            var rv = b.Right.TryGetConstBoolValue();
            var cmp = b.Left.TryEvalAlternativeComparison(b.Right, model, assume);

            // prep utility funcs for adding simplifications
            var actions = new List<ReplaceAction>();
            Action<String, ExpressionSyntax> include = (desc, rep) =>
                actions.Add(new ReplaceAction(desc, b, rep));
            Action<bool> useRight = v => {
                if (!leftEffects)
                    include(v ? "rhs" : "!rhs", b.Right.MaybeInverted(!v));
            };
            Action<bool> useLeft = v => {
                if (!rightEffects)
                    include(v ? "lhs" : "!lhs", b.Left.MaybeInverted(!v));
            };
            Action<bool> useBool = v => {
                if (!leftEffects && !rightEffects) {
                    actions.Clear(); // override left/right
                    include(v + "", v.AsLiteral());
                }
            };

            // try to simplify equality operators ==, !=, ^
            bool? equality = null;
            if (b.Kind == SyntaxKind.EqualsExpression) equality = true;
            if (b.Kind == SyntaxKind.ExclusiveOrExpression || b.Kind == SyntaxKind.NotEqualsExpression) equality = false;
            if (equality != null) {
                if (lv != null) useRight(lv == equality);
                if (rv != null) useLeft(rv == equality);
                if (cmp != null) useBool(cmp == equality);
            }

            // try to simplify and/or operators &&, &, ||, |
            var sticky = b.Kind.IsAndBL() ? false
                       : b.Kind.IsOrBL() ? true
                       : (bool?)null;
            if (sticky != null) {
                if (b.Kind.IsShortCircuitingLogic() && lv == sticky) rightEffects = false; // short-circuit prevents effects
                if (cmp == true || lv == !sticky) useRight(true);
                if (cmp == true || rv == !sticky) useLeft(true);
                if (cmp == false || lv == sticky || rv == sticky) useBool(sticky.Value);
            }

            // expose simplifications as code issues/actions
            foreach (var action in actions)
                yield return action;
        }
        private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, BinaryExpressionSyntax syntax)
        {
            var newNode = SyntaxFactory.ParenthesizedExpression(syntax.WithoutTrivia())
                .WithTriviaFrom(syntax)
                .WithoutFormatting();

            var newSyntaxRoot = root.ReplaceNode(syntax, newNode);

            return Task.FromResult(document.WithSyntaxRoot(newSyntaxRoot));
        }
Example #18
0
		/// <summary>
		///     Normalizes the <paramref name="binaryExpression" />.
		/// </summary>
		public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax binaryExpression)
		{
			var expressionType = DetermineType(binaryExpression);
			if (expressionType == ExpressionType.Other)
				return base.VisitBinaryExpression(binaryExpression);

			var left = ReplaceImplicitConversion(expressionType, binaryExpression.Left);
			var right = ReplaceImplicitConversion(expressionType, binaryExpression.Right);
			return binaryExpression.Update(left, binaryExpression.OperatorToken, right);
		}
 internal static SyntaxNode CreateNestedIf(BinaryExpressionSyntax condition, SyntaxNode root)
 {
     var ifStatement = condition.FirstAncestorOfType<IfStatementSyntax>();
     var nestedIf = SyntaxFactory.IfStatement(condition.Right, ifStatement.Statement);
     var newStatement = ifStatement.Statement.IsKind(SyntaxKind.Block) ? (StatementSyntax)SyntaxFactory.Block(nestedIf) : nestedIf;
     var newIf = ifStatement.WithCondition(condition.Left)
         .WithStatement(newStatement)
         .WithAdditionalAnnotations(Formatter.Annotation);
     var newRoot = root.ReplaceNode(ifStatement, newIf);
     return newRoot;
 }
        private async Task<Document> IntegrateStringsAsync(Document document, BinaryExpressionSyntax addExpression, CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var newExpression = ToIntegratedString(addExpression.Left, addExpression.Right);

            var newRoot = root.ReplaceNode(addExpression, newExpression);

            var newDocument = document.WithSyntaxRoot(newRoot);

            return newDocument;
        }
        static bool CheckConditionAndAssignment(SyntaxNodeAnalysisContext nodeContext, AssignmentExpressionSyntax assignment, BinaryExpressionSyntax condition)
        {
            if (assignment == null)
                return false;

            var assignmentTarget = nodeContext.SemanticModel.GetSymbolInfo(assignment.Left).Symbol;
            if (assignmentTarget == null)
                return false;

            var condLeftSymbol = nodeContext.SemanticModel.GetSymbolInfo(condition.Left).Symbol;
            var condRightSymbol = nodeContext.SemanticModel.GetSymbolInfo(condition.Right).Symbol;

            var assignmentValue = nodeContext.SemanticModel.GetSymbolInfo(assignment.Right).Symbol;
            var constant = nodeContext.SemanticModel.GetConstantValue(assignment.Right);

            bool constantAssignment = assignmentValue == null && constant.HasValue;

            if (assignmentTarget.Equals(condLeftSymbol))
            {
                if (constantAssignment)
                {
                    var condRightValue = nodeContext.SemanticModel.GetConstantValue(condition.Right);
                    if (condRightValue.HasValue)
                        return condRightValue.Value == constant.Value;
                }
                else
                {
                    if ((assignmentValue == null) || !assignmentValue.Equals(condRightSymbol))
                        return false;
                }
                return true;
            }

            // flipped operands
            if (assignmentTarget.Equals(condRightSymbol))
            {
                if (constantAssignment)
                {
                    var condLeftValue = nodeContext.SemanticModel.GetConstantValue(condition.Left);
                    if (condLeftValue.HasValue)
                        return condLeftValue.Value == constant.Value;
                }
                else
                {
                    if ((assignmentValue == null) || !assignmentValue.Equals(condLeftSymbol))
                        return false;
                }
                return true;
            }

            return false;
        }
 private static async Task<Document> ChangeToIsNotAsync(Document document, UnaryExpressionSyntax unary, BinaryExpressionSyntax isExpression,
     CancellationToken cancellationToken)
 {
     var root = await document.GetSyntaxRootAsync(cancellationToken);
     var newRoot = root.ReplaceNode(
         unary,
         SyntaxFactory.BinaryExpression(
             SyntaxKind.IsNotExpression,
             isExpression.Left,
             SyntaxFactory.Token(SyntaxKind.IsNotKeyword).WithTriviaFrom(isExpression.OperatorToken),
             isExpression.Right));
     return document.WithSyntaxRoot(newRoot);
 }
 internal static ExpressionSyntax GetLeftSide(BinaryExpressionSyntax expression)
 {
     var parent = expression.Parent as BinaryExpressionSyntax;
     if (parent != null)
     {
         if (parent.Right.IsEquivalentTo(expression))
         {
             var parentClone = parent.WithRight(expression.Left);
             return parentClone;
         }
     }
     return expression.Left;
 }
        Document PerformAction(Document document, SyntaxNode root, BinaryExpressionSyntax boP, ExpressionSyntax flagsExpression, ExpressionSyntax targetExpression, bool testFlagset)
        {
            var nodeToReplace = boP.SkipParens();

            var castExpr = BuildHasFlagExpression(targetExpression, flagsExpression);

            if (testFlagset)
            {
                castExpr = SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, castExpr);
            }

            var newRoot = root.ReplaceNode((SyntaxNode)nodeToReplace, castExpr.WithAdditionalAnnotations(Formatter.Annotation));
            return document.WithSyntaxRoot(newRoot);
        }
 SyntaxNode CreateEquals(SemanticModel model, BinaryExpressionSyntax node)
 {
     var expr = SyntaxFactory.InvocationExpression(
         GenerateTarget(model, node),
         SyntaxFactory.ArgumentList(
             new SeparatedSyntaxList<ArgumentSyntax>()
             .Add(SyntaxFactory.Argument(node.Left))
             .Add(SyntaxFactory.Argument(node.Right))
         )
     );
     if (node.IsKind(SyntaxKind.NotEqualsExpression))
         return SyntaxFactory.PrefixUnaryExpression(SyntaxKind.LogicalNotExpression, expr).WithAdditionalAnnotations(Formatter.Annotation);
     return expr.WithAdditionalAnnotations(Formatter.Annotation);
 }
        public override void VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            node.Left.Accept(this);
            node.Right.Accept(this);

            switch (node.Kind())
            {
                case SyntaxKind.LogicalAndExpression:
                case SyntaxKind.LogicalOrExpression:
                    break;
                default:
                    throw new InvalidPreprocessorExpressionException("Expected logical and/or expression");
            }
        }
        public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            node = node.WithLeft((ExpressionSyntax)base.Visit((SyntaxNode)node.Left));
            node = node.WithRight((ExpressionSyntax)base.Visit((SyntaxNode)node.Right));

            switch (node.Left.Kind)
            {
                case SyntaxKind.CharacterLiteralExpression:
                case SyntaxKind.FalseLiteralExpression:
                case SyntaxKind.NumericLiteralExpression:
                case SyntaxKind.StringLiteralExpression:
                case SyntaxKind.TrueLiteralExpression:
                    break;
                default:
                    return node;
            }
            switch (node.Right.Kind)
            {
                case SyntaxKind.CharacterLiteralExpression:
                case SyntaxKind.FalseLiteralExpression:
                case SyntaxKind.NumericLiteralExpression:
                case SyntaxKind.StringLiteralExpression:
                case SyntaxKind.TrueLiteralExpression:
                    break;
                default:
                    return node;
            }

            dynamic nodeValue = (dynamic)session.Execute(node.ToFullString());
            if (nodeValue is String)
            {
                return Syntax.LiteralExpression(SyntaxKind.StringLiteralExpression, Syntax.Literal(nodeValue));
            }
            else if (nodeValue is Char)
            {
                return Syntax.LiteralExpression(SyntaxKind.CharacterLiteralExpression, Syntax.Literal(nodeValue));
            }
            else if (nodeValue is Boolean)
            {
                if (nodeValue == true)
                {
                    return Syntax.LiteralExpression(SyntaxKind.TrueLiteralExpression, Syntax.Token(SyntaxKind.TrueKeyword));
                }
                else
                {
                    return Syntax.LiteralExpression(SyntaxKind.FalseLiteralExpression, Syntax.Token(SyntaxKind.FalseKeyword));
                }
            }
            return Syntax.LiteralExpression(SyntaxKind.NumericLiteralExpression, Syntax.Literal(nodeValue));
        }
        private bool IsEqualButNotTheSame(BinaryExpressionSyntax exp1, BinaryExpressionSyntax exp2, SemanticModel semanticModel)
        {
            if (exp1.Equals(exp2)) return false;

            var exp1AndNestings = exp1.DescendantNodesAndSelf().OfType<BinaryExpressionSyntax>().ToList();
            var exp2AndNestings = exp2.DescendantNodesAndSelf().OfType<BinaryExpressionSyntax>().ToList();

            if (exp1AndNestings.Count() != exp2AndNestings.Count()) return false;

            for (var i = 0; i < exp1AndNestings.Count(); i++)
            {
                if (!IsOperatorEqual(exp1AndNestings[i], exp2AndNestings[i])) return false;
                if (!AreContainedLiteralExpressionsEqual(exp1AndNestings[i], exp2AndNestings[i])) return false;
                if (!AreContainedSymbolsEqual(exp1AndNestings[i], exp2AndNestings[i], semanticModel)) return false;
            }
            return true;
        }
        private static ExpressionSyntax GetRefactoredExpression(BinaryExpressionSyntax binary)
        {
            var typeofExpression = binary.Left as TypeOfExpressionSyntax;
            var getTypeSide = binary.Right;
            if (typeofExpression == null)
            {
                typeofExpression = (TypeOfExpressionSyntax)binary.Right;
                getTypeSide = binary.Left;
            }

            var isOperatorCall = GetIsOperatorCall(typeofExpression, getTypeSide, true);

            return binary.IsKind(SyntaxKind.EqualsExpression)
                ? GetExpressionWithParensIfNeeded(isOperatorCall, binary.Parent)
                : SyntaxFactory.PrefixUnaryExpression(
                    SyntaxKind.LogicalNotExpression,
                    SyntaxFactory.ParenthesizedExpression(isOperatorCall));
        }
            public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
            {
                var result = base.VisitBinaryExpression(node);
                var reducedNode = result as BinaryExpressionSyntax;
                if (reducedNode != node && reducedNode != null)
                {
                    if ((node.Left.IsKind(SyntaxKind.CastExpression) && !reducedNode.Left.IsKind(SyntaxKind.CastExpression)) ||
                        (node.Right.IsKind(SyntaxKind.CastExpression) && !reducedNode.Right.IsKind(SyntaxKind.CastExpression)))
                    {
                        // Cast simplification inside a binary expression, check if we need to parenthesize the binary expression to avoid breaking parent syntax.
                        // For example, cast removal in below case leads to syntax errors in error free code, unless parenting binary expression is parenthesized:
                        //   Original:                  Foo(x < (int)i, x > y)
                        //   Incorrect cast removal:    Foo(x < i, x > y)
                        //   Correct cast removal:      Foo((x < i), x > y)

                        // We'll do the following to detect such cases:
                        // 1) Get the topmostExpressionAncestor of node.
                        // 2) Get the reducedAncestor after replacing node with reducedNode within it.
                        // 3) Reparse the reducedAncestor to get reparsedAncestor.
                        // 4) Check for syntax equivalence of reducedAncestor and reparsedAncestor. If not syntactically equivalent,
                        //    then cast removal breaks the syntax and needs explicit parentheses around the binary expression.

                        var topmostExpressionAncestor = node
                            .AncestorsAndSelf()
                            .OfType<ExpressionSyntax>()
                            .LastOrDefault();

                        if (topmostExpressionAncestor != null && topmostExpressionAncestor != node)
                        {
                            var reducedAncestor = topmostExpressionAncestor.ReplaceNode(node, reducedNode);
                            var reparsedAncestor = SyntaxFactory.ParseExpression(reducedAncestor.ToFullString());
                            if (reparsedAncestor != null && !reparsedAncestor.IsEquivalentTo(reducedAncestor))
                            {
                                return SyntaxFactory.ParenthesizedExpression(reducedNode)
                                    .WithAdditionalAnnotations(Simplifier.Annotation);
                            }
                        }
                    }
                }

                return result;
            }
Example #31
0
        internal static IEnumerable <CodeAction> ScanIfElse(SemanticModel ctx, Document document, SyntaxNode root, IfStatementSyntax ifElseStatement, BinaryExpressionSyntax isExpression, out int foundCastCount)
        {
            foundCastCount = 0;

            var innerCondition = ifElseStatement.Condition.SkipParens();

            if (innerCondition != null && innerCondition.IsKind(SyntaxKind.LogicalNotExpression))
            {
                var c2 = ((PrefixUnaryExpressionSyntax)innerCondition).Operand.SkipParens();
                if (c2.IsKind(SyntaxKind.IsExpression))
                {
                    return(HandleNegatedCase(ctx, document, root, ifElseStatement, ifElseStatement.Condition, isExpression, out foundCastCount));
                }
                return(Enumerable.Empty <CodeAction>());
            }

            var castToType       = isExpression.Right;
            var embeddedStatment = ifElseStatement.Statement;

            var rr = ctx.GetTypeInfo(castToType);

            if (rr.Type == null || !rr.Type.IsReferenceType)
            {
                return(Enumerable.Empty <CodeAction>());
            }
            List <SyntaxNode> foundCasts;

            foundCasts = embeddedStatment.DescendantNodesAndSelf(n => !IsCast(ctx, n, rr.Type)).Where(arg => IsCast(ctx, arg, rr.Type)).ToList();
            foundCasts.AddRange(ifElseStatement.Condition.DescendantNodesAndSelf(n => !IsCast(ctx, n, rr.Type)).Where(arg => arg.SpanStart > isExpression.Span.End && IsCast(ctx, arg, rr.Type)));
            foundCastCount = foundCasts.Count;

            return(new[] {
                CodeActionFactory.Create(
                    isExpression.Span,
                    DiagnosticSeverity.Info,
                    GettextCatalog.GetString("Use 'as' and check for null"),
                    t2 => {
                    var varName = NameGenerator.GenerateSafeCSharpName(
                        ReplaceAutoPropertyWithPropertyAndBackingFieldCodeRefactoringProvider.GetNameProposal(RefactoringHelpers.GuessNameFromType(rr.Type), ctx, isExpression));

                    var varDec = SyntaxFactory.LocalDeclarationStatement(
                        SyntaxFactory.VariableDeclaration(
                            SyntaxFactory.ParseTypeName("var"),
                            SyntaxFactory.SeparatedList(new [] {
                        SyntaxFactory.VariableDeclarator(varName)
                        .WithInitializer(SyntaxFactory.EqualsValueClause(
                                             SyntaxFactory.BinaryExpression(SyntaxKind.AsExpression, isExpression.Left, isExpression.Right)
                                             ))
                    })
                            ));
                    var outerIs = isExpression.AncestorsAndSelf().FirstOrDefault(e => !(e.Parent is ParenthesizedExpressionSyntax));
                    var binaryOperatorExpression = SyntaxFactory.BinaryExpression(SyntaxKind.NotEqualsExpression, SyntaxFactory.IdentifierName(varName), SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression));
                    SyntaxNode newRoot;
                    if (IsEmbeddedStatement(ifElseStatement))
                    {
                        foundCasts = ifElseStatement.DescendantNodesAndSelf(n => !IsCast(ctx, n, rr.Type)).Where(arg => IsCast(ctx, arg, rr.Type)).ToList();
                        var newIf = ifElseStatement.TrackNodes(foundCasts.Concat(new [] { outerIs }));

                        newIf = newIf.ReplaceNode((SyntaxNode)newIf.GetCurrentNode(outerIs), binaryOperatorExpression.WithAdditionalAnnotations(Formatter.Annotation));

                        foreach (var c in foundCasts)
                        {
                            newIf = newIf.ReplaceNode((SyntaxNode)newIf.GetCurrentNode(c), SyntaxFactory.IdentifierName(varName).WithAdditionalAnnotations(Formatter.Annotation));
                        }

                        var block = SyntaxFactory.Block(new StatementSyntax[] {
                            varDec,
                            newIf
                        });
                        newRoot = root.ReplaceNode((SyntaxNode)ifElseStatement, block.WithAdditionalAnnotations(Formatter.Annotation));
                    }
                    else
                    {
                        newRoot = root.TrackNodes(foundCasts.Concat(new SyntaxNode[] { ifElseStatement, outerIs }));
                        newRoot = newRoot.InsertNodesBefore(newRoot.GetCurrentNode(ifElseStatement), new [] { varDec.WithAdditionalAnnotations(Formatter.Annotation) });
                        newRoot = newRoot.ReplaceNode((SyntaxNode)newRoot.GetCurrentNode(outerIs), binaryOperatorExpression.WithAdditionalAnnotations(Formatter.Annotation));
                        foreach (var c in foundCasts)
                        {
                            newRoot = newRoot.ReplaceNode((SyntaxNode)newRoot.GetCurrentNode(c), SyntaxFactory.IdentifierName(varName).WithAdditionalAnnotations(Formatter.Annotation));
                        }
                    }

                    return Task.FromResult(document.WithSyntaxRoot(newRoot));
                }
                    )
            });
        }
        private ProgramState VisitComparisonBinaryOperator(ProgramState programState, BinaryExpressionSyntax comparison,
                                                           Func <SymbolicValue, SymbolicValue, SymbolicValue> svFactory)
        {
            var newProgramState = programState
                                  .PopValue(out var rightSymbol)
                                  .PopValue(out var leftSymbol);

            var op = SemanticModel.GetSymbolInfo(comparison).Symbol as IMethodSymbol;

            var isValueTypeOperator = op?.ContainingType?.IsValueType ?? false;

            var isLiftedOperator = isValueTypeOperator &&
                                   (leftSymbol.IsNull(programState) || rightSymbol.IsNull(programState));

            var comparisonValue = isLiftedOperator ? SymbolicValue.False : svFactory(leftSymbol, rightSymbol);

            return(newProgramState.PushValue(comparisonValue));
        }
 public override void VisitBinaryExpression(BinaryExpressionSyntax node)
 {
     Check(node.Left);
     Check(node.Right);
 }
Example #34
0
        private static async Task <Document> UseConditionalAccessAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            SyntaxKind kind = binaryExpression.Kind();

            (ExpressionSyntax left, ExpressionSyntax right) = UseConditionalAccessAnalyzer.GetFixableExpressions(binaryExpression, kind, semanticModel, cancellationToken);

            NullCheckStyles allowedStyles = (kind == SyntaxKind.LogicalAndExpression)
                ? NullCheckStyles.NotEqualsToNull
                : NullCheckStyles.EqualsToNull;

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

            ExpressionSyntax expression = nullCheck.Expression;

            bool isNullable = semanticModel.GetTypeSymbol(expression, cancellationToken).IsNullableType();

            ExpressionSyntax expression2 = UseConditionalAccessAnalyzer.FindExpressionThatCanBeConditionallyAccessed(
                expression,
                right,
                isNullable: isNullable,
                semanticModel,
                cancellationToken);

            var builder = new SyntaxNodeTextBuilder(binaryExpression, StringBuilderCache.GetInstance(binaryExpression.FullSpan.Length));

            builder.Append(TextSpan.FromBounds(binaryExpression.FullSpan.Start, left.SpanStart));

            int parenDiff = GetParenTokenDiff();

            if (parenDiff > 0)
            {
                builder.Append('(', parenDiff);
            }

            builder.AppendSpan(expression);
            builder.Append("?");
            builder.Append(TextSpan.FromBounds(expression2.Span.End, right.Span.End));

            switch (right.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;
            }

            case SyntaxKind.LogicalNotExpression:
            {
                builder.Append((kind == SyntaxKind.LogicalAndExpression) ? " == false" : " != true");
                break;
            }

            default:
            {
                builder.Append((kind == SyntaxKind.LogicalAndExpression) ? " == true" : " != false");
                break;
            }
            }

            if (parenDiff < 0)
            {
                builder.Append(')', -parenDiff);
            }

            builder.Append(TextSpan.FromBounds(right.Span.End, binaryExpression.FullSpan.End));

            string text = StringBuilderCache.GetStringAndFree(builder.StringBuilder);

            ParenthesizedExpressionSyntax newNode = SyntaxFactory.ParseExpression(text)
                                                    .WithFormatterAnnotation()
                                                    .Parenthesize();

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

            int GetParenTokenDiff()
            {
                int count = 0;

                foreach (SyntaxToken token in binaryExpression.DescendantTokens(TextSpan.FromBounds(left.SpanStart, expression2.Span.End)))
                {
                    SyntaxKind tokenKind = token.Kind();

                    if (tokenKind == SyntaxKind.OpenParenToken)
                    {
                        if (token.IsParentKind(SyntaxKind.ParenthesizedExpression))
                        {
                            count++;
                        }
                    }
                    else if (tokenKind == SyntaxKind.CloseParenToken)
                    {
                        if (token.IsParentKind(SyntaxKind.ParenthesizedExpression))
                        {
                            count--;
                        }
                    }
                }

                return(count);
            }
        }
Example #35
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression))
            {
                return;
            }

            Document document = context.Document;

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.ConstantValuesShouldBePlacedOnRightSideOfComparisons:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Swap operands",
                        ct => document.ReplaceNodeAsync(binaryExpression, SyntaxRefactorings.SwapBinaryOperands(binaryExpression), ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        ct => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        ct => SimplifyCoalesceExpressionRefactoring.RefactorAsync(document, binaryExpression, expression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        ct => RemoveRedundantAsOperatorRefactoring.RefactorAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        ct => UseStringLengthInsteadOfComparisonWithEmptyStringAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use EqualityComparer<{typeSymbol.Name}>.Default",
                        ct => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    string title;

                    if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) ||
                        typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName))
                    {
                        ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions());

                        title = $"Replace 'null' with '{expression}'";
                    }
                    else
                    {
                        title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.DisplayName)}>.Default";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        ct => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.JoinStringExpressions:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Join string expressions",
                        ct => JoinStringExpressionsRefactoring.RefactorAsync(document, binaryExpression, context.Span, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseExclusiveOrOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use ^ operator",
                        ct => UseExclusiveOrOperatorRefactoring.RefactorAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UnnecessaryNullCheck:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary null check",
                        ct => RemoveUnnecessaryNullCheckAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseShortCircuitingOperator:
                {
                    SyntaxToken operatorToken = binaryExpression.OperatorToken;

                    SyntaxKind kind = binaryExpression.Kind();

                    SyntaxToken newToken = default;

                    if (kind == SyntaxKind.BitwiseAndExpression)
                    {
                        newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, operatorToken.TrailingTrivia);
                    }
                    else if (kind == SyntaxKind.BitwiseOrExpression)
                    {
                        newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.BarBarToken, operatorToken.TrailingTrivia);
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Use '{newToken.ToString()}' operator",
                        ct =>
                        {
                            BinaryExpressionSyntax newBinaryExpression = null;

                            if (kind == SyntaxKind.BitwiseAndExpression)
                            {
                                newBinaryExpression = LogicalAndExpression(binaryExpression.Left, newToken, binaryExpression.Right);
                            }
                            else if (kind == SyntaxKind.BitwiseOrExpression)
                            {
                                newBinaryExpression = LogicalOrExpression(binaryExpression.Left, newToken, binaryExpression.Right);
                            }

                            return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UnnecessaryOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use '==' operator",
                        ct =>
                        {
                            SyntaxToken operatorToken = binaryExpression.OperatorToken;

                            BinaryExpressionSyntax newBinaryExpression = EqualsExpression(
                                binaryExpression.Left,
                                Token(operatorToken.LeadingTrivia, SyntaxKind.EqualsEqualsToken, operatorToken.TrailingTrivia),
                                binaryExpression.Right);

                            return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        private static bool IsTopLevelSubtraction(BinaryExpressionSyntax subtraction)
        {
            var parent = subtraction.Parent as BinaryExpressionSyntax;

            return(parent == null || !parent.IsKind(SyntaxKind.SubtractExpression));
        }
Example #37
0
 private static bool IsStringConcatenation(SyntaxNodeAnalysisContext context, BinaryExpressionSyntax binaryExpression)
 {
     return(binaryExpression.IsKind(SyntaxKind.AddExpression) &&
            (IsStringExpression(context, binaryExpression.Left) || IsStringExpression(context, binaryExpression.Right)));
 }
Example #38
0
 public override void VisitBinaryExpression(BinaryExpressionSyntax node)
 {
     Emit <BinaryExpressionBlock, BinaryExpressionSyntax>(node);
 }
 private static IsPatternExpressionSyntax RewriteWorker(BinaryExpressionSyntax binary)
 => binary.Right.IsKind(SyntaxKind.NullLiteralExpression)
         ? Rewrite(binary, binary.Left, binary.Right)
         : Rewrite(binary, binary.Right, binary.Left);
 private bool IsVariableAndLiteralBinaryExpression(BinaryExpressionSyntax binaryExpression, string identifierName) =>
 (IsIdentifier(binaryExpression.Left, identifierName) && binaryExpression.Right.IsKind(SyntaxKind.NumericLiteralExpression)) ||
 (binaryExpression.Left.IsKind(SyntaxKind.NumericLiteralExpression) && IsIdentifier(binaryExpression.Right, identifierName));
 private static bool IsShortcuttingExpression(BinaryExpressionSyntax expression, bool constantValueIsTrue)
 {
     return(expression != null &&
            (expression.IsKind(SyntaxKind.LogicalAndExpression) && !constantValueIsTrue ||
             expression.IsKind(SyntaxKind.LogicalOrExpression) && constantValueIsTrue));
 }
Example #42
0
        private bool TryCheckVariableAndIfStatementForm(
            SyntaxNodeAnalysisContext syntaxContext,
            IfStatementSyntax ifStatement,
            BinaryExpressionSyntax condition,
            ExpressionStatementSyntax expressionStatement,
            InvocationExpressionSyntax invocationExpression,
            ReportDiagnostic severity)
        {
            var cancellationToken = syntaxContext.CancellationToken;

            cancellationToken.ThrowIfCancellationRequested();

            // look for the form "if (a != null)" or "if (null != a)"
            if (!ifStatement.Parent.IsKind(SyntaxKind.Block))
            {
                return(false);
            }

            if (!IsNullCheckExpression(condition.Left, condition.Right) &&
                !IsNullCheckExpression(condition.Right, condition.Left))
            {
                return(false);
            }

            var expression = invocationExpression.Expression;

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

            var conditionName = condition.Left is IdentifierNameSyntax
                ? (IdentifierNameSyntax)condition.Left
                : (IdentifierNameSyntax)condition.Right;

            var invocationName = (IdentifierNameSyntax)expression;

            if (!Equals(conditionName.Identifier.ValueText, invocationName.Identifier.ValueText))
            {
                return(false);
            }

            // Now make sure the previous statement is "var a = ..."
            var parentBlock = (BlockSyntax)ifStatement.Parent;
            var ifIndex     = parentBlock.Statements.IndexOf(ifStatement);

            if (ifIndex == 0)
            {
                return(false);
            }

            var previousStatement = parentBlock.Statements[ifIndex - 1];

            if (!previousStatement.IsKind(SyntaxKind.LocalDeclarationStatement))
            {
                return(false);
            }

            var localDeclarationStatement = (LocalDeclarationStatementSyntax)previousStatement;
            var variableDeclaration       = localDeclarationStatement.Declaration;

            if (variableDeclaration.Variables.Count != 1)
            {
                return(false);
            }

            var declarator = variableDeclaration.Variables[0];

            if (declarator.Initializer == null)
            {
                return(false);
            }

            cancellationToken.ThrowIfCancellationRequested();
            if (!Equals(declarator.Identifier.ValueText, conditionName.Identifier.ValueText))
            {
                return(false);
            }

            // Syntactically this looks good.  Now make sure that the local is a delegate type.
            var semanticModel = syntaxContext.SemanticModel;
            var localSymbol   = (ILocalSymbol)semanticModel.GetDeclaredSymbol(declarator, cancellationToken);

            // Ok, we made a local just to check it for null and invoke it.  Looks like something
            // we can suggest an improvement for!
            // But first make sure we're only using the local only within the body of this if statement.
            var analysis = semanticModel.AnalyzeDataFlow(localDeclarationStatement, ifStatement);

            if (analysis.ReadOutside.Contains(localSymbol) || analysis.WrittenOutside.Contains(localSymbol))
            {
                return(false);
            }

            // Looks good!
            var tree = semanticModel.SyntaxTree;
            var additionalLocations = new List <Location>
            {
                Location.Create(tree, localDeclarationStatement.Span),
                Location.Create(tree, ifStatement.Span),
                Location.Create(tree, expressionStatement.Span)
            };

            ReportDiagnostics(syntaxContext,
                              localDeclarationStatement, ifStatement, expressionStatement,
                              severity, additionalLocations, Constants.VariableAndIfStatementForm);

            return(true);
        }
        public bool TryGetPatternPieces(
            BinaryExpressionSyntax isExpression,
            out IfStatementSyntax ifStatement,
            out LocalDeclarationStatementSyntax localDeclarationStatement,
            out VariableDeclaratorSyntax declarator,
            out CastExpressionSyntax castExpression)
        {
            ifStatement = null;
            localDeclarationStatement = null;
            declarator     = null;
            castExpression = null;

            // The is check has to be in an if check: "if (x is Type)
            if (!isExpression.Parent.IsKind(SyntaxKind.IfStatement, out ifStatement))
            {
                return(false);
            }

            if (!ifStatement.Statement.IsKind(SyntaxKind.Block, out BlockSyntax ifBlock))
            {
                return(false);
            }

            if (ifBlock.Statements.Count == 0)
            {
                return(false);
            }

            var firstStatement = ifBlock.Statements[0];

            if (!firstStatement.IsKind(SyntaxKind.LocalDeclarationStatement, out localDeclarationStatement))
            {
                return(false);
            }

            if (localDeclarationStatement.Declaration.Variables.Count != 1)
            {
                return(false);
            }

            declarator = localDeclarationStatement.Declaration.Variables[0];
            if (declarator.Initializer == null)
            {
                return(false);
            }

            var declaratorValue = declarator.Initializer.Value.WalkDownParentheses();

            if (!declaratorValue.IsKind(SyntaxKind.CastExpression, out castExpression))
            {
                return(false);
            }

            if (!SyntaxFactory.AreEquivalent(isExpression.Left.WalkDownParentheses(), castExpression.Expression.WalkDownParentheses(), topLevel: false) ||
                !SyntaxFactory.AreEquivalent(isExpression.Right.WalkDownParentheses(), castExpression.Type, topLevel: false))
            {
                return(false);
            }

            return(true);
        }
Example #44
0
 public Task <Document> RefactorAsync(
     Document document,
     IfStatementSyntax ifStatement,
     BinaryExpressionSyntax condition,
     in ExpressionChain expressionChain,
Example #45
0
 private static void CheckRightExpressionForRemovableToStringCall(SyntaxNodeAnalysisContext context,
                                                                  BinaryExpressionSyntax binary)
 {
     CheckExpressionForRemovableToStringCall(context, binary.Right, binary.Left, 1);
 }
Example #46
0
        public override void VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            var ci   = m_ClassInfoStack.Peek();
            var oper = m_Model.GetOperation(node) as IHasOperatorMethodExpression;

            if (null != oper && oper.UsesOperatorMethod)
            {
                IMethodSymbol msym     = oper.OperatorMethod;
                var           castOper = oper as IConversionExpression;
                if (null != castOper)
                {
                    InvocationInfo ii      = new InvocationInfo();
                    var            arglist = new List <ExpressionSyntax>()
                    {
                        node.Left
                    };
                    ii.Init(msym, arglist, m_Model);
                    OutputOperatorInvoke(ii, node);
                }
                else
                {
                    InvocationInfo ii      = new InvocationInfo();
                    var            arglist = new List <ExpressionSyntax>()
                    {
                        node.Left, node.Right
                    };
                    ii.Init(msym, arglist, m_Model);
                    OutputOperatorInvoke(ii, node);
                }
            }
            else
            {
                string op = node.OperatorToken.Text;
                ProcessBinaryOperator(node, ref op);
                string functor;
                if (s_BinaryFunctor.TryGetValue(op, out functor))
                {
                    CodeBuilder.AppendFormat("{0}(", functor);
                    VisitExpressionSyntax(node.Left);
                    CodeBuilder.Append(", ");
                    if (op == "as" || op == "is")
                    {
                        var typeInfo = m_Model.GetTypeInfo(node.Right);
                        var type     = typeInfo.Type;
                        OutputType(type, node, ci, op);
                    }
                    else if (op == "??")
                    {
                        var  rightOper    = m_Model.GetOperation(node.Right);
                        bool rightIsConst = null != rightOper && rightOper.ConstantValue.HasValue;
                        if (rightIsConst)
                        {
                            CodeBuilder.Append("true, ");
                            VisitExpressionSyntax(node.Right);
                        }
                        else
                        {
                            CodeBuilder.Append("false, (function() return ");
                            VisitExpressionSyntax(node.Right);
                            CodeBuilder.Append("; end)");
                        }
                    }
                    else
                    {
                        VisitExpressionSyntax(node.Right);
                    }
                    CodeBuilder.Append(")");
                }
                else if (op == "+")
                {
                    ProcessAddOrStringConcat(node.Left, node.Right);
                }
                else if (op == "==" || op == "~=")
                {
                    ProcessEqualOrNotEqual(op, node.Left, node.Right);
                }
                else
                {
                    CodeBuilder.Append("(");
                    VisitExpressionSyntax(node.Left);
                    CodeBuilder.AppendFormat(" {0} ", op);
                    VisitExpressionSyntax(node.Right);
                    CodeBuilder.Append(")");
                }
            }
        }
Example #47
0
        public override JsExpression VisitBinaryExpression(BinaryExpressionSyntax node)
        {
            switch (node.Kind())
            {
            case SyntaxKind.IsExpression:
            {
                var operand = node.Left.Accept(this);
                var type    = (INamedTypeSymbol)model.GetSymbolInfo(node.Right).Symbol;
                var typeIs  = GetExpressionMethod("TypeIs", Context.Instance.Expression, Context.Instance.TypeType);
                return(idioms.InvokeStatic(typeIs, operand, idioms.TypeOf(type)));
            }

            case SyntaxKind.AsExpression:
            {
                var operand = node.Left.Accept(this);
                var type    = (INamedTypeSymbol)model.GetSymbolInfo(node.Right).Symbol;
                var typeAs  = GetExpressionMethod("TypeAs", Context.Instance.Expression, Context.Instance.TypeType);
                return(idioms.InvokeStatic(typeAs, operand, idioms.TypeOf(type)));
            }
            }

            ExpressionType op;

            switch (node.Kind())
            {
            case SyntaxKind.AddExpression:
                op = ExpressionType.Add;
                break;

            case SyntaxKind.MultiplyExpression:
                op = ExpressionType.Multiply;
                break;

            case SyntaxKind.BitwiseAndExpression:
                op = ExpressionType.And;
                break;

            case SyntaxKind.BitwiseOrExpression:
                op = ExpressionType.Or;
                break;

            case SyntaxKind.DivideExpression:
                op = ExpressionType.Divide;
                break;

            case SyntaxKind.GreaterThanExpression:
                op = ExpressionType.GreaterThan;
                break;

            case SyntaxKind.EqualsExpression:
                op = ExpressionType.Equal;
                break;

            case SyntaxKind.ExclusiveOrExpression:
                op = ExpressionType.OrElse;
                break;

            case SyntaxKind.GreaterThanOrEqualExpression:
                op = ExpressionType.GreaterThanOrEqual;
                break;

            case SyntaxKind.LessThanExpression:
                op = ExpressionType.LessThan;
                break;

            case SyntaxKind.LessThanOrEqualExpression:
                op = ExpressionType.LessThanOrEqual;
                break;

            case SyntaxKind.ModuloExpression:
                op = ExpressionType.Modulo;
                break;

            case SyntaxKind.LeftShiftExpression:
                op = ExpressionType.LeftShift;
                break;

            case SyntaxKind.RightShiftExpression:
                op = ExpressionType.RightShift;
                break;

            case SyntaxKind.SubtractExpression:
                op = ExpressionType.Subtract;
                break;

            case SyntaxKind.CoalesceExpression:
                op = ExpressionType.Coalesce;
                break;

            case SyntaxKind.LogicalAndExpression:
                op = ExpressionType.AndAlso;
                break;

            case SyntaxKind.LogicalOrExpression:
                op = ExpressionType.OrElse;
                break;

            default:
                throw new Exception("Unknown operation: " + node.Kind());
            }

            var left  = node.Left.Accept(this);
            var right = node.Right.Accept(this);

            var jsMethodInfo = GetExpressionMethod("MakeBinary", Context.Instance.ExpressionType, Context.Instance.Expression, Context.Instance.Expression);
            var opExpression = idioms.GetEnumValue(Context.Instance.ExpressionType.GetMembers(op.ToString()).OfType <IFieldSymbol>().Single());

            var jsMethod = idioms.InvokeStatic(jsMethodInfo, opExpression, left, right);

            return(jsMethod);
        }
Example #48
0
        private static async Task <ExpressionSyntax> CreateNewNodeAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax left  = binaryExpression.Left;
            ExpressionSyntax right = binaryExpression.Right;

            TextSpan span = TextSpan.FromBounds(left.Span.End, right.SpanStart);

            IEnumerable <SyntaxTrivia> trivia = binaryExpression.DescendantTrivia(span);

            bool isWhiteSpaceOrEndOfLine = trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia());

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

            if (CSharpFacts.IsBooleanLiteralExpression(left.Kind()))
            {
                SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia();

                if (!isWhiteSpaceOrEndOfLine)
                {
                    leadingTrivia = leadingTrivia.AddRange(trivia);
                }

                if (right.IsKind(SyntaxKind.LogicalNotExpression))
                {
                    var logicalNot = (PrefixUnaryExpressionSyntax)right;

                    ExpressionSyntax operand = logicalNot.Operand;

                    if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean))
                    {
                        return(binaryExpression
                               .WithLeft(Inverter.LogicallyNegate(left, semanticModel, cancellationToken))
                               .WithRight(operand.WithTriviaFrom(right)));
                    }
                }

                return(Inverter.LogicallyNegate(right, semanticModel, cancellationToken)
                       .WithLeadingTrivia(leadingTrivia));
            }
            else if (CSharpFacts.IsBooleanLiteralExpression(right.Kind()))
            {
                SyntaxTriviaList trailingTrivia = binaryExpression.GetTrailingTrivia();

                if (!isWhiteSpaceOrEndOfLine)
                {
                    trailingTrivia = trailingTrivia.InsertRange(0, trivia);
                }

                if (left.IsKind(SyntaxKind.LogicalNotExpression))
                {
                    var logicalNot = (PrefixUnaryExpressionSyntax)left;

                    ExpressionSyntax operand = logicalNot.Operand;

                    if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean))
                    {
                        return(binaryExpression
                               .WithLeft(operand.WithTriviaFrom(left))
                               .WithRight(Inverter.LogicallyNegate(right, semanticModel, cancellationToken)));
                    }
                }

                return(Inverter.LogicallyNegate(left, semanticModel, cancellationToken)
                       .WithTrailingTrivia(trailingTrivia));
            }

            Debug.Fail(binaryExpression.ToString());

            return(binaryExpression);
        }
Example #49
0
        private bool ReplacementBreaksIsOrAsExpression(BinaryExpressionSyntax originalIsOrAsExpression, BinaryExpressionSyntax newIsOrAsExpression)
        {
            // Special case: Lambda expressions and anonymous delegates cannot appear
            // on the left-side of an 'is' or 'as' cast. We can handle this case syntactically.
            if (!originalIsOrAsExpression.Left.WalkDownParentheses().IsAnyLambdaOrAnonymousMethod() &&
                newIsOrAsExpression.Left.WalkDownParentheses().IsAnyLambdaOrAnonymousMethod())
            {
                return(true);
            }

            var originalConvertedType = this.OriginalSemanticModel.GetTypeInfo(originalIsOrAsExpression.Right).Type;
            var newConvertedType      = this.SpeculativeSemanticModel.GetTypeInfo(newIsOrAsExpression.Right).Type;

            if (originalConvertedType == null || newConvertedType == null)
            {
                return(originalConvertedType != newConvertedType);
            }

            var originalConversion = this.OriginalSemanticModel.ClassifyConversion(originalIsOrAsExpression.Left, originalConvertedType, isExplicitInSource: true);
            var newConversion      = this.SpeculativeSemanticModel.ClassifyConversion(newIsOrAsExpression.Left, newConvertedType, isExplicitInSource: true);

            // Is and As operators do not consider any user-defined operators, just ensure that the conversion exists.
            return(originalConversion.Exists != newConversion.Exists);
        }
 private static bool IsIgnoredNullableOperation(BinaryExpressionSyntax expression, SemanticModel semanticModel)
 {
     return(expression.OperatorToken.IsAnyKind(ignoredNullableOperators) &&
            (IsNullable(expression.Left, semanticModel) || IsNullable(expression.Right, semanticModel)));
 }
Example #51
0
        private bool ReplacementBreaksBinaryExpression(BinaryExpressionSyntax binaryExpression, BinaryExpressionSyntax newBinaryExpression)
        {
            if ((binaryExpression.IsKind(SyntaxKind.AsExpression) ||
                 binaryExpression.IsKind(SyntaxKind.IsExpression)) &&
                ReplacementBreaksIsOrAsExpression(binaryExpression, newBinaryExpression))
            {
                return(true);
            }

            return(!SymbolsAreCompatible(binaryExpression, newBinaryExpression) ||
                   !TypesAreCompatible(binaryExpression, newBinaryExpression));
        }
Example #52
0
        private static void CheckFollowingExpressions(SyntaxNodeAnalysisContext c, int currentExpressionIndex,
                                                      List <ExpressionSyntax> expressionsInChain,
                                                      ExpressionSyntax expressionComparedToNull, BinaryExpressionSyntax comparisonToNull)
        {
            for (var j = currentExpressionIndex + 1; j < expressionsInChain.Count; j++)
            {
                var descendantNodes = expressionsInChain[j].DescendantNodes()
                                      .Where(descendant =>
                                             descendant.IsKind(expressionComparedToNull.Kind()) &&
                                             EquivalenceChecker.AreEquivalent(expressionComparedToNull, descendant))
                                      .Where(descendant =>
                                             (descendant.Parent is MemberAccessExpressionSyntax &&
                                              EquivalenceChecker.AreEquivalent(expressionComparedToNull,
                                                                               ((MemberAccessExpressionSyntax)descendant.Parent).Expression)) ||
                                             (descendant.Parent is ElementAccessExpressionSyntax &&
                                              EquivalenceChecker.AreEquivalent(expressionComparedToNull,
                                                                               ((ElementAccessExpressionSyntax)descendant.Parent).Expression)))
                                      .ToList();

                if (descendantNodes.Any())
                {
                    c.ReportDiagnostic(Diagnostic.Create(Rule, comparisonToNull.GetLocation(),
                                                         expressionComparedToNull.ToString()));
                }
            }
        }
Example #53
0
        private static async Task <Document> FixAllAsync(
            Document document,
            ImmutableArray <Diagnostic> diagnostics,
            bool negate,
            CancellationToken cancellationToken
            )
        {
            var semanticModel = await document
                                .GetSemanticModelAsync(cancellationToken)
                                .ConfigureAwait(false);

            var root = await document
                       .GetRequiredSyntaxRootAsync(cancellationToken)
                       .ConfigureAwait(false);

            var editor            = new SyntaxEditor(root, document.Project.Solution.Workspace);
            var generator         = editor.Generator;
            var generatorInternal = document.GetRequiredLanguageService <SyntaxGeneratorInternal>();

            foreach (var diagnostic in diagnostics)
            {
                var node = diagnostic.AdditionalLocations[0].FindNode(
                    getInnermostNodeForTie: true,
                    cancellationToken
                    );
                Debug.Assert(
                    node.IsKind(SyntaxKind.IsExpression) ||
                    node.IsKind(SyntaxKind.IsPatternExpression)
                    );

                // Negate the result if requested.
                var updatedNode = negate
                    ? generator.Negate(generatorInternal, node, semanticModel, cancellationToken)
                    : node;

                var isNode = updatedNode
                             .DescendantNodesAndSelf()
                             .First(
                    n =>
                    n.IsKind(SyntaxKind.IsExpression) ||
                    n.IsKind(SyntaxKind.IsPatternExpression)
                    );
                var left = isNode switch
                {
                    BinaryExpressionSyntax binary => binary.Left,
                    IsPatternExpressionSyntax isPattern => isPattern.Expression,
                    _ => throw ExceptionUtilities.UnexpectedValue(node),
                };

                // Remove the suppression operator.
                var suppression        = (PostfixUnaryExpressionSyntax)left;
                var withoutSuppression = suppression.Operand.WithAppendedTrailingTrivia(
                    suppression.OperatorToken.GetAllTrivia()
                    );
                var isWithoutSuppression = updatedNode.ReplaceNode(suppression, withoutSuppression);

                editor.ReplaceNode(node, isWithoutSuppression);
            }

            return(document.WithSyntaxRoot(editor.GetChangedRoot()));
        }
        private static void AnalyzeEqualsNotEquals(
            SyntaxNodeAnalysisContext context,
            BinaryExpressionSyntax binaryExpression,
            ExpressionSyntax left,
            ExpressionSyntax right,
            SyntaxKind kind,
            SyntaxKind kind2)
        {
            SyntaxKind leftKind = left.Kind();

            if (leftKind == kind)
            {
                switch (AnalyzeExpression(right, context.SemanticModel, context.CancellationToken))
                {
                case AnalysisResult.Boolean:
                {
                    SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: true);
                    break;
                }

                case AnalysisResult.LogicalNotWithNullableBoolean:
                {
                    SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                    break;
                }
                }
            }
            else if (leftKind == kind2)
            {
                switch (AnalyzeExpression(right, context.SemanticModel, context.CancellationToken))
                {
                case AnalysisResult.Boolean:
                {
                    RemoveRedundantBooleanLiteralAnalysis.ReportDiagnostic(context, binaryExpression, left, right);
                    break;
                }

                case AnalysisResult.LogicalNotWithNullableBoolean:
                {
                    SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                    break;
                }
                }
            }
            else
            {
                SyntaxKind rightKind = right.Kind();

                if (rightKind == kind)
                {
                    switch (AnalyzeExpression(left, context.SemanticModel, context.CancellationToken))
                    {
                    case AnalysisResult.Boolean:
                    {
                        SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: true);
                        break;
                    }

                    case AnalysisResult.LogicalNotWithNullableBoolean:
                    {
                        SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                        break;
                    }
                    }
                }
                else if (rightKind == kind2)
                {
                    switch (AnalyzeExpression(left, context.SemanticModel, context.CancellationToken))
                    {
                    case AnalysisResult.Boolean:
                    {
                        RemoveRedundantBooleanLiteralAnalysis.ReportDiagnostic(context, binaryExpression, left, right);
                        break;
                    }

                    case AnalysisResult.LogicalNotWithNullableBoolean:
                    {
                        SimplifyBooleanComparisonAnalysis.ReportDiagnostic(context, binaryExpression, left, right, fadeOut: false);
                        break;
                    }
                    }
                }
            }
        }
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, BinaryExpressionSyntax binaryExpression)
        {
            if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateOperator))
            {
                SyntaxToken operatorToken = binaryExpression.OperatorToken;

                if (operatorToken.Span.Contains(context.Span) &&
                    NegateOperatorRefactoring.CanBeNegated(operatorToken))
                {
                    context.RegisterRefactoring(
                        "Negate operator",
                        cancellationToken => NegateOperatorRefactoring.RefactorAsync(context.Document, operatorToken, cancellationToken));
                }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.FormatBinaryExpression))
            {
                FormatBinaryExpressionRefactoring.ComputeRefactorings(context, binaryExpression);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateBinaryExpression))
            {
                NegateBinaryExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExpandCoalesceExpression) &&
                binaryExpression.OperatorToken.Span.Contains(context.Span))
            {
                ExpandCoalesceExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.IsAnyRefactoringEnabled(
                    RefactoringIdentifiers.JoinStringExpressions,
                    RefactoringIdentifiers.UseStringBuilderInsteadOfConcatenation) &&
                context.Span.IsBetweenSpans(binaryExpression) &&
                binaryExpression.IsKind(SyntaxKind.AddExpression))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                StringConcatenationExpressionInfo concatenationInfo = SyntaxInfo.StringConcatenationExpressionInfo(binaryExpression, semanticModel, context.CancellationToken);
                if (concatenationInfo.Success)
                {
                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.JoinStringExpressions))
                    {
                        JoinStringExpressionsRefactoring.ComputeRefactoring(context, concatenationInfo);
                    }

                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.UseStringBuilderInsteadOfConcatenation))
                    {
                        UseStringBuilderInsteadOfConcatenationRefactoring.ComputeRefactoring(context, concatenationInfo);
                    }
                }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.SwapExpressionsInBinaryExpression) &&
                context.Span.IsBetweenSpans(binaryExpression))
            {
                SwapExpressionsInBinaryExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceAsWithCast) &&
                context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(binaryExpression))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                if (ReplaceAsWithCastAnalysis.IsFixable(binaryExpression, semanticModel, context.CancellationToken))
                {
                    context.RegisterRefactoring(
                        "Replace as with cast",
                        cancellationToken => ReplaceAsWithCastRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken));
                }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.NegateIsExpression))
            {
                NegateIsExpressionRefactoring.ComputeRefactoring(context, binaryExpression);
            }

            if (context.Span.IsContainedInSpanOrBetweenSpans(binaryExpression.OperatorToken))
            {
                if (context.IsRefactoringEnabled(RefactoringIdentifiers.ReplaceEqualsExpressionWithStringEquals))
                {
                    await ReplaceEqualsExpressionWithStringEqualsRefactoring.ComputeRefactoringAsync(context, binaryExpression).ConfigureAwait(false);
                }

                if (context.IsAnyRefactoringEnabled(
                        RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrEmpty,
                        RefactoringIdentifiers.ReplaceEqualsExpressionWithStringIsNullOrWhiteSpace))
                {
                    await ReplaceEqualsExpressionRefactoring.ComputeRefactoringsAsync(context, binaryExpression).ConfigureAwait(false);
                }
            }

            if (!context.Span.IsBetweenSpans(binaryExpression) &&
                context.IsAnyRefactoringEnabled(
                    RefactoringIdentifiers.ExtractExpressionFromCondition,
                    RefactoringIdentifiers.JoinStringExpressions))
            {
                BinaryExpressionSelection binaryExpressionSelection = BinaryExpressionSelection.Create(binaryExpression, context.Span);

                if (binaryExpressionSelection.Success &&
                    binaryExpressionSelection.Expressions.Length > 1)
                {
                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExtractExpressionFromCondition))
                    {
                        ExtractConditionRefactoring.ComputeRefactoring(context, binaryExpressionSelection);
                    }

                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.JoinStringExpressions) &&
                        binaryExpression.IsKind(SyntaxKind.AddExpression))
                    {
                        SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                        StringConcatenationExpressionInfo concatenation = SyntaxInfo.StringConcatenationExpressionInfo(binaryExpressionSelection, semanticModel, context.CancellationToken);
                        if (concatenation.Success)
                        {
                            JoinStringExpressionsRefactoring.ComputeRefactoring(context, concatenation);
                        }
                    }
                }
            }
        }
Example #56
0
 public override void VisitBinaryExpression(BinaryExpressionSyntax node)
 {
 }
Example #57
0
                public override IEnumerable <MemberAccessExpressionSyntax> VisitBinaryExpression(BinaryExpressionSyntax node)
                {
                    switch (node.Kind())
                    {
                    case SyntaxKind.BitwiseAndExpression:
                    case SyntaxKind.BitwiseOrExpression:
                    case SyntaxKind.ExclusiveOrExpression:
                    case SyntaxKind.AddExpression:
                        break;

                    default:
                        throw new CodeGeneratorException(node.GetLocation(), $"Unsupported binary expression {node.Kind()}. Only bitwise OR, AND, XOR and addition is allowed.");
                    }

                    return(node.ChildNodes().SelectMany(n => Visit(n)));
                }
Example #58
0
 public static bool IsStringConcatenation(BinaryExpressionSyntax addExpression, SemanticModel semanticModel, CancellationToken cancellationToken = default)
 {
     return(addExpression.Kind() == SyntaxKind.AddExpression &&
            SymbolUtility.IsStringAdditionOperator(semanticModel.GetMethodSymbol(addExpression, cancellationToken)));
 }
        public static Task <Document> RefactorAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (!(binaryExpression.Left is InvocationExpressionSyntax invocationExpression))
            {
                invocationExpression = (InvocationExpressionSyntax)binaryExpression.Right;
            }

            ExpressionSyntax left = binaryExpression.Left;

            ExpressionSyntax right = binaryExpression.Right;

            ExpressionSyntax newNode = null;

            SyntaxKind kind = binaryExpression.Kind();

            if (kind == SyntaxKind.EqualsExpression)
            {
                // Count() == 0 >>> !Any()
                newNode = ChangeInvokedMethodName(invocationExpression, "Any");
                newNode = LogicalNotExpression(newNode.Parenthesize());
            }
            else if (kind == SyntaxKind.NotEqualsExpression)
            {
                // Count() != 0 >>> Any()
                newNode = ChangeInvokedMethodName(invocationExpression, "Any");
            }
            else if (kind == SyntaxKind.LessThanExpression)
            {
                if (invocationExpression == left)
                {
                    // Count() < 1 >>> !Any()
                    // Count() < i >>> !Skip(i - 1).Any()
                    newNode = CreateNewExpression(invocationExpression, right, "1", subtract: true, negate: true);
                }
                else
                {
                    // 0 < Count() >>> Any()
                    // i < Count() >>> Skip(i).Any()
                    newNode = CreateNewExpression(invocationExpression, left, "0");
                }
            }
            else if (kind == SyntaxKind.LessThanOrEqualExpression)
            {
                if (invocationExpression == left)
                {
                    // Count() <= 0 >>> !Any()
                    // Count() <= i >>> !Skip(i).Any()
                    newNode = CreateNewExpression(invocationExpression, right, "0", negate: true);
                }
                else
                {
                    // 1 <= Count() >>> Any()
                    // i <= Count() >>> Skip(i - 1).Any()
                    newNode = CreateNewExpression(invocationExpression, left, "1", subtract: true);
                }
            }
            else if (kind == SyntaxKind.GreaterThanExpression)
            {
                if (invocationExpression == left)
                {
                    // Count() > 0 >>> Any()
                    // Count() > i >>> Skip(i).Any()
                    newNode = CreateNewExpression(invocationExpression, right, "0");
                }
                else
                {
                    // 1 > Count() >>> !Any()
                    // i > Count() >>> !Skip(i - 1).Any()
                    newNode = CreateNewExpression(invocationExpression, left, "1", subtract: true, negate: true);
                }
            }
            else if (kind == SyntaxKind.GreaterThanOrEqualExpression)
            {
                if (invocationExpression == left)
                {
                    // Count() >= 1 >>> Any()
                    // Count() >= i >>> Skip(i - 1).Any()
                    newNode = CreateNewExpression(invocationExpression, right, "1", subtract: true);
                }
                else
                {
                    // 0 >= Count() >>> !Any()
                    // i >= Count() >>> !Skip(i).Any()
                    newNode = CreateNewExpression(invocationExpression, left, "0", negate: true);
                }
            }

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

            return(document.ReplaceNodeAsync(binaryExpression, newNode, cancellationToken));
        }
        private static async Task <Document> RefactorAsync(
            Document document,
            StatementSyntax statement,
            CancellationToken cancellationToken)
        {
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(statement);

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            int index = statements.IndexOf(statement);

            switch (statement)
            {
            case IfStatementSyntax ifStatement:
            {
                var expressionStatement = (ExpressionStatementSyntax)ifStatement.SingleNonBlockStatementOrDefault();

                var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;

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

                BinaryExpressionSyntax coalesceExpression = CreateCoalesceExpression(
                    left.WithoutLeadingTrivia().WithTrailingTrivia(Space),
                    right.WithLeadingTrivia(Space),
                    semanticModel.GetTypeSymbol(left, cancellationToken));

                AssignmentExpressionSyntax newAssignment = assignment.WithRight(coalesceExpression.WithTriviaFrom(right));

                ExpressionStatementSyntax newNode = expressionStatement.WithExpression(newAssignment);

                IEnumerable <SyntaxTrivia> trivia = ifStatement.DescendantTrivia(TextSpan.FromBounds(ifStatement.SpanStart, expressionStatement.SpanStart));

                if (trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                {
                    newNode = newNode.WithLeadingTrivia(ifStatement.GetLeadingTrivia());
                }
                else
                {
                    newNode = newNode
                              .WithLeadingTrivia(ifStatement.GetLeadingTrivia().Concat(trivia))
                              .WithFormatterAnnotation();
                }

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

            case ExpressionStatementSyntax expressionStatement:
            {
                var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression;

                return(await RefactorAsync(document, expressionStatement, (IfStatementSyntax)statements[index + 1], index, statementsInfo, assignment.Right, semanticModel, cancellationToken).ConfigureAwait(false));
            }

            case LocalDeclarationStatementSyntax localDeclaration:
            {
                ExpressionSyntax value = localDeclaration
                                         .Declaration
                                         .Variables[0]
                                         .Initializer
                                         .Value;

                return(await RefactorAsync(document, localDeclaration, (IfStatementSyntax)statements[index + 1], index, statementsInfo, value, semanticModel, cancellationToken).ConfigureAwait(false));
            }

            default:
            {
                Debug.Fail(statement.Kind().ToString());

                return(document);
            }
            }
        }