Incremental KAPT - invalidate obsolete types

Once set of dirty symbols is computed, filter these types
when they are requested from the JavaFileManager. This is accomplished
by tracking all declared types in the sources and generated sources.
It is not necessary track types in generated class files, as these will
be removed before the APs are incrementally run.

Motivation: APs (e.g. Dagger) may use Elements.getTypeElement(String)
to determine if type is already present, and if it is, they will not
generate it. Therefore, whenever generated sources is invalidated, types
it defines need to be filtered in the JavaFileManager.

Issue is https://youtrack.jetbrains.com/issue/KT-23880
This commit is contained in:
Ivan Gavrilovic
2019-03-15 17:50:10 +00:00
committed by Alexey Tsvetkov
parent 2f3d234516
commit b2ad82b7d2
14 changed files with 271 additions and 48 deletions
@@ -34,7 +34,7 @@ object Kapt {
logger.info { options.logString("stand-alone mode") }
val javaSourceFiles = options.collectJavaSourceFiles(kaptContext.cacheManager)
val javaSourceFiles = options.collectJavaSourceFiles(kaptContext.sourcesToReprocess)
val processorLoader = ProcessorLoader(options, logger)
@@ -14,6 +14,7 @@ import com.sun.tools.javac.util.Options
import org.jetbrains.kotlin.base.kapt3.KaptFlag
import org.jetbrains.kotlin.base.kapt3.KaptOptions
import org.jetbrains.kotlin.kapt3.base.incremental.JavaClassCacheManager
import org.jetbrains.kotlin.kapt3.base.incremental.SourcesToReprocess
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaCompiler
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaFileManager
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaLog
@@ -32,6 +33,8 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
val javaLog: KaptJavaLog
val cacheManager: JavaClassCacheManager?
val sourcesToReprocess: SourcesToReprocess
protected open fun preregisterTreeMaker(context: Context) {}
private fun preregisterLog(context: Context) {
@@ -53,6 +56,13 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
KaptJavaCompiler.preRegister(context)
cacheManager = options.incrementalCache?.let {
JavaClassCacheManager(it, options.classpathFqNamesHistory!!)
}
sourcesToReprocess = cacheManager?.invalidateAndGetDirtyFiles(
options.changedFiles.filter { it.extension == "java" }
) ?: SourcesToReprocess.FullRebuild
javacOptions = Options.instance(context).apply {
for ((key, value) in options.processingOptions) {
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
@@ -78,7 +88,7 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
put("accessInternalAPI", "true")
}
val compileClasspath = if (options.changedFiles.isEmpty()) {
val compileClasspath = if (sourcesToReprocess is SourcesToReprocess.FullRebuild || options.changedFiles.isEmpty()) {
options.compileClasspath
} else {
options.compileClasspath + options.compiledSources
@@ -101,6 +111,10 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
}
fileManager = context.get(JavaFileManager::class.java) as KaptJavaFileManager
if (sourcesToReprocess is SourcesToReprocess.Incremental) {
fileManager.typeToIgnore = sourcesToReprocess.dirtyTypes
fileManager.rootsToFilter = options.compiledSources.toSet()
}
if (isJava9OrLater()) {
for (option in Option.getJavacFileManagerOptions()) {
@@ -114,10 +128,6 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
ClassReader.instance(context).saveParameterNames = true
cacheManager = options.incrementalCache?.let {
JavaClassCacheManager(it, options.classpathFqNamesHistory!!)
}
javaLog = compiler.log as KaptJavaLog
}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.base.kapt3
import org.jetbrains.kotlin.kapt3.base.incremental.JavaClassCacheManager
import org.jetbrains.kotlin.kapt3.base.incremental.SourcesToReprocess
import java.io.File
import java.nio.file.Files
@@ -129,7 +128,7 @@ enum class AptMode(override val stringValue: String) : KaptSelector {
get() = this != APT_ONLY
}
fun KaptOptions.collectJavaSourceFiles(cacheManager: JavaClassCacheManager? = null): List<File> {
fun KaptOptions.collectJavaSourceFiles(sourcesToReprocess: SourcesToReprocess = SourcesToReprocess.FullRebuild): List<File> {
fun allSources(): List<File> {
return (javaSourceRoots + stubsOutputDir)
.sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
@@ -138,15 +137,9 @@ fun KaptOptions.collectJavaSourceFiles(cacheManager: JavaClassCacheManager? = nu
.distinctBy { it.canonicalPath }
}
return if (cacheManager != null && changedFiles.isNotEmpty()) {
val toReprocess = cacheManager.invalidateAndGetDirtyFiles(changedFiles.filter { it.extension == "java" })
when (toReprocess) {
is SourcesToReprocess.FullRebuild -> allSources()
is SourcesToReprocess.Incremental -> toReprocess.toReprocess.filter { it.exists() }
}
} else {
allSources()
return when (sourcesToReprocess) {
is SourcesToReprocess.FullRebuild -> allSources()
is SourcesToReprocess.Incremental -> sourcesToReprocess.toReprocess.filter { it.exists() }
}
}
@@ -12,8 +12,10 @@ import com.sun.tools.javac.processing.JavacFiler
import com.sun.tools.javac.processing.JavacProcessingEnvironment
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.base.kapt3.KaptFlag
import org.jetbrains.kotlin.base.kapt3.collectJavaSourceFiles
import org.jetbrains.kotlin.kapt3.base.incremental.*
import org.jetbrains.kotlin.kapt3.base.incremental.DeclaredProcType
import org.jetbrains.kotlin.kapt3.base.incremental.GeneratedTypesTaskListener
import org.jetbrains.kotlin.kapt3.base.incremental.IncrementalProcessor
import org.jetbrains.kotlin.kapt3.base.incremental.MentionedTypesTaskListener
import org.jetbrains.kotlin.kapt3.base.util.KaptBaseError
import org.jetbrains.kotlin.kapt3.base.util.isJava9OrLater
import org.jetbrains.kotlin.kapt3.base.util.measureTimeMillisWithResult
@@ -50,8 +52,8 @@ fun KaptContext.doAnnotationProcessing(
}
val parsedJavaFiles = parseJavaFiles(javaSourceFiles)
val listener = cacheManager?.let {
if (processors.any { it.kind == DeclaredProcType.NON_INCREMENTAL}) return@let null
val sourcesStructureListener = cacheManager?.let {
if (processors.any { it.kind == DeclaredProcType.NON_INCREMENTAL }) return@let null
val recordTypesListener = MentionedTypesTaskListener(cacheManager.javaCache, processingEnvironment.elementUtils)
compiler.getTaskListeners().add(recordTypesListener)
@@ -64,15 +66,19 @@ fun KaptContext.doAnnotationProcessing(
CompileState.PARSE, compiler.enterTrees(parsedJavaFiles + additionalSources)
)
listener?.let { compiler.getTaskListeners().remove(it) }
val generatedSourcesListener = sourcesStructureListener?.let {
compiler.getTaskListeners().remove(it)
GeneratedTypesTaskListener(cacheManager!!.javaCache)
}?.also { compiler.getTaskListeners().add(it) }
if (isJava9OrLater()) {
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
processAnnotationsMethod.invoke(compiler, analyzedFiles)
compiler
} else {
val processAnnotations = compiler.processAnnotations(analyzedFiles)
processAnnotations
compiler.processAnnotations(analyzedFiles).also {
generatedSourcesListener?.let { compiler.getTaskListeners().remove(it) }
}
}
} catch (e: AnnotationProcessingError) {
throw KaptBaseError(KaptBaseError.Kind.EXCEPTION, e.cause ?: e)
@@ -49,25 +49,34 @@ class IncrementalAptCache : Serializable {
return true
}
fun invalidateAggregatingAndGetAnnotations(): Set<String> {
fun getAggregatingClaimedAnnotations(): Set<String> = aggregatingClaimedAnnotations
/** Returns generated Java sources originating from aggregating APs. */
fun invalidateAggregating(): List<File> {
val dirtyAggregating = aggregatingGenerated.filter { it.extension == "java" }
aggregatingGenerated.forEach { it.delete() }
aggregatingGenerated.clear()
return aggregatingClaimedAnnotations
return dirtyAggregating
}
fun invalidateIsolatingGenerated(fromSources: Set<File>) {
/** Returns generated Java sources originating from the specified sources, and generated by isloating APs. */
fun invalidateIsolatingGenerated(fromSources: Set<File>): List<File> {
val allInvalidated = mutableListOf<File>()
var changedSources = fromSources.toSet()
// We need to do it in a loop because mapping could be: [AGenerated.java -> A.java, AGeneratedGenerated.java -> AGenerated.java]
while(changedSources.isNotEmpty()) {
while (changedSources.isNotEmpty()) {
val generated = isolatingMapping.filter { changedSources.contains(it.value) }.keys
generated.forEach {
if (it.extension == "java") allInvalidated.add(it)
it.delete()
isolatingMapping.remove(it)
}
changedSources = generated
}
return allInvalidated
}
private fun invalidateCache() {
@@ -8,15 +8,15 @@ package org.jetbrains.kotlin.kapt3.base.incremental
import java.io.*
// TODO(gavra): switch away from Java serialization
class JavaClassCacheManager(private val file: File, private val classpathFqNamesHistory: File) : Closeable {
class JavaClassCacheManager(val file: File, private val classpathFqNamesHistory: File) : Closeable {
internal val javaCacheFile = file.resolve("java-cache.bin")
private val javaCacheFile = file.resolve("java-cache.bin")
internal val javaCache = maybeGetJavaCacheFromFile()
internal val aptCacheFile = file.resolve("apt-cache.bin")
internal val aptCache = maybeGetAptCacheFromFile()
private val aptCacheFile = file.resolve("apt-cache.bin")
private val aptCache = maybeGetAptCacheFromFile()
internal val lastBuildTimestamp = file.resolve("last-build-ts.bin")
private val lastBuildTimestamp = file.resolve("last-build-ts.bin")
private var closed = false
@@ -75,15 +75,20 @@ class JavaClassCacheManager(private val file: File, private val classpathFqNames
is SourcesToReprocess.Incremental -> {
val toReprocess = filesToReprocess.toReprocess.toMutableSet()
aptCache.invalidateIsolatingGenerated(toReprocess)
val isolatingGenerated = aptCache.invalidateIsolatingGenerated(toReprocess)
val generatedDirtyTypes = javaCache.invalidateGeneratedTypes(isolatingGenerated).toMutableSet()
if (!toReprocess.isEmpty()) {
// only if there are some files to reprocess we should invalidate the aggregating ones
val aggregatingGenerated = aptCache.invalidateAggregating()
generatedDirtyTypes.addAll(javaCache.invalidateGeneratedTypes(aggregatingGenerated))
toReprocess.addAll(
javaCache.invalidateEntriesAnnotatedWith(aptCache.invalidateAggregatingAndGetAnnotations())
javaCache.invalidateEntriesAnnotatedWith(aptCache.getAggregatingClaimedAnnotations())
)
}
SourcesToReprocess.Incremental(toReprocess.toList())
SourcesToReprocess.Incremental(toReprocess.toList(), generatedDirtyTypes)
}
}
}
@@ -147,7 +152,7 @@ class JavaClassCacheManager(private val file: File, private val classpathFqNames
}
sealed class SourcesToReprocess {
class Incremental(val toReprocess: List<File>): SourcesToReprocess()
class Incremental(val toReprocess: List<File>, val dirtyTypes: Set<String>) : SourcesToReprocess()
object FullRebuild : SourcesToReprocess()
}
@@ -7,12 +7,17 @@ package org.jetbrains.kotlin.kapt3.base.incremental
import com.sun.tools.javac.processing.JavacProcessingEnvironment
import java.io.File
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable
import java.net.URI
class JavaClassCache() : Serializable {
private var sourceCache = mutableMapOf<URI, SourceFileStructure>()
/** Record these separately because we only need to know where each generated type is coming from. */
private var generatedTypes = mutableMapOf<File, MutableList<String>>()
/** Map from types to files they are mentioned in. */
@Transient
private var dependencyCache = mutableMapOf<String, MutableSet<URI>>()
@@ -23,9 +28,21 @@ class JavaClassCache() : Serializable {
sourceCache[sourceStructure.sourceFile] = sourceStructure
}
private fun readObject(input: java.io.ObjectInputStream) {
fun addGeneratedType(type: String, generatedFile: File) {
val typesInFile = generatedTypes[generatedFile] ?: ArrayList(1)
typesInFile.add(type)
generatedTypes[generatedFile] = typesInFile
}
fun invalidateGeneratedTypes(files: List<File>): Set<String> {
return files.mapNotNull { generatedTypes.remove(it) }.flatten().toSet()
}
private fun readObject(input: ObjectInputStream) {
@Suppress("UNCHECKED_CAST")
sourceCache = input.readObject() as MutableMap<URI, SourceFileStructure>
@Suppress("UNCHECKED_CAST")
generatedTypes = input.readObject() as MutableMap<File, MutableList<String>>
dependencyCache = HashMap(sourceCache.size * 4)
for (sourceInfo in sourceCache.values) {
@@ -45,6 +62,11 @@ class JavaClassCache() : Serializable {
}
}
private fun writeObject(output: ObjectOutputStream) {
output.writeObject(sourceCache)
output.writeObject(generatedTypes)
}
fun isAlreadyProcessed(sourceFile: URI) = sourceCache.containsKey(sourceFile)
/** Used for testing only. */
@@ -57,6 +79,7 @@ class JavaClassCache() : Serializable {
fun invalidateEntriesForChangedFiles(changes: Changes): SourcesToReprocess {
val allDirtyFiles = mutableSetOf<URI>()
var currentDirtyFiles = changes.sourceChanges.map { it.toURI() }
val allDirtyTypes = mutableSetOf<String>()
// check for constants first because they cause full rebuilt
for (sourceChange in currentDirtyFiles) {
@@ -76,6 +99,7 @@ class JavaClassCache() : Serializable {
val structure = sourceCache.remove(dirtyFile) ?: continue
val dirtyTypes = structure.getDeclaredTypes()
allDirtyTypes.addAll(dirtyTypes)
dirtyTypes.forEach { type ->
nonTransitiveCache[type]?.let {
@@ -91,7 +115,7 @@ class JavaClassCache() : Serializable {
currentDirtyFiles = nextRound.filter { !allDirtyFiles.contains(it) }
}
return SourcesToReprocess.Incremental(allDirtyFiles.map { File(it) })
return SourcesToReprocess.Incremental(allDirtyFiles.map { File(it) }, allDirtyTypes)
}
/**
@@ -119,6 +143,7 @@ class JavaClassCache() : Serializable {
internal fun invalidateAll() {
sourceCache.clear()
generatedTypes.clear()
}
}
@@ -125,12 +125,13 @@ internal class AnnotationProcessorDependencyCollector(private val runtimeProcTyp
}
private fun getSrcFiles(elements: Array<out Element?>): List<File> {
return elements.filterNotNull().mapNotNull {
var origin = it
return elements.filterNotNull().mapNotNull { elem ->
var origin = elem
while (origin.enclosingElement != null && origin.enclosingElement !is PackageElement) {
origin = origin.enclosingElement
}
(origin as? Symbol.ClassSymbol)?.sourcefile?.let { src -> File(src.toUri()) }
val uri = (origin as? Symbol.ClassSymbol)?.sourcefile?.toUri()?.takeIf { it.isAbsolute }
uri?.let { File(it) }
}
}
@@ -192,4 +192,28 @@ private class TypeTreeVisitor(val elementUtils: Elements, val sourceStructure: S
}
return true
}
}
class GeneratedTypesTaskListener(private val cache: JavaClassCache) : TaskListener {
override fun started(e: TaskEvent) {
// do nothing, we just process on finish
}
override fun finished(e: TaskEvent) {
if (e.kind != TaskEvent.Kind.ENTER || cache.isAlreadyProcessed(e.sourceFile.toUri())) return
val treeVisitor = object : SimpleTreeVisitor<Void, Void>() {
override fun visitClass(node: ClassTree, p: Void?): Void? {
node as JCTree.JCClassDecl
cache.addGeneratedType(node.sym.fullname.toString(), File(e.sourceFile.toUri()))
node.members.forEach { visit(it, null) }
return null
}
}
e.compilationUnit.typeDecls.forEach {
it.accept(treeVisitor, null)
}
}
}
@@ -5,10 +5,15 @@
package org.jetbrains.kotlin.kapt3.base.javac
import com.sun.tools.javac.file.BaseFileObject
import com.sun.tools.javac.file.JavacFileManager
import com.sun.tools.javac.main.Option
import com.sun.tools.javac.util.Context
import java.io.File
import java.util.*
import javax.tools.JavaFileManager
import javax.tools.JavaFileObject
import javax.tools.StandardLocation
class KaptJavaFileManager(context: Context) : JavacFileManager(context, true, null) {
fun handleOptionJavac9(option: Option, value: String) {
@@ -18,6 +23,57 @@ class KaptJavaFileManager(context: Context) : JavacFileManager(context, true, nu
handleOptionMethod.invoke(this, option, value)
}
var rootsToFilter = emptySet<File>()
// TODO (gavra): store these more efficiently by package (requires some changes to type collection).
var typeToIgnore = emptySet<String>()
override fun list(
location: JavaFileManager.Location?,
packageName: String?,
kinds: MutableSet<JavaFileObject.Kind>?,
recurse: Boolean
): MutableIterable<JavaFileObject> {
val originalList = super.list(location, packageName, kinds, recurse)
if (location == null
|| location != StandardLocation.CLASS_PATH
|| rootsToFilter.isEmpty()
|| typeToIgnore.isEmpty()
|| !filterThisPath(packageName)
) {
return originalList
}
val filteredList = LinkedList<JavaFileObject>()
for (file in originalList)
if (!shouldBeFiltered(packageName, file)) {
filteredList.add(file)
}
return filteredList
}
private fun filterThisPath(packageName: String?): Boolean {
packageName ?: return false
val relativePath = packageName.replace('.', File.separatorChar)
return rootsToFilter.any { it.resolve(relativePath).isDirectory }
}
private fun shouldBeFiltered(packageName: String?, fileObject: JavaFileObject): Boolean {
if (fileObject.kind != JavaFileObject.Kind.CLASS) return false
return when (fileObject.toUri().scheme) {
"jar", "zip" -> false
else -> {
if (fileObject !is BaseFileObject) return false
val typeName = packageName?.let { "$it." } + fileObject.shortName.dropLast(".class".length)
return typeToIgnore.contains(typeName)
}
}
}
companion object {
internal fun preRegister(context: Context) {
context.put(JavaFileManager::class.java, Context.Factory<JavaFileManager> { KaptJavaFileManager(it) })
@@ -50,8 +50,9 @@ class IncrementalKaptTest {
val logger = WriterBackedKaptLogger(isVerbose = true)
KaptContext(options, true, logger).use {
val toReprocess = it.cacheManager!!.invalidateAndGetDirtyFiles(options.changedFiles)
it.doAnnotationProcessing(
options.collectJavaSourceFiles(it.cacheManager), listOf(SimpleProcessor().toIsolating())
options.collectJavaSourceFiles(toReprocess), listOf(SimpleProcessor().toIsolating())
)
}
@@ -77,11 +78,12 @@ class IncrementalKaptTest {
}.build()
KaptContext(optionsForSecondRun, true, logger).use {
val sourcesToReprocess = optionsForSecondRun.collectJavaSourceFiles(it.cacheManager)
val sourcesToReprocess =
it.cacheManager!!.invalidateAndGetDirtyFiles(optionsForSecondRun.changedFiles)
assertFalse(outputDir.resolve("test/UserGenerated.java").exists())
it.doAnnotationProcessing(
sourcesToReprocess, listOf(SimpleProcessor().toIsolating())
optionsForSecondRun.collectJavaSourceFiles(sourcesToReprocess), listOf(SimpleProcessor().toIsolating())
)
}
@@ -90,12 +92,80 @@ class IncrementalKaptTest {
sourcesDir.resolve("User.java").delete()
KaptContext(optionsForSecondRun, true, logger).use {
val sourcesToReprocess = it.cacheManager!!.invalidateAndGetDirtyFiles(optionsForSecondRun.changedFiles)
it.doAnnotationProcessing(
optionsForSecondRun.collectJavaSourceFiles(it.cacheManager), listOf(SimpleProcessor().toIsolating())
optionsForSecondRun.collectJavaSourceFiles(sourcesToReprocess), listOf(SimpleProcessor().toIsolating())
)
}
assertEquals(addressTimestamp, outputDir.resolve("test/AddressGenerated.java").lastModified())
assertFalse(outputDir.resolve("test/UserGenerated.java").exists())
}
@Test
fun testGeneratedCompiledAreIgnored() {
val sourcesDir = tmp.newFolder().resolve("test").also { base ->
base.mkdir()
listOf("User.java", "Address.java", "Observable.java").map {
TEST_DATA_DIR.resolve(it).copyTo(base.resolve(it))
}
}
val outputDir = tmp.newFolder()
val incrementalCacheDir = tmp.newFolder()
val classpathHistory = tmp.newFolder().also {
it.resolve("0").createNewFile()
}
val options = KaptOptions.Builder().apply {
projectBaseDir = tmp.newFolder()
javaSourceRoots.add(sourcesDir)
sourcesOutputDir = outputDir
classesOutputDir = outputDir
stubsOutputDir = outputDir
incrementalDataOutputDir = outputDir
incrementalCache = incrementalCacheDir
classpathFqNamesHistory = classpathHistory
}.build()
val logger = WriterBackedKaptLogger(isVerbose = true)
KaptContext(options, true, logger).use {
val toReprocess = it.cacheManager!!.invalidateAndGetDirtyFiles(options.changedFiles)
it.doAnnotationProcessing(
options.collectJavaSourceFiles(toReprocess), listOf(SimpleGeneratingIfTypeDoesNotExist().toIsolating())
)
}
val classesOutput = tmp.newFolder()
compileSources(sourcesDir.listFiles().asIterable(), classesOutput)
compileSources(listOf(outputDir.resolve("test/UserGenerated.java")), classesOutput)
val optionsForSecondRun = KaptOptions.Builder().apply {
projectBaseDir = tmp.newFolder()
sourcesOutputDir = outputDir
classesOutputDir = outputDir
stubsOutputDir = outputDir
incrementalDataOutputDir = outputDir
incrementalCache = incrementalCacheDir
classpathFqNamesHistory = classpathHistory
compiledSources.add(classesOutput)
changedFiles.add(sourcesDir.resolve("User.java"))
}.build()
KaptContext(optionsForSecondRun, true, logger).use {
val sourcesToReprocess =
it.cacheManager!!.invalidateAndGetDirtyFiles(optionsForSecondRun.changedFiles)
assertFalse(outputDir.resolve("test/UserGenerated.java").exists())
it.doAnnotationProcessing(
optionsForSecondRun.collectJavaSourceFiles(sourcesToReprocess), listOf(SimpleGeneratingIfTypeDoesNotExist().toIsolating())
)
}
assertTrue(outputDir.resolve("test/UserGenerated.java").exists())
}
}
@@ -119,6 +119,30 @@ class SimpleCreatingClassFilesAndResources : SimpleProcessor() {
filer.createResource(StandardLocation.SOURCE_OUTPUT, "test", "${it.simpleName}GeneratedResource", it).openWriter().use { it.write("") }
}
return false
}
}
class SimpleGeneratingIfTypeDoesNotExist: SimpleProcessor() {
override fun process(annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment): Boolean {
if (annotations.isEmpty()) return false
roundEnv.getElementsAnnotatedWith(annotations.single()).forEach { element ->
element as TypeElement
val generatedName = "${element.qualifiedName}Generated"
if (processingEnv.elementUtils.getTypeElement(generatedName) == null) {
filer.createSourceFile(generatedName, element).openWriter().use {
it.write(
"""
package test;
public class ${element.simpleName}Generated {}
""".trimIndent()
)
}
}
}
return false
}
}
@@ -216,7 +216,7 @@ abstract class AbstractKapt3Extension(
private fun runAnnotationProcessing(kaptContext: KaptContext, processors: LoadedProcessors) {
if (!options.mode.runAnnotationProcessing) return
val javaSourceFiles = options.collectJavaSourceFiles(kaptContext.cacheManager)
val javaSourceFiles = options.collectJavaSourceFiles(kaptContext.sourcesToReprocess)
logger.info { "Java source files: " + javaSourceFiles.joinToString { it.canonicalPath } }
val (annotationProcessingTime) = measureTimeMillis {