Improve property delegation line breaks

Summary: A bunch of fixes when handling delegates or initializer for values.

Reviewed By: cgrushko

Differential Revision: D20166558

fbshipit-source-id: beb658965dd38d2c6f74a68c486c4a72cd025da5
diff --git a/core/src/main/java/com/facebook/ktfmt/KotlinInputAstVisitor.kt b/core/src/main/java/com/facebook/ktfmt/KotlinInputAstVisitor.kt
index 95ae76f..75f46ea 100644
--- a/core/src/main/java/com/facebook/ktfmt/KotlinInputAstVisitor.kt
+++ b/core/src/main/java/com/facebook/ktfmt/KotlinInputAstVisitor.kt
@@ -731,39 +731,42 @@
         }
       }
 
-      // Emits ": String" in "val thisIsALongName : String"
+      // For example `: String` in `val thisIsALongName: String` or `fun f(): String`
       if (type != null) {
         if (name != null) {
-          builder.breakOp(Doc.FillMode.INDEPENDENT, "", expressionBreakIndent)
-          builder.open(ZERO)
           builder.token(":")
-          builder.space()
+          builder.open(expressionBreakIndent) // open block for typed values
+          builder.breakOp(Doc.FillMode.UNIFIED, " ", ZERO)
         }
         type.accept(this)
       }
+
     }
 
+    // For example `where T : Int` in a generic method
     if (typeConstraintList != null) {
       builder.space()
       typeConstraintList.accept(this)
       builder.space()
     }
+
+    // for example `by lazy { compute() }`
     if (delegate != null) {
       builder.space()
       builder.token("by")
       builder.space()
       delegate.accept(this)
-    }
-    if (initializer != null) {
+    } else if (initializer != null) {
       builder.space()
       builder.token("=")
+      builder.breakOp(Doc.FillMode.UNIFIED, " ", expressionBreakIndent)
+      builder.block(expressionBreakIndent) {
+        initializer.accept(this)
+      }
     }
+
     if (type != null && name != null) {
-      builder.close()
-    }
-    if (initializer != null) {
-      builder.breakOp(Doc.FillMode.INDEPENDENT, " ", expressionBreakIndent)
-      builder.block(expressionBreakIndent) { initializer.accept(this) }
+      builder.close()  // close block for typed values
     }
 
     if (isField) {
diff --git a/core/src/test/java/com/facebook/ktfmt/FormatterKtTest.kt b/core/src/test/java/com/facebook/ktfmt/FormatterKtTest.kt
index 8a1ea14..bee247d 100644
--- a/core/src/test/java/com/facebook/ktfmt/FormatterKtTest.kt
+++ b/core/src/test/java/com/facebook/ktfmt/FormatterKtTest.kt
@@ -343,8 +343,8 @@
           """
       |--------------------
       |class Foo {
-      |  val thisIsALongName
-      |      : String =
+      |  val thisIsALongName:
+      |      String =
       |      "Hello there this is long"
       |    get() = field
       |}
@@ -1461,6 +1461,25 @@
       |""".trimMargin())
 
   @Test
+  fun `handle property delegation with type and breaks`() =
+      assertFormatted(
+          """
+      |---------------------------------
+      |val importantValue: Int by lazy {
+      |  1 + 1
+      |}
+      |
+      |val importantValue: Int by lazy {
+      |  val b = 1 + 1
+      |  b + b
+      |}
+      |
+      |val importantValueLonger:
+      |    Int by lazy { 1 + 1 }
+      |""".trimMargin(),
+          deduceMaxWidth = true)
+
+  @Test
   fun `handle lambda types`() =
       assertFormatted(
           """
@@ -1714,15 +1733,15 @@
   fun `properly break fully qualified nested user types`() =
       assertFormatted(
           """
-      |-----------------------------------------------------
-      |val complicated
-      |    : com.example.interesting.SomeType<
-      |    com.example.interesting.SomeType<Int, Nothing>,
+      |-------------------------------------------------------
+      |val complicated:
       |    com.example.interesting.SomeType<
+      |        com.example.interesting.SomeType<Int, Nothing>,
       |        com.example.interesting.SomeType<
-      |            Int,
-      |            Nothing>,
-      |        Nothing>> =
+      |            com.example.interesting.SomeType<
+      |                Int,
+      |                Nothing>,
+      |            Nothing>> =
       |    DUMMY
       |""".trimMargin(),
           deduceMaxWidth = true)