Skip to content

Commit a52451e

Browse files
evantJakeWharton
andauthored
Ksp opt in workaround (#1833)
* pass varargs literaly in kps's toAnnotaitonSpec() This works around an issue where OptIn annotations fail to compile using the explicit array syntax Fixes #1831 * Fixes from pr feedback * Add changelog entry * Update docs/changelog.md --------- Co-authored-by: Jake Wharton <[email protected]>
1 parent 906d7e9 commit a52451e

File tree

4 files changed

+70
-4
lines changed

4 files changed

+70
-4
lines changed

docs/changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Change Log
77
* Fix: Omit implicit modifiers on FileSpec.scriptBuilder (#1813).
88
* Fix: Fix trailing newline in PropertySpec (#1827).
99
Change: kotlinx-metadata 0.9.0. Note that the `KotlinClassMetadata .read` is deprecated in 0.9.0 and replaced with `readStrict` (#1830).
10+
* Fix: `KSAnnotation.toAnnotationSpec` writes varargs in place instead of making them an array to work around a Kotlin
11+
issue with `OptIn` annotations (#1831).
1012

1113
## Version 1.16.0
1214

interop/ksp/src/main/kotlin/com/squareup/kotlinpoet/ksp/Annotations.kt

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,35 @@ public fun KSAnnotation.toAnnotationSpec(omitDefaultValues: Boolean = false): An
3939
is ParameterizedTypeName -> AnnotationSpec.builder(type)
4040
else -> error("This is never possible.")
4141
}
42+
val params = (annotationType.resolve().declaration as KSClassDeclaration).primaryConstructor?.parameters.orEmpty()
43+
.associateBy { it.name }
4244
useSiteTarget?.let { builder.useSiteTarget(it.kpAnalog) }
4345
// TODO support type params once they're exposed https://github.com/google/ksp/issues/753
46+
var varargValues: List<*>? = null
4447
for (argument in arguments) {
4548
val value = argument.value ?: continue
4649
val name = argument.name!!.getShortName()
50+
val type = params[argument.name]
4751
if (omitDefaultValues) {
4852
val defaultValue = this.defaultArguments.firstOrNull { it.name?.asString() == name }?.value
4953
if (isDefaultValue(value, defaultValue)) { continue }
5054
}
51-
val member = CodeBlock.builder()
52-
member.add("%N = ", name)
53-
addValueToBlock(value, member, omitDefaultValues)
54-
builder.addMember(member.build())
55+
if (type?.isVararg == true) {
56+
// Wait to add varargs to end.
57+
varargValues = value as List<*>
58+
} else {
59+
val member = CodeBlock.builder()
60+
member.add("%N = ", name)
61+
addValueToBlock(value, member, omitDefaultValues)
62+
builder.addMember(member.build())
63+
}
64+
}
65+
if (varargValues != null) {
66+
for (item in varargValues) {
67+
val member = CodeBlock.builder()
68+
addValueToBlock(item!!, member, omitDefaultValues)
69+
builder.addMember(member.build())
70+
}
5571
}
5672
return builder.build()
5773
}

interop/ksp/test-processor/src/main/kotlin/com/squareup/kotlinpoet/ksp/test/processor/exampleAnnotations.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ annotation class AnotherAnnotation(val input: String)
7979
enum class AnnotationEnumValue {
8080
ONE, TWO, THREE
8181
}
82+
83+
annotation class AnnotationWithVararg(val simpleArg: Int, vararg val args: String)

interop/ksp/test-processor/src/test/kotlin/com/squareup/kotlinpoet/ksp/test/processor/TestProcessorTest.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,52 @@ class TestProcessorTest {
620620
)
621621
}
622622

623+
@Test
624+
fun varargArgument() {
625+
val compilation = prepareCompilation(
626+
kotlin(
627+
"Example.kt",
628+
"""
629+
package test
630+
631+
import com.squareup.kotlinpoet.ksp.test.processor.AnnotationWithVararg
632+
import com.squareup.kotlinpoet.ksp.test.processor.ExampleAnnotation
633+
634+
@RequiresOptIn
635+
annotation class MyOptIn
636+
637+
@ExampleAnnotation
638+
@OptIn(MyOptIn::class)
639+
@AnnotationWithVararg(0, "one", "two")
640+
interface Example
641+
""".trimIndent(),
642+
),
643+
)
644+
645+
val result = compilation.compile()
646+
assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK)
647+
val generatedFileText = File(compilation.kspSourcesDir, "kotlin/test/TestExample.kt")
648+
.readText()
649+
650+
assertThat(generatedFileText).isEqualTo(
651+
"""
652+
package test
653+
654+
import com.squareup.kotlinpoet.ksp.test.processor.AnnotationWithVararg
655+
import kotlin.OptIn
656+
657+
@OptIn(MyOptIn::class)
658+
@AnnotationWithVararg(
659+
simpleArg = 0,
660+
"one",
661+
"two",
662+
)
663+
public class TestExample
664+
665+
""".trimIndent(),
666+
)
667+
}
668+
623669
@Test
624670
fun regression_1513() {
625671
val compilation = prepareCompilation(

0 commit comments

Comments
 (0)