Repository: square/kotlinpoet
Issue: Type names in a line comment may break the line

`addComment()` replaces all the spaces in the format string with `·` for nonbreaking space, but not spaces in type arguments. 

```kotlin
builder.addComment("this is a long line with a possibly long type: %T", someLongParamterizedTypeName);
```

The above could end up generating code like

```kotlin
// this is a long line with a possibly long type: List<Map<String, Collection<Map<WackyKey,
  OhNoThisDoesNotCompile>>>>
```

Changed files:
kotlinpoet/src/main/java/com/squareup/kotlinpoet/ParameterizedTypeName.kt, kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeName.kt, kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt, kotlinpoet/src/main/java/com/squareup/kotlinpoet/WildcardTypeName.kt

diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeName.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeName.kt
index 8b31ee96..3f8514a3 100644
--- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeName.kt
+++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/LambdaTypeName.kt
@@ -59,7 +59,7 @@ public class LambdaTypeName private constructor(
     }
 
     if (isSuspending) {
-      out.emit("suspend ")
+      out.emit("suspend·")
     }
 
     receiver?.let {
@@ -71,7 +71,7 @@ public class LambdaTypeName private constructor(
     }
 
     parameters.emit(out)
-    out.emitCode(if (returnType is LambdaTypeName) " -> (%T)" else " -> %T", returnType)
+    out.emitCode(if (returnType is LambdaTypeName) "·->·(%T)" else "·->·%T", returnType)
 
     if (isNullable) {
       out.emit(")")
diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/ParameterizedTypeName.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/ParameterizedTypeName.kt
index af726bd4..fee91816 100644
--- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/ParameterizedTypeName.kt
+++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/ParameterizedTypeName.kt
@@ -83,7 +83,7 @@ public class ParameterizedTypeName internal constructor(
     if (typeArguments.isNotEmpty()) {
       out.emit("<")
       typeArguments.forEachIndexed { index, parameter ->
-        if (index > 0) out.emit(", ")
+        if (index > 0) out.emit(",·")
         parameter.emitAnnotations(out)
         parameter.emit(out)
         parameter.emitNullable(out)
diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/WildcardTypeName.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/WildcardTypeName.kt
index 803091be..914df5a5 100644
--- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/WildcardTypeName.kt
+++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/WildcardTypeName.kt
@@ -46,9 +46,9 @@ public class WildcardTypeName private constructor(
 
   override fun emit(out: CodeWriter): CodeWriter {
     return when {
-      inTypes.size == 1 -> out.emitCode("in %T", inTypes[0])
+      inTypes.size == 1 -> out.emitCode("in·%T", inTypes[0])
       outTypes == STAR.outTypes -> out.emit("*")
-      else -> out.emitCode("out %T", outTypes[0])
+      else -> out.emitCode("out·%T", outTypes[0])
     }
   }
 
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt
index 2ac486bf..ef71a607 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt
@@ -1055,4 +1055,47 @@ class FileSpecTest {
       |""".trimMargin()
     )
   }
+
+  class WackyKey
+  class OhNoThisDoesNotCompile
+
+  @OptIn(ExperimentalStdlibApi::class)
+  @Test fun longCommentWithTypes() {
+    val someLongParameterizedTypeName = typeNameOf<List<Map<in String, Collection<Map<WackyKey, out OhNoThisDoesNotCompile>>>>>()
+    val param = ParameterSpec.builder("foo", someLongParameterizedTypeName).build()
+    val someLongLambdaTypeName = LambdaTypeName.get(STRING, listOf(param), STRING).copy(suspending = true)
+    val file = FileSpec.builder("com.squareup.tacos", "Taco")
+      .addFunction(
+        FunSpec.builder("f1")
+          .addComment("this is a long line with a possibly long parameterized type with annotation: %T", someLongParameterizedTypeName)
+          .build()
+      )
+      .addFunction(
+        FunSpec.builder("f2")
+          .addComment("this is a very very very very very very very very very very long line with a very long lambda type: %T", someLongLambdaTypeName)
+          .build()
+      )
+      .build()
+
+    assertThat(file.toString()).isEqualTo(
+      """
+      |package com.squareup.tacos
+      |
+      |import com.squareup.kotlinpoet.FileSpecTest
+      |import kotlin.String
+      |import kotlin.Unit
+      |import kotlin.collections.Collection
+      |import kotlin.collections.List
+      |import kotlin.collections.Map
+      |
+      |public fun f1(): Unit {
+      |  // this is a long line with a possibly long parameterized type with annotation: List<Map<in String, Collection<Map<FileSpecTest.WackyKey, out FileSpecTest.OhNoThisDoesNotCompile>>>>
+      |}
+      |
+      |public fun f2(): Unit {
+      |  // this is a very very very very very very very very very very long line with a very long lambda type: suspend String.(foo: List<Map<in String, Collection<Map<FileSpecTest.WackyKey, out FileSpecTest.OhNoThisDoesNotCompile>>>>) -> String
+      |}
+      |""".trimMargin()
+    )
+  }
 }