Process changed signatures of classes

This commit is contained in:
Alexey Tsvetkov
2015-12-17 21:58:20 +03:00
parent ab13b2ddfc
commit dfc08b8f38
2 changed files with 73 additions and 21 deletions
@@ -24,8 +24,6 @@ import gnu.trove.THashSet
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.builders.BuildTarget
import org.jetbrains.jps.builders.DirtyFilesHolder
import org.jetbrains.jps.builders.impl.BuildTargetRegistryImpl
import org.jetbrains.jps.builders.impl.TargetOutputIndexImpl
import org.jetbrains.jps.builders.java.JavaBuilderUtil
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor
import org.jetbrains.jps.incremental.*
@@ -59,6 +57,7 @@ import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledException
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import org.jetbrains.kotlin.utils.LibraryUtils
@@ -687,12 +686,12 @@ private fun processChanges(
compiledFiles: Set<File>,
allCompiledFiles: MutableSet<File>,
dataManager: BuildDataManager,
caches: List<IncrementalCacheImpl>,
caches: Collection<IncrementalCacheImpl>,
compilationResult: CompilationResult,
fsOperations: FSOperationsHelper
) {
if (IncrementalCompilation.isExperimental()) {
compilationResult.doProcessChangesUsingLookups(compiledFiles, dataManager, fsOperations)
doProcessChangesUsingLookups(compilationResult.changes.asIterable(), compiledFiles, dataManager, fsOperations, caches)
}
else {
compilationResult.doProcessChanges(compiledFiles, allCompiledFiles, caches, fsOperations)
@@ -728,33 +727,72 @@ private fun CompilationResult.doProcessChanges(
}
}
private fun CompilationResult.doProcessChangesUsingLookups(
private fun doProcessChangesUsingLookups(
changes: Iterable<ChangeInfo>,
compiledFiles: Set<File>,
dataManager: BuildDataManager,
fsOperations: FSOperationsHelper
fsOperations: FSOperationsHelper,
caches: Collection<IncrementalCacheImpl>
) {
val dirtyLookupSymbols = HashSet<LookupSymbol>()
val lookupStorage = dataManager.getStorage(KotlinDataContainerTarget, LookupStorageProvider)
KotlinBuilder.LOG.debug("Start processing changes")
// TODO group by fqName?
for (change in changes) {
KotlinBuilder.LOG.debug("Process $change")
if (change !is ChangeInfo.MembersChanged) continue
val files = change.names.asSequence()
.flatMap { lookupStorage.get(LookupSymbol(it, change.fqName.asString())).asSequence() }
.map(::File)
fsOperations.markFiles(files.asIterable(), excludeFiles = compiledFiles)
val changedSignatureFqNames = changes.filterIsInstance<ChangeInfo.SignatureChanged>().map { it.fqName }
for (classFqName in getSubtypesOf(changedSignatureFqNames, caches)) {
val scope = classFqName.parent().asString()
val name = classFqName.shortName().identifier
dirtyLookupSymbols.add(LookupSymbol(name, scope))
}
for (change in changes.filterIsInstance<ChangeInfo.MembersChanged>()) {
val scopes = getSubtypesOf(listOf(change.fqName), caches).map { it.asString() }
for (name in change.names) {
for (scope in scopes) {
dirtyLookupSymbols.add(LookupSymbol(name, scope))
}
}
}
val dirtyFiles = HashSet<File>()
for (lookup in dirtyLookupSymbols) {
val affectedFiles = lookupStorage.get(lookup).map(::File)
KotlinBuilder.LOG.debug { "${lookup.scope}#${lookup.name} caused recompilation of: $affectedFiles" }
dirtyFiles.addAll(affectedFiles)
}
fsOperations.markFiles(dirtyFiles.asIterable(), excludeFiles = compiledFiles)
KotlinBuilder.LOG.debug("End of processing changes")
}
private val Iterable<BuildTarget<*>>.moduleTargets: Iterable<ModuleBuildTarget>
get() = filterIsInstance(ModuleBuildTarget::class.java)
/**
* Gets subtypes of given types inclusively
*/
private fun getSubtypesOf(
typeFqNames: Iterable<FqName>,
caches: Collection<IncrementalCacheImpl>
): Set<FqName> {
val types = typeFqNames.toCollection(LinkedList())
val subtypes = hashSetOf<FqName>()
while (types.isNotEmpty()) {
val unprocessedType = types.pollFirst()
caches.asSequence()
.flatMap { it.getSubtypesOf(unprocessedType) }
.filter { it !in subtypes }
.forEach { types.addLast(it) }
subtypes.add(unprocessedType)
}
return subtypes
}
private fun getLookupTracker(project: JpsProject): LookupTracker {
var lookupTracker = LookupTracker.DO_NOTHING
@@ -855,3 +893,9 @@ class GeneratedJvmClass (
"Couldn't load KotlinClass from $outputFile; it may happen because class doesn't have valid Kotlin annotations"
}
}
private inline fun Logger.debug(message: ()->String) {
if (isDebugEnabled) {
debug(message())
}
}
@@ -105,8 +105,8 @@ class IncrementalCacheImpl(
private val dependents = arrayListOf<IncrementalCacheImpl>()
private val outputDir = requireNotNull(target.outputDir) { "Target is expected to have output directory: $target" }
private val dependentsWithThis: Iterable<IncrementalCacheImpl>
get() = dependents + this
private val dependentsWithThis: Sequence<IncrementalCacheImpl>
get() = sequenceOf(this).plus(dependents.asSequence())
override fun registerInline(fromPath: String, jvmSignature: String, toPath: String) {
inlinedTo.add(fromPath, jvmSignature, toPath)
@@ -142,6 +142,9 @@ class IncrementalCacheImpl(
return result.map { File(it) }
}
fun getSubtypesOf(className: FqName): Sequence<FqName> =
dependentsWithThis.flatMap { it.subtypesMap[className].asSequence() }
fun cleanDirtyInlineFunctions() {
dirtyInlineFunctionsMap.clean()
}
@@ -600,9 +603,14 @@ class IncrementalCacheImpl(
val supertypes = classData.classProto.supertypes(TypeTable(classData.classProto.typeTable))
val parents = supertypes.map { classData.nameResolver.getClassId(it.className).asSingleFqName() }
.filter { it.asString() != "kotlin.Any" }
.toSet()
val child = kotlinClass.classId.asSingleFqName()
parents.forEach { subtypesMap.add(it, child) }
val removedSupertypes = supertypesMap[child].filter { it !in parents }
removedSupertypes.forEach { subtypesMap.removeValues(it, setOf(child)) }
supertypesMap[child] = parents
}