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