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;
        }