diff --git a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/TypeSpec.kt b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/TypeSpec.kt index ad751c5449..3747c0054f 100644 --- a/kotlinpoet/src/main/java/com/squareup/kotlinpoet/TypeSpec.kt +++ b/kotlinpoet/src/main/java/com/squareup/kotlinpoet/TypeSpec.kt @@ -30,6 +30,7 @@ import com.squareup.kotlinpoet.KModifier.PUBLIC import com.squareup.kotlinpoet.KModifier.SEALED import com.squareup.kotlinpoet.KModifier.VALUE import java.lang.reflect.Type +import java.util.EnumSet import javax.lang.model.element.Element import kotlin.reflect.KClass @@ -299,10 +300,10 @@ public class TypeSpec private constructor( } // Functions. - for (funSpec in funSpecs) { + for (funSpec in funSpecsOmittingVisibility()) { if (funSpec.isConstructor) continue if (!firstMember) codeWriter.emit("\n") - funSpec.emit(codeWriter, name, kind.implicitFunctionModifiers(modifiers + implicitModifiers), true) + funSpec.emit(codeWriter, name, implicitFunctionModifiers(implicitModifiers), true) firstMember = false } @@ -324,6 +325,33 @@ public class TypeSpec private constructor( } } + /** + * Returns the list of [FunSpec], optionally removing all non-private visibility modifiers + * if this is a private type. + */ + private fun funSpecsOmittingVisibility(): List { + return if (PRIVATE in modifiers) { + val omitted = EnumSet.of(PUBLIC, INTERNAL) + funSpecs.map { + it.toBuilder().apply { modifiers.removeAll(omitted) }.build() + } + } else { + funSpecs + } + } + + /** + * Returns the implicit function modifiers for this kind, optionally removing PUBLIC + * if this is a private type. + */ + private fun implicitFunctionModifiers(implicitModifiers: Set): Set { + val fModifiers = kind.implicitFunctionModifiers(modifiers + implicitModifiers).toMutableSet() + if (PRIVATE in modifiers) { + fModifiers -= PUBLIC + } + return fModifiers + } + /** Returns the properties that can be declared inline as constructor parameters. */ private fun constructorProperties(): Map { if (primaryConstructor == null) return emptyMap() diff --git a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt index cf6c3e2982..5b657ae0be 100644 --- a/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt +++ b/kotlinpoet/src/test/java/com/squareup/kotlinpoet/TypeSpecTest.kt @@ -5358,6 +5358,39 @@ class TypeSpecTest { assertThat(t).hasMessageThat().contains("contextReceivers can only be applied on simple classes") } + // https://github.com/square/kotlinpoet/issues/1301 + @Test fun `function omits non-private modifiers on private type`() { + val taco = TypeSpec.classBuilder("Taco") + .addModifiers(PRIVATE) + .addFunctions( + listOf( + FunSpec.builder("f1").addModifiers(PUBLIC).build(), + FunSpec.builder("f2").addModifiers(INTERNAL).build(), + FunSpec.builder("f3").addModifiers(PRIVATE).build(), + ), + ) + .build() + assertThat(toString(taco)).isEqualTo( + """ + |package com.squareup.tacos + | + |import kotlin.Unit + | + |private class Taco { + | fun f1(): Unit { + | } + | + | fun f2(): Unit { + | } + | + | private fun f3(): Unit { + | } + |} + | + """.trimMargin(), + ) + } + companion object { private const val donutsPackage = "com.squareup.donuts" }