Skip to content

Instantly share code, notes, and snippets.

Avatar

David Rawson drawers

  • ClearPoint
  • Auckland, New Zealand
View GitHub Profile
View KSPTest.kt
@Test
fun `target is a data class`() {
val kotlinSource = SourceFile.kotlin(
"file1.kt", """
package com.tests.summable
import com.tsongkha.kspexample.IntSummable
@IntSummable
data class FooSummable(
View KSPGeneratedSources.kt
private fun KotlinCompilation.Result.kspGeneratedSources(): List<File> {
val kspWorkingDir = workingDir.resolve("ksp")
val kspGeneratedDir = kspWorkingDir.resolve("sources")
val kotlinGeneratedDir = kspGeneratedDir.resolve("kotlin")
val javaGeneratedDir = kspGeneratedDir.resolve("java")
return kotlinGeneratedDir.walk().toList() +
javaGeneratedDir.walk().toList()
}
private val KotlinCompilation.Result.workingDir: File
View Compile.kt
private fun compile(vararg source: SourceFile) = KotlinCompilation().apply {
sources = source.toList()
symbolProcessorProviders = listOf(IntSummableProcessor.IntSummableProcessorProvider())
workingDir = temporaryFolder.root
inheritClassPath = true
verbose = false
}.compile()
View build.gradle.kts
dependencies {
testImplementation("com.github.tschuchortdev:kotlin-compile-testing:1.4.2")
testImplementation("com.github.tschuchortdev:kotlin-compile-testing-ksp:1.4.2")
}
View CodeGeneration.kt
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
// continued from above
if (summables.isEmpty()) {
return
}
val fileSpec = FileSpec.builder(
packageName = packageName,
fileName = classDeclaration.simpleName.asString()
View KotlinPoet.kt
dependencies {
implementation("com.squareup:kotlinpoet:1.8.0")
}
View Visitor2.kt
inner class Visitor : KSVisitorVoid() {
private lateinit var className: String
private lateinit var packageName: String
private val summables: MutableList<String> = mutableListOf()
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
val qualifiedName = classDeclaration.qualifiedName?.asString()
className = qualifiedName
packageName = classDeclaration.packageName.asString()
View Visitor1.kt
inner class Visitor : KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
val qualifiedName = classDeclaration.qualifiedName?.asString()
if (!classDeclaration.isDataClass()) {
logger.error(
"@IntSummable cannot target non-data class $qualifiedName",
classDeclaration
)
View KSVisitor.kt
interface KSVisitor<D, R> {
fun visitNode(node: KSNode, data: D): R
fun visitAnnotated(annotated: KSAnnotated, data: D): R
// etc.
}
View IntSummableProcessor.kt
class IntSummableProcessor(
private val options: Map<String, String>,
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger
) : SymbolProcessor {
private lateinit var intType: KSType
override fun process(resolver: Resolver): List<KSAnnotated> {
intType = resolver.builtIns.intType