Proper support of aggregated processors

This commit is contained in:
Mikhael Bogdanov
2020-11-12 13:43:46 +01:00
committed by max-kammerer
parent f382a55b17
commit 6748560184
16 changed files with 525 additions and 28 deletions
@@ -42,7 +42,11 @@ object Kapt {
val processors = processorLoader.loadProcessors(findClassLoaderWithJavac())
val annotationProcessingTime = measureTimeMillis {
kaptContext.doAnnotationProcessing(javaSourceFiles, processors.processors)
kaptContext.doAnnotationProcessing(
javaSourceFiles,
processors.processors,
aggregatedTypes = collectAggregatedTypes(kaptContext.sourcesToReprocess)
)
}
logger.info { "Annotation processing took $annotationProcessingTime ms" }
@@ -111,7 +111,7 @@ open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logge
val compileClasspath = if (sourcesToReprocess is SourcesToReprocess.FullRebuild) {
options.compileClasspath
} else {
options.compileClasspath + options.compiledSources
options.compileClasspath + options.compiledSources + options.classesOutputDir
}
putJavacOption("CLASSPATH", "CLASS_PATH",
@@ -168,6 +168,15 @@ fun KaptOptions.collectJavaSourceFiles(sourcesToReprocess: SourcesToReprocess =
}
}
fun collectAggregatedTypes(sourcesToReprocess: SourcesToReprocess = SourcesToReprocess.FullRebuild): List<String> {
return when (sourcesToReprocess) {
is SourcesToReprocess.FullRebuild -> emptyList()
is SourcesToReprocess.Incremental -> {
sourcesToReprocess.unchangedAggregatedTypes
}
}
}
fun KaptOptions.logString(additionalInfo: String = "") = buildString {
val additionalInfoRendered = if (additionalInfo.isEmpty()) "" else " ($additionalInfo)"
appendLine("Kapt3 is enabled$additionalInfoRendered.")
@@ -31,7 +31,8 @@ import com.sun.tools.javac.util.List as JavacList
fun KaptContext.doAnnotationProcessing(
javaSourceFiles: List<File>,
processors: List<IncrementalProcessor>,
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil()
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil(),
aggregatedTypes: List<String> = emptyList()
) {
val processingEnvironment = JavacProcessingEnvironment.instance(context)
@@ -70,12 +71,14 @@ fun KaptContext.doAnnotationProcessing(
GeneratedTypesTaskListener(cacheManager!!.javaCache)
}?.also { compiler.getTaskListeners().add(it) }
val additionalClassNames = JavacList.from(aggregatedTypes)
if (isJava9OrLater()) {
val processAnnotationsMethod = compiler.javaClass.getMethod("processAnnotations", JavacList::class.java)
processAnnotationsMethod.invoke(compiler, analyzedFiles)
val processAnnotationsMethod =
compiler.javaClass.getMethod("processAnnotations", JavacList::class.java, java.util.Collection::class.java)
processAnnotationsMethod.invoke(compiler, analyzedFiles, additionalClassNames)
compiler
} else {
compiler.processAnnotations(analyzedFiles).also {
compiler.processAnnotations(analyzedFiles, additionalClassNames).also {
generatedSourcesListener?.let { compiler.getTaskListeners().remove(it) }
}
}
@@ -156,7 +159,7 @@ private class ProcessorWrapper(private val delegate: IncrementalProcessor) : Pro
private var initTime: Long = 0
private val roundTime = mutableListOf<Long>()
override fun process(annotations: MutableSet<out TypeElement>?, roundEnv: RoundEnvironment?): Boolean {
override fun process(annotations: MutableSet<out TypeElement>, roundEnv: RoundEnvironment): Boolean {
val (time, result) = measureTimeMillisWithResult {
delegate.process(annotations, roundEnv)
}
@@ -11,6 +11,7 @@ import java.io.Serializable
class IncrementalAptCache : Serializable {
private val aggregatingGenerated: MutableSet<File> = mutableSetOf()
private val aggregatedTypes: MutableSet<String> = linkedSetOf()
private val isolatingMapping: MutableMap<File, File> = mutableMapOf()
// Annotations claimed by aggregating annotation processors
private val aggregatingClaimedAnnotations: MutableSet<String> = mutableSetOf()
@@ -41,6 +42,9 @@ class IncrementalAptCache : Serializable {
aggregatingClaimedAnnotations.clear()
aggregatingClaimedAnnotations.addAll(aggregating.flatMap { it.supportedAnnotationTypes })
aggregatedTypes.clear()
aggregatedTypes.addAll(aggregating.flatMap { it.getAggregatedTypes() })
for (isolatingProcessor in isolating) {
isolatingProcessor.getGeneratedToSources().forEach {
isolatingMapping[it.key] = it.value!!
@@ -52,12 +56,15 @@ class IncrementalAptCache : Serializable {
fun getAggregatingClaimedAnnotations(): Set<String> = aggregatingClaimedAnnotations
/** Returns generated Java sources originating from aggregating APs. */
fun invalidateAggregating(): List<File> {
fun invalidateAggregating(): Pair<List<File>, List<String>> {
val dirtyAggregating = aggregatingGenerated.filter { it.extension == "java" }
aggregatingGenerated.forEach { it.delete() }
aggregatingGenerated.clear()
return dirtyAggregating
val dirtyAggregated = ArrayList(aggregatedTypes)
aggregatedTypes.clear()
return dirtyAggregating to dirtyAggregated
}
/** Returns generated Java sources originating from the specified sources, and generated by isloating APs. */
@@ -48,10 +48,11 @@ class JavaClassCacheManager(val file: File) : Closeable {
val isolatingGenerated = aptCache.invalidateIsolatingGenerated(toReprocess)
val generatedDirtyTypes = javaCache.invalidateGeneratedTypes(isolatingGenerated).toMutableSet()
val aggregatedTypes = mutableListOf<String>()
if (!toReprocess.isEmpty()) {
// only if there are some files to reprocess we should invalidate the aggregating ones
val aggregatingGenerated = aptCache.invalidateAggregating()
val (aggregatingGenerated, aggregatedTypes1) = aptCache.invalidateAggregating()
aggregatedTypes.addAll(aggregatedTypes1)
generatedDirtyTypes.addAll(javaCache.invalidateGeneratedTypes(aggregatingGenerated))
toReprocess.addAll(
@@ -59,7 +60,13 @@ class JavaClassCacheManager(val file: File) : Closeable {
)
}
SourcesToReprocess.Incremental(toReprocess.toList(), generatedDirtyTypes)
SourcesToReprocess.Incremental(
toReprocess.toList(),
generatedDirtyTypes,
aggregatedTypes.also {
it.removeAll(filesToReprocess.dirtyTypes)
it.removeAll(generatedDirtyTypes)
})
}
}
}
@@ -118,6 +125,11 @@ class JavaClassCacheManager(val file: File) : Closeable {
}
sealed class SourcesToReprocess {
class Incremental(val toReprocess: List<File>, val dirtyTypes: Set<String>) : SourcesToReprocess()
class Incremental(
val toReprocess: List<File>,
val dirtyTypes: Set<String>,
val unchangedAggregatedTypes: List<String>
) : SourcesToReprocess()
object FullRebuild : SourcesToReprocess()
}
@@ -139,7 +139,7 @@ class JavaClassCache() : Serializable {
currentDirtyFiles = nextRound.filter { !allDirtyFiles.contains(it) }.toMutableSet()
}
return SourcesToReprocess.Incremental(allDirtyFiles.map { File(it) }, allDirtyTypes)
return SourcesToReprocess.Incremental(allDirtyFiles.map { File(it) }, allDirtyTypes, emptyList())
}
/**
@@ -12,8 +12,10 @@ import java.net.URI
import javax.annotation.processing.Filer
import javax.annotation.processing.ProcessingEnvironment
import javax.annotation.processing.Processor
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.PackageElement
import javax.lang.model.element.TypeElement
import javax.tools.FileObject
import javax.tools.JavaFileManager
import javax.tools.JavaFileObject
@@ -69,7 +71,16 @@ class IncrementalProcessor(private val processor: Processor, private val kind: D
fun isUnableToRunIncrementally() = !kind.canRunIncrementally
fun getGeneratedToSources() = dependencyCollector.value.getGeneratedToSources()
fun getAggregatedTypes() = dependencyCollector.value.getAggregatedTypes()
fun getRuntimeType(): RuntimeProcType = dependencyCollector.value.getRuntimeType()
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
if (getRuntimeType() == RuntimeProcType.AGGREGATING) {
dependencyCollector.value.recordProcessingInputs(processor.supportedAnnotationTypes, annotations, roundEnv)
}
return processor.process(annotations, roundEnv)
}
}
internal class IncrementalProcessingEnvironment(private val processingEnv: ProcessingEnvironment, private val incFiler: IncrementalFiler) :
@@ -111,9 +122,29 @@ internal class AnnotationProcessorDependencyCollector(
private val warningCollector: (String) -> Unit
) {
private val generatedToSource = mutableMapOf<File, File?>()
private val aggregatedTypes = mutableSetOf<String>()
private var isFullRebuild = !runtimeProcType.isIncremental
internal fun add(createdFile: URI, originatingElements: Array<out Element?>) {
internal fun recordProcessingInputs(supportedAnnotationTypes: Set<String>, annotations: Set<TypeElement>, roundEnv: RoundEnvironment) {
if (isFullRebuild) return
if (supportedAnnotationTypes.contains("*")) {
aggregatedTypes.addAll(getTopLevelClassNames(roundEnv.rootElements?.filterNotNull() ?: emptyList()))
} else {
for (annotation in annotations) {
aggregatedTypes.addAll(
getTopLevelClassNames(
roundEnv.getElementsAnnotatedWith(
annotation
)?.filterNotNull() ?: emptyList()
)
)
}
}
}
internal fun add(createdFile: URI, originatingElements: Array<out Element?>, classId: String?) {
if (isFullRebuild) return
val generatedFile = File(createdFile)
@@ -134,6 +165,9 @@ internal class AnnotationProcessorDependencyCollector(
}
internal fun getGeneratedToSources(): Map<File, File?> = if (isFullRebuild) emptyMap() else generatedToSource
internal fun getAggregatedTypes(): Set<String> = if (isFullRebuild) emptySet() else aggregatedTypes
internal fun getRuntimeType(): RuntimeProcType {
return if (isFullRebuild) {
RuntimeProcType.NON_INCREMENTAL
@@ -154,6 +188,33 @@ private fun getSrcFiles(elements: Array<out Element?>): Set<File> {
}.toSet()
}
private const val PACKAGE_TYPE_NAME = "package-info"
fun getElementName(current: Element?): String? {
if (current is PackageElement) {
val packageName = current.qualifiedName.toString()
return if (packageName.isEmpty()) {
PACKAGE_TYPE_NAME
} else {
"$packageName.$PACKAGE_TYPE_NAME"
}
}
if (current is TypeElement) {
return current.qualifiedName.toString()
}
return null
}
private fun getTopLevelClassNames(elements: Collection<Element>): Collection<String> {
return elements.mapNotNull { elem ->
var origin = elem
while (origin.enclosingElement != null && origin.enclosingElement !is PackageElement) {
origin = origin.enclosingElement
}
getElementName(origin)
}
}
enum class DeclaredProcType(val canRunIncrementally: Boolean) {
AGGREGATING(true) {
override fun toRuntimeType() = RuntimeProcType.AGGREGATING