• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.facebook.ktfmt.format
18 
19 import com.google.common.base.Throwables
20 import com.google.common.collect.ImmutableList
21 import com.google.googlejavaformat.Doc
22 import com.google.googlejavaformat.FormattingError
23 import com.google.googlejavaformat.Indent
24 import com.google.googlejavaformat.Indent.Const.ZERO
25 import com.google.googlejavaformat.OpsBuilder
26 import com.google.googlejavaformat.Output.BreakTag
27 import java.util.ArrayDeque
28 import java.util.Optional
29 import org.jetbrains.kotlin.com.intellij.psi.PsiComment
30 import org.jetbrains.kotlin.com.intellij.psi.PsiElement
31 import org.jetbrains.kotlin.com.intellij.psi.PsiWhiteSpace
32 import org.jetbrains.kotlin.com.intellij.psi.stubs.PsiFileStubImpl
33 import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
34 import org.jetbrains.kotlin.lexer.KtTokens
35 import org.jetbrains.kotlin.psi.KtAnnotatedExpression
36 import org.jetbrains.kotlin.psi.KtAnnotation
37 import org.jetbrains.kotlin.psi.KtAnnotationEntry
38 import org.jetbrains.kotlin.psi.KtAnnotationUseSiteTarget
39 import org.jetbrains.kotlin.psi.KtArrayAccessExpression
40 import org.jetbrains.kotlin.psi.KtBinaryExpression
41 import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
42 import org.jetbrains.kotlin.psi.KtBlockExpression
43 import org.jetbrains.kotlin.psi.KtBreakExpression
44 import org.jetbrains.kotlin.psi.KtCallExpression
45 import org.jetbrains.kotlin.psi.KtCallableReferenceExpression
46 import org.jetbrains.kotlin.psi.KtCatchClause
47 import org.jetbrains.kotlin.psi.KtClass
48 import org.jetbrains.kotlin.psi.KtClassBody
49 import org.jetbrains.kotlin.psi.KtClassInitializer
50 import org.jetbrains.kotlin.psi.KtClassLiteralExpression
51 import org.jetbrains.kotlin.psi.KtClassOrObject
52 import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
53 import org.jetbrains.kotlin.psi.KtConstantExpression
54 import org.jetbrains.kotlin.psi.KtConstructorDelegationCall
55 import org.jetbrains.kotlin.psi.KtContainerNode
56 import org.jetbrains.kotlin.psi.KtContextReceiverList
57 import org.jetbrains.kotlin.psi.KtContinueExpression
58 import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
59 import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
60 import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
61 import org.jetbrains.kotlin.psi.KtDoWhileExpression
62 import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
63 import org.jetbrains.kotlin.psi.KtDynamicType
64 import org.jetbrains.kotlin.psi.KtElement
65 import org.jetbrains.kotlin.psi.KtEnumEntry
66 import org.jetbrains.kotlin.psi.KtExpression
67 import org.jetbrains.kotlin.psi.KtFile
68 import org.jetbrains.kotlin.psi.KtFileAnnotationList
69 import org.jetbrains.kotlin.psi.KtFinallySection
70 import org.jetbrains.kotlin.psi.KtForExpression
71 import org.jetbrains.kotlin.psi.KtFunctionType
72 import org.jetbrains.kotlin.psi.KtIfExpression
73 import org.jetbrains.kotlin.psi.KtImportDirective
74 import org.jetbrains.kotlin.psi.KtImportList
75 import org.jetbrains.kotlin.psi.KtIntersectionType
76 import org.jetbrains.kotlin.psi.KtIsExpression
77 import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
78 import org.jetbrains.kotlin.psi.KtLabeledExpression
79 import org.jetbrains.kotlin.psi.KtLambdaArgument
80 import org.jetbrains.kotlin.psi.KtLambdaExpression
81 import org.jetbrains.kotlin.psi.KtModifierList
82 import org.jetbrains.kotlin.psi.KtNamedFunction
83 import org.jetbrains.kotlin.psi.KtNullableType
84 import org.jetbrains.kotlin.psi.KtPackageDirective
85 import org.jetbrains.kotlin.psi.KtParameter
86 import org.jetbrains.kotlin.psi.KtParameterList
87 import org.jetbrains.kotlin.psi.KtParenthesizedExpression
88 import org.jetbrains.kotlin.psi.KtPostfixExpression
89 import org.jetbrains.kotlin.psi.KtPrefixExpression
90 import org.jetbrains.kotlin.psi.KtPrimaryConstructor
91 import org.jetbrains.kotlin.psi.KtProjectionKind
92 import org.jetbrains.kotlin.psi.KtProperty
93 import org.jetbrains.kotlin.psi.KtPropertyAccessor
94 import org.jetbrains.kotlin.psi.KtPropertyDelegate
95 import org.jetbrains.kotlin.psi.KtQualifiedExpression
96 import org.jetbrains.kotlin.psi.KtReferenceExpression
97 import org.jetbrains.kotlin.psi.KtReturnExpression
98 import org.jetbrains.kotlin.psi.KtScript
99 import org.jetbrains.kotlin.psi.KtScriptInitializer
100 import org.jetbrains.kotlin.psi.KtSecondaryConstructor
101 import org.jetbrains.kotlin.psi.KtSimpleNameExpression
102 import org.jetbrains.kotlin.psi.KtStringTemplateExpression
103 import org.jetbrains.kotlin.psi.KtSuperExpression
104 import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
105 import org.jetbrains.kotlin.psi.KtSuperTypeList
106 import org.jetbrains.kotlin.psi.KtThisExpression
107 import org.jetbrains.kotlin.psi.KtThrowExpression
108 import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
109 import org.jetbrains.kotlin.psi.KtTryExpression
110 import org.jetbrains.kotlin.psi.KtTypeAlias
111 import org.jetbrains.kotlin.psi.KtTypeArgumentList
112 import org.jetbrains.kotlin.psi.KtTypeConstraint
113 import org.jetbrains.kotlin.psi.KtTypeConstraintList
114 import org.jetbrains.kotlin.psi.KtTypeParameter
115 import org.jetbrains.kotlin.psi.KtTypeParameterList
116 import org.jetbrains.kotlin.psi.KtTypeProjection
117 import org.jetbrains.kotlin.psi.KtTypeReference
118 import org.jetbrains.kotlin.psi.KtUserType
119 import org.jetbrains.kotlin.psi.KtValueArgument
120 import org.jetbrains.kotlin.psi.KtValueArgumentList
121 import org.jetbrains.kotlin.psi.KtWhenConditionInRange
122 import org.jetbrains.kotlin.psi.KtWhenConditionIsPattern
123 import org.jetbrains.kotlin.psi.KtWhenConditionWithExpression
124 import org.jetbrains.kotlin.psi.KtWhenExpression
125 import org.jetbrains.kotlin.psi.KtWhileExpression
126 import org.jetbrains.kotlin.psi.psiUtil.children
127 import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespace
128 import org.jetbrains.kotlin.psi.psiUtil.startOffset
129 import org.jetbrains.kotlin.psi.psiUtil.startsWithComment
130 import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
131 import org.jetbrains.kotlin.psi.stubs.impl.KotlinPlaceHolderStubImpl
132 
133 /** An AST visitor that builds a stream of {@link Op}s to format. */
134 class KotlinInputAstVisitor(
135     private val options: FormattingOptions,
136     private val builder: OpsBuilder
137 ) : KtTreeVisitorVoid() {
138 
139   /** Standard indentation for a block */
140   private val blockIndent: Indent.Const = Indent.Const.make(options.blockIndent, 1)
141 
142   /**
143    * Standard indentation for a long expression or function call, it is different than block
144    * indentation on purpose
145    */
146   private val expressionBreakIndent: Indent.Const = Indent.Const.make(options.continuationIndent, 1)
147 
148   private val blockPlusExpressionBreakIndent: Indent.Const =
149       Indent.Const.make(options.blockIndent + options.continuationIndent, 1)
150 
151   private val doubleExpressionBreakIndent: Indent.Const =
152       Indent.Const.make(options.continuationIndent, 2)
153 
154   private val expressionBreakNegativeIndent: Indent.Const =
155       Indent.Const.make(-options.continuationIndent, 1)
156 
157   /** A record of whether we have visited into an expression. */
158   private val inExpression = ArrayDeque(ImmutableList.of(false))
159 
160   /** Tracks whether we are handling an import directive */
161   private var inImport = false
162 
163   /** Example: `fun foo(n: Int) { println(n) }` */
164   override fun visitNamedFunction(function: KtNamedFunction) {
165     builder.sync(function)
166     builder.block(ZERO) {
167       visitFunctionLikeExpression(
168           contextReceiverList =
169               function.getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER_LIST),
170           modifierList = function.modifierList,
171           keyword = "fun",
172           typeParameters = function.typeParameterList,
173           receiverTypeReference = function.receiverTypeReference,
174           name = function.nameIdentifier?.text,
175           parameterList = function.valueParameterList,
176           typeConstraintList = function.typeConstraintList,
177           bodyExpression = function.bodyBlockExpression ?: function.bodyExpression,
178           typeOrDelegationCall = function.typeReference,
179       )
180     }
181   }
182 
183   /** Example `Int`, `(String)` or `() -> Int` */
184   override fun visitTypeReference(typeReference: KtTypeReference) {
185     builder.sync(typeReference)
186     // Normally we'd visit the children nodes through accessors on 'typeReference', and  we wouldn't
187     // loop over children.
188     // But, in this case the modifier list can either be inside the parenthesis:
189     // ... (@Composable (x) -> Unit)
190     // or outside of them:
191     // ... @Composable ((x) -> Unit)
192     val modifierList = typeReference.modifierList
193     val typeElement = typeReference.typeElement
194     for (child in typeReference.node.children()) {
195       when {
196         child.psi == modifierList -> visit(modifierList)
197         child.psi == typeElement -> visit(typeElement)
198         child.elementType == KtTokens.LPAR -> builder.token("(")
199         child.elementType == KtTokens.RPAR -> builder.token(")")
200       }
201     }
202   }
203 
204   override fun visitDynamicType(type: KtDynamicType) {
205     builder.token("dynamic")
206   }
207 
208   /** Example: `String?` or `((Int) -> Unit)?` */
209   override fun visitNullableType(nullableType: KtNullableType) {
210     builder.sync(nullableType)
211 
212     // Normally we wouldn't loop over children, but there can be multiple layers of parens.
213     val modifierList = nullableType.modifierList
214     val innerType = nullableType.innerType
215     for (child in nullableType.node.children()) {
216       when {
217         child.psi == modifierList -> visit(modifierList)
218         child.psi == innerType -> visit(innerType)
219         child.elementType == KtTokens.LPAR -> builder.token("(")
220         child.elementType == KtTokens.RPAR -> builder.token(")")
221       }
222     }
223     builder.token("?")
224   }
225 
226   /** Example: `String` or `List<Int>`, */
227   override fun visitUserType(type: KtUserType) {
228     builder.sync(type)
229 
230     if (type.qualifier != null) {
231       visit(type.qualifier)
232       builder.token(".")
233     }
234     visit(type.referenceExpression)
235     val typeArgumentList = type.typeArgumentList
236     if (typeArgumentList != null) {
237       builder.block(expressionBreakIndent) { visit(typeArgumentList) }
238     }
239   }
240 
241   /** Example: `A & B`, */
242   override fun visitIntersectionType(type: KtIntersectionType) {
243     builder.sync(type)
244 
245     // TODO(strulovich): Should this have the same indentation behaviour as `x && y`?
246     visit(type.getLeftTypeRef())
247     builder.space()
248     builder.token("&")
249     builder.space()
250     visit(type.getRightTypeRef())
251   }
252 
253   /** Example `<Int, String>` in `List<Int, String>` */
254   override fun visitTypeArgumentList(typeArgumentList: KtTypeArgumentList) {
255     builder.sync(typeArgumentList)
256     visitEachCommaSeparated(
257         typeArgumentList.arguments,
258         typeArgumentList.trailingComma != null,
259         wrapInBlock = !options.manageTrailingCommas,
260         prefix = "<",
261         postfix = ">",
262     )
263   }
264 
265   override fun visitTypeProjection(typeProjection: KtTypeProjection) {
266     builder.sync(typeProjection)
267     val typeReference = typeProjection.typeReference
268     when (typeProjection.projectionKind) {
269       KtProjectionKind.IN -> {
270         builder.token("in")
271         builder.space()
272         visit(typeReference)
273       }
274       KtProjectionKind.OUT -> {
275         builder.token("out")
276         builder.space()
277         visit(typeReference)
278       }
279       KtProjectionKind.STAR -> builder.token("*")
280       KtProjectionKind.NONE -> visit(typeReference)
281     }
282   }
283 
284   /**
285    * @param keyword e.g., "fun" or "class".
286    * @param typeOrDelegationCall for functions, the return typeOrDelegationCall; for classes, the
287    *   list of supertypes.
288    */
289   private fun visitFunctionLikeExpression(
290       contextReceiverList: KtContextReceiverList?,
291       modifierList: KtModifierList?,
292       keyword: String?,
293       typeParameters: KtTypeParameterList?,
294       receiverTypeReference: KtTypeReference?,
295       name: String?,
296       parameterList: KtParameterList?,
297       typeConstraintList: KtTypeConstraintList?,
298       bodyExpression: KtExpression?,
299       typeOrDelegationCall: KtElement?,
300   ) {
301     fun emitTypeOrDelegationCall(block: () -> Unit) {
302       if (typeOrDelegationCall != null) {
303         builder.block(ZERO) {
304           if (typeOrDelegationCall is KtConstructorDelegationCall) {
305             builder.space()
306           }
307           builder.token(":")
308           block()
309         }
310       }
311     }
312 
313     val forceTrailingBreak = name != null
314     builder.block(ZERO, isEnabled = forceTrailingBreak) {
315       if (contextReceiverList != null) {
316         visitContextReceiverList(contextReceiverList)
317       }
318       if (modifierList != null) {
319         visitModifierList(modifierList)
320       }
321       if (keyword != null) {
322         builder.token(keyword)
323       }
324       if (typeParameters != null) {
325         builder.space()
326         builder.block(ZERO) { visit(typeParameters) }
327       }
328 
329       if (name != null || receiverTypeReference != null) {
330         builder.space()
331       }
332       builder.block(ZERO) {
333         if (receiverTypeReference != null) {
334           visit(receiverTypeReference)
335           builder.breakOp(Doc.FillMode.INDEPENDENT, "", expressionBreakIndent)
336           builder.token(".")
337         }
338         if (name != null) {
339           builder.token(name)
340         }
341       }
342 
343       if (parameterList != null && parameterList.hasEmptyParens()) {
344         builder.block(ZERO) {
345           builder.token("(")
346           builder.token(")")
347           emitTypeOrDelegationCall {
348             builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
349             builder.block(expressionBreakIndent) { visit(typeOrDelegationCall) }
350           }
351         }
352       } else {
353         builder.block(expressionBreakIndent) {
354           if (parameterList != null) {
355             visitEachCommaSeparated(
356                 list = parameterList.parameters,
357                 hasTrailingComma = parameterList.trailingComma != null,
358                 prefix = "(",
359                 postfix = ")",
360                 wrapInBlock = false,
361                 breakBeforePostfix = true,
362             )
363           }
364           emitTypeOrDelegationCall {
365             builder.space()
366             builder.block(expressionBreakNegativeIndent) { visit(typeOrDelegationCall) }
367           }
368         }
369       }
370 
371       if (typeConstraintList != null) {
372         builder.space()
373         visit(typeConstraintList)
374       }
375       if (bodyExpression is KtBlockExpression) {
376         builder.space()
377         visit(bodyExpression)
378       } else if (bodyExpression != null) {
379         builder.space()
380         builder.block(ZERO) {
381           builder.token("=")
382           if (isLambdaOrScopingFunction(bodyExpression)) {
383             visitLambdaOrScopingFunction(bodyExpression)
384           } else {
385             builder.block(expressionBreakIndent) {
386               builder.breakOp(Doc.FillMode.INDEPENDENT, " ", ZERO)
387               builder.block(ZERO) { visit(bodyExpression) }
388             }
389           }
390         }
391       }
392       builder.guessToken(";")
393     }
394     if (forceTrailingBreak) {
395       builder.forcedBreak()
396     }
397   }
398 
399   private fun genSym(): BreakTag {
400     return BreakTag()
401   }
402 
403   private fun emitBracedBlock(
404       bodyBlockExpression: PsiElement,
405       emitChildren: (Array<PsiElement>) -> Unit,
406   ) {
407     builder.token("{", Doc.Token.RealOrImaginary.REAL, blockIndent, Optional.of(blockIndent))
408     val statements = bodyBlockExpression.children
409     if (statements.isNotEmpty()) {
410       builder.block(blockIndent) {
411         builder.forcedBreak()
412         builder.blankLineWanted(OpsBuilder.BlankLineWanted.PRESERVE)
413         emitChildren(statements)
414       }
415       builder.forcedBreak()
416       builder.blankLineWanted(OpsBuilder.BlankLineWanted.NO)
417     }
418     builder.token("}", blockIndent)
419   }
420 
421   private fun visitStatement(statement: PsiElement) {
422     builder.block(ZERO) { visit(statement) }
423     builder.guessToken(";")
424   }
425 
426   private fun visitStatements(statements: Array<PsiElement>) {
427     var first = true
428     builder.guessToken(";")
429     for (statement in statements) {
430       builder.forcedBreak()
431       if (!first) {
432         builder.blankLineWanted(OpsBuilder.BlankLineWanted.PRESERVE)
433       }
434       first = false
435       visitStatement(statement)
436     }
437   }
438 
439   override fun visitProperty(property: KtProperty) {
440     builder.sync(property)
441     builder.block(ZERO) {
442       declareOne(
443           kind = DeclarationKind.FIELD,
444           modifiers = property.modifierList,
445           valOrVarKeyword = property.valOrVarKeyword.text,
446           typeParameters = property.typeParameterList,
447           receiver = property.receiverTypeReference,
448           name = property.nameIdentifier?.text,
449           type = property.typeReference,
450           typeConstraintList = property.typeConstraintList,
451           delegate = property.delegate,
452           initializer = property.initializer,
453           accessors = property.accessors)
454     }
455     builder.guessToken(";")
456     if (property.parent !is KtWhenExpression) {
457       builder.forcedBreak()
458     }
459   }
460 
461   /**
462    * Example: "com.facebook.bla.bla" in imports or "a.b.c.d" in expressions.
463    *
464    * There's a few cases that are different. We deal with imports by keeping them on the same line.
465    * For regular chained expressions we go the left most descendant so we can start indentation only
466    * before the first break (a `.` or `?.`), and keep the seem indentation for this chain of calls.
467    */
468   override fun visitQualifiedExpression(expression: KtQualifiedExpression) {
469     builder.sync(expression)
470     val receiver = expression.receiverExpression
471     when {
472       inImport -> {
473         visit(receiver)
474         val selectorExpression = expression.selectorExpression
475         if (selectorExpression != null) {
476           builder.token(".")
477           visit(selectorExpression)
478         }
479       }
480       receiver is KtStringTemplateExpression -> {
481         builder.block(expressionBreakIndent) {
482           visit(receiver)
483           builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO)
484           builder.token(expression.operationSign.value)
485           visit(expression.selectorExpression)
486         }
487       }
488       receiver is KtWhenExpression -> {
489         builder.block(ZERO) {
490           visit(receiver)
491           builder.token(expression.operationSign.value)
492           visit(expression.selectorExpression)
493         }
494       }
495       else -> {
496         emitQualifiedExpression(expression)
497       }
498     }
499   }
500 
501   /** Extra data to help [emitQualifiedExpression] know when to open and close a group */
502   private class GroupingInfo {
503     var groupOpenCount = 0
504     var shouldCloseGroup = false
505   }
506 
507   /**
508    * Handles a chain of qualified expressions, i.e. `a[5].b!!.c()[4].f()`
509    *
510    * This is by far the most complicated part of this formatter. We start by breaking the expression
511    * to the steps it is executed in (which are in the opposite order of how the syntax tree is
512    * built).
513    *
514    * We then calculate information to know which parts need to be groups, and finally go part by
515    * part, emitting it to the [builder] while closing and opening groups.
516    */
517   private fun emitQualifiedExpression(expression: KtExpression) {
518     val parts = breakIntoParts(expression)
519     // whether we want to make a lambda look like a block, this make Kotlin DSLs look as expected
520     val useBlockLikeLambdaStyle = parts.last().isLambda() && parts.count { it.isLambda() } == 1
521     val groupingInfos = computeGroupingInfo(parts, useBlockLikeLambdaStyle)
522     builder.block(expressionBreakIndent) {
523       val nameTag = genSym() // allows adjusting arguments indentation if a break will be made
524       for ((index, ktExpression) in parts.withIndex()) {
525         if (ktExpression is KtQualifiedExpression) {
526           builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO, Optional.of(nameTag))
527         }
528         repeat(groupingInfos[index].groupOpenCount) { builder.open(ZERO) }
529         when (ktExpression) {
530           is KtQualifiedExpression -> {
531             builder.token(ktExpression.operationSign.value)
532             val selectorExpression = ktExpression.selectorExpression
533             if (selectorExpression !is KtCallExpression) {
534               // selector is a simple field access
535               visit(selectorExpression)
536               if (groupingInfos[index].shouldCloseGroup) {
537                 builder.close()
538               }
539             } else {
540               // selector is a function call, we may close a group after its name
541               // emit `doIt` from `doIt(1, 2) { it }`
542               visit(selectorExpression.calleeExpression)
543               // close groups according to instructions
544               if (groupingInfos[index].shouldCloseGroup) {
545                 builder.close()
546               }
547               // close group due to last lambda to allow block-like style in `as.forEach { ... }`
548               val isTrailingLambda = useBlockLikeLambdaStyle && index == parts.size - 1
549               if (isTrailingLambda) {
550                 builder.close()
551               }
552               val argsIndentElse = if (index == parts.size - 1) ZERO else expressionBreakIndent
553               val lambdaIndentElse = if (isTrailingLambda) expressionBreakNegativeIndent else ZERO
554               val negativeLambdaIndentElse = if (isTrailingLambda) expressionBreakIndent else ZERO
555 
556               // emit `(1, 2) { it }` from `doIt(1, 2) { it }`
557               visitCallElement(
558                   null,
559                   selectorExpression.typeArgumentList,
560                   selectorExpression.valueArgumentList,
561                   selectorExpression.lambdaArguments,
562                   argumentsIndent = Indent.If.make(nameTag, expressionBreakIndent, argsIndentElse),
563                   lambdaIndent = Indent.If.make(nameTag, ZERO, lambdaIndentElse),
564                   negativeLambdaIndent = Indent.If.make(nameTag, ZERO, negativeLambdaIndentElse),
565               )
566             }
567           }
568           is KtArrayAccessExpression -> {
569             visitArrayAccessBrackets(ktExpression)
570             builder.close()
571           }
572           is KtPostfixExpression -> {
573             builder.token(ktExpression.operationReference.text)
574             builder.close()
575           }
576           else -> {
577             check(index == 0)
578             visit(ktExpression)
579           }
580         }
581       }
582     }
583   }
584 
585   /**
586    * Decomposes a qualified expression into parts, so `rainbow.red.orange.yellow` becomes `[rainbow,
587    * rainbow.red, rainbow.red.orange, rainbow.orange.yellow]`
588    */
589   private fun breakIntoParts(expression: KtExpression): List<KtExpression> {
590     val parts = ArrayDeque<KtExpression>()
591 
592     // use an ArrayDeque and add elements to the beginning so the innermost expression comes first
593     // foo.bar.yay -> [yay, bar.yay, foo.bar.yay]
594 
595     var node: KtExpression? = expression
596     while (node != null) {
597       parts.addFirst(node)
598       node =
599           when (node) {
600             is KtQualifiedExpression -> node.receiverExpression
601             is KtArrayAccessExpression -> node.arrayExpression
602             is KtPostfixExpression -> node.baseExpression
603             else -> null
604           }
605     }
606 
607     return parts.toList()
608   }
609 
610   /**
611    * Generates the [GroupingInfo] array to go with an array of [KtQualifiedExpression] parts
612    *
613    * For example, the expression `a.b[2].c.d()` is made of four expressions:
614    * 1. [KtQualifiedExpression] `a.b[2].c . d()` (this will be `parts[4]`)
615    * 1. [KtQualifiedExpression] `a.b[2] . c` (this will be `parts[3]`)
616    * 2. [KtArrayAccessExpression] `a.b [2]` (this will be `parts[2]`)
617    * 3. [KtQualifiedExpression] `a . b` (this will be `parts[1]`)
618    * 4. [KtSimpleNameExpression] `a` (this will be `parts[0]`)
619    *
620    * Once in parts, these are in the reverse order. To render the array correct we need to make sure
621    * `b` and [2] are in a group so we avoid splitting them. To do so we need to open a group for `b`
622    * (that will be done in part 2), and always close a group for an array.
623    *
624    * Here is the same expression, with justified braces marking the groupings it will get:
625    * ```
626    *  a . b [2] . c . d ()
627    * {a . b} --> Grouping `a.b` because it can be a package name or simple field access so we add 1
628    *             to the number of groups to open at groupingInfos[0], and mark to close a group at
629    *             groupingInfos[1]
630    * {a . b [2]} --> Grouping `a.b` with `[2]`, since otherwise we may break inside the brackets
631    *                 instead of preferring breaks before dots. So we open a group at [0], but since
632    *                 we always close a group after brackets, we don't store that information.
633    *             {c . d} --> another group to attach the first function name to the fields before it
634    *                         this time we don't start the group in the beginning, and use
635    *                         lastIndexToOpen to track the spot after the last time we stopped
636    *                         grouping.
637    * ```
638    *
639    * The final expression with groupings:
640    * ```
641    * {{a.b}[2]}.{c.d}()
642    * ```
643    */
644   private fun computeGroupingInfo(
645       parts: List<KtExpression>,
646       useBlockLikeLambdaStyle: Boolean
647   ): List<GroupingInfo> {
648     val groupingInfos = List(parts.size) { GroupingInfo() }
649     var lastIndexToOpen = 0
650     for ((index, part) in parts.withIndex()) {
651       when (part) {
652         is KtQualifiedExpression -> {
653           val receiverExpression = part.receiverExpression
654           val previous =
655               (receiverExpression as? KtQualifiedExpression)?.selectorExpression
656                   ?: receiverExpression
657           val current = checkNotNull(part.selectorExpression)
658           if (lastIndexToOpen == 0 &&
659               shouldGroupPartWithPrevious(parts, part, index, previous, current)) {
660             // this and the previous items should be grouped for better style
661             // we add another group to open in index 0
662             groupingInfos[0].groupOpenCount++
663             // we don't always close a group when emitting this node, so we need this flag to
664             // mark if we need to close a group
665             groupingInfos[index].shouldCloseGroup = true
666           } else {
667             // use this index in to open future groups for arrays and postfixes
668             // we will also stop grouping field access to the beginning of the expression
669             lastIndexToOpen = index
670           }
671         }
672         is KtArrayAccessExpression,
673         is KtPostfixExpression -> {
674           // we group these with the last item with a name, and we always close them
675           groupingInfos[lastIndexToOpen].groupOpenCount++
676         }
677       }
678     }
679     if (useBlockLikeLambdaStyle) {
680       // a trailing lambda adds a group that we stop before emitting the lambda
681       groupingInfos[0].groupOpenCount++
682     }
683     return groupingInfos
684   }
685 
686   /** Decide whether a [KtQualifiedExpression] part should be grouped with the previous part */
687   private fun shouldGroupPartWithPrevious(
688       parts: List<KtExpression>,
689       part: KtExpression,
690       index: Int,
691       previous: KtExpression,
692       current: KtExpression
693   ): Boolean {
694     // this is the second, and the first is short, avoid `.` "hanging in air"
695     if (index == 1 && previous.text.length < options.continuationIndent) {
696       return true
697     }
698     // the previous part is `this` or `super`
699     if (previous is KtSuperExpression || previous is KtThisExpression) {
700       return true
701     }
702     // this and the previous part are a package name, type name, or property
703     if (previous is KtSimpleNameExpression &&
704         current is KtSimpleNameExpression &&
705         part is KtDotQualifiedExpression) {
706       return true
707     }
708     // this is `Foo` in `com.facebook.Foo`, so everything before it is a package name
709     if (current.text.first().isUpperCase() &&
710         current is KtSimpleNameExpression &&
711         part is KtDotQualifiedExpression) {
712       return true
713     }
714     // this is the `foo()` in `com.facebook.Foo.foo()` or in `Foo.foo()`
715     if (current is KtCallExpression &&
716         (previous !is KtCallExpression) &&
717         previous.text?.firstOrNull()?.isUpperCase() == true) {
718       return true
719     }
720     // this is an invocation and the last item, and the previous it not, i.e. `a.b.c()`
721     // keeping it grouped and splitting the arguments makes `a.b(...)` feel like `aab()`
722     return current is KtCallExpression &&
723         previous !is KtCallExpression &&
724         index == parts.indices.last
725   }
726 
727   override fun visitCallExpression(callExpression: KtCallExpression) {
728     builder.sync(callExpression)
729     with(callExpression) {
730       visitCallElement(
731           calleeExpression,
732           typeArgumentList,
733           valueArgumentList,
734           lambdaArguments,
735       )
736     }
737   }
738 
739   /**
740    * Examples `foo<T>(a, b)`, `foo(a)`, `boo()`, `super(a)`
741    *
742    * @param lambdaIndent how to indent [lambdaArguments], if present
743    * @param negativeLambdaIndent the negative indentation of [lambdaIndent]
744    */
745   private fun visitCallElement(
746       callee: KtExpression?,
747       typeArgumentList: KtTypeArgumentList?,
748       argumentList: KtValueArgumentList?,
749       lambdaArguments: List<KtLambdaArgument>,
750       argumentsIndent: Indent = expressionBreakIndent,
751       lambdaIndent: Indent = ZERO,
752       negativeLambdaIndent: Indent = ZERO,
753   ) {
754     // Apply the lambda indent to the callee, type args, value args, and the lambda.
755     // This is undone for the first three by the negative lambda indent.
756     // This way they're in one block, and breaks in the argument list cause a break in the lambda.
757     builder.block(lambdaIndent) {
758 
759       // Used to keep track of whether or not we need to indent the lambda
760       // This is based on if there is a break in the argument list
761       var brokeBeforeBrace: BreakTag? = null
762 
763       builder.block(negativeLambdaIndent) {
764         visit(callee)
765         builder.block(argumentsIndent) {
766           builder.block(ZERO) { visit(typeArgumentList) }
767           if (argumentList != null) {
768             brokeBeforeBrace = visitValueArgumentListInternal(argumentList)
769           }
770         }
771       }
772       when (lambdaArguments.size) {
773         0 -> {}
774         1 -> {
775           builder.space()
776           visitArgumentInternal(
777               lambdaArguments.single(),
778               wrapInBlock = false,
779               brokeBeforeBrace = brokeBeforeBrace,
780           )
781         }
782         else -> throw ParseError("Maximum one trailing lambda is allowed", lambdaArguments[1])
783       }
784     }
785   }
786 
787   /** Example (`1, "hi"`) in a function call */
788   override fun visitValueArgumentList(list: KtValueArgumentList) {
789     visitValueArgumentListInternal(list)
790   }
791 
792   /**
793    * Example (`1, "hi"`) in a function call
794    *
795    * @return a [BreakTag] which can tell you if a break was taken, but only when the list doesn't
796    *   terminate in a negative closing indent. See [visitEachCommaSeparated] for examples.
797    */
798   private fun visitValueArgumentListInternal(list: KtValueArgumentList): BreakTag? {
799     builder.sync(list)
800 
801     val arguments = list.arguments
802     val isSingleUnnamedLambda =
803         arguments.size == 1 &&
804             arguments.first().getArgumentExpression() is KtLambdaExpression &&
805             arguments.first().getArgumentName() == null
806     val hasTrailingComma = list.trailingComma != null
807     val hasEmptyParens = list.hasEmptyParens()
808 
809     val wrapInBlock: Boolean
810     val breakBeforePostfix: Boolean
811     val leadingBreak: Boolean
812     val breakAfterPrefix: Boolean
813     if (isSingleUnnamedLambda) {
814       wrapInBlock = true
815       breakBeforePostfix = false
816       leadingBreak = !hasEmptyParens && hasTrailingComma
817       breakAfterPrefix = false
818     } else {
819       wrapInBlock = !options.manageTrailingCommas
820       breakBeforePostfix = options.manageTrailingCommas && !hasEmptyParens
821       leadingBreak = !hasEmptyParens
822       breakAfterPrefix = !hasEmptyParens
823     }
824 
825     return visitEachCommaSeparated(
826         arguments,
827         hasTrailingComma,
828         wrapInBlock = wrapInBlock,
829         breakBeforePostfix = breakBeforePostfix,
830         leadingBreak = leadingBreak,
831         prefix = "(",
832         postfix = ")",
833         breakAfterPrefix = breakAfterPrefix,
834     )
835   }
836 
837   /** Example `{ 1 + 1 }` (as lambda) or `{ (x, y) -> x + y }` */
838   override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
839     visitLambdaExpressionInternal(lambdaExpression, brokeBeforeBrace = null)
840   }
841 
842   /**
843    * The internal version of [visitLambdaExpression].
844    *
845    * @param brokeBeforeBrace used for tracking if a break was taken right before the lambda
846    *   expression. Useful for scoping functions where we want good looking indentation. For example,
847    *   here we have correct indentation before `bar()` and `car()` because we can detect the break
848    *   after the equals:
849    * ```
850    * fun foo() =
851    *     coroutineScope { x ->
852    *       bar()
853    *       car()
854    *     }
855    * ```
856    */
857   private fun visitLambdaExpressionInternal(
858       lambdaExpression: KtLambdaExpression,
859       brokeBeforeBrace: BreakTag?,
860   ) {
861     builder.sync(lambdaExpression)
862 
863     val valueParams = lambdaExpression.valueParameters
864     val hasParams = valueParams.isNotEmpty()
865     val bodyExpression = lambdaExpression.bodyExpression ?: fail()
866     val expressionStatements = bodyExpression.children
867     val hasStatements = expressionStatements.isNotEmpty()
868     val hasComments = bodyExpression.children().any { it is PsiComment }
869     val hasArrow = lambdaExpression.functionLiteral.arrow != null
870 
871     fun ifBrokeBeforeBrace(onTrue: Indent, onFalse: Indent): Indent {
872       if (brokeBeforeBrace == null) return onFalse
873       return Indent.If.make(brokeBeforeBrace, onTrue, onFalse)
874     }
875 
876     /**
877      * Enable correct formatting of the `fun foo() = scope {` syntax.
878      *
879      * We can't denote the lambda (+ scope function) as a block, since (for multiline lambdas) the
880      * rectangle rule would force the entire lambda onto a lower line. Instead, we conditionally
881      * indent all the interior levels of the lambda based on whether we had to break before the
882      * opening brace (or scope function). This mimics the look of a block when the break is taken.
883      *
884      * These conditional indents should not be used inside interior blocks, since that would apply
885      * the condition twice.
886      */
887     val bracePlusBlockIndent = ifBrokeBeforeBrace(blockPlusExpressionBreakIndent, blockIndent)
888     val bracePlusExpressionIndent =
889         ifBrokeBeforeBrace(doubleExpressionBreakIndent, expressionBreakIndent)
890     val bracePlusZeroIndent = ifBrokeBeforeBrace(expressionBreakIndent, ZERO)
891 
892     builder.token("{")
893 
894     if (hasParams || hasArrow) {
895       builder.space()
896       builder.block(bracePlusExpressionIndent) { visitEachCommaSeparated(valueParams) }
897       builder.block(bracePlusBlockIndent) {
898         if (lambdaExpression.functionLiteral.valueParameterList?.trailingComma != null) {
899           builder.token(",")
900           builder.forcedBreak()
901         } else if (hasParams) {
902           builder.breakOp(Doc.FillMode.INDEPENDENT, " ", ZERO)
903         }
904         builder.token("->")
905       }
906     }
907 
908     if (hasParams || hasArrow || hasStatements || hasComments) {
909       builder.breakOp(Doc.FillMode.UNIFIED, " ", bracePlusZeroIndent)
910     }
911 
912     if (hasStatements) {
913       builder.breakOp(Doc.FillMode.UNIFIED, "", bracePlusBlockIndent)
914       builder.block(bracePlusBlockIndent) {
915         builder.blankLineWanted(OpsBuilder.BlankLineWanted.NO)
916         if (expressionStatements.size == 1 &&
917             expressionStatements.first() !is KtReturnExpression &&
918             !bodyExpression.startsWithComment()) {
919           visitStatement(expressionStatements[0])
920         } else {
921           visitStatements(expressionStatements)
922         }
923         builder.breakOp(Doc.FillMode.UNIFIED, " ", bracePlusZeroIndent)
924       }
925     }
926 
927     if (hasParams || hasArrow || hasStatements) {
928       // If we had to break in the body, ensure there is a break before the closing brace
929       builder.breakOp(Doc.FillMode.UNIFIED, "", bracePlusZeroIndent)
930     }
931     builder.block(bracePlusZeroIndent) {
932       builder.fenceComments()
933       builder.token("}", blockIndent)
934     }
935   }
936 
937   /** Example `this` or `this@Foo` */
938   override fun visitThisExpression(expression: KtThisExpression) {
939     builder.sync(expression)
940     builder.token("this")
941     visit(expression.getTargetLabel())
942   }
943 
944   /** Example `Foo` or `@Foo` */
945   override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
946     builder.sync(expression)
947     when (expression) {
948       is KtLabelReferenceExpression -> {
949         if (expression.text[0] == '@') {
950           builder.token("@")
951           builder.token(expression.getIdentifier()?.text ?: fail())
952         } else {
953           builder.token(expression.getIdentifier()?.text ?: fail())
954           builder.token("@")
955         }
956       }
957       else -> {
958         if (expression.text.isNotEmpty()) {
959           builder.token(expression.text)
960         }
961       }
962     }
963   }
964 
965   /** e.g., `a: Int, b: Int, c: Int` in `fun foo(a: Int, b: Int, c: Int) { ... }`. */
966   override fun visitParameterList(list: KtParameterList) {
967     visitEachCommaSeparated(list.parameters, list.trailingComma != null, wrapInBlock = false)
968   }
969 
970   /**
971    * Visit each element in [list], with comma (,) tokens in-between.
972    *
973    * Example:
974    * ```
975    * a, b, c, 3, 4, 5
976    * ```
977    *
978    * Either the entire list fits in one line, or each element is put on its own line:
979    * ```
980    * a,
981    * b,
982    * c,
983    * 3,
984    * 4,
985    * 5
986    * ```
987    *
988    * Optionally include a prefix and postfix:
989    * ```
990    *   (
991    *     a,
992    *     b,
993    *     c,
994    * )
995    * ```
996    *
997    * @param hasTrailingComma if true, each element is placed on its own line (even if they could've
998    *   fit in a single line), and a trailing comma is emitted.
999    *
1000    * Example:
1001    * ```
1002    * a,
1003    * b,
1004    * ```
1005    *
1006    * @param wrapInBlock if true, place all the elements in a block. When there's no [leadingBreak],
1007    *   this will be negatively indented. Note that the [prefix] and [postfix] aren't included in the
1008    *   block.
1009    * @param leadingBreak if true, break before the first element.
1010    * @param prefix if provided, emit this before the first element.
1011    * @param postfix if provided, emit this after the last element (or trailing comma).
1012    * @param breakAfterPrefix if true, emit a break after [prefix], but before the start of the
1013    *   block.
1014    * @param breakBeforePostfix if true, place a break after the last element. Redundant when
1015    *   [hasTrailingComma] is true.
1016    * @return a [BreakTag] which can tell you if a break was taken, but only when the list doesn't
1017    *   terminate in a negative closing indent.
1018    *
1019    * Example 1, this returns a BreakTag which tells you a break wasn't taken:
1020    * ```
1021    * (arg1, arg2)
1022    * ```
1023    *
1024    * Example 2, this returns a BreakTag which tells you a break WAS taken:
1025    * ```
1026    * (
1027    *     arg1,
1028    *     arg2)
1029    * ```
1030    *
1031    * Example 3, this returns null:
1032    * ```
1033    * (
1034    *     arg1,
1035    *     arg2,
1036    * )
1037    * ```
1038    *
1039    * Example 4, this also returns null (similar to example 2, but Google style):
1040    * ```
1041    * (
1042    *     arg1,
1043    *     arg2
1044    * )
1045    * ```
1046    */
1047   private fun visitEachCommaSeparated(
1048       list: Iterable<PsiElement>,
1049       hasTrailingComma: Boolean = false,
1050       wrapInBlock: Boolean = true,
1051       leadingBreak: Boolean = true,
1052       prefix: String? = null,
1053       postfix: String? = null,
1054       breakAfterPrefix: Boolean = true,
1055       breakBeforePostfix: Boolean = options.manageTrailingCommas,
1056   ): BreakTag? {
1057     val breakAfterLastElement = hasTrailingComma || (postfix != null && breakBeforePostfix)
1058     val nameTag = if (breakAfterLastElement) null else genSym()
1059 
1060     if (prefix != null) {
1061       builder.token(prefix)
1062       if (breakAfterPrefix) {
1063         builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO, Optional.ofNullable(nameTag))
1064       }
1065     }
1066 
1067     val breakType = if (hasTrailingComma) Doc.FillMode.FORCED else Doc.FillMode.UNIFIED
1068     fun emitComma() {
1069       builder.token(",")
1070       builder.breakOp(breakType, " ", ZERO)
1071     }
1072 
1073     val indent = if (leadingBreak) ZERO else expressionBreakNegativeIndent
1074     builder.block(indent, isEnabled = wrapInBlock) {
1075       if (leadingBreak) {
1076         builder.breakOp(breakType, "", ZERO)
1077       }
1078 
1079       var first = true
1080       for (value in list) {
1081         if (!first) emitComma()
1082         first = false
1083         visit(value)
1084       }
1085 
1086       if (hasTrailingComma) {
1087         emitComma()
1088       }
1089     }
1090 
1091     if (breakAfterLastElement) {
1092       // a negative closing indent places the postfix to the left of the elements
1093       // see examples 2 and 4 in the docstring
1094       builder.breakOp(breakType, "", expressionBreakNegativeIndent)
1095     }
1096 
1097     if (postfix != null) {
1098       if (breakAfterLastElement) {
1099         builder.block(expressionBreakNegativeIndent) {
1100           builder.fenceComments()
1101           builder.token(postfix, expressionBreakIndent)
1102         }
1103       } else {
1104         builder.token(postfix)
1105       }
1106     }
1107 
1108     return nameTag
1109   }
1110 
1111   /** Example `a` in `foo(a)`, or `*a`, or `limit = 50` */
1112   override fun visitArgument(argument: KtValueArgument) {
1113     visitArgumentInternal(
1114         argument,
1115         wrapInBlock = true,
1116         brokeBeforeBrace = null,
1117     )
1118   }
1119 
1120   /**
1121    * The internal version of [visitArgument].
1122    *
1123    * @param wrapInBlock if true places the argument expression in a block.
1124    */
1125   private fun visitArgumentInternal(
1126       argument: KtValueArgument,
1127       wrapInBlock: Boolean,
1128       brokeBeforeBrace: BreakTag?,
1129   ) {
1130     builder.sync(argument)
1131     val hasArgName = argument.getArgumentName() != null
1132     val isLambda = argument.getArgumentExpression() is KtLambdaExpression
1133     if (hasArgName) {
1134       visit(argument.getArgumentName())
1135       builder.space()
1136       builder.token("=")
1137       if (isLambda) {
1138         builder.space()
1139       }
1140     }
1141     val indent = if (hasArgName && !isLambda) expressionBreakIndent else ZERO
1142     builder.block(indent, isEnabled = wrapInBlock) {
1143       if (hasArgName && !isLambda) {
1144         builder.breakOp(Doc.FillMode.INDEPENDENT, " ", ZERO)
1145       }
1146       if (argument.isSpread) {
1147         builder.token("*")
1148       }
1149       if (isLambda) {
1150         visitLambdaExpressionInternal(
1151             argument.getArgumentExpression() as KtLambdaExpression,
1152             brokeBeforeBrace = brokeBeforeBrace,
1153         )
1154       } else {
1155         visit(argument.getArgumentExpression())
1156       }
1157     }
1158   }
1159 
1160   override fun visitReferenceExpression(expression: KtReferenceExpression) {
1161     builder.sync(expression)
1162     builder.token(expression.text)
1163   }
1164 
1165   override fun visitReturnExpression(expression: KtReturnExpression) {
1166     builder.sync(expression)
1167     builder.token("return")
1168     visit(expression.getTargetLabel())
1169     val returnedExpression = expression.returnedExpression
1170     if (returnedExpression != null) {
1171       builder.space()
1172       visit(returnedExpression)
1173     }
1174     builder.guessToken(";")
1175   }
1176 
1177   /**
1178    * For example `a + b`, `a + b + c` or `a..b`
1179    *
1180    * The extra handling here drills to the left most expression and handles it for long chains of
1181    * binary expressions that are formatted not accordingly to the associative values That is, we
1182    * want to think of `a + b + c` as `(a + b) + c`, whereas the AST parses it as `a + (b + c)`
1183    */
1184   override fun visitBinaryExpression(expression: KtBinaryExpression) {
1185     builder.sync(expression)
1186     val op = expression.operationToken
1187 
1188     if (KtTokens.ALL_ASSIGNMENTS.contains(op) && isLambdaOrScopingFunction(expression.right)) {
1189       // Assignments are statements in Kotlin; we don't have to worry about compound assignment.
1190       visit(expression.left)
1191       builder.space()
1192       builder.token(expression.operationReference.text)
1193       visitLambdaOrScopingFunction(expression.right)
1194       return
1195     }
1196 
1197     val parts =
1198         ArrayDeque<KtBinaryExpression>().apply {
1199           var current: KtExpression? = expression
1200           while (current is KtBinaryExpression && current.operationToken == op) {
1201             addFirst(current)
1202             current = current.left
1203           }
1204         }
1205 
1206     val leftMostExpression = parts.first()
1207     visit(leftMostExpression.left)
1208     for (leftExpression in parts) {
1209       val isFirst = leftExpression === leftMostExpression
1210 
1211       when (leftExpression.operationToken) {
1212         KtTokens.RANGE,
1213         KtTokens.RANGE_UNTIL -> {
1214           if (isFirst) {
1215             builder.open(expressionBreakIndent)
1216           }
1217           builder.token(leftExpression.operationReference.text)
1218         }
1219         KtTokens.ELVIS -> {
1220           if (isFirst) {
1221             builder.open(expressionBreakIndent)
1222           }
1223           builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1224           builder.token(leftExpression.operationReference.text)
1225           builder.space()
1226         }
1227         else -> {
1228           builder.space()
1229           if (isFirst) {
1230             builder.open(expressionBreakIndent)
1231           }
1232           builder.token(leftExpression.operationReference.text)
1233           builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1234         }
1235       }
1236       visit(leftExpression.right)
1237     }
1238     builder.close()
1239   }
1240 
1241   override fun visitPostfixExpression(expression: KtPostfixExpression) {
1242     builder.sync(expression)
1243     builder.block(ZERO) {
1244       val baseExpression = expression.baseExpression
1245       val operator = expression.operationReference.text
1246 
1247       visit(baseExpression)
1248       if (baseExpression is KtPostfixExpression &&
1249           baseExpression.operationReference.text.last() == operator.first()) {
1250         builder.space()
1251       }
1252       builder.token(operator)
1253     }
1254   }
1255 
1256   override fun visitPrefixExpression(expression: KtPrefixExpression) {
1257     builder.sync(expression)
1258     builder.block(ZERO) {
1259       val baseExpression = expression.baseExpression
1260       val operator = expression.operationReference.text
1261 
1262       builder.token(operator)
1263       if (baseExpression is KtPrefixExpression &&
1264           operator.last() == baseExpression.operationReference.text.first()) {
1265         builder.space()
1266       }
1267       visit(baseExpression)
1268     }
1269   }
1270 
1271   override fun visitLabeledExpression(expression: KtLabeledExpression) {
1272     builder.sync(expression)
1273     visit(expression.labelQualifier)
1274     if (expression.baseExpression !is KtLambdaExpression) {
1275       builder.space()
1276     }
1277     visit(expression.baseExpression)
1278   }
1279 
1280   internal enum class DeclarationKind {
1281     FIELD,
1282     PARAMETER
1283   }
1284 
1285   /**
1286    * Declare one variable or variable-like thing.
1287    *
1288    * Examples:
1289    * - `var a: Int = 5`
1290    * - `a: Int`
1291    * - `private val b:
1292    */
1293   private fun declareOne(
1294       kind: DeclarationKind,
1295       modifiers: KtModifierList?,
1296       valOrVarKeyword: String?,
1297       typeParameters: KtTypeParameterList? = null,
1298       receiver: KtTypeReference? = null,
1299       name: String?,
1300       type: KtTypeReference?,
1301       typeConstraintList: KtTypeConstraintList? = null,
1302       initializer: KtExpression?,
1303       delegate: KtPropertyDelegate? = null,
1304       accessors: List<KtPropertyAccessor>? = null
1305   ): Int {
1306     val verticalAnnotationBreak = genSym()
1307 
1308     val isField = kind == DeclarationKind.FIELD
1309 
1310     if (isField) {
1311       builder.blankLineWanted(OpsBuilder.BlankLineWanted.conditional(verticalAnnotationBreak))
1312     }
1313 
1314     visit(modifiers)
1315     builder.block(ZERO) {
1316       builder.block(ZERO) {
1317         if (valOrVarKeyword != null) {
1318           builder.token(valOrVarKeyword)
1319           builder.space()
1320         }
1321 
1322         if (typeParameters != null) {
1323           visit(typeParameters)
1324           builder.space()
1325         }
1326 
1327         // conditionally indent the name and initializer +4 if the type spans
1328         // multiple lines
1329         if (name != null) {
1330           if (receiver != null) {
1331             visit(receiver)
1332             builder.token(".")
1333           }
1334           builder.token(name)
1335         }
1336       }
1337 
1338       builder.block(expressionBreakIndent, isEnabled = name != null) {
1339         // For example `: String` in `val thisIsALongName: String` or `fun f(): String`
1340         if (type != null) {
1341           if (name != null) {
1342             builder.token(":")
1343             builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1344           }
1345           visit(type)
1346         }
1347       }
1348 
1349       // For example `where T : Int` in a generic method
1350       if (typeConstraintList != null) {
1351         builder.space()
1352         visit(typeConstraintList)
1353         builder.space()
1354       }
1355 
1356       // for example `by lazy { compute() }`
1357       if (delegate != null) {
1358         builder.space()
1359         builder.token("by")
1360         if (isLambdaOrScopingFunction(delegate.expression)) {
1361           builder.space()
1362           visit(delegate)
1363         } else {
1364           builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
1365           builder.block(expressionBreakIndent) {
1366             builder.fenceComments()
1367             visit(delegate)
1368           }
1369         }
1370       } else if (initializer != null) {
1371         builder.space()
1372         builder.token("=")
1373         if (isLambdaOrScopingFunction(initializer)) {
1374           visitLambdaOrScopingFunction(initializer)
1375         } else {
1376           builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
1377           builder.block(expressionBreakIndent) {
1378             builder.fenceComments()
1379             visit(initializer)
1380           }
1381         }
1382       }
1383     }
1384     // for example `private set` or `get = 2 * field`
1385     if (accessors?.isNotEmpty() == true) {
1386       builder.block(blockIndent) {
1387         for (accessor in accessors) {
1388           builder.forcedBreak()
1389           // The semicolon must come after the newline, or the output code will not parse.
1390           builder.guessToken(";")
1391 
1392           builder.block(ZERO) {
1393             visitFunctionLikeExpression(
1394                 contextReceiverList = null,
1395                 modifierList = accessor.modifierList,
1396                 keyword = accessor.namePlaceholder.text,
1397                 typeParameters = null,
1398                 receiverTypeReference = null,
1399                 name = null,
1400                 parameterList = getParameterListWithBugFixes(accessor),
1401                 typeConstraintList = null,
1402                 bodyExpression = accessor.bodyBlockExpression ?: accessor.bodyExpression,
1403                 typeOrDelegationCall = accessor.returnTypeReference,
1404             )
1405           }
1406         }
1407       }
1408     }
1409 
1410     builder.guessToken(";")
1411 
1412     if (isField) {
1413       builder.blankLineWanted(OpsBuilder.BlankLineWanted.conditional(verticalAnnotationBreak))
1414     }
1415 
1416     return 0
1417   }
1418 
1419   // Bug in Kotlin 1.9.10: KtPropertyAccessor is the direct parent of the left and right paren
1420   // elements. Also parameterList is always null for getters. As a workaround, we create our own
1421   // fake KtParameterList.
1422   // TODO: won't need this after https://youtrack.jetbrains.com/issue/KT-70922
1423   private fun getParameterListWithBugFixes(accessor: KtPropertyAccessor): KtParameterList? {
1424     if (accessor.bodyExpression == null && accessor.bodyBlockExpression == null) return null
1425 
1426     val stub = accessor.stub ?: PsiFileStubImpl(accessor.containingFile)
1427 
1428     return object :
1429         KtParameterList(KotlinPlaceHolderStubImpl(stub, KtStubElementTypes.VALUE_PARAMETER_LIST)) {
1430       override fun getParameters(): List<KtParameter> {
1431         return accessor.valueParameters
1432       }
1433 
1434       override fun getTrailingComma(): PsiElement? {
1435         return accessor.parameterList?.trailingComma
1436       }
1437 
1438       override fun getLeftParenthesis(): PsiElement? {
1439         return accessor.leftParenthesis
1440       }
1441 
1442       override fun getRightParenthesis(): PsiElement? {
1443         return accessor.rightParenthesis
1444       }
1445     }
1446   }
1447 
1448   /**
1449    * Returns whether an expression is a lambda or initializer expression in which case we will want
1450    * to avoid indenting the lambda block
1451    *
1452    * Examples:
1453    * 1. '... = { ... }' is a lambda expression
1454    * 2. '... = Runnable { ... }' is considered a scoping function
1455    * 3. '... = scope { ... }' '... = apply { ... }' is a scoping function
1456    *
1457    * but not:
1458    * 1. '... = foo() { ... }' due to the empty parenthesis
1459    * 2. '... = Runnable @Annotation { ... }' due to the annotation
1460    */
1461   private fun isLambdaOrScopingFunction(expression: KtExpression?): Boolean {
1462     if (expression == null) return false
1463     if (expression.getPrevSiblingIgnoringWhitespace() is PsiComment) {
1464       return false // Leading comments cause weird indentation.
1465     }
1466 
1467     var carry = expression
1468     if (carry is KtCallExpression) {
1469       if (carry.valueArgumentList?.leftParenthesis == null &&
1470           carry.lambdaArguments.isNotEmpty() &&
1471           carry.typeArgumentList?.arguments.isNullOrEmpty()) {
1472         carry = carry.lambdaArguments[0].getArgumentExpression()
1473       } else {
1474         return false
1475       }
1476     }
1477     if (carry is KtLabeledExpression) {
1478       carry = carry.baseExpression
1479     }
1480     if (carry is KtLambdaExpression) {
1481       return true
1482     }
1483 
1484     return false
1485   }
1486 
1487   /** See [isLambdaOrScopingFunction] for examples. */
1488   private fun visitLambdaOrScopingFunction(expr: PsiElement?) {
1489     val breakToExpr = genSym()
1490     builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent, Optional.of(breakToExpr))
1491 
1492     var carry = expr
1493     if (carry is KtCallExpression) {
1494       visit(carry.calleeExpression)
1495       builder.space()
1496       carry = carry.lambdaArguments[0].getArgumentExpression()
1497     }
1498     if (carry is KtLabeledExpression) {
1499       visit(carry.labelQualifier)
1500       carry = carry.baseExpression ?: fail()
1501     }
1502     if (carry is KtLambdaExpression) {
1503       visitLambdaExpressionInternal(carry, brokeBeforeBrace = breakToExpr)
1504       return
1505     }
1506 
1507     throw AssertionError(carry)
1508   }
1509 
1510   override fun visitClassOrObject(classOrObject: KtClassOrObject) {
1511     builder.sync(classOrObject)
1512     val contextReceiverList =
1513         classOrObject.getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER_LIST)
1514     val modifierList = classOrObject.modifierList
1515     builder.block(ZERO) {
1516       if (contextReceiverList != null) {
1517         visitContextReceiverList(contextReceiverList)
1518       }
1519       if (modifierList != null) {
1520         visitModifierList(modifierList)
1521       }
1522       val declarationKeyword = classOrObject.getDeclarationKeyword()
1523       if (declarationKeyword != null) {
1524         builder.token(declarationKeyword.text ?: fail())
1525       }
1526       val name = classOrObject.nameIdentifier
1527       if (name != null) {
1528         builder.space()
1529         builder.token(name.text)
1530         visit(classOrObject.typeParameterList)
1531       }
1532       visit(classOrObject.primaryConstructor)
1533       val superTypes = classOrObject.getSuperTypeList()
1534       if (superTypes != null) {
1535         builder.space()
1536         builder.block(ZERO) {
1537           builder.token(":")
1538           builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
1539           visit(superTypes)
1540         }
1541       }
1542       builder.space()
1543       val typeConstraintList = classOrObject.typeConstraintList
1544       if (typeConstraintList != null) {
1545         if (superTypes?.entries?.lastOrNull() is KtDelegatedSuperTypeEntry) {
1546           builder.forcedBreak()
1547         }
1548         visit(typeConstraintList)
1549         builder.space()
1550       }
1551       visit(classOrObject.body)
1552     }
1553     if (classOrObject.nameIdentifier != null) {
1554       builder.forcedBreak()
1555     }
1556   }
1557 
1558   override fun visitPrimaryConstructor(constructor: KtPrimaryConstructor) {
1559     builder.sync(constructor)
1560     builder.block(ZERO) {
1561       if (constructor.hasConstructorKeyword()) {
1562         builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1563       }
1564       visitFunctionLikeExpression(
1565           contextReceiverList = null,
1566           modifierList = constructor.modifierList,
1567           keyword = if (constructor.hasConstructorKeyword()) "constructor" else null,
1568           typeParameters = null,
1569           receiverTypeReference = null,
1570           name = null,
1571           parameterList = constructor.valueParameterList,
1572           typeConstraintList = null,
1573           bodyExpression = constructor.bodyExpression,
1574           typeOrDelegationCall = null,
1575       )
1576     }
1577   }
1578 
1579   /** Example `private constructor(n: Int) : this(4, 5) { ... }` inside a class's body */
1580   override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) {
1581     builder.sync(constructor)
1582     builder.block(ZERO) {
1583       val delegationCall = constructor.getDelegationCall()
1584       visitFunctionLikeExpression(
1585           contextReceiverList =
1586               constructor.getStubOrPsiChild(KtStubElementTypes.CONTEXT_RECEIVER_LIST),
1587           modifierList = constructor.modifierList,
1588           keyword = "constructor",
1589           typeParameters = null,
1590           receiverTypeReference = null,
1591           name = null,
1592           parameterList = constructor.valueParameterList,
1593           typeConstraintList = null,
1594           bodyExpression = constructor.bodyExpression,
1595           typeOrDelegationCall = if (!delegationCall.isImplicit) delegationCall else null,
1596       )
1597     }
1598   }
1599 
1600   override fun visitConstructorDelegationCall(call: KtConstructorDelegationCall) {
1601     // Work around a misfeature in kotlin-compiler: call.calleeExpression.accept doesn't call
1602     // visitReferenceExpression, but calls visitElement instead.
1603     builder.block(ZERO) {
1604       builder.token(if (call.isCallToThis) "this" else "super")
1605       visitCallElement(
1606           null,
1607           call.typeArgumentList,
1608           call.valueArgumentList,
1609           call.lambdaArguments,
1610       )
1611     }
1612   }
1613 
1614   override fun visitClassInitializer(initializer: KtClassInitializer) {
1615     builder.sync(initializer)
1616     builder.token("init")
1617     builder.space()
1618     visit(initializer.body)
1619   }
1620 
1621   override fun visitConstantExpression(expression: KtConstantExpression) {
1622     builder.sync(expression)
1623     builder.token(expression.text)
1624   }
1625 
1626   /** Example `(1 + 1)` */
1627   override fun visitParenthesizedExpression(expression: KtParenthesizedExpression) {
1628     builder.sync(expression)
1629     builder.token("(")
1630     visit(expression.expression)
1631     builder.token(")")
1632   }
1633 
1634   override fun visitPackageDirective(directive: KtPackageDirective) {
1635     builder.sync(directive)
1636     if (directive.packageKeyword == null) {
1637       return
1638     }
1639     builder.token("package")
1640     builder.space()
1641     var first = true
1642     for (packageName in directive.packageNames) {
1643       if (first) {
1644         first = false
1645       } else {
1646         builder.token(".")
1647       }
1648       builder.token(packageName.getIdentifier()?.text ?: packageName.getReferencedName())
1649     }
1650 
1651     builder.guessToken(";")
1652     builder.forcedBreak()
1653   }
1654 
1655   /** Example `import com.foo.A; import com.bar.B` */
1656   override fun visitImportList(importList: KtImportList) {
1657     builder.sync(importList)
1658     importList.imports.forEach { visit(it) }
1659   }
1660 
1661   /** Example `import com.foo.A` */
1662   override fun visitImportDirective(directive: KtImportDirective) {
1663     builder.sync(directive)
1664     builder.token("import")
1665     builder.space()
1666 
1667     val importedReference = directive.importedReference
1668     if (importedReference != null) {
1669       inImport = true
1670       visit(importedReference)
1671       inImport = false
1672     }
1673     if (directive.isAllUnder) {
1674       builder.token(".")
1675       builder.token("*")
1676     }
1677 
1678     // Possible alias.
1679     val alias = directive.alias?.nameIdentifier
1680     if (alias != null) {
1681       builder.space()
1682       builder.token("as")
1683       builder.space()
1684       builder.token(alias.text ?: fail())
1685     }
1686 
1687     // Force a newline afterwards.
1688     builder.guessToken(";")
1689     builder.forcedBreak()
1690   }
1691 
1692   /** Example `context(Logger, Raise<Error>)` */
1693   override fun visitContextReceiverList(contextReceiverList: KtContextReceiverList) {
1694     builder.sync(contextReceiverList)
1695     builder.token("context")
1696     visitEachCommaSeparated(
1697         contextReceiverList.contextReceivers(),
1698         prefix = "(",
1699         postfix = ")",
1700         breakAfterPrefix = false,
1701         breakBeforePostfix = false,
1702     )
1703     builder.forcedBreak()
1704   }
1705 
1706   /** For example `@Magic private final` */
1707   override fun visitModifierList(list: KtModifierList) {
1708     builder.sync(list)
1709     var onlyAnnotationsSoFar = true
1710 
1711     for (child in list.node.children()) {
1712       val psi = child.psi
1713       if (psi is PsiWhiteSpace) {
1714         continue
1715       }
1716 
1717       if (child.elementType is KtModifierKeywordToken) {
1718         onlyAnnotationsSoFar = false
1719         builder.token(child.text)
1720       } else {
1721         visit(psi)
1722       }
1723 
1724       if (onlyAnnotationsSoFar) {
1725         builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1726       } else {
1727         builder.space()
1728       }
1729     }
1730   }
1731 
1732   /**
1733    * Example:
1734    * ```
1735    * @SuppressLint("MagicNumber")
1736    * print(10)
1737    * ```
1738    *
1739    * in
1740    *
1741    * ```
1742    * fun f() {
1743    *   @SuppressLint("MagicNumber")
1744    *   print(10)
1745    * }
1746    * ```
1747    */
1748   override fun visitAnnotatedExpression(expression: KtAnnotatedExpression) {
1749     builder.sync(expression)
1750     builder.block(ZERO) {
1751       val baseExpression = expression.baseExpression
1752 
1753       builder.block(ZERO) {
1754         val annotationEntries = expression.annotationEntries
1755         for (annotationEntry in annotationEntries) {
1756           if (annotationEntry !== annotationEntries.first()) {
1757             builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1758           }
1759           visit(annotationEntry)
1760         }
1761       }
1762 
1763       // Binary expressions in a block have a different meaning according to their formatting.
1764       // If there in the line above, they refer to the entire expression, if they're in the same
1765       // line then only to the first operand of the operator.
1766       // We force a break to avoid such semantic changes
1767       when {
1768         (baseExpression is KtBinaryExpression || baseExpression is KtBinaryExpressionWithTypeRHS) &&
1769             expression.parent is KtBlockExpression -> builder.forcedBreak()
1770         baseExpression is KtLambdaExpression -> builder.space()
1771         baseExpression is KtReturnExpression -> builder.forcedBreak()
1772         else -> builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1773       }
1774 
1775       visit(expression.baseExpression)
1776     }
1777   }
1778 
1779   /**
1780    * For example, @field:[Inject Named("WEB_VIEW")]
1781    *
1782    * A KtAnnotation is used only to group multiple annotations with the same use-site-target. It
1783    * only appears in a modifier list since annotated expressions do not have use-site-targets.
1784    */
1785   override fun visitAnnotation(annotation: KtAnnotation) {
1786     builder.sync(annotation)
1787     builder.block(ZERO) {
1788       builder.token("@")
1789       val useSiteTarget = annotation.useSiteTarget
1790       if (useSiteTarget != null) {
1791         visit(useSiteTarget)
1792         builder.token(":")
1793       }
1794       builder.block(expressionBreakIndent) {
1795         builder.token("[")
1796 
1797         builder.block(ZERO) {
1798           var first = true
1799           builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO)
1800           for (value in annotation.entries) {
1801             if (!first) {
1802               builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
1803             }
1804             first = false
1805 
1806             visit(value)
1807           }
1808         }
1809       }
1810       builder.token("]")
1811     }
1812     builder.forcedBreak()
1813   }
1814 
1815   /** For example, 'field' in @field:[Inject Named("WEB_VIEW")] */
1816   override fun visitAnnotationUseSiteTarget(
1817       annotationTarget: KtAnnotationUseSiteTarget,
1818       data: Void?
1819   ): Void? {
1820     builder.token(annotationTarget.getAnnotationUseSiteTarget().renderName)
1821     return null
1822   }
1823 
1824   /** For example `@Magic` or `@Fred(1, 5)` */
1825   override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry) {
1826     builder.sync(annotationEntry)
1827     if (annotationEntry.atSymbol != null) {
1828       builder.token("@")
1829     }
1830     val useSiteTarget = annotationEntry.useSiteTarget
1831     if (useSiteTarget != null && useSiteTarget.parent == annotationEntry) {
1832       visit(useSiteTarget)
1833       builder.token(":")
1834     }
1835     visitCallElement(
1836         annotationEntry.calleeExpression,
1837         null, // Type-arguments are included in the annotation's callee expression.
1838         annotationEntry.valueArgumentList,
1839         listOf())
1840   }
1841 
1842   override fun visitFileAnnotationList(
1843       fileAnnotationList: KtFileAnnotationList,
1844       data: Void?
1845   ): Void? {
1846     for (child in fileAnnotationList.node.children()) {
1847       if (child is PsiElement) {
1848         continue
1849       }
1850       visit(child.psi)
1851       builder.forcedBreak()
1852     }
1853 
1854     return null
1855   }
1856 
1857   override fun visitSuperTypeList(list: KtSuperTypeList) {
1858     builder.sync(list)
1859     builder.block(expressionBreakIndent) { visitEachCommaSeparated(list.entries) }
1860   }
1861 
1862   override fun visitSuperTypeCallEntry(call: KtSuperTypeCallEntry) {
1863     builder.sync(call)
1864     visitCallElement(call.calleeExpression, null, call.valueArgumentList, call.lambdaArguments)
1865   }
1866 
1867   /**
1868    * Example `Collection<Int> by list` in `class MyList(list: List<Int>) : Collection<Int> by list`
1869    */
1870   override fun visitDelegatedSuperTypeEntry(specifier: KtDelegatedSuperTypeEntry) {
1871     builder.sync(specifier)
1872     visit(specifier.typeReference)
1873     builder.space()
1874     builder.token("by")
1875     builder.space()
1876     visit(specifier.delegateExpression)
1877   }
1878 
1879   override fun visitWhenExpression(expression: KtWhenExpression) {
1880     builder.sync(expression)
1881     builder.block(ZERO) {
1882       emitKeywordWithCondition("when", expression.subjectExpression)
1883 
1884       builder.space()
1885       builder.token("{", Doc.Token.RealOrImaginary.REAL, blockIndent, Optional.of(blockIndent))
1886 
1887       expression.entries.forEachIndexed { index, whenEntry ->
1888         builder.block(blockIndent) {
1889           if (index != 0) {
1890             // preserve new line if there's one
1891             builder.blankLineWanted(OpsBuilder.BlankLineWanted.PRESERVE)
1892           }
1893           builder.forcedBreak()
1894           if (whenEntry.isElse) {
1895             builder.token("else")
1896           } else {
1897             builder.block(ZERO) {
1898               val conditions = whenEntry.conditions
1899               for ((index, condition) in conditions.withIndex()) {
1900                 visit(condition)
1901                 builder.guessToken(",")
1902                 if (index != conditions.lastIndex) {
1903                   builder.forcedBreak()
1904                 }
1905               }
1906             }
1907           }
1908           val whenExpression = whenEntry.expression
1909           builder.space()
1910           builder.token("->")
1911           if (whenExpression is KtBlockExpression) {
1912             builder.space()
1913             visit(whenExpression)
1914           } else {
1915             builder.block(expressionBreakIndent) {
1916               builder.breakOp(Doc.FillMode.INDEPENDENT, " ", ZERO)
1917               visit(whenExpression)
1918             }
1919           }
1920           builder.guessToken(";")
1921         }
1922         builder.forcedBreak()
1923       }
1924       builder.token("}")
1925     }
1926   }
1927 
1928   override fun visitClassBody(body: KtClassBody) {
1929     builder.sync(body)
1930     emitBracedBlock(body) { children ->
1931       val enumEntryList = EnumEntryList.extractChildList(body)
1932       val members = children.filter { it !is KtEnumEntry }
1933 
1934       if (enumEntryList != null) {
1935         builder.block(ZERO) {
1936           builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO)
1937           for (value in enumEntryList.enumEntries) {
1938             visit(value)
1939             if (builder.peekToken() == Optional.of(",")) {
1940               builder.token(",")
1941               builder.forcedBreak()
1942             }
1943           }
1944         }
1945         builder.guessToken(";")
1946 
1947         if (members.isNotEmpty()) {
1948           builder.forcedBreak()
1949           builder.blankLineWanted(OpsBuilder.BlankLineWanted.YES)
1950         }
1951       } else {
1952         val parent = body.parent
1953         if (parent is KtClass && parent.isEnum() && children.isNotEmpty()) {
1954           builder.token(";")
1955           builder.forcedBreak()
1956         }
1957       }
1958 
1959       var prev: PsiElement? = null
1960       for (curr in members) {
1961         val blankLineBetweenMembers =
1962             when {
1963               prev == null -> OpsBuilder.BlankLineWanted.PRESERVE
1964               prev !is KtProperty -> OpsBuilder.BlankLineWanted.YES
1965               prev.getter != null || prev.setter != null -> OpsBuilder.BlankLineWanted.YES
1966               curr is KtProperty -> OpsBuilder.BlankLineWanted.PRESERVE
1967               else -> OpsBuilder.BlankLineWanted.YES
1968             }
1969         builder.blankLineWanted(blankLineBetweenMembers)
1970 
1971         builder.block(ZERO) { visit(curr) }
1972         builder.guessToken(";")
1973         builder.forcedBreak()
1974 
1975         prev = curr
1976       }
1977     }
1978   }
1979 
1980   override fun visitBlockExpression(expression: KtBlockExpression) {
1981     builder.sync(expression)
1982     emitBracedBlock(expression) { children -> visitStatements(children) }
1983   }
1984 
1985   override fun visitWhenConditionWithExpression(condition: KtWhenConditionWithExpression) {
1986     builder.sync(condition)
1987     visit(condition.expression)
1988   }
1989 
1990   override fun visitWhenConditionIsPattern(condition: KtWhenConditionIsPattern) {
1991     builder.sync(condition)
1992     builder.token(if (condition.isNegated) "!is" else "is")
1993     builder.space()
1994     visit(condition.typeReference)
1995   }
1996 
1997   /** Example `in 1..2` as part of a when expression */
1998   override fun visitWhenConditionInRange(condition: KtWhenConditionInRange) {
1999     builder.sync(condition)
2000     // TODO: replace with 'condition.isNegated' once https://youtrack.jetbrains.com/issue/KT-34395
2001     // is fixed.
2002     val isNegated = condition.firstChild?.node?.findChildByType(KtTokens.NOT_IN) != null
2003     builder.token(if (isNegated) "!in" else "in")
2004     builder.space()
2005     visit(condition.rangeExpression)
2006   }
2007 
2008   override fun visitIfExpression(expression: KtIfExpression) {
2009     builder.sync(expression)
2010     builder.block(ZERO) {
2011       emitKeywordWithCondition("if", expression.condition)
2012 
2013       if (expression.then is KtBlockExpression) {
2014         builder.space()
2015         builder.block(ZERO) { visit(expression.then) }
2016       } else {
2017         builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
2018         builder.block(expressionBreakIndent) { visit(expression.then) }
2019       }
2020 
2021       if (expression.elseKeyword != null) {
2022         if (expression.then is KtBlockExpression) {
2023           builder.space()
2024         } else {
2025           builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
2026         }
2027 
2028         builder.block(ZERO) {
2029           builder.token("else")
2030           if (expression.`else` is KtBlockExpression || expression.`else` is KtIfExpression) {
2031             builder.space()
2032             builder.block(ZERO) { visit(expression.`else`) }
2033           } else {
2034             builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
2035             builder.block(expressionBreakIndent) { visit(expression.`else`) }
2036           }
2037         }
2038       }
2039     }
2040   }
2041 
2042   /** Example `a[3]`, `b["a", 5]` or `a.b.c[4]` */
2043   override fun visitArrayAccessExpression(expression: KtArrayAccessExpression) {
2044     builder.sync(expression)
2045     if (expression.arrayExpression is KtQualifiedExpression) {
2046       emitQualifiedExpression(expression)
2047     } else {
2048       visit(expression.arrayExpression)
2049       visitArrayAccessBrackets(expression)
2050     }
2051   }
2052 
2053   /**
2054    * Example `[3]` in `a[3]` or `a[3].b` Separated since it needs to be used from a top level array
2055    * expression (`a[3]`) and from within a qualified chain (`a[3].b)
2056    */
2057   private fun visitArrayAccessBrackets(expression: KtArrayAccessExpression) {
2058     builder.block(ZERO) {
2059       builder.token("[")
2060       builder.breakOp(Doc.FillMode.UNIFIED, "", expressionBreakIndent)
2061       builder.block(expressionBreakIndent) {
2062         visitEachCommaSeparated(
2063             expression.indexExpressions, expression.trailingComma != null, wrapInBlock = true)
2064       }
2065     }
2066     builder.token("]")
2067   }
2068 
2069   /** Example `val (a, b: Int) = Pair(1, 2)` */
2070   override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
2071     builder.sync(destructuringDeclaration)
2072     val valOrVarKeyword = destructuringDeclaration.valOrVarKeyword
2073     if (valOrVarKeyword != null) {
2074       builder.token(valOrVarKeyword.text)
2075       builder.space()
2076     }
2077     val hasTrailingComma = destructuringDeclaration.trailingComma != null
2078     builder.block(ZERO) {
2079       builder.token("(")
2080       builder.breakOp(Doc.FillMode.UNIFIED, "", expressionBreakIndent)
2081       builder.block(expressionBreakIndent) {
2082         visitEachCommaSeparated(
2083             destructuringDeclaration.entries, hasTrailingComma, wrapInBlock = true)
2084       }
2085     }
2086     builder.token(")")
2087     val initializer = destructuringDeclaration.initializer
2088     if (initializer != null) {
2089       builder.space()
2090       builder.token("=")
2091       if (hasTrailingComma) {
2092         builder.space()
2093       } else {
2094         builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
2095       }
2096       builder.block(expressionBreakIndent, !hasTrailingComma) { visit(initializer) }
2097     }
2098   }
2099 
2100   /** Example `a: String` which is part of `(a: String, b: String)` */
2101   override fun visitDestructuringDeclarationEntry(
2102       multiDeclarationEntry: KtDestructuringDeclarationEntry
2103   ) {
2104     builder.sync(multiDeclarationEntry)
2105     declareOne(
2106         initializer = null,
2107         kind = DeclarationKind.PARAMETER,
2108         modifiers = multiDeclarationEntry.modifierList,
2109         name = multiDeclarationEntry.nameIdentifier?.text ?: fail(),
2110         type = multiDeclarationEntry.typeReference,
2111         valOrVarKeyword = null,
2112     )
2113   }
2114 
2115   /** Example `"Hello $world!"` or `"""Hello world!"""` */
2116   override fun visitStringTemplateExpression(expression: KtStringTemplateExpression) {
2117     builder.sync(expression)
2118     builder.token(WhitespaceTombstones.replaceTrailingWhitespaceWithTombstone(expression.text))
2119   }
2120 
2121   /** Example `super` in `super.doIt(5)` or `super<Foo>` in `super<Foo>.doIt(5)` */
2122   override fun visitSuperExpression(expression: KtSuperExpression) {
2123     builder.sync(expression)
2124     builder.token("super")
2125     val superTypeQualifier = expression.superTypeQualifier
2126     if (superTypeQualifier != null) {
2127       builder.token("<")
2128       visit(superTypeQualifier)
2129       builder.token(">")
2130     }
2131     visit(expression.labelQualifier)
2132   }
2133 
2134   /** Example `<T, S>` */
2135   override fun visitTypeParameterList(list: KtTypeParameterList) {
2136     builder.sync(list)
2137     builder.block(expressionBreakIndent) {
2138       visitEachCommaSeparated(
2139           list = list.parameters,
2140           hasTrailingComma = list.trailingComma != null,
2141           prefix = "<",
2142           postfix = ">",
2143           wrapInBlock = !options.manageTrailingCommas,
2144       )
2145     }
2146   }
2147 
2148   override fun visitTypeParameter(parameter: KtTypeParameter) {
2149     builder.sync(parameter)
2150     visit(parameter.modifierList)
2151     builder.token(parameter.nameIdentifier?.text ?: "")
2152     val extendsBound = parameter.extendsBound
2153     if (extendsBound != null) {
2154       builder.space()
2155       builder.token(":")
2156       builder.space()
2157       visit(extendsBound)
2158     }
2159   }
2160 
2161   /** Example `where T : View, T : Listener` */
2162   override fun visitTypeConstraintList(list: KtTypeConstraintList) {
2163     builder.token("where")
2164     builder.space()
2165     builder.sync(list)
2166     visitEachCommaSeparated(list.constraints)
2167   }
2168 
2169   /** Example `T : Foo` */
2170   override fun visitTypeConstraint(constraint: KtTypeConstraint) {
2171     builder.sync(constraint)
2172     // TODO(nreid260): What about annotations on the type reference? `where @A T : Int`
2173     visit(constraint.subjectTypeParameterName)
2174     builder.space()
2175     builder.token(":")
2176     builder.space()
2177     visit(constraint.boundTypeReference)
2178   }
2179 
2180   /** Example `for (i in items) { ... }` */
2181   override fun visitForExpression(expression: KtForExpression) {
2182     builder.sync(expression)
2183     builder.block(ZERO) {
2184       builder.token("for")
2185       builder.space()
2186       builder.token("(")
2187       visit(expression.loopParameter)
2188       builder.space()
2189       builder.token("in")
2190       builder.block(ZERO) {
2191         builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
2192         builder.block(expressionBreakIndent) { visit(expression.loopRange) }
2193       }
2194       builder.token(")")
2195       builder.space()
2196       visit(expression.body)
2197     }
2198   }
2199 
2200   /** Example `while (a < b) { ... }` */
2201   override fun visitWhileExpression(expression: KtWhileExpression) {
2202     builder.sync(expression)
2203     emitKeywordWithCondition("while", expression.condition)
2204     builder.space()
2205     visit(expression.body)
2206   }
2207 
2208   /** Example `do { ... } while (a < b)` */
2209   override fun visitDoWhileExpression(expression: KtDoWhileExpression) {
2210     builder.sync(expression)
2211     builder.token("do")
2212     builder.space()
2213     if (expression.body != null) {
2214       visit(expression.body)
2215       builder.space()
2216     }
2217     emitKeywordWithCondition("while", expression.condition)
2218   }
2219 
2220   /** Example `break` or `break@foo` in a loop */
2221   override fun visitBreakExpression(expression: KtBreakExpression) {
2222     builder.sync(expression)
2223     builder.token("break")
2224     visit(expression.labelQualifier)
2225   }
2226 
2227   /** Example `continue` or `continue@foo` in a loop */
2228   override fun visitContinueExpression(expression: KtContinueExpression) {
2229     builder.sync(expression)
2230     builder.token("continue")
2231     visit(expression.labelQualifier)
2232   }
2233 
2234   /** Example `f: String`, or `private val n: Int` or `(a: Int, b: String)` (in for-loops) */
2235   override fun visitParameter(parameter: KtParameter) {
2236     builder.sync(parameter)
2237     builder.block(ZERO) {
2238       val destructuringDeclaration = parameter.destructuringDeclaration
2239       val typeReference = parameter.typeReference
2240       if (destructuringDeclaration != null) {
2241         builder.block(ZERO) {
2242           visit(destructuringDeclaration)
2243           if (typeReference != null) {
2244             builder.token(":")
2245             builder.space()
2246             visit(typeReference)
2247           }
2248         }
2249       } else {
2250         declareOne(
2251             kind = DeclarationKind.PARAMETER,
2252             modifiers = parameter.modifierList,
2253             valOrVarKeyword = parameter.valOrVarKeyword?.text,
2254             name = parameter.nameIdentifier?.text,
2255             type = typeReference,
2256             initializer = parameter.defaultValue)
2257       }
2258     }
2259   }
2260 
2261   /** Example `String::isNullOrEmpty` */
2262   override fun visitCallableReferenceExpression(expression: KtCallableReferenceExpression) {
2263     builder.sync(expression)
2264     visit(expression.receiverExpression)
2265 
2266     // For some reason, expression.receiverExpression doesn't contain the question-mark token in
2267     // case of a nullable type, e.g., in String?::isNullOrEmpty.
2268     // Instead, KtCallableReferenceExpression exposes a method that looks for the QUEST token in
2269     // its children.
2270     if (expression.hasQuestionMarks) {
2271       builder.token("?")
2272     }
2273 
2274     builder.block(expressionBreakIndent) {
2275       builder.token("::")
2276       builder.breakOp(Doc.FillMode.INDEPENDENT, "", ZERO)
2277       visit(expression.callableReference)
2278     }
2279   }
2280 
2281   override fun visitClassLiteralExpression(expression: KtClassLiteralExpression) {
2282     builder.sync(expression)
2283     val receiverExpression = expression.receiverExpression
2284     if (receiverExpression is KtCallExpression) {
2285       visitCallElement(
2286           receiverExpression.calleeExpression,
2287           receiverExpression.typeArgumentList,
2288           receiverExpression.valueArgumentList,
2289           receiverExpression.lambdaArguments)
2290     } else {
2291       visit(receiverExpression)
2292     }
2293     builder.token("::")
2294     builder.token("class")
2295   }
2296 
2297   override fun visitFunctionType(type: KtFunctionType) {
2298     builder.sync(type)
2299 
2300     type.contextReceiverList?.let { visitContextReceiverList(it) }
2301 
2302     val receiver = type.receiver
2303     if (receiver != null) {
2304       visit(receiver)
2305       builder.token(".")
2306     }
2307     builder.block(expressionBreakIndent) {
2308       val parameterList = type.parameterList
2309       if (parameterList != null) {
2310         visitEachCommaSeparated(
2311             parameterList.parameters,
2312             prefix = "(",
2313             postfix = ")",
2314             hasTrailingComma = parameterList.trailingComma != null,
2315         )
2316       }
2317     }
2318     builder.space()
2319     builder.token("->")
2320     builder.space()
2321     builder.block(expressionBreakIndent) { visit(type.returnTypeReference) }
2322   }
2323 
2324   /** Example `a is Int` or `b !is Int` */
2325   override fun visitIsExpression(expression: KtIsExpression) {
2326     builder.sync(expression)
2327     val openGroupBeforeLeft = expression.leftHandSide !is KtQualifiedExpression
2328     if (openGroupBeforeLeft) builder.open(ZERO)
2329     visit(expression.leftHandSide)
2330     if (!openGroupBeforeLeft) builder.open(ZERO)
2331     val parent = expression.parent
2332     if (parent is KtValueArgument ||
2333         parent is KtParenthesizedExpression ||
2334         parent is KtContainerNode) {
2335       builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
2336     } else {
2337       builder.space()
2338     }
2339     visit(expression.operationReference)
2340     builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
2341     builder.block(expressionBreakIndent) { visit(expression.typeReference) }
2342     builder.close()
2343   }
2344 
2345   /** Example `a as Int` or `a as? Int` */
2346   override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS) {
2347     builder.sync(expression)
2348     val openGroupBeforeLeft = expression.left !is KtQualifiedExpression
2349     if (openGroupBeforeLeft) builder.open(ZERO)
2350     visit(expression.left)
2351     if (!openGroupBeforeLeft) builder.open(ZERO)
2352     builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
2353     visit(expression.operationReference)
2354     builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
2355     builder.block(expressionBreakIndent) { visit(expression.right) }
2356     builder.close()
2357   }
2358 
2359   /**
2360    * Example:
2361    * ```
2362    * fun f() {
2363    *   val a: Array<Int> = [1, 2, 3]
2364    * }
2365    * ```
2366    */
2367   override fun visitCollectionLiteralExpression(expression: KtCollectionLiteralExpression) {
2368     builder.sync(expression)
2369     builder.block(expressionBreakIndent) {
2370       visitEachCommaSeparated(
2371           expression.getInnerExpressions(),
2372           expression.trailingComma != null,
2373           prefix = "[",
2374           postfix = "]",
2375           wrapInBlock = !options.manageTrailingCommas)
2376     }
2377   }
2378 
2379   override fun visitTryExpression(expression: KtTryExpression) {
2380     builder.sync(expression)
2381     builder.token("try")
2382     builder.space()
2383     visit(expression.tryBlock)
2384     for (catchClause in expression.catchClauses) {
2385       visit(catchClause)
2386     }
2387     visit(expression.finallyBlock)
2388   }
2389 
2390   override fun visitCatchSection(catchClause: KtCatchClause) {
2391     builder.sync(catchClause)
2392     builder.space()
2393     builder.token("catch")
2394     builder.space()
2395     builder.block(ZERO) {
2396       builder.token("(")
2397       builder.block(expressionBreakIndent) {
2398         builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO)
2399         visit(catchClause.catchParameter)
2400         builder.guessToken(",")
2401       }
2402     }
2403     builder.token(")")
2404     builder.space()
2405     visit(catchClause.catchBody)
2406   }
2407 
2408   override fun visitFinallySection(finallySection: KtFinallySection) {
2409     builder.sync(finallySection)
2410     builder.space()
2411     builder.token("finally")
2412     builder.space()
2413     visit(finallySection.finalExpression)
2414   }
2415 
2416   override fun visitThrowExpression(expression: KtThrowExpression) {
2417     builder.sync(expression)
2418     builder.token("throw")
2419     builder.space()
2420     visit(expression.thrownExpression)
2421   }
2422 
2423   /** Example `RED(0xFF0000)` in an enum class */
2424   override fun visitEnumEntry(enumEntry: KtEnumEntry) {
2425     builder.sync(enumEntry)
2426     builder.block(ZERO) {
2427       visit(enumEntry.modifierList)
2428       builder.token(enumEntry.nameIdentifier?.text ?: fail())
2429       enumEntry.initializerList?.initializers?.forEach { visit(it) }
2430       enumEntry.body?.let { enumBody ->
2431         builder.space()
2432         visit(enumBody)
2433       }
2434     }
2435   }
2436 
2437   /** Example `private typealias TextChangedListener = (string: String) -> Unit` */
2438   override fun visitTypeAlias(typeAlias: KtTypeAlias) {
2439     builder.sync(typeAlias)
2440     builder.block(ZERO) {
2441       visit(typeAlias.modifierList)
2442       builder.token("typealias")
2443       builder.space()
2444       builder.token(typeAlias.nameIdentifier?.text ?: fail())
2445       visit(typeAlias.typeParameterList)
2446 
2447       builder.space()
2448       builder.token("=")
2449       builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
2450       builder.block(expressionBreakIndent) {
2451         visit(typeAlias.getTypeReference())
2452         visit(typeAlias.typeConstraintList)
2453         builder.guessToken(";")
2454       }
2455       builder.forcedBreak()
2456     }
2457   }
2458 
2459   /**
2460    * visitElement is called for almost all types of AST nodes. We use it to keep track of whether
2461    * we're currently inside an expression or not.
2462    *
2463    * @throws FormattingError
2464    */
2465   override fun visitElement(element: PsiElement) {
2466     inExpression.addLast(element is KtExpression || inExpression.last())
2467     val previous = builder.depth()
2468     try {
2469       super.visitElement(element)
2470     } catch (e: FormattingError) {
2471       throw e
2472     } catch (t: Throwable) {
2473       throw FormattingError(builder.diagnostic(Throwables.getStackTraceAsString(t)))
2474     } finally {
2475       inExpression.removeLast()
2476     }
2477     builder.checkClosed(previous)
2478   }
2479 
2480   override fun visitKtFile(file: KtFile) {
2481     markForPartialFormat()
2482     val importListEmpty = file.importList?.text?.isBlank() ?: true
2483 
2484     var isFirst = true
2485     for (child in file.children) {
2486       if (child.text.isBlank()) {
2487         continue
2488       }
2489 
2490       builder.blankLineWanted(
2491           when {
2492             isFirst -> OpsBuilder.BlankLineWanted.NO
2493             child is PsiComment -> continue
2494             child is KtScript && importListEmpty -> OpsBuilder.BlankLineWanted.PRESERVE
2495             else -> OpsBuilder.BlankLineWanted.YES
2496           })
2497 
2498       visit(child)
2499       isFirst = false
2500     }
2501     markForPartialFormat()
2502   }
2503 
2504   override fun visitScript(script: KtScript) {
2505     markForPartialFormat()
2506     var lastChildHadBlankLineBefore = false
2507     var lastChildIsContextReceiver = false
2508     var first = true
2509     for (child in script.blockExpression.children) {
2510       if (child.text.isBlank()) {
2511         continue
2512       }
2513       builder.forcedBreak()
2514       val childGetsBlankLineBefore = child !is KtProperty
2515       if (first) {
2516         builder.blankLineWanted(OpsBuilder.BlankLineWanted.PRESERVE)
2517       } else if (lastChildIsContextReceiver) {
2518         builder.blankLineWanted(OpsBuilder.BlankLineWanted.NO)
2519       } else if (child !is PsiComment &&
2520           (childGetsBlankLineBefore || lastChildHadBlankLineBefore)) {
2521         builder.blankLineWanted(OpsBuilder.BlankLineWanted.YES)
2522       }
2523       visit(child)
2524       builder.guessToken(";")
2525       lastChildHadBlankLineBefore = childGetsBlankLineBefore
2526       lastChildIsContextReceiver =
2527           child is KtScriptInitializer &&
2528               child.firstChild?.firstChild?.firstChild?.text == "context"
2529       first = false
2530     }
2531     markForPartialFormat()
2532   }
2533 
2534   /**
2535    * markForPartialFormat is used to delineate the smallest areas of code that must be formatted
2536    * together.
2537    *
2538    * When only parts of the code are being formatted, the requested area is expanded until it's
2539    * covered by an area marked by this method.
2540    */
2541   private fun markForPartialFormat() {
2542     if (!inExpression.last()) {
2543       builder.markForPartialFormat()
2544     }
2545   }
2546 
2547   /**
2548    * Emit a [Doc.Token].
2549    *
2550    * @param token the [String] to wrap in a [Doc.Token]
2551    * @param plusIndentCommentsBefore extra block for comments before this token
2552    */
2553   private fun OpsBuilder.token(token: String, plusIndentCommentsBefore: Indent = ZERO) {
2554     token(
2555         token,
2556         Doc.Token.RealOrImaginary.REAL,
2557         plusIndentCommentsBefore,
2558         /* breakAndIndentTrailingComment */ Optional.empty())
2559   }
2560 
2561   /**
2562    * Opens a new level, emits into it and closes it.
2563    *
2564    * This is a helper method to make it easier to keep track of [OpsBuilder.open] and
2565    * [OpsBuilder.close] calls
2566    *
2567    * @param plusIndent the block level to pass to the block
2568    * @param block a code block to be run in this block level
2569    */
2570   private fun OpsBuilder.block(plusIndent: Indent, isEnabled: Boolean = true, block: () -> Unit) {
2571     if (isEnabled) {
2572       open(plusIndent)
2573     }
2574     block()
2575     if (isEnabled) {
2576       close()
2577     }
2578   }
2579 
2580   /** Helper method to sync the current offset to match any element in the AST */
2581   private fun OpsBuilder.sync(psiElement: PsiElement) {
2582     sync(psiElement.startOffset)
2583   }
2584 
2585   /** Prevent subsequent comments from being moved ahead of this point, into parent [Level]s. */
2586   private fun OpsBuilder.fenceComments() {
2587     addAll(FenceCommentsOp.AS_LIST)
2588   }
2589 
2590   /**
2591    * Throws a formatting error
2592    *
2593    * This is used as `expr ?: fail()` to avoid using the !! operator and provide better error
2594    * messages.
2595    */
2596   private fun fail(message: String = "Unexpected"): Nothing {
2597     throw FormattingError(builder.diagnostic(message))
2598   }
2599 
2600   /** Helper function to improve readability */
2601   private fun visit(element: PsiElement?) {
2602     element?.accept(this)
2603   }
2604 
2605   /** Emits a key word followed by a condition, e.g. `if (b)` or `while (c < d )` */
2606   private fun emitKeywordWithCondition(keyword: String, condition: KtExpression?) {
2607     if (condition == null) {
2608       builder.token(keyword)
2609       return
2610     }
2611 
2612     builder.block(ZERO) {
2613       builder.token(keyword)
2614       builder.space()
2615       builder.token("(")
2616       if (options.manageTrailingCommas) {
2617         builder.block(expressionBreakIndent) {
2618           builder.breakOp(Doc.FillMode.UNIFIED, "", ZERO)
2619           visit(condition)
2620           builder.breakOp(Doc.FillMode.UNIFIED, "", expressionBreakNegativeIndent)
2621         }
2622       } else {
2623         builder.block(ZERO) { visit(condition) }
2624       }
2625     }
2626     builder.token(")")
2627   }
2628 }
2629