Proper support of aggregated processors
This commit is contained in:
committed by
max-kammerer
parent
f382a55b17
commit
6748560184
@@ -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.")
|
||||
|
||||
+8
-5
@@ -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)
|
||||
}
|
||||
|
||||
+9
-2
@@ -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()
|
||||
}
|
||||
+1
-1
@@ -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())
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+62
-1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user