Files generated through KSP not showing
gfreivasc opened this issue · comments
I'm having a problem with compiler testing. For some reason, it does not detect KSP generated files. They have been successfully generated and it's possible to browse to them through the file system, but they're not reported on the compilation result. It looks like it's looking for kapt generated stuff instead.
Here's how I'm running it:
compile(folder: File, vararg sourceFiles: SourceFile): KotlinCompilation.Result {
val processors = provider.provide()
val kspProcessors = processors.filterIsInstance<SymbolProcessor>()
val kaptProcessors = processors.filterIsInstance<BasicAnnotationProcessor>()
return KotlinCompilation()
.apply {
workingDir = folder
inheritClassPath = true
if (kspProcessors.isNotEmpty()) {
symbolProcessors = kspProcessors
} else if (kaptProcessors.isNotEmpty()) {
annotationProcessors = kaptProcessors.asProcessorList
}
sources = sourceFiles.asList()
verbose = false
kspIncremental = true
}.compile()
}
// ... during test
val result = compile(
temporaryFolder.root, // The jUnit rule for temporary folders
SourceFile.kotlin(
"source.kt",
"""
package test
import com.gabrielfv.crane.annotations.RoutedBy
class R
@RoutedBy(R::class)
class A
"""
)
)
The variable result
won't contain no generated sources, all the properties generatedFiles
, generatedStubFiles
, sourcesGeneratedByAnnotationProcessor
and compiledClassAndResourceFiles
return empty for my KSP round. Everything works just fine for my KAPT rounds.
I am able to reproduce your issue. Strictly speaking it's "working as intended". Unfortunately, the current implementation of KotlinCompilation
is quite limited in its extensibility and KSP, being implemented as a third-party extension instead of being integrated like KAPT, can not add its generated files to the Result
class. Let me think of a way to gather all the new files in the working directory and I will add it as a new method to the Result
class.
I see, so not a bug but rather that it's not designed to fully support KSP at least just yet. Other than this kind of behavior, what else do you think would be necessary to extend KSP support, and do you intend to do it in the sorter term?
I've been able to apply the following workaround:
internal val KotlinCompilation.Result.workingDir: File get() =
outputDirectory.parentFile!!
val KotlinCompilation.Result.kspGeneratedSources: List<File> get() {
val kspWorkingDir = workingDir.resolve("ksp")
val kspGeneratedDir = kspWorkingDir.resolve("sources")
val kotlinGeneratedDir = kspGeneratedDir.resolve("kotlin")
val javaGeneratedDir = kspGeneratedDir.resolve("java")
return kotlinGeneratedDir.listFilesRecursively() +
javaGeneratedDir.listFilesRecursively()
}
This allows me to test for what I want without problems. Perhaps a similar strategy could be adopted for the KSP extensions? I could open a PR if you'd believe it to be applicable.
Here's how I'm testing this:
assertThat(result.exitCode)
.isEqualTo(KotlinCompilation.ExitCode.OK)
val generated = if (backend == "ksp") {
assertThat(result.kspGeneratedSources)
.isNotEmpty
result.kspGeneratedSources
} else {
assertThat(result.sourcesGeneratedByAnnotationProcessor)
.isNotEmpty
result.sourcesGeneratedByAnnotationProcessor
}
@gfreivasc Can you explain, where the listFilesRecursively
comes from?
I could not elaborate this, so I use walkTopDown
extension method method from kotlin.io
instead:
val KotlinCompilation.Result.kspGeneratedSources: List<File> get() {
val kspWorkingDir = workingDir.resolve("ksp")
val kspGeneratedDir = kspWorkingDir.resolve("sources")
val kotlinGeneratedDir = kspGeneratedDir.resolve("kotlin")
val javaGeneratedDir = kspGeneratedDir.resolve("java")
return kotlinGeneratedDir.walkTopDown().toList() +
javaGeneratedDir.walkTopDown()
}
@chausknecht I created this method, or got it from somewhere Idk it's been a while. I didn't include it in this excerpt for shortness sake but you can see it in this PR
@gfreivasc Thx for answering :-) After looking at the handcrafted method, I tend to prefer the walkTopDown
approach.