Process changed signatures of classes

Original commit: dfc08b8f38
This commit is contained in:
Alexey Tsvetkov
2015-12-17 21:58:20 +03:00
parent aaf2c5573d
commit 04e2c6c342
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.ModuleChunk
import org.jetbrains.jps.builders.BuildTarget import org.jetbrains.jps.builders.BuildTarget
import org.jetbrains.jps.builders.DirtyFilesHolder 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.JavaBuilderUtil
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor
import org.jetbrains.jps.incremental.* 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.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledException import org.jetbrains.kotlin.progress.CompilationCanceledException
import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.progress.CompilationCanceledStatus
import org.jetbrains.kotlin.utils.LibraryUtils import org.jetbrains.kotlin.utils.LibraryUtils
@@ -687,12 +686,12 @@ private fun processChanges(
compiledFiles: Set<File>, compiledFiles: Set<File>,
allCompiledFiles: MutableSet<File>, allCompiledFiles: MutableSet<File>,
dataManager: BuildDataManager, dataManager: BuildDataManager,
caches: List<IncrementalCacheImpl>, caches: Collection<IncrementalCacheImpl>,
compilationResult: CompilationResult, compilationResult: CompilationResult,
fsOperations: FSOperationsHelper fsOperations: FSOperationsHelper
) { ) {
if (IncrementalCompilation.isExperimental()) { if (IncrementalCompilation.isExperimental()) {
compilationResult.doProcessChangesUsingLookups(compiledFiles, dataManager, fsOperations) doProcessChangesUsingLookups(compilationResult.changes.asIterable(), compiledFiles, dataManager, fsOperations, caches)
} }
else { else {
compilationResult.doProcessChanges(compiledFiles, allCompiledFiles, caches, fsOperations) 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>, compiledFiles: Set<File>,
dataManager: BuildDataManager, dataManager: BuildDataManager,
fsOperations: FSOperationsHelper fsOperations: FSOperationsHelper,
caches: Collection<IncrementalCacheImpl>
) { ) {
val dirtyLookupSymbols = HashSet<LookupSymbol>()
val lookupStorage = dataManager.getStorage(KotlinDataContainerTarget, LookupStorageProvider) val lookupStorage = dataManager.getStorage(KotlinDataContainerTarget, LookupStorageProvider)
KotlinBuilder.LOG.debug("Start processing changes") KotlinBuilder.LOG.debug("Start processing changes")
// TODO group by fqName? val changedSignatureFqNames = changes.filterIsInstance<ChangeInfo.SignatureChanged>().map { it.fqName }
for (change in changes) { for (classFqName in getSubtypesOf(changedSignatureFqNames, caches)) {
KotlinBuilder.LOG.debug("Process $change") val scope = classFqName.parent().asString()
val name = classFqName.shortName().identifier
if (change !is ChangeInfo.MembersChanged) continue dirtyLookupSymbols.add(LookupSymbol(name, scope))
val files = change.names.asSequence()
.flatMap { lookupStorage.get(LookupSymbol(it, change.fqName.asString())).asSequence() }
.map(::File)
fsOperations.markFiles(files.asIterable(), excludeFiles = compiledFiles)
} }
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") 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 { private fun getLookupTracker(project: JpsProject): LookupTracker {
var lookupTracker = LookupTracker.DO_NOTHING 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" "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 dependents = arrayListOf<IncrementalCacheImpl>()
private val outputDir = requireNotNull(target.outputDir) { "Target is expected to have output directory: $target" } private val outputDir = requireNotNull(target.outputDir) { "Target is expected to have output directory: $target" }
private val dependentsWithThis: Iterable<IncrementalCacheImpl> private val dependentsWithThis: Sequence<IncrementalCacheImpl>
get() = dependents + this get() = sequenceOf(this).plus(dependents.asSequence())
override fun registerInline(fromPath: String, jvmSignature: String, toPath: String) { override fun registerInline(fromPath: String, jvmSignature: String, toPath: String) {
inlinedTo.add(fromPath, jvmSignature, toPath) inlinedTo.add(fromPath, jvmSignature, toPath)
@@ -142,6 +142,9 @@ class IncrementalCacheImpl(
return result.map { File(it) } return result.map { File(it) }
} }
fun getSubtypesOf(className: FqName): Sequence<FqName> =
dependentsWithThis.flatMap { it.subtypesMap[className].asSequence() }
fun cleanDirtyInlineFunctions() { fun cleanDirtyInlineFunctions() {
dirtyInlineFunctionsMap.clean() dirtyInlineFunctionsMap.clean()
} }
@@ -600,9 +603,14 @@ class IncrementalCacheImpl(
val supertypes = classData.classProto.supertypes(TypeTable(classData.classProto.typeTable)) val supertypes = classData.classProto.supertypes(TypeTable(classData.classProto.typeTable))
val parents = supertypes.map { classData.nameResolver.getClassId(it.className).asSingleFqName() } val parents = supertypes.map { classData.nameResolver.getClassId(it.className).asSingleFqName() }
.filter { it.asString() != "kotlin.Any" } .filter { it.asString() != "kotlin.Any" }
.toSet()
val child = kotlinClass.classId.asSingleFqName() val child = kotlinClass.classId.asSingleFqName()
parents.forEach { subtypesMap.add(it, child) } parents.forEach { subtypesMap.add(it, child) }
val removedSupertypes = supertypesMap[child].filter { it !in parents }
removedSupertypes.forEach { subtypesMap.removeValues(it, setOf(child)) }
supertypesMap[child] = parents supertypesMap[child] = parents
} }