Repository: square/kotlinpoet
Issue: Modified keywords not escape when generating enums.

For instance, KP will generate the following and this doesn't compile because of `open`.
```kt
enum class Sort {
  open,
  sort
}
```

Changed files:
kotlinpoet-metadata-specs-tests/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/test/KotlinPoetMetadataSpecsTest.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/MemberNameTest.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/AnnotationSpecTest.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/CrossplatformTest.kt
kotlinpoet/src/main/java/com/squareup/kotlinpoet/Util.kt
kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt

diff --git a/kotlinpoet-metadata-specs-tests/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/test/KotlinPoetMetadataSpecsTest.kt b/kotlinpoet-metadata-specs-tests/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/test/KotlinPoetMetadataSpecsTest.kt
index 6d483d1c..f19dcab7 100644
--- a/kotlinpoet-metadata-specs-tests/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/test/KotlinPoetMetadataSpecsTest.kt
+++ b/kotlinpoet-metadata-specs-tests/src/test/kotlin/com/squareup/kotlinpoet/metadata/specs/test/KotlinPoetMetadataSpecsTest.kt
@@ -290,10 +290,10 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
         public inline fun hasDefault(param1: kotlin.String = throw NotImplementedError("Stub!")): kotlin.Unit {
         }
 
-        public inline fun inline(crossinline param1: () -> kotlin.String): kotlin.Unit {
+        public inline fun `inline`(crossinline param1: () -> kotlin.String): kotlin.Unit {
         }
 
-        public inline fun noinline(noinline param1: () -> kotlin.String): kotlin.String {
+        public inline fun `noinline`(noinline param1: () -> kotlin.String): kotlin.String {
           throw NotImplementedError("Stub!")
         }
       }
@@ -382,7 +382,7 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
     assertThat(typeSpec.trimmedToString()).isEqualTo(
       """
       public class FunctionsReferencingTypeParameters<T> {
-        public fun test(param: T): kotlin.Unit {
+        public fun test(`param`: T): kotlin.Unit {
         }
       }
       """.trimIndent()
@@ -830,19 +830,19 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
     assertThat(typeSpec.trimmedToString()).isEqualTo(
       """
       public class GenericClass<T> {
-        public fun <T> functionAlsoWithT(param: T): kotlin.Unit {
+        public fun <T> functionAlsoWithT(`param`: T): kotlin.Unit {
         }
 
-        public fun <R> functionWithADifferentType(param: R): kotlin.Unit {
+        public fun <R> functionWithADifferentType(`param`: R): kotlin.Unit {
         }
 
-        public fun functionWithT(param: T): kotlin.Unit {
+        public fun functionWithT(`param`: T): kotlin.Unit {
         }
 
         /**
          * Note: Since this is a synthetic function, some JVM information (annotations, modifiers) may be missing.
          */
-        public inline fun <reified T> reified(param: T): kotlin.Unit {
+        public inline fun <reified T> `reified`(`param`: T): kotlin.Unit {
         }
       }
       """.trimIndent()
@@ -900,7 +900,7 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
       """
       public class AnnotationHolders @com.squareup.kotlinpoet.metadata.specs.test.KotlinPoetMetadataSpecsTest.ConstructorAnnotation constructor() {
         @field:com.squareup.kotlinpoet.metadata.specs.test.KotlinPoetMetadataSpecsTest.FieldAnnotation
-        public var field: kotlin.String? = null
+        public var `field`: kotlin.String? = null
 
         @get:com.squareup.kotlinpoet.metadata.specs.test.KotlinPoetMetadataSpecsTest.GetterAnnotation
         public var getter: kotlin.String? = null
@@ -972,7 +972,7 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
     assertThat(typeSpec.trimmedToString()).isEqualTo(
       """
       public class Constants(
-        public val param: kotlin.String = throw NotImplementedError("Stub!")
+        public val `param`: kotlin.String = throw NotImplementedError("Stub!")
       ) {
         public val binaryProp: kotlin.Int = throw NotImplementedError("Stub!")
 
@@ -1065,7 +1065,7 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
     assertThat(typeSpec.trimmedToString()).isEqualTo(
       """
       public class Constants(
-        public val param: kotlin.String = throw NotImplementedError("Stub!")
+        public val `param`: kotlin.String = throw NotImplementedError("Stub!")
       ) {
         public val binaryProp: kotlin.Int = throw NotImplementedError("Stub!")
 
@@ -1278,7 +1278,7 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
       """
       public class JvmNameData(
         @get:kotlin.jvm.JvmName(name = "jvmParam")
-        public val param: kotlin.String
+        public val `param`: kotlin.String
       ) {
         @get:kotlin.jvm.JvmName(name = "jvmPropertyGet")
         public val propertyGet: kotlin.String? = null
@@ -1325,7 +1325,7 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
       """
       public class JvmNameData(
         @get:kotlin.jvm.JvmName(name = "jvmParam")
-        public val param: kotlin.String
+        public val `param`: kotlin.String
       ) {
         @get:kotlin.jvm.JvmName(name = "jvmPropertyGet")
         public val propertyGet: kotlin.String? = null
@@ -1524,13 +1524,13 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
       """
       public class Synthetics(
         @get:kotlin.jvm.JvmSynthetic
-        public val param: kotlin.String
+        public val `param`: kotlin.String
       ) {
         @field:kotlin.jvm.JvmSynthetic
         public val fieldProperty: kotlin.String? = null
 
         @field:kotlin.jvm.JvmSynthetic
-        public val property: kotlin.String? = null
+        public val `property`: kotlin.String? = null
 
         @get:kotlin.jvm.JvmSynthetic
         public val propertyGet: kotlin.String? = null
@@ -1589,13 +1589,13 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
       """
       public class Synthetics(
         @get:kotlin.jvm.JvmSynthetic
-        public val param: kotlin.String
+        public val `param`: kotlin.String
       ) {
         @field:kotlin.jvm.JvmSynthetic
         public val fieldProperty: kotlin.String? = null
 
         @field:kotlin.jvm.JvmSynthetic
-        public val property: kotlin.String? = null
+        public val `property`: kotlin.String? = null
 
         @get:kotlin.jvm.JvmSynthetic
         public val propertyGet: kotlin.String? = null
@@ -1737,8 +1737,8 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
     assertThat(typeSpec.trimmedToString()).isEqualTo(
       """
       @kotlin.SinceKotlin(version = "1.3")
-      @kotlin.annotation.Retention(value = kotlin.annotation.AnnotationRetention.RUNTIME)
-      @kotlin.annotation.Target(allowedTargets = [kotlin.annotation.AnnotationTarget.CLASS])
+      @kotlin.`annotation`.Retention(value = kotlin.`annotation`.AnnotationRetention.RUNTIME)
+      @kotlin.`annotation`.Target(allowedTargets = [kotlin.`annotation`.AnnotationTarget.CLASS])
       public annotation class Metadata(
         @get:kotlin.jvm.JvmName(name = "k")
         public val kind: kotlin.Int = throw NotImplementedError("Stub!"),
@@ -1772,8 +1772,8 @@ class KotlinPoetMetadataSpecsTest : MultiClassInspectorTest() {
     //language=kotlin
     assertThat(typeSpec.trimmedToString()).isEqualTo(
       """
-      @kotlin.annotation.Retention(value = kotlin.annotation.AnnotationRetention.RUNTIME)
-      @kotlin.annotation.Target(allowedTargets = [kotlin.annotation.AnnotationTarget.CLASS])
+      @kotlin.`annotation`.Retention(value = kotlin.`annotation`.AnnotationRetention.RUNTIME)
+      @kotlin.`annotation`.Target(allowedTargets = [kotlin.`annotation`.AnnotationTarget.CLASS])
       public annotation class Metadata(
         @get:kotlin.jvm.JvmName(name = "k")
         public val kind: kotlin.Int = throw NotImplementedError("Stub!"),
diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/Util.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/Util.kt
index 5fc89930..2c64f003 100644
--- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/Util.kt
+++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/Util.kt
@@ -165,36 +165,87 @@ private val IDENTIFIER_REGEX =
 
 internal val String.isIdentifier get() = IDENTIFIER_REGEX.matches(this)
 
-// https://github.com/JetBrains/kotlin/search?q=KeywordStringsGenerated.java
+// https://kotlinlang.org/docs/reference/keyword-reference.html
 private val KEYWORDS = setOf(
-  "package",
+  // Hard keywords
   "as",
-  "typealias",
+  "break",
   "class",
-  "this",
-  "super",
-  "val",
-  "var",
-  "fun",
-  "for",
-  "null",
-  "true",
+  "continue",
+  "do",
+  "else",
   "false",
-  "is",
+  "for",
+  "fun",
+  "if",
   "in",
-  "throw",
-  "return",
-  "break",
-  "continue",
+  "interface",
+  "is",
+  "null",
   "object",
-  "if",
+  "package",
+  "return",
+  "super",
+  "this",
+  "throw",
+  "true",
   "try",
-  "else",
-  "while",
-  "do",
+  "typealias",
+  "typeof",
+  "val",
+  "var",
   "when",
-  "interface",
-  "typeof"
+  "while",
+
+  // Soft keywords
+  "by",
+  "catch",
+  "constructor",
+  "delegate",
+  "dynamic",
+  "field",
+  "file",
+  "finally",
+  "get",
+  "import",
+  "init",
+  "param",
+  "property",
+  "receiver",
+  "set",
+  "setparam",
+  "where",
+
+  // Modifier keywords
+  "actual",
+  "abstract",
+  "annotation",
+  "companion",
+  "const",
+  "crossinline",
+  "data",
+  "enum",
+  "expect",
+  "external",
+  "final",
+  "infix",
+  "inline",
+  "inner",
+  "internal",
+  "lateinit",
+  "noinline",
+  "open",
+  "operator",
+  "out",
+  "override",
+  "private",
+  "protected",
+  "public",
+  "reified",
+  "sealed",
+  "suspend",
+  "tailrec",
+  "vararg",
 )
 
 private const val ALLOWED_CHARACTER = '$'
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/AnnotationSpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/AnnotationSpecTest.kt
index 70a657ee..704ffe61 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/AnnotationSpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/AnnotationSpecTest.kt
@@ -570,18 +570,18 @@ class AnnotationSpecTest {
       @Parcelize
       @TypeParceler<ExternalClass, ExternalClassParceler>
       public class MyClass(
-        public val external: ExternalClass
+        public val `external`: ExternalClass
       )
 
       @Parcelize
       public class MyClass(
         @TypeParceler<ExternalClass, ExternalClassParceler>
-        public val external: ExternalClass
+        public val `external`: ExternalClass
       )
 
       @Parcelize
       public class MyClass(
-        public val external: @WriteWith<ExternalClassParceler> ExternalClass
+        public val `external`: @WriteWith<ExternalClassParceler> ExternalClass
       )
 
       """.trimIndent()
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/CrossplatformTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/CrossplatformTest.kt
index 63a2dc58..b4bd213f 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/CrossplatformTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/CrossplatformTest.kt
@@ -80,13 +80,13 @@ class CrossplatformTest {
       |) {
       |  public val value: V
       |
-      |  public fun get(): V
+      |  public fun `get`(): V
       |
-      |  public fun set(value: V): Unit
+      |  public fun `set`(value: V): Unit
       |
       |  public fun getAndSet(value: V): V
       |
-      |  public fun compareAndSet(expect: V, update: V): Boolean
+      |  public fun compareAndSet(`expect`: V, update: V): Boolean
       |}
       |
       |public actual typealias AtomicRef<V> = AtomicReference<V>
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt
index 68d0317b..0f9b1c17 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/FileSpecTest.kt
@@ -103,9 +103,9 @@ class FileSpecTest {
       """
         |package com.squareup.tacos
         |
+        |import java.lang.System.`out`
         |import java.lang.System.gc
         |import java.lang.System.nanoTime
-        |import java.lang.System.out
         |import java.lang.Thread
         |import java.lang.Thread.State.BLOCKED
         |import java.lang.Thread.State.valueOf
@@ -140,8 +140,8 @@ class FileSpecTest {
       """
         |package com.squareup.tacos
         |
-        |import com.squareup.tacos.internal.INGREDIENTS
-        |import com.squareup.tacos.internal.wrap
+        |import com.squareup.tacos.`internal`.INGREDIENTS
+        |import com.squareup.tacos.`internal`.wrap
         |import kotlin.collections.List
         |
         |public fun prepareTacos(): List<Taco> = wrap(INGREDIENTS)
@@ -1002,7 +1002,7 @@ class FileSpecTest {
       .build()
     assertThat(spec.toString()).isEqualTo(
       """
-      |package com.squareup.taco.enchilada.quesadillas.tamales.burritos.`super`.burritos.trying.to.get.a.really.large.packagename
+      |package com.squareup.taco.enchilada.quesadillas.tamales.burritos.`super`.burritos.trying.to.`get`.a.really.large.packagename
       |
       |import kotlin.Unit
       |
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
index 3448a514..e8f2cf9e 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
@@ -714,7 +714,7 @@ class KotlinPoetTest {
         |import kotlin.String
         |
         |public open class A {
-        |  protected open external infix operator fun get(v: String): String
+        |  protected open external infix operator fun `get`(v: String): String
         |
         |  internal final tailrec inline fun loop(): String = "a"
         |}
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/MemberNameTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/MemberNameTest.kt
index b048ca89..7de5ad85 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/MemberNameTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/MemberNameTest.kt
@@ -406,9 +406,9 @@ class MemberNameTest {
       |package com.example
       |
       |import com.squareup.tacos.Taco
+      |import com.squareup.tacos.`internal`.iterator
+      |import com.squareup.tacos.`internal`.minusAssign
       |import com.squareup.tacos.ingredient.Meat
-      |import com.squareup.tacos.internal.iterator
-      |import com.squareup.tacos.internal.minusAssign
       |import kotlin.Unit
       |
       |public fun makeTacoHealthy(taco: Taco): Unit {
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
index 5b85123d..7ecd53ff 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
@@ -275,7 +275,7 @@ class PropertySpecTest {
       .build()
     assertThat(prop.toString()).isEqualTo(
       """
-      |private val <T, R : kotlin.Any> java.util.function.Function<T, R>.property: kotlin.String where T : java.io.Serializable, T : kotlin.Cloneable
+      |private val <T, R : kotlin.Any> java.util.function.Function<T, R>.`property`: kotlin.String where T : java.io.Serializable, T : kotlin.Cloneable
       |  get() = ""
       |""".trimMargin()
     )
@@ -394,7 +394,7 @@ class PropertySpecTest {
       .build()
     assertThat(property.toString()).isEqualTo(
       """
-      |val property: com.example.SomeTypeAlias = { arg: kotlin.Any ->
+      |val `property`: com.example.SomeTypeAlias = { arg: kotlin.Any ->
       |  println("arg=${'$'}arg")
       |}
       |
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
index 812c9718..1e5fdb14 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
@@ -346,7 +346,7 @@ class TypeSpecTest {
       """
         |package com.squareup.tacos
         |
-        |import javax.annotation.FreeRange
+        |import javax.`annotation`.FreeRange
         |import kotlin.String
         |
         |public class EthicalTaco {
@@ -1058,7 +1058,6 @@ class TypeSpecTest {
     )
   }
 
-  @Ignore("Broken, see https://github.com/square/kotlinpoet/issues/991")
   @Test fun enumWithConstructorsAndKeywords() {
     val primaryConstructor = FunSpec.constructorBuilder()
       .addParameter("value", Int::class)
@@ -2343,7 +2342,7 @@ class TypeSpecTest {
       .addAnnotation(ClassName("javax.annotation", "Nullable"))
       .build()
     assertThat(parameter.toString())
-      .isEqualTo("@javax.annotation.Nullable final taco: com.squareup.tacos.Taco")
+      .isEqualTo("@javax.`annotation`.Nullable final taco: com.squareup.tacos.Taco")
   }
 
   @Test fun classToString() {
@@ -3003,7 +3002,7 @@ class TypeSpecTest {
 
   @Test fun nameFromProperty() {
     val property = PropertySpec.builder("property", String::class).build()
-    assertThat(CodeBlock.of("%N", property).toString()).isEqualTo("property")
+    assertThat(CodeBlock.of("%N", property).toString()).isEqualTo("`property`")
   }
 
   @Test fun nameFromParameter() {