public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     return SimplifyExpression(
         node,
         newNode: base.VisitParenthesizedExpression(node),
         simplifier: SimplifyParentheses);
 }
        private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, ParenthesizedExpressionSyntax syntax)
        {
            var newSyntaxRoot = root.ReplaceNode(syntax, GetReplacement(syntax));

            var changedDocument = document.WithSyntaxRoot(newSyntaxRoot);

            return Task.FromResult(changedDocument);
        }
        private static SyntaxNode GetReplacement(ParenthesizedExpressionSyntax oldNode)
        {
            var leadingTrivia = SyntaxFactory.TriviaList(oldNode.OpenParenToken.GetAllTrivia().Concat(oldNode.Expression.GetLeadingTrivia()));
            var trailingTrivia = oldNode.Expression.GetTrailingTrivia().AddRange(oldNode.CloseParenToken.GetAllTrivia());

            return oldNode.Expression
                .WithLeadingTrivia(leadingTrivia.Any() ? leadingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker))
                .WithTrailingTrivia(trailingTrivia.Any() ? trailingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker));
        }
            public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
            {
                var newNode = base.VisitParenthesizedExpression(node);

                if (node != newNode && newNode.Kind() == SyntaxKind.ParenthesizedExpression)
                {
                    return newNode.WithAdditionalAnnotations(Simplifier.Annotation);
                }

                return newNode;
            }
			public override SyntaxNode VisitParenthesizedExpression (ParenthesizedExpressionSyntax node)
			{
				var newNode = base.VisitParenthesizedExpression (node);
				if (node != newNode &&
					newNode.IsKind (SyntaxKind.ParenthesizedExpression)) {
					var parenthesizedExpression = (ParenthesizedExpressionSyntax)newNode;
					var innerExpression = parenthesizedExpression.OpenParenToken.GetNextToken ().Parent;
					if (innerExpression.HasAnnotation (_replacementAnnotation)) {
						return newNode.WithAdditionalAnnotations (Simplifier.Annotation);
					}
				}

				return newNode;
			}
        private static Task<Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, ParenthesizedExpressionSyntax syntax)
        {
            var leadingTrivia = SyntaxFactory.TriviaList(syntax.OpenParenToken.GetAllTrivia().Concat(syntax.Expression.GetLeadingTrivia()));
            var trailingTrivia = syntax.Expression.GetTrailingTrivia().AddRange(syntax.CloseParenToken.GetAllTrivia());

            var newNode = syntax.Expression
                .WithLeadingTrivia(leadingTrivia.Any() ? leadingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker))
                .WithTrailingTrivia(trailingTrivia.Any() ? trailingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker));

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

            var changedDocument = document.WithSyntaxRoot(newSyntaxRoot);

            return Task.FromResult(changedDocument);
        }
        private bool GetOuterMostParenthesizedExpressionInSpan(SyntaxNode root, int position,
         ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken, out ParenthesizedExpressionSyntax result)
        {
            result = null;
            while (TryGetParenthesizedExpression(SignatureHelpTriggerReason.InvokeSignatureHelpCommand,
                root, position, syntaxFacts, cancellationToken, out var expression))
            {
                if (!currentSpan.Contains(expression.Span))
                {
                    break;
                }

                result = expression;
                position = expression.SpanStart;
            }

            return result != null;
        }
        private static SyntaxNode GetReplacement(ParenthesizedExpressionSyntax oldNode)
        {
            var leadingTrivia = SyntaxFactory.TriviaList(oldNode.OpenParenToken.GetAllTrivia().Concat(oldNode.Expression.GetLeadingTrivia()));
            var trailingTrivia = oldNode.Expression.GetTrailingTrivia().AddRange(oldNode.CloseParenToken.GetAllTrivia());

            // Workaround for Roslyn not handling elastic markers for directive trivia correctly.
            if (!leadingTrivia.Any())
            {
                var previousToken = oldNode.OpenParenToken.GetPreviousToken();
                if (TriviaHelper.IndexOfTrailingWhitespace(previousToken.TrailingTrivia) == -1)
                {
                    leadingTrivia = SyntaxFactory.TriviaList(SyntaxFactory.Space);
                }
            }

            return oldNode.Expression
                .WithLeadingTrivia(leadingTrivia)
                .WithTrailingTrivia(trailingTrivia.Any() ? trailingTrivia : SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker));
        }
        private static SyntaxNode SimplifyParentheses(
            ParenthesizedExpressionSyntax node,
            SemanticModel semanticModel,
            OptionSet optionSet,
            CancellationToken cancellationToken)
        {
            if (node.CanRemoveParentheses())
            {
                // TODO(DustinCa): We should not be skipping elastic trivia below.
                // However, the formatter seems to mess up trailing trivia in some
                // cases if elastic trivia is there -- and it's not clear why.
                // Specifically remove the elastic trivia formatting rule doesn't
                // have any effect.

                var leadingTrivia = node.OpenParenToken.LeadingTrivia
                    .Concat(node.OpenParenToken.TrailingTrivia)
                    .Where(t => !t.IsElastic())
                    .Concat(node.Expression.GetLeadingTrivia());

                var trailingTrivia = node.Expression.GetTrailingTrivia()
                    .Concat(node.CloseParenToken.LeadingTrivia)
                    .Where(t => !t.IsElastic())
                    .Concat(node.CloseParenToken.TrailingTrivia);

                var resultNode = node.Expression
                    .WithLeadingTrivia(leadingTrivia)
                    .WithTrailingTrivia(trailingTrivia);

                resultNode = SimplificationHelpers.CopyAnnotations(from: node, to: resultNode);

                return resultNode;
            }

            // We don't know how to simplifiy this.
            return node;
        }
        public void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
        {
            if (node == null)
                throw new ArgumentNullException("node");

            node.Validate();

            ExpressionStart(node);

            _writer.WriteSyntax(Syntax.OpenParen);

            if (_writer.Configuration.Spaces.WithinParentheses.Parentheses)
                _writer.WriteSpace();

            node.Expression.Accept(this);

            if (_writer.Configuration.Spaces.WithinParentheses.Parentheses)
                _writer.WriteSpace();

            _writer.WriteSyntax(Syntax.CloseParen);

            ExpressionEnd(node);
        }
        private static bool RemovalChangesAssociation(ParenthesizedExpressionSyntax node, ExpressionSyntax expression, ExpressionSyntax parentExpression)
        {
            var precedence       = expression.GetOperatorPrecedence();
            var parentPrecedence = parentExpression.GetOperatorPrecedence();

            if (precedence == OperatorPrecedence.None || parentPrecedence == OperatorPrecedence.None)
            {
                // Be conservative if the expression or its parent has no precedence.
                return(true);
            }

            if (precedence > parentPrecedence)
            {
                // Association never changes if the expression's precedence is higher than its parent.
                return(false);
            }
            else if (precedence < parentPrecedence)
            {
                // Association always changes if the expression's precedence is lower that its parent.
                return(true);
            }
            else if (precedence == parentPrecedence)
            {
                // If the expression's precedence is the same as its parent, and both are binary expressions,
                // check for associativity and commutability.

                if (!(expression is BinaryExpressionSyntax || expression is AssignmentExpressionSyntax))
                {
                    // If the expression is not a binary expression, association never changes.
                    return(false);
                }

                var parentBinaryExpression = parentExpression as BinaryExpressionSyntax;
                if (parentBinaryExpression != null)
                {
                    // If both the expression and its parent are binary expressions and their kinds
                    // are the same, check to see if they are commutative (e.g. + or *).
                    if (parentBinaryExpression.IsKind(SyntaxKind.AddExpression, SyntaxKind.MultiplyExpression) &&
                        node.Expression.Kind() == parentBinaryExpression.Kind())
                    {
                        return(false);
                    }

                    // Null-coalescing is right associative; removing parens from the LHS changes the association.
                    if (parentExpression.IsKind(SyntaxKind.CoalesceExpression))
                    {
                        return(parentBinaryExpression.Left == node);
                    }

                    // All other binary operators are left associative; removing parens from the RHS changes the association.
                    return(parentBinaryExpression.Right == node);
                }

                var parentAssignmentExpression = parentExpression as AssignmentExpressionSyntax;
                if (parentAssignmentExpression != null)
                {
                    // Assignment expressions are right associative; removing parens from the LHS changes the association.
                    return(parentAssignmentExpression.Left == node);
                }

                // If the parent is not a binary expression, association never changes.
                return(false);
            }

            throw ExceptionUtilities.Unreachable;
        }
 public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     emit("(");
     base.Visit(node.Expression);
     emit(")");
 }
        public static async Task <Document> RefactorAsync(
            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, allowedStyles: allowedStyles);

            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);
            }
        }
        public static bool CanRemoveParentheses(this ParenthesizedExpressionSyntax node)
        {
            var expression       = node.Expression;
            var parentExpression = node.Parent as ExpressionSyntax;

            // Simplest cases:
            //   ((x)) -> (x)
            if (expression.IsKind(SyntaxKind.ParenthesizedExpression) ||
                parentExpression.IsKind(SyntaxKind.ParenthesizedExpression))
            {
                return(true);
            }

            // Don't change (x?.Count).GetValueOrDefault() to x?.Count.GetValueOrDefault()
            if (expression.IsKind(SyntaxKind.ConditionalAccessExpression) && parentExpression is MemberAccessExpressionSyntax)
            {
                return(false);
            }

            // Easy statement-level cases:
            //   var y = (x);           -> var y = x;
            //   if ((x))               -> if (x)
            //   return (x);            -> return x;
            //   yield return (x);      -> yield return x;
            //   throw (x);             -> throw x;
            //   switch ((x))           -> switch (x)
            //   while ((x))            -> while (x)
            //   do { } while ((x))     -> do { } while (x)
            //   for(;(x);)             -> for(;x;)
            //   foreach (var y in (x)) -> foreach (var y in x)
            //   lock ((x))             -> lock (x)
            //   using ((x))            -> using (x)
            //   catch when ((x))       -> catch when (x)
            if ((node.IsParentKind(SyntaxKind.EqualsValueClause) && ((EqualsValueClauseSyntax)node.Parent).Value == node) ||
                (node.IsParentKind(SyntaxKind.IfStatement) && ((IfStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ReturnStatement) && ((ReturnStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.YieldReturnStatement) && ((YieldStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.ThrowStatement) && ((ThrowStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.SwitchStatement) && ((SwitchStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.WhileStatement) && ((WhileStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.DoStatement) && ((DoStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ForStatement) && ((ForStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ForEachStatement) && ((ForEachStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.LockStatement) && ((LockStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.UsingStatement) && ((UsingStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.CatchFilterClause) && ((CatchFilterClauseSyntax)node.Parent).FilterExpression == node))
            {
                return(true);
            }

            // Handle expression-level ambiguities
            if (RemovalMayIntroduceCastAmbiguity(node) ||
                RemovalMayIntroduceCommaListAmbiguity(node) ||
                RemovalMayIntroduceInterpolationAmbiguity(node))
            {
                return(false);
            }

            // Cases:
            //   y((x)) -> y(x)
            if (node.IsParentKind(SyntaxKind.Argument) && ((ArgumentSyntax)node.Parent).Expression == node)
            {
                return(true);
            }

            // Cases:
            //   $"{(x)}" -> $"{x}"
            if (node.IsParentKind(SyntaxKind.Interpolation))
            {
                return(true);
            }

            // Cases:
            //   ($"{x}") -> $"{x}"
            if (expression.IsKind(SyntaxKind.InterpolatedStringExpression))
            {
                return(true);
            }

            // Cases:
            //   {(x)} -> {x}
            if (node.Parent is InitializerExpressionSyntax)
            {
                // Assignment expressions are not allowed in initializers
                if (expression.IsAnyAssignExpression())
                {
                    return(false);
                }

                return(true);
            }

            // Cases:
            // where (x + 1 > 14) -> where x + 1 > 14
            if (node.Parent is QueryClauseSyntax)
            {
                return(true);
            }

            // Cases:
            //   (x)   -> x
            //   (x.y) -> x.y
            if (IsSimpleOrDottedName(expression))
            {
                return(true);
            }

            // Cases:
            //   ('')    -> ''
            //   ("")    -> ""
            //   (false) -> false
            //   (true)  -> true
            //   (null)  -> null
            //   (1)     -> 1
            if (expression.IsAnyLiteralExpression())
            {
                return(true);
            }

            // Operator precedence cases:
            // - If the parent is not an expression, do not remove parentheses
            // - Otherwise, parentheses may be removed if doing so does not change operator associations.
            return(parentExpression != null
                ? !RemovalChangesAssociation(node, expression, parentExpression)
                : false);
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="node"></param>
 public override sealed void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     this.OnNodeVisited(node);
     if (!this.traverseRootOnly) base.VisitParenthesizedExpression(node);
 }
        public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
        {
            node = node.WithExpression((ExpressionSyntax)base.Visit((SyntaxNode)node.Expression));
            switch (node.Expression.Kind)
            {
                case SyntaxKind.CharacterLiteralExpression:
                case SyntaxKind.FalseLiteralExpression:
                case SyntaxKind.NumericLiteralExpression:
                case SyntaxKind.StringLiteralExpression:
                case SyntaxKind.TrueLiteralExpression:
                    return node.Expression;
            }

            return node;
        }
 protected abstract void CompileParenthesizedExpression(ParenthesizedExpressionSyntax expression);
Beispiel #18
0
 public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     _output.TrivialWrite('(');
     this.VisitExpression(node.Expression);
     _output.TrivialWrite(')');
     return node;
 }
Beispiel #19
0
 public override void VisitParenthesizedExpressionSyntax(ParenthesizedExpressionSyntax syntax)
 {
     this.AppendError(syntax);
 }
 public override IExpression VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     return(this.Visit(node.Expression));
 }
 public static void Go(OutputWriter writer, ParenthesizedExpressionSyntax expression)
 {
     writer.Write("(");
     Core.Write(writer, expression.Expression);
     writer.Write(")");
 }
Beispiel #22
0
        private static bool RemovalChangesAssociation(ParenthesizedExpressionSyntax node, ExpressionSyntax expression, ExpressionSyntax parentExpression, SemanticModel semanticModel)
        {
            var precedence       = expression.GetOperatorPrecedence();
            var parentPrecedence = parentExpression.GetOperatorPrecedence();

            if (precedence == OperatorPrecedence.None || parentPrecedence == OperatorPrecedence.None)
            {
                // Be conservative if the expression or its parent has no precedence.
                return(true);
            }

            if (precedence > parentPrecedence)
            {
                // Association never changes if the expression's precedence is higher than its parent.
                return(false);
            }
            else if (precedence < parentPrecedence)
            {
                // Association always changes if the expression's precedence is lower that its parent.
                return(true);
            }
            else if (precedence == parentPrecedence)
            {
                // If the expression's precedence is the same as its parent, and both are binary expressions,
                // check for associativity and commutability.

                if (!(expression is BinaryExpressionSyntax || expression is AssignmentExpressionSyntax))
                {
                    // If the expression is not a binary expression, association never changes.
                    return(false);
                }

                if (parentExpression is BinaryExpressionSyntax parentBinaryExpression)
                {
                    // If both the expression and its parent are binary expressions and their kinds
                    // are the same, check to see if they are commutative (e.g. + or *).
                    if (parentBinaryExpression.IsKind(SyntaxKind.AddExpression, SyntaxKind.MultiplyExpression) &&
                        node.Expression.Kind() == parentBinaryExpression.Kind())
                    {
                        // At this point, we know our parenthesized expression contains a binary expression.
                        var binaryExpression = (BinaryExpressionSyntax)node.Expression;

                        // Now we'll perform a few semantic checks to determine whether removal of the parentheses
                        // might break semantics. Note that we'll try and be fairly conservative with these. For example,
                        // we'll assume that failing any of these checks results in the parentheses being declared as
                        // necessary -- even if they could be removed depending on whether the parenthesized expression
                        // appears on the left or right side of the parent binary expression.

                        // First, does the binary expression result in an operator overload being called?
                        var symbolInfo = semanticModel.GetSymbolInfo(binaryExpression);
                        if (symbolInfo.Symbol != null)
                        {
                            if (symbolInfo.Symbol is IMethodSymbol methodSymbol &&
                                methodSymbol.MethodKind == MethodKind.UserDefinedOperator)
                            {
                                return(true);
                            }
                        }

                        // Second, check the type and converted type of the binary expression. Are they the same?
                        var typeInfo = semanticModel.GetTypeInfo(binaryExpression);
                        if (typeInfo.Type != null && typeInfo.ConvertedType != null)
                        {
                            if (!typeInfo.Type.Equals(typeInfo.ConvertedType))
                            {
                                return(true);
                            }
                        }

                        return(false);
                    }

                    // Null-coalescing is right associative; removing parens from the LHS changes the association.
                    if (parentExpression.IsKind(SyntaxKind.CoalesceExpression))
                    {
                        return(parentBinaryExpression.Left == node);
                    }

                    // All other binary operators are left associative; removing parens from the RHS changes the association.
                    return(parentBinaryExpression.Right == node);
                }

                if (parentExpression is AssignmentExpressionSyntax parentAssignmentExpression)
                {
                    // Assignment expressions are right associative; removing parens from the LHS changes the association.
                    return(parentAssignmentExpression.Left == node);
                }

                // If the parent is not a binary expression, association never changes.
                return(false);
            }

            throw ExceptionUtilities.Unreachable;
        }
 public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     node.Expression.Accept(this);
 }
 public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     base.VisitParenthesizedExpression(node);
 }
Beispiel #25
0
 public virtual void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node) => DefaultVisit(node);
 private bool TryGetParenthesizedExpression(SignatureHelpTriggerReason triggerReason, SyntaxNode root, int position,
     ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken, out ParenthesizedExpressionSyntax parenthesizedExpression)
 {
     return CommonSignatureHelpUtilities.TryGetSyntax(root, position, syntaxFacts, triggerReason, 
         IsParenthesizedExpressionTriggerToken, IsParenthesizedExpressionToken, cancellationToken, out parenthesizedExpression);
 }
        private static bool RemovalMayIntroduceCommaListAmbiguity(ParenthesizedExpressionSyntax node)
        {
            if (IsSimpleOrDottedName(node.Expression))
            {
                // We can't remove parentheses from an identifier name in the following cases:
                //   F((x) < x, x > (1 + 2))
                //   F(x < (x), x > (1 + 2))
                //   F(x < x, (x) > (1 + 2))
                //   {(x) < x, x > (1 + 2)}
                //   {x < (x), x > (1 + 2)}
                //   {x < x, (x) > (1 + 2)}

                var binaryExpression = node.Parent as BinaryExpressionSyntax;
                if (binaryExpression != null &&
                    binaryExpression.MatchesKind(SyntaxKind.LessThanExpression, SyntaxKind.GreaterThanExpression) &&
                    (binaryExpression.IsParentKind(SyntaxKind.Argument) || binaryExpression.Parent is InitializerExpressionSyntax))
                {
                    if (binaryExpression.IsKind(SyntaxKind.LessThanExpression))
                    {
                        if ((binaryExpression.Left == node && IsSimpleOrDottedName(binaryExpression.Right)) ||
                            (binaryExpression.Right == node && IsSimpleOrDottedName(binaryExpression.Left)))
                        {
                            if (IsNextExpressionPotentiallyAmbiguous(binaryExpression))
                            {
                                return true;
                            }
                        }

                        return false;
                    }
                    else if (binaryExpression.IsKind(SyntaxKind.GreaterThanExpression))
                    {
                        if (binaryExpression.Left == node &&
                            binaryExpression.Right.MatchesKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.CastExpression))
                        {
                            if (IsPreviousExpressionPotentiallyAmbiguous(binaryExpression))
                            {
                                return true;
                            }
                        }

                        return false;
                    }
                }
            }
            else if (node.Expression.MatchesKind(SyntaxKind.LessThanExpression))
            {
                // We can't remove parentheses from a less-than expression in the following cases:
                //   F((x < x), x > (1 + 2))
                //   {(x < x), x > (1 + 2)}

                var lessThanExpression = (BinaryExpressionSyntax)node.Expression;
                if (IsNextExpressionPotentiallyAmbiguous(node))
                {
                    return true;
                }

                return false;
            }
            else if (node.Expression.MatchesKind(SyntaxKind.GreaterThanExpression))
            {
                // We can't remove parentheses from a greater-than expression in the following cases:
                //   F(x < x, (x > (1 + 2)))
                //   {x < x, (x > (1 + 2))}

                var greaterThanExpression = (BinaryExpressionSyntax)node.Expression;
                if (IsPreviousExpressionPotentiallyAmbiguous(node))
                {
                    return true;
                }

                return false;
            }

            return false;
        }
 public override string VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     return(node.OpenParenToken
            + Visit(node.Expression)
            + node.CloseParenToken);
 }
 /// <inheritdoc />
 public override Expression VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     return(node.Expression.Accept(this));
 }
 public void Render(ParenthesizedExpressionSyntax parenthesizedExpression)
 {
     Render(parenthesizedExpression.OpenParenthesisSymbol);
     Render(parenthesizedExpression.ExpressionNode);
     Render(parenthesizedExpression.CloseParenthesisSymbol);
 }
        private static bool RemovalMayIntroduceInterpolationAmbiguity(ParenthesizedExpressionSyntax node)
        {
            // First, find the parenting interpolation. If we find a parenthesize expression first,
            // we can bail out early.
            InterpolationSyntax interpolation = null;
            foreach (var ancestor in node.Parent.AncestorsAndSelf())
            {
                switch (ancestor.Kind())
                {
                    case SyntaxKind.ParenthesizedExpression:
                        return false;
                    case SyntaxKind.Interpolation:
                        interpolation = (InterpolationSyntax)ancestor;
                        break;
                }
            }

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

            // In order determine whether removing this parenthesized expression will introduce a
            // parsing ambiguity, we must dig into the child tokens and nodes to determine whether
            // they include any : or :: tokens. If they do, we can't remove the parentheses because
            // the parser would assume that the first : would begin the format clause of the interpolation.

            var stack = s_nodeStackPool.AllocateAndClear();
            try
            {
                stack.Push(node.Expression);

                while (stack.Count > 0)
                {
                    var expression = stack.Pop();

                    foreach (var nodeOrToken in expression.ChildNodesAndTokens())
                    {
                        // Note: There's no need drill into other parenthesized expressions, since any colons in them would be unambiguous.
                        if (nodeOrToken.IsNode && !nodeOrToken.IsKind(SyntaxKind.ParenthesizedExpression))
                        {
                            stack.Push(nodeOrToken.AsNode());
                        }
                        else if (nodeOrToken.IsToken)
                        {
                            if (nodeOrToken.IsKind(SyntaxKind.ColonToken) || nodeOrToken.IsKind(SyntaxKind.ColonColonToken))
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            finally
            {
                s_nodeStackPool.ClearAndFree(stack);
            }

            return false;
        }
Beispiel #32
0
 public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node) => node.Expression.Accept(this);
        private static bool RemovalChangesAssociation(ParenthesizedExpressionSyntax node, ExpressionSyntax expression, ExpressionSyntax parentExpression)
        {
            var precedence = expression.GetOperatorPrecedence();
            var parentPrecedence = parentExpression.GetOperatorPrecedence();
            if (precedence == OperatorPrecedence.None || parentPrecedence == OperatorPrecedence.None)
            {
                // Be conservative if the expression or its parent has no precedence.
                return true;
            }

            if (precedence > parentPrecedence)
            {
                // Association never changes if the expression's precedence is higher than its parent.
                return false;
            }
            else if (precedence < parentPrecedence)
            {
                // Association always changes if the expression's precedence is lower that its parent.
                return true;
            }
            else if (precedence == parentPrecedence)
            {
                // If the expression's precedence is the same as its parent, and both are binary expressions,
                // check for associativity and commutability.

                if (!(expression is BinaryExpressionSyntax || expression is AssignmentExpressionSyntax))
                {
                    // If the expression is not a binary expression, association never changes.
                    return false;
                }

                var parentBinaryExpression = parentExpression as BinaryExpressionSyntax;
                if (parentBinaryExpression != null)
                {
                    // If both the expression and its parent are binary expressions and their kinds
                    // are the same, check to see if they are commutative (e.g. + or *).
                    if (parentBinaryExpression.IsKind(SyntaxKind.AddExpression, SyntaxKind.MultiplyExpression) &&
                        node.Expression.Kind() == parentBinaryExpression.Kind())
                    {
                        return false;
                    }

                    // Null-coalescing is right associative; removing parens from the LHS changes the association.
                    if (parentExpression.IsKind(SyntaxKind.CoalesceExpression))
                    {
                        return parentBinaryExpression.Left == node;
                    }

                    // All other binary operators are left associative; removing parens from the RHS changes the association.
                    return parentBinaryExpression.Right == node;
                }

                var parentAssignmentExpression = parentExpression as AssignmentExpressionSyntax;
                if (parentAssignmentExpression != null)
                {
                    // Assignment expressions are right associative; removing parens from the LHS changes the association.
                    return parentAssignmentExpression.Left == node;
                }

                // If the parent is not a binary expression, association never changes.
                return false;
            }

            throw ExceptionUtilities.Unreachable;
        }
        private static bool RemovalMayIntroduceCastAmbiguity(ParenthesizedExpressionSyntax node)
        {
            // Be careful not to break the special case around (x)(-y)
            // as defined in section 7.7.6 of the C# language specification.

            if (node.IsParentKind(SyntaxKind.CastExpression))
            {
                var castExpression = (CastExpressionSyntax)node.Parent;
                if (castExpression.Type is PredefinedTypeSyntax)
                {
                    return false;
                }

                var expression = node.Expression;

                if (expression.IsKind(SyntaxKind.UnaryMinusExpression))
                {
                    return true;
                }

                if (expression.IsKind(SyntaxKind.NumericLiteralExpression))
                {
                    var numericLiteral = (LiteralExpressionSyntax)expression;
                    if (numericLiteral.Token.ValueText.StartsWith("-"))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
 public ParenthesizedExpressionTranslation(ParenthesizedExpressionSyntax syntax, SyntaxTranslation parent) : base(syntax, parent)
 {
     Expression = syntax.Expression.Get <ExpressionTranslation>(this);
 }
Beispiel #36
0
        public override Evaluation VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
        {
            node.Expression?.Accept <Evaluation>(this);

            return(base.VisitParenthesizedExpression(node));
        }
Beispiel #37
0
        private static Task <Document> GetTransformedDocumentAsync(Document document, SyntaxNode root, ParenthesizedExpressionSyntax syntax)
        {
            var newSyntaxRoot = root.ReplaceNode(syntax, GetReplacement(syntax));

            var changedDocument = document.WithSyntaxRoot(newSyntaxRoot);

            return(Task.FromResult(changedDocument));
        }
 public static void Go(OutputWriter writer, ParenthesizedExpressionSyntax expression)
 {
     writer.Write("(");
     Core.Write(writer, expression.Expression);
     writer.Write(")");
 }
 private bool TryGetParenthesizedExpression(SignatureHelpTriggerReason triggerReason, SyntaxNode root, int position,
                                            ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken, out ParenthesizedExpressionSyntax parenthesizedExpression)
 {
     return(CommonSignatureHelpUtilities.TryGetSyntax(root, position, syntaxFacts, triggerReason,
                                                      IsParenthesizedExpressionTriggerToken, IsParenthesizedExpressionToken, cancellationToken, out parenthesizedExpression));
 }
        private static bool RemovalMayIntroduceInterpolationAmbiguity(ParenthesizedExpressionSyntax node)
        {
            // First, find the parenting interpolation. If we find a parenthesize expression first,
            // we can bail out early.
            InterpolationSyntax interpolation = null;

            foreach (var ancestor in node.Parent.AncestorsAndSelf())
            {
                switch (ancestor.Kind())
                {
                case SyntaxKind.ParenthesizedExpression:
                    return(false);

                case SyntaxKind.Interpolation:
                    interpolation = (InterpolationSyntax)ancestor;
                    break;
                }
            }

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

            // In order determine whether removing this parenthesized expression will introduce a
            // parsing ambiguity, we must dig into the child tokens and nodes to determine whether
            // they include any : or :: tokens. If they do, we can't remove the parentheses because
            // the parser would assume that the first : would begin the format clause of the interpolation.

            var stack = s_nodeStackPool.AllocateAndClear();

            try
            {
                stack.Push(node.Expression);

                while (stack.Count > 0)
                {
                    var expression = stack.Pop();

                    foreach (var nodeOrToken in expression.ChildNodesAndTokens())
                    {
                        // Note: There's no need drill into other parenthesized expressions, since any colons in them would be unambiguous.
                        if (nodeOrToken.IsNode && !nodeOrToken.IsKind(SyntaxKind.ParenthesizedExpression))
                        {
                            stack.Push(nodeOrToken.AsNode());
                        }
                        else if (nodeOrToken.IsToken)
                        {
                            if (nodeOrToken.IsKind(SyntaxKind.ColonToken) || nodeOrToken.IsKind(SyntaxKind.ColonColonToken))
                            {
                                return(true);
                            }
                        }
                    }
                }
            }
            finally
            {
                s_nodeStackPool.ClearAndFree(stack);
            }

            return(false);
        }
        private bool GetOuterMostParenthesizedExpressionInSpan(SyntaxNode root, int position,
                                                               ISyntaxFactsService syntaxFacts, TextSpan currentSpan, CancellationToken cancellationToken, out ParenthesizedExpressionSyntax result)
        {
            result = null;
            while (TryGetParenthesizedExpression(SignatureHelpTriggerReason.InvokeSignatureHelpCommand,
                                                 root, position, syntaxFacts, cancellationToken, out var expression))
            {
                if (!currentSpan.Contains(expression.Span))
                {
                    break;
                }

                result   = expression;
                position = expression.SpanStart;
            }

            return(result != null);
        }
        private static bool RemovalMayIntroduceCommaListAmbiguity(ParenthesizedExpressionSyntax node)
        {
            if (IsSimpleOrDottedName(node.Expression))
            {
                // We can't remove parentheses from an identifier name in the following cases:
                //   F((x) < x, x > (1 + 2))
                //   F(x < (x), x > (1 + 2))
                //   F(x < x, (x) > (1 + 2))
                //   {(x) < x, x > (1 + 2)}
                //   {x < (x), x > (1 + 2)}
                //   {x < x, (x) > (1 + 2)}

                var binaryExpression = node.Parent as BinaryExpressionSyntax;
                if (binaryExpression != null &&
                    binaryExpression.IsKind(SyntaxKind.LessThanExpression, SyntaxKind.GreaterThanExpression) &&
                    (binaryExpression.IsParentKind(SyntaxKind.Argument) || binaryExpression.Parent is InitializerExpressionSyntax))
                {
                    if (binaryExpression.IsKind(SyntaxKind.LessThanExpression))
                    {
                        if ((binaryExpression.Left == node && IsSimpleOrDottedName(binaryExpression.Right)) ||
                            (binaryExpression.Right == node && IsSimpleOrDottedName(binaryExpression.Left)))
                        {
                            if (IsNextExpressionPotentiallyAmbiguous(binaryExpression))
                            {
                                return(true);
                            }
                        }

                        return(false);
                    }
                    else if (binaryExpression.IsKind(SyntaxKind.GreaterThanExpression))
                    {
                        if (binaryExpression.Left == node &&
                            binaryExpression.Right.IsKind(SyntaxKind.ParenthesizedExpression, SyntaxKind.CastExpression))
                        {
                            if (IsPreviousExpressionPotentiallyAmbiguous(binaryExpression))
                            {
                                return(true);
                            }
                        }

                        return(false);
                    }
                }
            }
            else if (node.Expression.IsKind(SyntaxKind.LessThanExpression))
            {
                // We can't remove parentheses from a less-than expression in the following cases:
                //   F((x < x), x > (1 + 2))
                //   {(x < x), x > (1 + 2)}

                var lessThanExpression = (BinaryExpressionSyntax)node.Expression;
                if (IsNextExpressionPotentiallyAmbiguous(node))
                {
                    return(true);
                }

                return(false);
            }
            else if (node.Expression.IsKind(SyntaxKind.GreaterThanExpression))
            {
                // We can't remove parentheses from a greater-than expression in the following cases:
                //   F(x < x, (x > (1 + 2)))
                //   {x < x, (x > (1 + 2))}

                var greaterThanExpression = (BinaryExpressionSyntax)node.Expression;
                if (IsPreviousExpressionPotentiallyAmbiguous(node))
                {
                    return(true);
                }

                return(false);
            }

            return(false);
        }
Beispiel #43
0
 private BoundExpression BindParenthesizedExpression(ParenthesizedExpressionSyntax expressionSyntax)
 {
     return(BindExpression(expressionSyntax.Expression));
 }
        public static bool CanRemoveParentheses(this ParenthesizedExpressionSyntax node)
        {
            var expression       = node.Expression;
            var parentExpression = node.Parent as ExpressionSyntax;

            // Simplest cases:
            //   ((x)) -> (x)
            if (expression.IsKind(SyntaxKind.ParenthesizedExpression))
            {
                return(true);
            }

            // Easy statement-level cases:
            //   var y = (x);           -> var y = x;
            //   if ((x))               -> if (x)
            //   return (x);            -> return x;
            //   yield return (x);      -> yield return x;
            //   throw (x);             -> throw x;
            //   switch ((x))           -> switch (x)
            //   while ((x))            -> while (x)
            //   do { } while ((x))     -> do { } while (x)
            //   for(;(x);)             -> for(;x;)
            //   foreach (var y in (x)) -> foreach (var y in x)
            //   lock ((x))             -> lock (x)
            //   using ((x))            -> using (x)
            if ((node.IsParentKind(SyntaxKind.EqualsValueClause) && ((EqualsValueClauseSyntax)node.Parent).Value == node) ||
                (node.IsParentKind(SyntaxKind.IfStatement) && ((IfStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ReturnStatement) && ((ReturnStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.YieldReturnStatement) && ((YieldStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.ThrowStatement) && ((ThrowStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.SwitchStatement) && ((SwitchStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.WhileStatement) && ((WhileStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.DoStatement) && ((DoStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ForStatement) && ((ForStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ForEachStatement) && ((ForEachStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.LockStatement) && ((LockStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.UsingStatement) && ((UsingStatementSyntax)node.Parent).Expression == node))
            {
                return(true);
            }

            // Handle expression-level ambiguities
            if (RemovalMayIntroduceCastAmbiguity(node) ||
                RemovalMayIntroduceCommaListAmbiguity(node))
            {
                return(false);
            }

            // Cases:
            //   y((x)) -> y(x)
            if (node.IsParentKind(SyntaxKind.Argument) && ((ArgumentSyntax)node.Parent).Expression == node)
            {
                return(true);
            }

            // Cases:
            //   {(x)} -> {x}
            if (node.Parent is InitializerExpressionSyntax)
            {
                // Assignment expressions are not allowed in initializers
                if (expression.IsAnyAssignExpression())
                {
                    return(false);
                }

                return(true);
            }

            // Cases:
            // where (x + 1 > 14) -> where x + 1 > 14
            if (node.Parent is QueryClauseSyntax)
            {
                return(true);
            }

            // Cases:
            //   (x)   -> x
            //   (x.y) -> x.y
            if (IsSimpleOrDottedName(expression))
            {
                return(true);
            }

            // Cases:
            //   ('')    -> ''
            //   ("")    -> ""
            //   (false) -> false
            //   (true)  -> true
            //   (null)  -> null
            //   (1)     -> 1
            if (expression.IsAnyLiteralExpression())
            {
                return(true);
            }

            // Operator precedence cases:
            var precedence = expression.GetOperatorPrecedence();

            if (parentExpression != null)
            {
                var parentPrecedence = parentExpression.GetOperatorPrecedence();

                // Only remove if the expression's precedence is higher than its parent.
                if (parentPrecedence != OperatorPrecedence.None &&
                    precedence > parentPrecedence)
                {
                    return(true);
                }

                // If the expression's precedence is the same as its parent, and both are binary expressions,
                // check for associativity and commutability.
                if (precedence != OperatorPrecedence.None && precedence == parentPrecedence)
                {
                    var binaryExpression       = expression as BinaryExpressionSyntax;
                    var parentBinaryExpression = parentExpression as BinaryExpressionSyntax;
                    if (binaryExpression == null || parentBinaryExpression == null)
                    {
                        return(true);
                    }

                    // Handle associate cases. Note that all binary expressions except assignment
                    // and null-coalescing are left associative.
                    if (parentBinaryExpression.Left == node)
                    {
                        if (!parentBinaryExpression.IsAnyAssignExpression() &&
                            !parentBinaryExpression.IsKind(SyntaxKind.CoalesceExpression))
                        {
                            return(true);
                        }
                    }
                    else if (parentBinaryExpression.Right == node)
                    {
                        if (parentBinaryExpression.IsAnyAssignExpression() ||
                            parentBinaryExpression.IsKind(SyntaxKind.CoalesceExpression))
                        {
                            return(true);
                        }
                    }

                    // If both the expression and it's parent are binary expressions and their kinds
                    // are the same, check to see if they are commutative (e.g. + or *).
                    if (parentBinaryExpression.MatchesKind(SyntaxKind.AddExpression, SyntaxKind.MultiplyExpression) &&
                        expression.CSharpKind() == parentExpression.CSharpKind())
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="node"></param>
 public override sealed void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     this.OnNodeVisited(node, this.type.IsInstanceOfType(node));
     base.VisitParenthesizedExpression(node);
 }
 private static bool IsParenthesizedExpressionToken(ParenthesizedExpressionSyntax expr, SyntaxToken token)
 {
     return(expr.FullSpan.Contains(token.SpanStart) &&
            token != expr.CloseParenToken);
 }
 private static void ReportDiagnostic(SyntaxNodeAnalysisContext context, ParenthesizedExpressionSyntax node)
 {
     context.ReportDiagnostic(Diagnostic.Create(Descriptor, node.GetLocation()));
     context.ReportDiagnostic(Diagnostic.Create(ParenthesisDescriptor, node.OpenParenToken.GetLocation()));
     context.ReportDiagnostic(Diagnostic.Create(ParenthesisDescriptor, node.CloseParenToken.GetLocation()));
 }
Beispiel #48
0
 public override BoundNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     return(VisitExpression(node.Expression));
 }
        public static bool CanRemoveParentheses(this ParenthesizedExpressionSyntax node, SemanticModel semanticModel)
        {
            var expression = node.Expression;

            // The 'direct' expression that contains this parenthesized node.  Note: in the case
            // of code like: ```x is (y)``` there is an intermediary 'no-syntax' 'ConstantPattern'
            // node between the 'is-pattern' node and the parenthesized expression.  So we manually
            // jump past that as, for all intents and purposes, we want to consider the 'is' expression
            // as the parent expression of the (y) expression.
            var parentExpression = node.IsParentKind(SyntaxKind.ConstantPattern)
                ? node.Parent.Parent as ExpressionSyntax
                : node.Parent as ExpressionSyntax;

            // Simplest cases:
            //   ((x)) -> (x)
            if (expression.IsKind(SyntaxKind.ParenthesizedExpression) ||
                parentExpression.IsKind(SyntaxKind.ParenthesizedExpression))
            {
                return(true);
            }

            // (x); -> x;
            if (node.IsParentKind(SyntaxKind.ExpressionStatement))
            {
                return(true);
            }

            // => (x)   ->   => x
            if (node.IsParentKind(SyntaxKind.ArrowExpressionClause))
            {
                return(true);
            }

            // checked((x)) -> checked(x)
            if (node.IsParentKind(SyntaxKind.CheckedExpression) ||
                node.IsParentKind(SyntaxKind.UncheckedExpression))
            {
                return(true);
            }
            // ((x, y)) -> (x, y)
            if (expression.IsKind(SyntaxKind.TupleExpression))
            {
                return(true);
            }

            // int Prop => (x); -> int Prop => x;
            if (node.Parent is ArrowExpressionClauseSyntax arrowExpressionClause && arrowExpressionClause.Expression == node)
            {
                return(true);
            }

            // Don't change (x?.Count).GetValueOrDefault() to x?.Count.GetValueOrDefault()
            if (expression.IsKind(SyntaxKind.ConditionalAccessExpression) && parentExpression is MemberAccessExpressionSyntax)
            {
                return(false);
            }

            // Easy statement-level cases:
            //   var y = (x);           -> var y = x;
            //   var (y, z) = (x);      -> var (y, z) = x;
            //   if ((x))               -> if (x)
            //   return (x);            -> return x;
            //   yield return (x);      -> yield return x;
            //   throw (x);             -> throw x;
            //   switch ((x))           -> switch (x)
            //   while ((x))            -> while (x)
            //   do { } while ((x))     -> do { } while (x)
            //   for(;(x);)             -> for(;x;)
            //   foreach (var y in (x)) -> foreach (var y in x)
            //   lock ((x))             -> lock (x)
            //   using ((x))            -> using (x)
            //   catch when ((x))       -> catch when (x)
            if ((node.IsParentKind(SyntaxKind.EqualsValueClause) && ((EqualsValueClauseSyntax)node.Parent).Value == node) ||
                (node.IsParentKind(SyntaxKind.IfStatement) && ((IfStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ReturnStatement) && ((ReturnStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.YieldReturnStatement) && ((YieldStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.ThrowStatement) && ((ThrowStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.SwitchStatement) && ((SwitchStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.WhileStatement) && ((WhileStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.DoStatement) && ((DoStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ForStatement) && ((ForStatementSyntax)node.Parent).Condition == node) ||
                (node.IsParentKind(SyntaxKind.ForEachStatement, SyntaxKind.ForEachVariableStatement) && ((CommonForEachStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.LockStatement) && ((LockStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.UsingStatement) && ((UsingStatementSyntax)node.Parent).Expression == node) ||
                (node.IsParentKind(SyntaxKind.CatchFilterClause) && ((CatchFilterClauseSyntax)node.Parent).FilterExpression == node))
            {
                return(true);
            }

            // Handle expression-level ambiguities
            if (RemovalMayIntroduceCastAmbiguity(node) ||
                RemovalMayIntroduceCommaListAmbiguity(node) ||
                RemovalMayIntroduceInterpolationAmbiguity(node))
            {
                return(false);
            }

            // Cases:
            //   (C)(this) -> (C)this
            if (node.IsParentKind(SyntaxKind.CastExpression) && expression.IsKind(SyntaxKind.ThisExpression))
            {
                return(true);
            }

            // Cases:
            //   y((x)) -> y(x)
            if (node.IsParentKind(SyntaxKind.Argument) && ((ArgumentSyntax)node.Parent).Expression == node)
            {
                return(true);
            }

            // Cases:
            //   $"{(x)}" -> $"{x}"
            if (node.IsParentKind(SyntaxKind.Interpolation))
            {
                return(true);
            }

            // Cases:
            //   ($"{x}") -> $"{x}"
            if (expression.IsKind(SyntaxKind.InterpolatedStringExpression))
            {
                return(true);
            }

            // Cases:
            //   {(x)} -> {x}
            if (node.Parent is InitializerExpressionSyntax)
            {
                // Assignment expressions are not allowed in initializers
                if (expression.IsAnyAssignExpression())
                {
                    return(false);
                }

                return(true);
            }

            // Cases:
            //   new {(x)} -> {x}
            //   new { a = (x)} -> { a = x }
            //   new { a = (x = c)} -> { a = x = c }
            if (node.Parent is AnonymousObjectMemberDeclaratorSyntax anonymousDeclarator)
            {
                // Assignment expressions are not allowed unless member is named
                if (anonymousDeclarator.NameEquals == null && expression.IsAnyAssignExpression())
                {
                    return(false);
                }

                return(true);
            }

            // Cases:
            // where (x + 1 > 14) -> where x + 1 > 14
            if (node.Parent is QueryClauseSyntax)
            {
                return(true);
            }

            // Cases:
            //   (x)   -> x
            //   (x.y) -> x.y
            if (IsSimpleOrDottedName(expression))
            {
                return(true);
            }

            // Cases:
            //   ('')    -> ''
            //   ("")    -> ""
            //   (false) -> false
            //   (true)  -> true
            //   (null)  -> null
            //   (1)     -> 1
            if (expression.IsAnyLiteralExpression())
            {
                return(true);
            }

            // x ?? (throw ...) -> x ?? throw ...
            if (expression.IsKind(SyntaxKind.ThrowExpression) &&
                node.IsParentKind(SyntaxKind.CoalesceExpression) &&
                ((BinaryExpressionSyntax)node.Parent).Right == node)
            {
                return(true);
            }

            // case (x): -> case x:
            if (node.IsParentKind(SyntaxKind.CaseSwitchLabel))
            {
                return(true);
            }

            // case (x) when y: -> case x when y:
            if (node.IsParentKind(SyntaxKind.ConstantPattern) &&
                node.Parent.IsParentKind(SyntaxKind.CasePatternSwitchLabel))
            {
                return(true);
            }

            // case x when (y): -> case x when y:
            if (node.IsParentKind(SyntaxKind.WhenClause))
            {
                return(true);
            }

            // Operator precedence cases:
            // - If the parent is not an expression, do not remove parentheses
            // - Otherwise, parentheses may be removed if doing so does not change operator associations.
            return(parentExpression != null && !RemovalChangesAssociation(node, parentExpression, semanticModel));
        }
Beispiel #50
0
 public override void VisitParenthesizedExpressionSyntax(ParenthesizedExpressionSyntax syntax) =>
 this.BuildWithConcat(() => base.VisitParenthesizedExpressionSyntax(syntax));
        private static bool RemovalChangesAssociation(
            ParenthesizedExpressionSyntax node, ExpressionSyntax parentExpression, SemanticModel semanticModel)
        {
            var expression       = node.Expression;
            var precedence       = expression.GetOperatorPrecedence();
            var parentPrecedence = parentExpression.GetOperatorPrecedence();

            if (precedence == OperatorPrecedence.None || parentPrecedence == OperatorPrecedence.None)
            {
                // Be conservative if the expression or its parent has no precedence.
                return(true);
            }

            if (precedence > parentPrecedence)
            {
                // Association never changes if the expression's precedence is higher than its parent.
                return(false);
            }
            else if (precedence < parentPrecedence)
            {
                // Association always changes if the expression's precedence is lower that its parent.
                return(true);
            }
            else if (precedence == parentPrecedence)
            {
                // If the expression's precedence is the same as its parent, and both are binary expressions,
                // check for associativity and commutability.

                if (!(expression is BinaryExpressionSyntax || expression is AssignmentExpressionSyntax))
                {
                    // If the expression is not a binary expression, association never changes.
                    return(false);
                }

                if (parentExpression is BinaryExpressionSyntax parentBinaryExpression)
                {
                    // If both the expression and its parent are binary expressions and their kinds
                    // are the same, and the parenthesized expression is on hte right and the
                    // operation is associative, it can sometimes be safe to remove these parens.
                    //
                    // i.e. if you have "a && (b && c)" it can be converted to "a && b && c"
                    // as that new interpretation "(a && b) && c" operates the exact same way at
                    // runtime.
                    //
                    // Specifically:
                    //  1) the operands are still executed in the same order: a, b, then c.
                    //     So even if they have side effects, it will not matter.
                    //  2) the same shortcircuiting happens.
                    //  3) for logical operators the result will always be the same (there are
                    //     additional conditions that are checked for non-logical operators).
                    if (IsAssociative(parentBinaryExpression.Kind()) &&
                        node.Expression.Kind() == parentBinaryExpression.Kind() &&
                        parentBinaryExpression.Right == node)
                    {
                        return(!node.IsSafeToChangeAssociativity(
                                   node.Expression, parentBinaryExpression.Left,
                                   parentBinaryExpression.Right, semanticModel));
                    }

                    // Null-coalescing is right associative; removing parens from the LHS changes the association.
                    if (parentExpression.IsKind(SyntaxKind.CoalesceExpression))
                    {
                        return(parentBinaryExpression.Left == node);
                    }

                    // All other binary operators are left associative; removing parens from the RHS changes the association.
                    return(parentBinaryExpression.Right == node);
                }

                if (parentExpression is AssignmentExpressionSyntax parentAssignmentExpression)
                {
                    // Assignment expressions are right associative; removing parens from the LHS changes the association.
                    return(parentAssignmentExpression.Left == node);
                }

                // If the parent is not a binary expression, association never changes.
                return(false);
            }

            throw ExceptionUtilities.Unreachable;
        }
 private bool TryGenerateParentheses(ParenthesizedExpressionSyntax parenthesizedExpression)
 {
     using (ParenthesesTag())
     {
         return TryGenerateExpression(parenthesizedExpression.Expression);
     }
 }
 private static void ReportDiagnostic(SyntaxNodeAnalysisContext context, ParenthesizedExpressionSyntax node)
 {
     context.ReportDiagnostic(Diagnostic.Create(Descriptor, node.GetLocation()));
     context.ReportDiagnostic(Diagnostic.Create(ParenthesisDescriptor, node.OpenParenToken.GetLocation()));
     context.ReportDiagnostic(Diagnostic.Create(ParenthesisDescriptor, node.CloseParenToken.GetLocation()));
 }
 private static bool IsParenthesizedExpressionToken(ParenthesizedExpressionSyntax expr, SyntaxToken token)
 {
     return expr.FullSpan.Contains(token.SpanStart) &&
         token != expr.CloseParenToken;
 }
Beispiel #55
0
 public override void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     throw new NotImplementedException();
 }
        public static Task <Document> RefactorAsync(
            Document document,
            ParenthesizedExpressionSyntax parenthesizedExpression,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            ExpressionSyntax expression = parenthesizedExpression.Expression;

            SyntaxTriviaList leading = parenthesizedExpression.GetLeadingTrivia()
                                       .Concat(parenthesizedExpression.OpenParenToken.TrailingTrivia)
                                       .Concat(expression.GetLeadingTrivia())
                                       .ToSyntaxTriviaList();

            SyntaxTriviaList trailing = expression.GetTrailingTrivia()
                                        .Concat(parenthesizedExpression.CloseParenToken.LeadingTrivia)
                                        .Concat(parenthesizedExpression.GetTrailingTrivia())
                                        .ToSyntaxTriviaList();

            ExpressionSyntax newExpression = expression
                                             .WithLeadingTrivia(leading)
                                             .WithTrailingTrivia(trailing)
                                             .WithFormatterAnnotation();

            if (!leading.Any())
            {
                SyntaxNode parent = parenthesizedExpression.Parent;

                switch (parent.Kind())
                {
                case SyntaxKind.ReturnStatement:
                {
                    var returnStatement = (ReturnStatementSyntax)parent;

                    SyntaxToken returnKeyword = returnStatement.ReturnKeyword;

                    if (!returnKeyword.TrailingTrivia.Any())
                    {
                        ReturnStatementSyntax newNode = returnStatement.Update(returnKeyword.WithTrailingTrivia(Space), newExpression, returnStatement.SemicolonToken);

                        return(document.ReplaceNodeAsync(returnStatement, newNode, cancellationToken));
                    }

                    break;
                }

                case SyntaxKind.YieldReturnStatement:
                {
                    var yieldReturn = (YieldStatementSyntax)parent;

                    SyntaxToken returnKeyword = yieldReturn.ReturnOrBreakKeyword;

                    if (!returnKeyword.TrailingTrivia.Any())
                    {
                        YieldStatementSyntax newNode = yieldReturn.Update(yieldReturn.YieldKeyword, returnKeyword.WithTrailingTrivia(Space), newExpression, yieldReturn.SemicolonToken);

                        return(document.ReplaceNodeAsync(yieldReturn, newNode, cancellationToken));
                    }

                    break;
                }

                case SyntaxKind.AwaitExpression:
                {
                    var awaitExpression = (AwaitExpressionSyntax)parent;

                    SyntaxToken awaitKeyword = awaitExpression.AwaitKeyword;

                    if (!awaitKeyword.TrailingTrivia.Any())
                    {
                        AwaitExpressionSyntax newNode = awaitExpression.Update(awaitKeyword.WithTrailingTrivia(Space), newExpression);

                        return(document.ReplaceNodeAsync(awaitExpression, newNode, cancellationToken));
                    }

                    break;
                }
                }
            }

            return(document.ReplaceNodeAsync(parenthesizedExpression, newExpression, cancellationToken));
        }
Beispiel #57
0
 public virtual void VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
 {
     DefaultVisit(node);
 }
        public override SyntaxNode VisitParenthesizedExpression(ParenthesizedExpressionSyntax node)
        {
            var newExpression = (ExpressionSyntax)node.Expression.Accept(this);

            // Remove unnecessary parentheses around non-binary expressions
            if (!(newExpression is BinaryExpressionSyntax))
            {
                return newExpression
                    .WithLeadingTrivia(node.GetLeadingTrivia())
                    .WithTrailingTrivia(node.GetTrailingTrivia());
            }
            else
            {
                return node.Expression != newExpression ?
                    node.WithExpression(newExpression) : node;
            }
        }
 public ParenthesizedExpressionTranslation(ParenthesizedExpressionSyntax syntax, SyntaxTranslation parent) : base(syntax, parent)
 {
     Expression = syntax.Expression.Get<ExpressionTranslation>(this);
 }