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