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