Repository: square/kotlinpoet
Issue: Accessors get public visibility on non-public properties

Test case:

```kotlin
val file = FileSpec.builder("com.squareup.tacos", "Taco")
    .addProperty(PropertySpec.builder("foo", String::class, PRIVATE)
        .mutable()
        .getter(FunSpec.getterBuilder()
            .addStatement("return %S", "foo")
            .build())
        .setter(FunSpec.setterBuilder()
            .addParameter("foo", String::class)
            .build())
        .build())
    .build()
```

Prints:

```kotlin
package com.squareup.tacos
    
import kotlin.String
    
private var foo: String
  public get() = "foo"
  public set(foo) {
  }
```

Which doesn't compile (`Getter visibility must be the same as property visibility`).

Properties should either propagate their visibility to the accessors, or check that the accessors have visibility specified explicitly. My preference is for the former approach.

Changed files:
kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt, kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt, kotlinpoet/src/main/java/com/squareup/kotlinpoet/KModifier.kt, kotlinpoet/src/main/java/com/squareup/kotlinpoet/PropertySpec.kt, kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt, kotlinpoet/src/test/java/com/squareup/kotlinpoet/jvm/JvmAnnotationsTest.kt

diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/KModifier.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/KModifier.kt
index 9425e048..936dde06 100644
--- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/KModifier.kt
+++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/KModifier.kt
@@ -15,6 +15,12 @@
  */
 package com.squareup.kotlinpoet
 
+import com.squareup.kotlinpoet.KModifier.INTERNAL
+import com.squareup.kotlinpoet.KModifier.PRIVATE
+import com.squareup.kotlinpoet.KModifier.PROTECTED
+import com.squareup.kotlinpoet.KModifier.PUBLIC
+import java.util.EnumSet
+
 public enum class KModifier(
   internal val keyword: String,
   private vararg val targets: Target
@@ -81,3 +87,5 @@ public enum class KModifier(
     require(target in targets) { "unexpected modifier $this for $target" }
   }
 }
+
+internal val VISIBILITY_MODIFIERS: Set<KModifier> = EnumSet.of(PUBLIC, INTERNAL, PROTECTED, PRIVATE)
diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/PropertySpec.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/PropertySpec.kt
index 673bb9fe..ddaba96e 100644
--- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/PropertySpec.kt
+++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/PropertySpec.kt
@@ -19,6 +19,7 @@ import com.squareup.kotlinpoet.FunSpec.Companion.GETTER
 import com.squareup.kotlinpoet.FunSpec.Companion.SETTER
 import com.squareup.kotlinpoet.KModifier.Target.PROPERTY
 import java.lang.reflect.Type
+import java.util.EnumSet
 import javax.lang.model.element.Element
 import kotlin.reflect.KClass
 
@@ -98,10 +99,15 @@ public class PropertySpec private constructor(
     }
     codeWriter.emitWhereBlock(typeVariables)
     if (!inline) codeWriter.emit("\\n")
-    val implicitAccessorModifiers = if (isInlineProperty) {
-      implicitModifiers + KModifier.INLINE
-    } else {
-      implicitModifiers
+    val implicitAccessorModifiers = EnumSet.noneOf(KModifier::class.java)
+    for (modifier in implicitModifiers) {
+      // Omit visibility modifiers, accessor visibility will default to the property's visibility.
+      if (modifier !in VISIBILITY_MODIFIERS) {
+        implicitAccessorModifiers.add(modifier)
+      }
+    }
+    if (isInlineProperty) {
+      implicitAccessorModifiers.add(KModifier.INLINE)
     }
     if (getter != null) {
       codeWriter.emitCode("⇥")
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
index e8f2cf9e..ecf7e3bc 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/KotlinPoetTest.kt
@@ -524,7 +524,7 @@ class KotlinPoetTest {
         |import kotlin.String
         |
         |public val String.extensionProperty: Int
-        |  public get() = length
+        |  get() = length
         |
         """.trimMargin()
     )
@@ -556,7 +556,7 @@ class KotlinPoetTest {
         |import kotlin.String
         |
         |public val ((String) -> String).extensionProperty: Int
-        |  public get() = length
+        |  get() = length
         |
         """.trimMargin()
     )
@@ -598,11 +598,11 @@ class KotlinPoetTest {
         |import kotlin.Int
         |
         |public var propertyWithCustomAccessors: Int = 1
-        |  public get() {
+        |  get() {
         |    println("getter")
         |    return field
         |  }
-        |  public set(value) {
+        |  set(value) {
         |    println("setter")
         |    field = value
         |  }
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
index 7ecd53ff..3679efb9 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/PropertySpecTest.kt
@@ -16,6 +16,7 @@
 package com.squareup.kotlinpoet
 
 import com.google.common.truth.Truth.assertThat
+import com.squareup.kotlinpoet.KModifier.PRIVATE
 import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
 import java.io.Serializable
 import java.util.function.Function
@@ -41,7 +42,7 @@ class PropertySpecTest {
       .mutable()
       .setter(
         FunSpec.setterBuilder()
-          .addModifiers(KModifier.PRIVATE)
+          .addModifiers(PRIVATE)
           .build()
       )
       .build()
@@ -213,7 +214,7 @@ class PropertySpecTest {
   @Test fun modifyModifiers() {
     val builder = PropertySpec
       .builder("word", String::class)
-      .addModifiers(KModifier.PRIVATE)
+      .addModifiers(PRIVATE)
 
     builder.modifiers.clear()
     builder.modifiers.add(KModifier.INTERNAL)
@@ -242,7 +243,7 @@ class PropertySpecTest {
   // https://github.com/square/kotlinpoet/issues/437
   @Test fun typeVariable() {
     val t = TypeVariableName("T", Any::class)
-    val prop = PropertySpec.builder("someFunction", t, KModifier.PRIVATE)
+    val prop = PropertySpec.builder("someFunction", t, PRIVATE)
       .addTypeVariable(t)
       .receiver(KClass::class.asClassName().parameterizedBy(t))
       .getter(
@@ -264,7 +265,7 @@ class PropertySpecTest {
     val t = TypeVariableName("T", Serializable::class, Cloneable::class)
     val r = TypeVariableName("R", Any::class)
     val function = Function::class.asClassName().parameterizedBy(t, r)
-    val prop = PropertySpec.builder("property", String::class, KModifier.PRIVATE)
+    val prop = PropertySpec.builder("property", String::class, PRIVATE)
       .receiver(function)
       .addTypeVariables(listOf(t, r))
       .getter(
@@ -283,7 +284,7 @@ class PropertySpecTest {
 
   @Test fun reifiedTypeVariable() {
     val t = TypeVariableName("T").copy(reified = true)
-    val prop = PropertySpec.builder("someFunction", t, KModifier.PRIVATE)
+    val prop = PropertySpec.builder("someFunction", t, PRIVATE)
       .addTypeVariable(t)
       .receiver(KClass::class.asClassName().parameterizedBy(t))
       .getter(
@@ -488,4 +489,39 @@ class PropertySpecTest {
       |""".trimMargin()
     )
   }
+
+  // https://github.com/square/kotlinpoet/issues/1002
+  @Test fun visibilityOmittedOnAccessors() {
+    val file = FileSpec.builder("com.squareup.tacos", "Taco")
+      .addProperty(
+        PropertySpec.builder("foo", String::class, PRIVATE)
+          .mutable()
+          .getter(
+            FunSpec.getterBuilder()
+              .addStatement("return %S", "foo")
+              .build()
+          )
+          .setter(
+            FunSpec.setterBuilder()
+              .addParameter("foo", String::class)
+              .build()
+          )
+          .build()
+      )
+      .build()
+    assertThat(file.toString()).isEqualTo(
+      //language=kotlin
+      """
+        package com.squareup.tacos
+
+        import kotlin.String
+
+        private var foo: String
+          get() = "foo"
+          set(foo) {
+          }
+
+      """.trimIndent()
+    )
+  }
 }
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
index 1e5fdb14..9c3ad6c7 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt
@@ -691,7 +691,7 @@ class TypeSpecTest {
         |  contents: String
         |) {
         |  public val contents: String = contents
-        |    public get() {
+        |    get() {
         |      println("contents observed!")
         |      return field
         |    }
@@ -729,7 +729,7 @@ class TypeSpecTest {
         |  contents: String
         |) {
         |  public var contents: String = contents
-        |    public set(value) {
+        |    set(value) {
         |      println("contents changed!")
         |      field = value
         |    }
diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/jvm/JvmAnnotationsTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/jvm/JvmAnnotationsTest.kt
index ff6d2fc6..18b7d196 100644
--- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/jvm/JvmAnnotationsTest.kt
+++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/jvm/JvmAnnotationsTest.kt
@@ -194,7 +194,7 @@ class JvmAnnotationsTest {
       |  public companion object {
       |    public val foo: String
       |      @JvmStatic
-      |      public get() = "foo"
+      |      get() = "foo"
       |  }
       |}
       |""".trimMargin()
@@ -235,7 +235,7 @@ class JvmAnnotationsTest {
       |  public companion object {
       |    public var foo: String = "foo"
       |      @JvmStatic
-      |      public set(value) {
+      |      set(value) {
       |      }
       |  }
       |}
@@ -350,7 +350,7 @@ class JvmAnnotationsTest {
       |
       |public val foo: String
       |  @Throws(IOException::class)
-      |  public get() = "foo"
+      |  get() = "foo"
       |""".trimMargin()
     )
   }
@@ -380,7 +380,7 @@ class JvmAnnotationsTest {
       |
       |public var foo: String
       |  @Throws(IOException::class)
-      |  public set(value) {
+      |  set(value) {
       |    print("foo")
       |  }
       |""".trimMargin()
@@ -532,7 +532,7 @@ class JvmAnnotationsTest {
       |
       |public val foo: String
       |  @JvmName("foo")
-      |  public get() = "foo"
+      |  get() = "foo"
       |""".trimMargin()
     )
   }
@@ -561,7 +561,7 @@ class JvmAnnotationsTest {
       |
       |public var foo: String = "foo"
       |  @JvmName("foo")
-      |  public set(value) {
+      |  set(value) {
       |  }
       |""".trimMargin()
     )
@@ -779,7 +779,7 @@ class JvmAnnotationsTest {
       |
       |public val foo: String
       |  @Synchronized
-      |  public get() = "foo"
+      |  get() = "foo"
       |""".trimMargin()
     )
   }
@@ -808,7 +808,7 @@ class JvmAnnotationsTest {
       |
       |public var foo: String = "foo"
       |  @Synchronized
-      |  public set(value) {
+      |  set(value) {
       |  }
       |""".trimMargin()
     )
@@ -1014,7 +1014,7 @@ class JvmAnnotationsTest {
       |
       |public val foo: String
       |  @Strictfp
-      |  public get() = "foo"
+      |  get() = "foo"
       |""".trimMargin()
     )
   }
@@ -1043,7 +1043,7 @@ class JvmAnnotationsTest {
       |
       |public var foo: String
       |  @Strictfp
-      |  public set(value) {
+      |  set(value) {
       |    print("foo")
       |  }
       |""".trimMargin()