public static boolean areParenthesesNecessary()

in compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtPsiUtil.java [421:568]


    public static boolean areParenthesesNecessary(
            @NotNull KtExpression innerExpression,
            @NotNull KtExpression currentInner,
            @NotNull KtElement parentElement
    ) {
        if (parentElement instanceof KtDelegatedSuperTypeEntry) return true;

        if (parentElement instanceof KtParenthesizedExpression || innerExpression instanceof KtParenthesizedExpression) {
            return false;
        }

        if (parentElement instanceof KtPackageDirective) return false;

        if (parentElement instanceof KtWhenExpression || innerExpression instanceof KtWhenExpression) {
            return false;
        }

        if (parentElement instanceof KtCollectionLiteralExpression) return false;

        if (innerExpression instanceof KtIfExpression) {
            if (parentElement instanceof KtQualifiedExpression) return true;

            PsiElement current = parentElement;

            while (!(current instanceof KtBlockExpression || current instanceof KtDeclaration || current instanceof KtStatementExpression || current instanceof KtFile)) {
                if (current.getTextRange().getEndOffset() != currentInner.getTextRange().getEndOffset()) {
                    return !(current instanceof KtParenthesizedExpression) && !(current instanceof KtValueArgumentList); // if current expression is "guarded" by parenthesis, no extra parenthesis is necessary
                }

                current = current.getParent();
            }
        }

        if (innerExpression instanceof KtLambdaExpression) {
            PsiElement prevSibling = PsiTreeUtil.skipWhitespacesAndCommentsBackward(currentInner);
            if (endWithParenthesisOrCallExpression(prevSibling)) return true;
        }

        if (parentElement instanceof KtCallExpression && currentInner == ((KtCallExpression) parentElement).getCalleeExpression()) {
            KtCallExpression parentCall = (KtCallExpression) parentElement;
            KtExpression targetInnerExpression = innerExpression;
            if (targetInnerExpression instanceof KtDotQualifiedExpression) {
                KtExpression selector = ((KtDotQualifiedExpression) targetInnerExpression).getSelectorExpression();
                if (selector != null) {
                    targetInnerExpression = selector;
                }
            }
            if (targetInnerExpression instanceof KtSimpleNameExpression) return false;
            if (KtPsiUtilKt.getQualifiedExpressionForSelector(parentElement) != null) return true;
            if (targetInnerExpression instanceof KtCallExpression && parentCall.getValueArgumentList() == null) return true;
            return !(targetInnerExpression instanceof KtThisExpression
                     || targetInnerExpression instanceof KtArrayAccessExpression
                     || targetInnerExpression instanceof KtConstantExpression
                     || targetInnerExpression instanceof KtStringTemplateExpression
                     || targetInnerExpression instanceof KtCallExpression);
        }

        if (parentElement instanceof KtValueArgument) {
            // a(___, d > (e + f)) => a((b < c), d > (e + f)) to prevent parsing < c, d > as type argument list
            KtValueArgument nextArg = PsiTreeUtil.getNextSiblingOfType(parentElement, KtValueArgument.class);
            PsiElement nextExpression = nextArg != null ? nextArg.getArgumentExpression() : null;
            if (innerExpression instanceof KtBinaryExpression &&
                ((KtBinaryExpression) innerExpression).getOperationToken() == KtTokens.LT &&
                nextExpression instanceof KtBinaryExpression &&
                ((KtBinaryExpression) nextExpression).getOperationToken() == KtTokens.GT) return true;
        }

        IElementType innerOperation = getOperation(innerExpression);

        if (innerExpression instanceof KtBinaryExpression) {
            // '(x operator return [...]) operator ...' case
            if (parentElement instanceof KtBinaryExpression) {
                KtBinaryExpression innerBinary = (KtBinaryExpression) innerExpression;
                if (innerBinary.getRight() instanceof KtReturnExpression) {
                    return true;
                }
            }
            // '(x operator y)' case
            if (innerOperation != KtTokens.ELVIS &&
                !(parentElement instanceof KtValueArgument) &&
                !(parentElement instanceof KtParameter) &&
                !(parentElement instanceof KtBlockStringTemplateEntry) &&
                !(parentElement instanceof KtContainerNode &&
                  // for `if` branch, `else` branch, loops body and `when` entry parentheses are required
                  !(parentElement instanceof KtContainerNodeForControlStructureBody)) &&
                isKeepBinaryExpressionParenthesized((KtBinaryExpression) innerExpression)) {
                return true;
            }
        }

        if (!(parentElement instanceof KtExpression)) return false;

        IElementType parentOperation = getOperation((KtExpression) parentElement);

        // 'return (@label{...})' case
        if (parentElement instanceof KtReturnExpression
            && (innerExpression instanceof KtLabeledExpression || innerExpression instanceof KtAnnotatedExpression)) return true;

        // '(x: Int) < y' case
        if (innerExpression instanceof KtBinaryExpressionWithTypeRHS && parentOperation == KtTokens.LT) {
            return true;
        }

        if (parentElement instanceof KtLabeledExpression) return false;

        // 'x ?: ...' case
        if (parentElement instanceof KtBinaryExpression &&
            parentOperation == KtTokens.ELVIS &&
            !(innerExpression instanceof KtBinaryExpression) &&
            currentInner == ((KtBinaryExpression) parentElement).getRight()) {
            return false;
        }

        // 'x = fun {}' case
        if (parentElement instanceof KtBinaryExpression &&
            parentOperation == KtTokens.EQ &&
            innerExpression instanceof KtNamedFunction &&
            currentInner == ((KtBinaryExpression) parentElement).getRight()) {
            return false;
        }

        int innerPriority = getPriority(innerExpression);
        int parentPriority = getPriority((KtExpression) parentElement);

        if (innerPriority == parentPriority) {
            if (parentElement instanceof KtBinaryExpression) {
                if (innerOperation == KtTokens.ANDAND || innerOperation == KtTokens.OROR) {
                    return false;
                }
                return ((KtBinaryExpression) parentElement).getRight() == currentInner;
            }

            if (parentElement instanceof KtPrefixExpression && innerExpression instanceof KtPrefixExpression) {
                // +(++x) or +(+x) case
                if (parentOperation == KtTokens.PLUS) {
                    return innerOperation == KtTokens.PLUS || innerOperation == KtTokens.PLUSPLUS;
                }

                // -(--x) or -(-x) case
                if (parentOperation == KtTokens.MINUS) {
                    return innerOperation == KtTokens.MINUS || innerOperation == KtTokens.MINUSMINUS;
                }
            }
            return false;
        }

        return innerPriority < parentPriority;
    }