Skip to content

Commit 5af5b77

Browse files
yigittschuchortdev
authored andcommitted
create new module for ksp support
Fixes
1 parent ff533ba commit 5af5b77

File tree

9 files changed

+209
-2
lines changed

9 files changed

+209
-2
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,4 @@ hs_err_pid*
233233

234234
!gradle/wrapper/gradle-wrapper.jar
235235

236+
ksp/build

build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
buildscript {
2-
ext.kotlin_version = '1.3.72'
2+
ext.kotlin_version = '1.4-M1'
33

44
repositories {
55
mavenCentral()
66
maven { url 'https://jitpack.io' }
7+
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
78
}
89

910
dependencies {
@@ -15,7 +16,6 @@ buildscript {
1516

1617
plugins {
1718
id 'java'
18-
id 'org.jetbrains.kotlin.jvm' version "$kotlin_version"
1919
id "com.github.gmazzo.buildconfig" version "2.0.1"
2020
}
2121

@@ -32,6 +32,7 @@ repositories {
3232
maven { url 'https://jitpack.io' }
3333
maven { url 'https://kotlin.bintray.com/kotlinx' }
3434
jcenter()
35+
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
3536
}
3637

3738
idea {

ksp/build.gradle

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apply plugin: 'kotlin'
2+
// TODO remove group and version
3+
group 'com.github.tschuchortdev'
4+
version '1.2.8'
5+
ext.ksp_version='1.4-M1-dev-experimental-20200610'
6+
7+
repositories {
8+
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
9+
mavenCentral()
10+
google()
11+
}
12+
13+
dependencies {
14+
api(rootProject)
15+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
16+
implementation "org.jetbrains.kotlin:kotlin-symbol-processing-api:$ksp_version"
17+
implementation "org.jetbrains.kotlin:kotlin-ksp:$ksp_version"
18+
implementation "org.jetbrains.kotlin:kotlin-compiler-embeddable:$kotlin_version"
19+
20+
testImplementation group: 'junit', name: 'junit', version: '4.12'
21+
testImplementation "org.assertj:assertj-core:3.11.1"
22+
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
23+
}
24+
25+
compileKotlin {
26+
kotlinOptions.jvmTarget = "1.8"
27+
}
28+
compileTestKotlin {
29+
kotlinOptions.jvmTarget = "1.8"
30+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Adds support for KSP (https://goo.gle/ksp).
3+
*/
4+
package com.tschuchort.compiletesting
5+
6+
import org.jetbrains.kotlin.ksp.KotlinSymbolProcessingCommandLineProcessor
7+
import org.jetbrains.kotlin.ksp.KotlinSymbolProcessingComponentRegistrar
8+
import org.jetbrains.kotlin.ksp.processing.SymbolProcessor
9+
10+
private const val KSP_PLUGIN_ID = "org.jetbrains.kotlin.ksp"
11+
12+
// TODO can we add support for instances?
13+
fun KotlinCompilation.symbolProcessor(
14+
vararg processors : Class<out SymbolProcessor>
15+
) {
16+
check(processors.isNotEmpty()) {
17+
"Must provide at least 1 symbol processor"
18+
}
19+
val kspWorkingDir = workingDir.resolve("ksp")
20+
21+
// create a fake classpath that references our symbol processor
22+
val processorClasspath = kspWorkingDir.resolve("synthetic-ksp-service").apply {
23+
resolve("META-INF/services/org.jetbrains.kotlin.ksp.processing.SymbolProcessor").apply {
24+
parentFile.mkdirs()
25+
val processorNames = processors.joinToString(System.lineSeparator()) {
26+
it.typeName
27+
}
28+
writeText(
29+
processorNames
30+
)
31+
}
32+
}
33+
34+
val classesFolder = kspWorkingDir.resolve("outClasses").also {
35+
it.mkdirs()
36+
}
37+
val sourceFolder = kspWorkingDir.resolve("outSources").also {
38+
it.mkdirs()
39+
}
40+
val kspOptions = listOf(
41+
PluginOption(KSP_PLUGIN_ID, "apclasspath", processorClasspath.path),
42+
PluginOption(KSP_PLUGIN_ID, "classes", classesFolder.path),
43+
PluginOption(KSP_PLUGIN_ID, "sources", sourceFolder.path)
44+
)
45+
compilerPlugins += KotlinSymbolProcessingComponentRegistrar()
46+
commandLineProcessors += listOf(KotlinSymbolProcessingCommandLineProcessor())
47+
pluginOptions += kspOptions
48+
this.kaptSourceDir
49+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.tschuchort.compiletesting
2+
3+
import org.jetbrains.kotlin.ksp.processing.CodeGenerator
4+
import org.jetbrains.kotlin.ksp.processing.Resolver
5+
import org.jetbrains.kotlin.ksp.processing.SymbolProcessor
6+
7+
internal open class AbstractSymbolProcessor : SymbolProcessor {
8+
override fun finish() {
9+
}
10+
11+
override fun init(options: Map<String, String>, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator) {
12+
}
13+
14+
override fun process(resolver: Resolver) {
15+
}
16+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.tschuchort.compiletesting
2+
3+
import org.jetbrains.kotlin.ksp.processing.CodeGenerator
4+
import org.jetbrains.kotlin.ksp.processing.Resolver
5+
import org.jetbrains.kotlin.ksp.processing.SymbolProcessor
6+
import org.junit.rules.TestWatcher
7+
import org.junit.runner.Description
8+
9+
internal class DelegateProcessor : SymbolProcessor {
10+
private val delegate
11+
get() = checkNotNull(Companion.delegate) {
12+
"Delegate is not provided"
13+
}
14+
15+
override fun finish() {
16+
delegate.finish()
17+
}
18+
19+
override fun init(options: Map<String, String>, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator) {
20+
delegate.init(
21+
options = options,
22+
kotlinVersion = kotlinVersion,
23+
codeGenerator = codeGenerator
24+
)
25+
}
26+
27+
override fun process(resolver: Resolver) {
28+
delegate.process(resolver)
29+
}
30+
31+
companion object {
32+
var delegate: SymbolProcessor? = null
33+
}
34+
}
35+
36+
class DelegatingSymbolProcessorRule : TestWatcher() {
37+
fun delegateTo(processor: SymbolProcessor): Class<out SymbolProcessor> {
38+
check(DelegateProcessor.delegate == null) {
39+
"Cannot use DelegatingSymbolProcessorRule more than once"
40+
}
41+
DelegateProcessor.delegate = processor
42+
return DelegateProcessor::class.java
43+
}
44+
45+
override fun finished(description: Description?) {
46+
DelegateProcessor.delegate = null
47+
super.finished(description)
48+
}
49+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.tschuchort.compiletesting
2+
3+
import com.nhaarman.mockitokotlin2.any
4+
import com.nhaarman.mockitokotlin2.inOrder
5+
import com.nhaarman.mockitokotlin2.mock
6+
import com.nhaarman.mockitokotlin2.verify
7+
import com.tschuchort.compiletesting.KotlinCompilation.ExitCode
8+
import org.assertj.core.api.Assertions.assertThat
9+
import org.jetbrains.kotlin.ksp.processing.Resolver
10+
import org.jetbrains.kotlin.ksp.processing.SymbolProcessor
11+
import org.junit.Rule
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
import org.junit.runners.JUnit4
15+
16+
@RunWith(JUnit4::class)
17+
class KspTest {
18+
@Rule
19+
@JvmField
20+
val processorRule = DelegatingSymbolProcessorRule()
21+
22+
@Test
23+
fun failedKspTest() {
24+
val result = KotlinCompilation().apply {
25+
sources = listOf(DUMMY_KOTLIN_SRC)
26+
symbolProcessor(processorRule.delegateTo(object : AbstractSymbolProcessor() {
27+
override fun process(resolver: Resolver) {
28+
throw RuntimeException("intentional fail")
29+
}
30+
}))
31+
}.compile()
32+
assertThat(result.exitCode).isEqualTo(ExitCode.INTERNAL_ERROR)
33+
assertThat(result.messages).contains("intentional fail")
34+
}
35+
36+
@Test
37+
fun processorIsCalled() {
38+
val instance = mock<SymbolProcessor>()
39+
val result = KotlinCompilation().apply {
40+
sources = listOf(DUMMY_KOTLIN_SRC)
41+
symbolProcessor(processorRule.delegateTo(instance))
42+
}.compile()
43+
assertThat(result.exitCode).isEqualTo(ExitCode.OK)
44+
instance.inOrder {
45+
verify().init(any(), any(), any())
46+
verify().process(any())
47+
verify().finish()
48+
}
49+
}
50+
51+
companion object {
52+
private val DUMMY_KOTLIN_SRC = SourceFile.kotlin(
53+
"foo.bar.Dummy.kt", """
54+
class Dummy {}
55+
""".trimIndent()
56+
)
57+
}
58+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package com.tschuchort.compiletesting
2+

settings.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
rootProject.name = 'kotlin-compile-testing'
2+
include("ksp")
23

0 commit comments

Comments
 (0)