Incremental KAPT: simplify impacted types computation

Process aggregating types first, and when computing impacted types
compute isolating generated impacted by classpath changes first.
This commit is contained in:
Ivan Gavrilovic
2020-11-27 11:21:10 +00:00
committed by Mikhael Bogdanov
parent c7e5beece5
commit 05e47da458
3 changed files with 31 additions and 53 deletions
@@ -115,8 +115,8 @@ class IncrementalAptCache : Serializable {
} }
/** Gets the originating type for the specified type generated by isolating AP. */ /** Gets the originating type for the specified type generated by isolating AP. */
fun getOriginForGeneratedIsolatingType(generatedType: String, sourceFileProvider: (String) -> File?): String { fun getOriginForGeneratedIsolatingType(generatedType: String, sourceFileProvider: (String) -> File): String {
val generatedFile = checkNotNull(sourceFileProvider(generatedType)) { "Unable to find source for $generatedType" } val generatedFile = sourceFileProvider(generatedType)
return isolatingMapping.getValue(generatedFile) return isolatingMapping.getValue(generatedFile)
} }
@@ -55,49 +55,40 @@ class JavaClassCacheManager(val file: File) : Closeable {
val sourcesToReprocess = changedSources.toMutableSet() val sourcesToReprocess = changedSources.toMutableSet()
val classNamesToReprocess = mutableListOf<String>() val classNamesToReprocess = mutableListOf<String>()
var shouldProcessAggregating = false
for (impactedType in impactedTypes) { if (changedSources.isNotEmpty() || impactedTypes.isNotEmpty()) {
if (impactedType !in isolatingGeneratedTypes && impactedType !in aggregatingGeneratedTypes) {
// Reprocess only if original source
javaCache.getSourceForType(impactedType)?.let {
sourcesToReprocess.add(it)
}
} else if (impactedType in isolatingGeneratedTypes) {
// this is a generated type by isolating AP
val isolatingOrigin = aptCache.getOriginForGeneratedIsolatingType(impactedType, javaCache::getSourceForType)
if (isolatingOrigin in impactedTypes) {
// we'll process origin, no need to do it now
continue
}
val originSource = javaCache.getSourceForType(isolatingOrigin)
if (originSource?.extension == "java") {
sourcesToReprocess.add(originSource)
} else if (originSource?.extension == "class") {
// This is a generated .class file that we need to reprocess.
classNamesToReprocess.add(isolatingOrigin)
} else {
// This is a type from classpath that was used as origin, just ignore it. It is used just to remove the generated file.
}
} else {
// processed separately
shouldProcessAggregating = true
}
}
if (shouldProcessAggregating || sourcesToReprocess.isNotEmpty() || classNamesToReprocess.isNotEmpty()) {
for (aggregatingOrigin in aptCache.getAggregatingOrigins()) { for (aggregatingOrigin in aptCache.getAggregatingOrigins()) {
if (aggregatingOrigin in impactedTypes) continue if (aggregatingOrigin in impactedTypes) continue
val originSource = javaCache.getSourceForType(aggregatingOrigin) val originSource = javaCache.getSourceForType(aggregatingOrigin)
if (originSource?.extension == "java") { if (originSource.extension == "java") {
sourcesToReprocess.add(originSource) sourcesToReprocess.add(originSource)
} else if (originSource?.extension == "class") { } else if (originSource.extension == "class") {
// This is a generated .class file that we need to reprocess. // This is a generated .class file that we need to reprocess.
classNamesToReprocess.add(aggregatingOrigin) classNamesToReprocess.add(aggregatingOrigin)
} }
} }
}
for (impactedType in impactedTypes) {
if (impactedType !in isolatingGeneratedTypes && impactedType !in aggregatingGeneratedTypes) {
sourcesToReprocess.add(javaCache.getSourceForType(impactedType))
} else if (impactedType in isolatingGeneratedTypes) {
// this is a generated type by isolating AP
val isolatingOrigin = aptCache.getOriginForGeneratedIsolatingType(impactedType, javaCache::getSourceForType)
if (isolatingOrigin in impactedTypes || isolatingOrigin in dirtyClasspathFqNames) {
continue
}
val originSource = javaCache.getSourceForType(isolatingOrigin)
if (originSource.extension == "java") {
sourcesToReprocess.add(originSource)
} else if (originSource.extension == "class") {
classNamesToReprocess.add(isolatingOrigin)
}
}
}
if (sourcesToReprocess.isNotEmpty() || classNamesToReprocess.isNotEmpty()) {
// Invalidate state only if there are some files that will be reprocessed // Invalidate state only if there are some files that will be reprocessed
javaCache.invalidateDataForTypes(impactedTypes) javaCache.invalidateDataForTypes(impactedTypes)
aptCache.invalidateAggregating() aptCache.invalidateAggregating()
@@ -111,27 +102,13 @@ class JavaClassCacheManager(val file: File) : Closeable {
private fun getAllImpactedTypes(changes: Changes, aggregatingGeneratedTypes: Set<String>): MutableSet<String> { private fun getAllImpactedTypes(changes: Changes, aggregatingGeneratedTypes: Set<String>): MutableSet<String> {
val impactedTypes = javaCache.getAllImpactedTypes(changes) val impactedTypes = javaCache.getAllImpactedTypes(changes)
// check isolating with origins from the classpath
/** impactedTypes.addAll(aptCache.getIsolatingGeneratedTypesForOrigins(changes.dirtyFqNamesFromClasspath, javaCache::getTypesForFiles))
* In order to find all impacted types we do the following:
* - impacted types is a set of types that have changed from the previous compilation
* - if there is a changed source or a source file that is impacted by type changes, we'll need to run aggregating APs, so we
* invalidate all aggregating generated types, and add them to set of impacted types.
* - using this new impacted types set, we find all types generated by isolating APs with origins in those types
* - if there are some generated types by isolating APs, we'll need to run aggregating APs, so we invalidate all aggregating types
* and add them to impacted types.
* - using the final value of impacted types we get all generated types by isolating APs and add them to impacted types
*/
if (changes.sourceChanges.isNotEmpty() || impactedTypes.isNotEmpty()) { if (changes.sourceChanges.isNotEmpty() || impactedTypes.isNotEmpty()) {
// Any source change or any source impacted by type change invalidates aggregating APs generated types // Any source change or any source impacted by type change invalidates aggregating APs generated types
impactedTypes.addAll(aggregatingGeneratedTypes) impactedTypes.addAll(aggregatingGeneratedTypes)
} }
aptCache.getIsolatingGeneratedTypesForOrigins(changes.dirtyFqNamesFromClasspath, javaCache::getTypesForFiles).let { // now check isolating with origins in any of the impacted types
if (it.isNotEmpty()) {
impactedTypes.addAll(it)
impactedTypes.addAll(aggregatingGeneratedTypes)
}
}
aptCache.getIsolatingGeneratedTypesForOrigins(impactedTypes, javaCache::getTypesForFiles).let { aptCache.getIsolatingGeneratedTypesForOrigins(impactedTypes, javaCache::getTypesForFiles).let {
impactedTypes.addAll(it) impactedTypes.addAll(it)
} }
@@ -10,6 +10,7 @@ import java.io.ObjectInputStream
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
import java.io.Serializable import java.io.Serializable
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
import java.lang.IllegalStateException
import java.net.URI import java.net.URI
/** /**
@@ -147,13 +148,13 @@ class JavaClassCache() : Serializable {
sourceCache.clear() sourceCache.clear()
} }
fun getSourceForType(type: String): File? { fun getSourceForType(type: String): File {
sourceCache.forEach { (fileUri, typeInfo) -> sourceCache.forEach { (fileUri, typeInfo) ->
if (type in typeInfo.getDeclaredTypes()) { if (type in typeInfo.getDeclaredTypes()) {
return File(fileUri) return File(fileUri)
} }
} }
return null throw IllegalStateException("Unable to find source file for type $type")
} }
fun invalidateDataForTypes(impactedTypes: MutableSet<String>) { fun invalidateDataForTypes(impactedTypes: MutableSet<String>) {