Introduce ChangesCollector

Original commit: 6fedf07f56
This commit is contained in:
Alexey Tsvetkov
2017-08-10 15:59:56 +03:00
parent b5cf0960f4
commit 2fbd8c4beb
4 changed files with 60 additions and 55 deletions
@@ -21,11 +21,8 @@ import org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants
import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.incremental.ClassProtoData
import org.jetbrains.kotlin.incremental.Difference
import org.jetbrains.kotlin.incremental.difference as differenceImpl
import org.jetbrains.kotlin.incremental.PackagePartProtoData
import org.jetbrains.kotlin.incremental.ProtoData
import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.utils.TestMessageCollector
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl
@@ -72,28 +69,33 @@ abstract class AbstractJsProtoComparisonTest : AbstractProtoComparisonTest<Proto
val classes = hashMapOf<ClassId, ProtoData>()
for ((sourceFile, protoBytes, _) in incrementalResults.packageParts) {
val proto = ProtoBuf.PackageFragment.parseFrom(protoBytes, JsSerializerProtocol.extensionRegistry)
val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
proto.class_List.forEach {
val classId = nameResolver.getClassId(it.fqName)
classes[classId] = ClassProtoData(it, nameResolver)
}
proto.`package`.apply {
val packageFqName = if (hasExtension(JsProtoBuf.packageFqName)) {
nameResolver.getPackageFqName(getExtension(JsProtoBuf.packageFqName))
}
else FqName.ROOT
val packagePartClassId = ClassId(packageFqName, Name.identifier(sourceFile.nameWithoutExtension.capitalize() + "Kt"))
classes[packagePartClassId] = PackagePartProtoData(this, nameResolver)
}
classes.putAll(getProtoData(sourceFile, protoBytes))
}
return classes
}
override fun difference(oldData: ProtoData, newData: ProtoData): Difference? =
differenceImpl(oldData, newData)
override fun ProtoData.toProtoData(): ProtoData? = this
}
fun getProtoData(sourceFile: File, metadata: ByteArray): Map<ClassId, ProtoData> {
val classes = hashMapOf<ClassId, ProtoData>()
val proto = ProtoBuf.PackageFragment.parseFrom(metadata, JsSerializerProtocol.extensionRegistry)
val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
proto.class_List.forEach {
val classId = nameResolver.getClassId(it.fqName)
classes[classId] = ClassProtoData(it, nameResolver)
}
proto.`package`.apply {
val packageFqName = if (hasExtension(JsProtoBuf.packageFqName)) {
nameResolver.getPackageFqName(getExtension(JsProtoBuf.packageFqName))
}
else FqName.ROOT
val packagePartClassId = ClassId(packageFqName, Name.identifier(sourceFile.nameWithoutExtension.capitalize() + "Kt"))
classes[packagePartClassId] = PackagePartProtoData(this, nameResolver, packageFqName)
}
return classes
}
@@ -16,9 +16,7 @@
package org.jetbrains.kotlin.jps.incremental
import org.jetbrains.kotlin.incremental.Difference
import org.jetbrains.kotlin.incremental.LocalFileKotlinClass
import org.jetbrains.kotlin.incremental.difference
import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.storage.ProtoMapValue
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -36,25 +34,20 @@ abstract class AbstractJvmProtoComparisonTest : AbstractProtoComparisonTest<Loca
return localClassFiles.associateBy { it.classId }
}
override fun difference(oldData: LocalFileKotlinClass, newData: LocalFileKotlinClass): Difference? {
val oldProto = oldData.readProto() ?: return null
val newProto = newData.readProto() ?: return null
return difference(oldProto, newProto)
}
private fun KotlinJvmBinaryClass.readProto(): ProtoMapValue? {
override fun LocalFileKotlinClass.toProtoData(): ProtoData? {
assert(classHeader.metadataVersion.isCompatible()) { "Incompatible class ($classHeader): $location" }
val bytes by lazy { BitEncoding.decodeBytes(classHeader.data!!) }
val strings by lazy { classHeader.strings!! }
val packageFqName = classId.packageFqName
return when (classHeader.kind) {
KotlinClassHeader.Kind.CLASS -> {
ProtoMapValue(false, bytes, strings)
ProtoMapValue(false, bytes, strings).toProtoData(packageFqName)
}
KotlinClassHeader.Kind.FILE_FACADE,
KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> {
ProtoMapValue(true, bytes, strings)
ProtoMapValue(true, bytes, strings).toProtoData(packageFqName)
}
else -> {
null
@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.jps.incremental
import org.jetbrains.kotlin.TestWithWorkingDir
import org.jetbrains.kotlin.incremental.Difference
import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.utils.Printer
@@ -25,7 +25,7 @@ import java.io.File
abstract class AbstractProtoComparisonTest<PROTO_DATA> : TestWithWorkingDir() {
protected abstract fun compileAndGetClasses(sourceDir: File, outputDir: File): Map<ClassId, PROTO_DATA>
protected abstract fun difference(oldData: PROTO_DATA, newData: PROTO_DATA): Difference?
protected abstract fun PROTO_DATA.toProtoData(): ProtoData?
protected open fun expectedOutputFile(testDir: File): File =
File(testDir, "result.out")
@@ -48,32 +48,41 @@ abstract class AbstractProtoComparisonTest<PROTO_DATA> : TestWithWorkingDir() {
}
(oldClassMap.keys.intersect(newClassMap.keys)).sortedBy { it.toString() }.forEach { classId ->
val oldData = oldClassMap[classId]!!
val newData = newClassMap[classId]!!
val diff = difference(oldData, newData)
val oldData = oldClassMap[classId]!!.toProtoData()
val newData = newClassMap[classId]!!.toProtoData()
if (diff == null) {
if (oldData == null || newData == null) {
p.println("SKIPPED $classId")
return@forEach
}
diff.rawProtoDifference?.let {
val rawProtoDifference = when {
oldData is ClassProtoData && newData is ClassProtoData -> {
ProtoCompareGenerated(oldData.nameResolver, newData.nameResolver).difference(oldData.proto, newData.proto)
}
oldData is PackagePartProtoData && newData is PackagePartProtoData -> {
ProtoCompareGenerated(oldData.nameResolver, newData.nameResolver).difference(oldData.proto, newData.proto)
}
else -> null
}
rawProtoDifference?.let {
if (it.isNotEmpty()) {
p.println("PROTO DIFFERENCE in $classId: ${it.sortedBy { it.name }.joinToString()}")
}
}
val changes = arrayListOf<String>()
if (diff.isClassAffected) {
changes.add("CLASS_SIGNATURE")
}
if (diff.changedMembersNames.isNotEmpty()) {
changes.add("MEMBERS\n ${diff.changedMembersNames.sorted()}")
}
if (changes.isEmpty()) {
val changesInfo = ChangesCollector().apply { collectProtoChanges(oldData, newData) }.changes()
if (changesInfo.isEmpty()) {
return@forEach
}
val changes = changesInfo.map {
when (it) {
is ChangeInfo.SignatureChanged -> "CLASS_SIGNATURE"
is ChangeInfo.MembersChanged -> "MEMBERS\n ${it.names.sorted()}"
}
}.sorted()
p.println("CHANGES in $classId: ${changes.joinToString()}")
}
@@ -314,8 +314,9 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
context.checkCanceled()
val changesInfo = generatedFiles.entries.fold(CompilationResult.NO_CHANGES) { acc, (target, files) ->
acc + updateIncrementalCache(files, incrementalCaches[target]!!)
val changesCollector = ChangesCollector()
for ((target, files) in generatedFiles) {
updateIncrementalCache(files, incrementalCaches[target]!!, changesCollector)
}
updateLookupStorage(chunk, lookupTracker, dataManager, dirtyFilesHolder, filesToCompile)
@@ -323,7 +324,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
return OK
}
changesInfo.processChangesUsingLookups(filesToCompile.values().toSet(), dataManager, fsOperations, incrementalCaches.values)
changesCollector.processChangesUsingLookups(filesToCompile.values().toSet(), dataManager, fsOperations, incrementalCaches.values)
return OK
}
@@ -432,7 +433,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
for (target in chunk.targets) {
val cache = incrementalCaches[target]!!
val removedAndDirtyFiles = filesToCompile[target] + dirtyFilesHolder.getRemovedFiles(target).map(::File)
cache.markOutputClassesDirty(removedAndDirtyFiles)
cache.markDirty(removedAndDirtyFiles)
}
}
@@ -774,7 +775,7 @@ private class JpsICReporter : ICReporter {
}
}
private fun CompilationResult.processChangesUsingLookups(
private fun ChangesCollector.processChangesUsingLookups(
compiledFiles: Set<File>,
dataManager: BuildDataManager,
fsOperations: FSOperationsHelper,