From 03f83ff33945306048663ef335eed62734971361 Mon Sep 17 00:00:00 2001 From: Hung Nguyen Date: Sun, 4 Sep 2022 15:39:32 +0100 Subject: [PATCH] New IC: Include inline property accessors in class/package members Problem: ClasspathChangesComputer (a core component of the new IC) uses the existing inline function analysis from the old IC (IncrementalJvmCache.InlineFunctionsMap). If an inline property accessor has changed, the inline function analysis will report the name of the property accessor, not the name of the property. ClasspathChangesComputer doesn't see the property accessor's name in the list of class/package members, so it will throw an exception. Solution: There are 2 options: 1. If an inline property accessor has changed, the inline function analysis can report the name of the property instead of the property accessor. 2. ClasspathChangesComputer can include property accessors in the list of class/package members. In this commit, we will choose option 2 as it is simpler. Test: New KotlinOnlyClasspathChangesComputerTest.testPropertyAccessors Small cleanup - PLS SQUASH INTO PREVIOUS COMMIT - Address review - Fix failed tests - Add some trivial changes ^KT-53871 Fixed --- .../kotlin/incremental/ChangesCollector.kt | 32 +----- .../kotlin/incremental/IncrementalJvmCache.kt | 105 ++++++++++++------ .../incremental/protoDifferenceUtils.kt | 57 ++++++++-- .../org/jetbrains/kotlin/inline/inlineUtil.kt | 74 ++++++------ .../incremental/AbiSnapshotDiffService.kt | 4 +- .../classpathDiff/BasicClassInfo.kt | 6 +- .../ClasspathSnapshotSerializer.kt | 4 +- .../classpathDiff/ClasspathSnapshotter.kt | 5 +- .../incremental/classpathDiff/Impact.kt | 6 +- .../classpathDiff/JavaClassSnapshotter.kt | 8 +- .../ClasspathChangesComputerTest.kt | 25 +++++ .../com/example/SomeClass.class | Bin 1695 -> 1854 bytes .../com/example/SomeClass.class | Bin 1659 -> 1817 bytes .../com/example/SomeClass.kt | 2 + .../com/example/SomeClass.kt | 2 + .../com/example/SomeClass.class | Bin 0 -> 2242 bytes .../com/example/SomeClassKt.class | Bin 0 -> 3941 bytes .../com/example/SomeClass.class | Bin 0 -> 2182 bytes .../com/example/SomeClassKt.class | Bin 0 -> 3881 bytes .../com/example/SomeClass.kt | 79 +++++++++++++ .../com/example/SomeClass.kt | 79 +++++++++++++ .../com/example/SimpleClass.json | 2 +- .../kotlin/codegen/InlineTestUtil.kt | 12 +- 23 files changed, 376 insertions(+), 126 deletions(-) create mode 100644 compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/current-classpath/com/example/SomeClass.class create mode 100644 compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/current-classpath/com/example/SomeClassKt.class create mode 100644 compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/previous-classpath/com/example/SomeClass.class create mode 100644 compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/previous-classpath/com/example/SomeClassKt.class create mode 100644 compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/current-classpath/com/example/SomeClass.kt create mode 100644 compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/previous-classpath/com/example/SomeClass.kt diff --git a/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt b/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt index 564042f283b..d28e0ce336b 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/ChangesCollector.kt @@ -36,32 +36,6 @@ class ChangesCollector { fun protoDataChanges(): Map = storage fun protoDataRemoved(): List = removed - companion object { - fun T.getNonPrivateNames(nameResolver: NameResolver, vararg members: T.() -> List) = - members.flatMap { this.it().filterNot { it.isPrivate }.names(nameResolver) }.toSet() - - fun ClassProtoData.getNonPrivateMemberNames(): Set { - return proto.getNonPrivateNames( - nameResolver, - // The types below should match the logic at `DifferenceCalculatorForClass.difference` - ProtoBuf.Class::getConstructorList, - ProtoBuf.Class::getFunctionList, - ProtoBuf.Class::getPropertyList, - ProtoBuf.Class::getTypeAliasList - ) + proto.enumEntryList.map { nameResolver.getString(it.name) } - } - - fun PackagePartProtoData.getNonPrivateMemberNames(): Set { - return proto.getNonPrivateNames( - nameResolver, - // The types below should match the logic at `DifferenceCalculatorForPackageFacade.difference` - ProtoBuf.Package::getFunctionList, - ProtoBuf.Package::getPropertyList, - ProtoBuf.Package::getTypeAliasList - ) - } - } - fun changes(): List { val changes = arrayListOf() @@ -192,7 +166,7 @@ class ChangesCollector { } private fun PackagePartProtoData.collectAllFromPackage(isRemoved: Boolean) { - val memberNames = getNonPrivateMemberNames() + val memberNames = getNonPrivateMemberNames(includeInlineAccessors = true) if (isRemoved) { collectRemovedMembers(packageFqName, memberNames) } else { @@ -204,14 +178,14 @@ class ChangesCollector { val classFqName = nameResolver.getClassId(proto.fqName).asSingleFqName() if (proto.isCompanionObject) { - val memberNames = getNonPrivateMemberNames() + val memberNames = getNonPrivateMemberNames(includeInlineAccessors = true) val collectMember = if (isRemoved) this@ChangesCollector::collectRemovedMember else this@ChangesCollector::collectChangedMember collectMember(classFqName.parent(), classFqName.shortName().asString()) memberNames.forEach { collectMember(classFqName, it) } } else { if (!isRemoved && collectAllMembersForNewClass) { - val memberNames = getNonPrivateMemberNames() + val memberNames = getNonPrivateMemberNames(includeInlineAccessors = true) memberNames.forEach { this@ChangesCollector.collectChangedMember(classFqName, it) } } diff --git a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt index ef7abb55439..41248f93b7e 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/IncrementalJvmCache.kt @@ -23,8 +23,11 @@ import com.intellij.util.io.EnumeratorStringDescriptor import gnu.trove.THashSet import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.build.GeneratedJvmClass +import org.jetbrains.kotlin.incremental.DifferenceCalculatorForClass.Companion.getNonPrivateMembers +import org.jetbrains.kotlin.incremental.DifferenceCalculatorForPackageFacade.Companion.getNonPrivateMembers import org.jetbrains.kotlin.incremental.storage.* -import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames +import org.jetbrains.kotlin.inline.inlineAccessors +import org.jetbrains.kotlin.inline.inlineFunctionsAndAccessors import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto @@ -39,7 +42,8 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.org.objectweb.asm.* -import org.jetbrains.org.objectweb.asm.ClassReader.* +import org.jetbrains.org.objectweb.asm.ClassReader.SKIP_CODE +import org.jetbrains.org.objectweb.asm.ClassReader.SKIP_DEBUG import java.io.File import java.security.MessageDigest @@ -570,19 +574,26 @@ open class IncrementalJvmCache( val key = kotlinClassInfo.className.internalName val oldMap = storage[key] ?: emptyMap() - val newMap = kotlinClassInfo.inlineFunctionsMap + val newMap = kotlinClassInfo.inlineFunctionsAndAccessorsMap if (newMap.isNotEmpty()) { storage[key] = newMap } else { storage.remove(key) } - for (fn in oldMap.keys + newMap.keys) { + for (methodSignature in oldMap.keys + newMap.keys) { + val inlineFunctionOrAccessorName = functionNameBySignature(methodSignature) + // Note: If we detect a change in an inline property accessor (e.g., `getFoo`), we have two options: + // 1. Report that property `foo` has changed (and ignore `getFoo`) + // 2. Report that property accessor `getFoo` has changed (and ignore `foo`) + // Both options are possible (the compiler generates `LookupSymbol`s for both `foo` and `getFoo` when `getFoo` is inlined). + // Currently, we choose option 2 as it is simpler (i.e., even though inline property accessors are not immediate members of + // a class/package, we treat them like immediate members). changesCollector.collectMemberIfValueWasChanged( kotlinClassInfo.scopeFqName(), - functionNameBySignature(fn), - oldMap[fn], - newMap[fn] + inlineFunctionOrAccessorName, + oldMap[methodSignature], + newMap[methodSignature] ) } } @@ -659,6 +670,28 @@ fun , V> Map.dumpMap(dumpValue: (V) -> String): String = fun > Collection.dumpCollection(): String = "[${sorted().joinToString(", ", transform = Any::toString)}]" +/** + * @param includeInlineAccessors If `true`, also include inline property accessors in the returned list. This is necessary because property + * accessors are not immediate members of a class/package, and in some cases we treat them like immediate members (see + * [org.jetbrains.kotlin.incremental.IncrementalJvmCache.InlineFunctionsMap.process]). Note that here we deal with *inline* property + * accessors only as [org.jetbrains.kotlin.incremental.IncrementalJvmCache.InlineFunctionsMap.process] is written only to handle *inline* + * property accessors (and functions). + */ +fun ProtoData.getNonPrivateMemberNames(includeInlineAccessors: Boolean): List { + return when (this) { + is ClassProtoData -> { + getNonPrivateMembers() + (if (includeInlineAccessors) { + inlineAccessors(proto.propertyList, nameResolver, excludePrivateAccessors = true).map { it.name } + } else emptyList()) + } + is PackagePartProtoData -> { + getNonPrivateMembers() + (if (includeInlineAccessors) { + inlineAccessors(proto.propertyList, nameResolver, excludePrivateAccessors = true).map { it.name } + } else emptyList()) + } + } +} + /** * Minimal information about a Kotlin class to compute recompilation-triggering changes during an incremental run of the `KotlinCompile` * task (see [IncrementalJvmCache.saveClassToCache]). @@ -674,7 +707,7 @@ class KotlinClassInfo constructor( val classHeaderStrings: Array, // Can be empty val multifileClassName: String?, // Not null iff classKind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART val constantsMap: LinkedHashMap, - val inlineFunctionsMap: LinkedHashMap + val inlineFunctionsAndAccessorsMap: LinkedHashMap ) { val className: JvmClassName by lazy { JvmClassName.byClassId(classId) } @@ -726,48 +759,55 @@ class KotlinClassInfo constructor( } fun createFrom(classId: ClassId, classHeader: KotlinClassHeader, classContents: ByteArray): KotlinClassInfo { - val constantsAndInlineFunctions = getConstantsAndInlineFunctions(classHeader, classContents) + val (constants, inlineFunctionsAndAccessors) = getConstantsAndInlineFunctionsOrAccessors(classHeader, classContents) return KotlinClassInfo( classId, classHeader.kind, - classHeader.data ?: classHeader.incompatibleData ?: emptyArray(), + classHeader.data ?: emptyArray(), classHeader.strings ?: emptyArray(), classHeader.multifileClassName, - constantsMap = constantsAndInlineFunctions.first, - inlineFunctionsMap = constantsAndInlineFunctions.second + constants.mapKeysTo(LinkedHashMap()) { it.key.name }, + inlineFunctionsAndAccessors.mapKeysTo(LinkedHashMap()) { it.key.asString() }, ) } } } -/** Parses the class file only once to get both constants and inline functions. */ -private fun getConstantsAndInlineFunctions( +/** + * Parses the class file only once to get both constants and inline functions/property accessors. This is faster than getting them + * separately in two passes. + */ +private fun getConstantsAndInlineFunctionsOrAccessors( classHeader: KotlinClassHeader, classContents: ByteArray -): Pair, LinkedHashMap> { +): Pair, Map> { val constantsClassVisitor = ConstantsClassVisitor() - val inlineFunctionSignatures = inlineFunctionsJvmNames(classHeader) + val inlineFunctionsAndAccessors = inlineFunctionsAndAccessors(classHeader) - return if (inlineFunctionSignatures.isEmpty()) { - ClassReader(classContents).accept(constantsClassVisitor, SKIP_CODE or SKIP_DEBUG or SKIP_FRAMES) - Pair(constantsClassVisitor.getResult(), LinkedHashMap()) + return if (inlineFunctionsAndAccessors.isEmpty()) { + // parsingOptions = (SKIP_CODE, SKIP_DEBUG) as method bodies and debug info are not important for constants + ClassReader(classContents).accept(constantsClassVisitor, SKIP_CODE or SKIP_DEBUG) + Pair(constantsClassVisitor.getResult(), emptyMap()) } else { - val inlineFunctionsClassVisitor = InlineFunctionsClassVisitor(inlineFunctionSignatures, constantsClassVisitor) - ClassReader(classContents).accept(inlineFunctionsClassVisitor, 0) - Pair(constantsClassVisitor.getResult(), inlineFunctionsClassVisitor.getResult()) + val inlineFunctionsAndAccessorsClassVisitor = + InlineFunctionsAndAccessorsClassVisitor(inlineFunctionsAndAccessors.toSet(), constantsClassVisitor) + // parsingOptions must not include (SKIP_CODE, SKIP_DEBUG) as method bodies and debug info (e.g., line numbers) are important for + // inline functions/accessors + ClassReader(classContents).accept(inlineFunctionsAndAccessorsClassVisitor, 0) + Pair(constantsClassVisitor.getResult(), inlineFunctionsAndAccessorsClassVisitor.getResult()) } } private class ConstantsClassVisitor : ClassVisitor(Opcodes.API_VERSION) { - private val result = LinkedHashMap() + private val result = mutableMapOf() override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? { if (access and Opcodes.ACC_PRIVATE == Opcodes.ACC_PRIVATE) return null val staticFinal = Opcodes.ACC_STATIC or Opcodes.ACC_FINAL if (value != null && access and staticFinal == staticFinal) { - result[name] = value + result[JvmMemberSignature.Field(name, desc)] = value } return null } @@ -775,12 +815,12 @@ private class ConstantsClassVisitor : ClassVisitor(Opcodes.API_VERSION) { fun getResult() = result } -private class InlineFunctionsClassVisitor( - private val inlineFunctionSignatures: Set, - cv: ConstantsClassVisitor // Note: cv must not override the visitMethod (it will not be called with the current implementation below) +private class InlineFunctionsAndAccessorsClassVisitor( + private val inlineFunctionsAndAccessors: Set, + cv: ConstantsClassVisitor // Note: cv must not override `visitMethod` (it will not be called with the current implementation below) ) : ClassVisitor(Opcodes.API_VERSION, cv) { - private val result = LinkedHashMap() + private val result = mutableMapOf() private var classVersion: Int? = null override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array?) { @@ -791,11 +831,8 @@ private class InlineFunctionsClassVisitor( override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array?): MethodVisitor? { if (access and Opcodes.ACC_PRIVATE == Opcodes.ACC_PRIVATE) return null - // Note: Here, functionSignature = name + descriptor. - // It is different from the `signature` parameter above, which is essentially a more detailed descriptor when generics are used - // (or null otherwise). - val functionSignature = JvmMemberSignature.Method(name, desc).asString() - if (functionSignature !in inlineFunctionSignatures) return null + val method = JvmMemberSignature.Method(name, desc) + if (method !in inlineFunctionsAndAccessors) return null val classWriter = ClassWriter(0) @@ -804,7 +841,7 @@ private class InlineFunctionsClassVisitor( return object : MethodVisitor(Opcodes.API_VERSION, classWriter.visitMethod(access, name, desc, signature, exceptions)) { override fun visitEnd() { - result[functionSignature] = classWriter.toByteArray().md5() + result[method] = classWriter.toByteArray().md5() } } } diff --git a/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt b/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt index 53c7c83a450..6e817a3a0ec 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/protoDifferenceUtils.kt @@ -51,17 +51,17 @@ fun ProtoMapValue.toProtoData(packageFqName: FqName): ProtoData = } internal val MessageLite.isPrivate: Boolean - get() = DescriptorVisibilities.isPrivate( - ProtoEnumFlags.descriptorVisibility( - when (this) { - is ProtoBuf.Constructor -> Flags.VISIBILITY.get(flags) - is ProtoBuf.Function -> Flags.VISIBILITY.get(flags) - is ProtoBuf.Property -> Flags.VISIBILITY.get(flags) - is ProtoBuf.TypeAlias -> Flags.VISIBILITY.get(flags) - else -> error("Unknown message: $this") - } - ) - ) + get() { + val visibility = when (this) { + is ProtoBuf.Constructor -> Flags.VISIBILITY.get(flags) + is ProtoBuf.Function -> Flags.VISIBILITY.get(flags) + is ProtoBuf.Property -> Flags.VISIBILITY.get(flags) + is ProtoBuf.TypeAlias -> Flags.VISIBILITY.get(flags) + is ProtoBuf.EnumEntry -> return false // EnumEntry doesn't have a visibility flag + else -> error("Unknown message: $this") + } + return DescriptorVisibilities.isPrivate(ProtoEnumFlags.descriptorVisibility(visibility)) + } private fun MessageLite.name(nameResolver: NameResolver): String { return when (this) { @@ -69,6 +69,7 @@ private fun MessageLite.name(nameResolver: NameResolver): String { is ProtoBuf.Function -> nameResolver.getString(name) is ProtoBuf.Property -> nameResolver.getString(name) is ProtoBuf.TypeAlias -> nameResolver.getString(name) + is ProtoBuf.EnumEntry -> nameResolver.getString(name) else -> error("Unknown message: $this") } } @@ -307,6 +308,25 @@ class DifferenceCalculatorForClass( return Difference(isClassAffected, areSubclassesAffected, names, changedSupertypes) } + + companion object { + + fun ClassProtoData.getNonPrivateMembers(): List { + val membersResolvers: List<(ProtoBuf.Class) -> List> = listOf( + // This list must match the logic in `DifferenceCalculatorForClass.difference` + // TODO: Consider adding COMPANION_OBJECT_NAME and NESTED_CLASS_NAME_LIST as they are also members of a class (see + // `DifferenceCalculatorForClass.difference`) + ProtoBuf.Class::getConstructorList, + ProtoBuf.Class::getFunctionList, + ProtoBuf.Class::getPropertyList, + ProtoBuf.Class::getTypeAliasList, + ProtoBuf.Class::getEnumEntryList + ) + return membersResolvers.flatMap { membersResolver -> + membersResolver(proto).filterNot { it.isPrivate }.names(nameResolver) + } + } + } } class DifferenceCalculatorForPackageFacade( @@ -362,6 +382,21 @@ class DifferenceCalculatorForPackageFacade( return Difference(changedMembersNames = names) } + + companion object { + + fun PackagePartProtoData.getNonPrivateMembers(): List { + val membersResolvers: List<(ProtoBuf.Package) -> List> = listOf( + // This list must match the logic in `DifferenceCalculatorForPackageFacade.difference` + ProtoBuf.Package::getFunctionList, + ProtoBuf.Package::getPropertyList, + ProtoBuf.Package::getTypeAliasList + ) + return membersResolvers.flatMap { membersResolver -> + membersResolver(proto).filterNot { it.isPrivate }.names(nameResolver) + } + } + } } private val ProtoBuf.Class.isSealed: Boolean diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt index 237aefd25e6..edd4e01c5cc 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/inline/inlineUtil.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.inline +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags @@ -24,57 +25,68 @@ import org.jetbrains.kotlin.metadata.deserialization.TypeTable import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf.JvmMethodSignature +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMemberSignature import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil +import org.jetbrains.kotlin.serialization.deserialization.ProtoEnumFlags +import org.jetbrains.kotlin.serialization.deserialization.descriptorVisibility -fun inlineFunctionsJvmNames(header: KotlinClassHeader): Set { - val annotationData = header.data ?: return emptySet() - val strings = header.strings ?: return emptySet() +fun inlineFunctionsAndAccessors(header: KotlinClassHeader): List { + val data = header.data ?: return emptyList() + val strings = header.strings ?: return emptyList() return when (header.kind) { KotlinClassHeader.Kind.CLASS -> { - val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings) - inlineFunctionsJvmNames(classProto.functionList, nameResolver, classProto.typeTable) + - inlineAccessorsJvmNames(classProto.propertyList, nameResolver) + val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(data, strings) + inlineFunctions(classProto.functionList, nameResolver, classProto.typeTable) + + inlineAccessors(classProto.propertyList, nameResolver) } KotlinClassHeader.Kind.FILE_FACADE, KotlinClassHeader.Kind.MULTIFILE_CLASS_PART -> { - val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings) - inlineFunctionsJvmNames(packageProto.functionList, nameResolver, packageProto.typeTable) + - inlineAccessorsJvmNames(packageProto.propertyList, nameResolver) + val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(data, strings) + inlineFunctions(packageProto.functionList, nameResolver, packageProto.typeTable) + + inlineAccessors(packageProto.propertyList, nameResolver) } - else -> emptySet() + else -> emptyList() } } -private fun inlineFunctionsJvmNames(functions: List, nameResolver: NameResolver, protoTypeTable: ProtoBuf.TypeTable): Set { +private fun inlineFunctions( + functions: List, + nameResolver: NameResolver, + protoTypeTable: ProtoBuf.TypeTable +): List { val typeTable = TypeTable(protoTypeTable) - val inlineFunctions = functions.filter { Flags.IS_INLINE.get(it.flags) } - val jvmNames = inlineFunctions.mapNotNull { - JvmProtoBufUtil.getJvmMethodSignature(it, nameResolver, typeTable)?.asString() + return functions.filter { Flags.IS_INLINE.get(it.flags) }.mapNotNull { + JvmProtoBufUtil.getJvmMethodSignature(it, nameResolver, typeTable) } - return jvmNames.toSet() } -private fun inlineAccessorsJvmNames(properties: List, nameResolver: NameResolver): Set { - val propertiesWithInlineAccessors = properties.filter { proto -> - proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.getterFlags) || - proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.setterFlags) - } - val inlineAccessors = arrayListOf() - propertiesWithInlineAccessors.forEach { proto -> - val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) - if (signature != null) { - if (proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.getterFlags)) { - inlineAccessors.add(signature.getter) - } +fun inlineAccessors( + properties: List, + nameResolver: NameResolver, + excludePrivateAccessors: Boolean = false +): List { + val inlineAccessors = mutableListOf() - if (proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(proto.setterFlags)) { - inlineAccessors.add(signature.setter) + fun isInline(flags: Int) = Flags.IS_INLINE_ACCESSOR.get(flags) + fun isPrivate(flags: Int) = DescriptorVisibilities.isPrivate(ProtoEnumFlags.descriptorVisibility(Flags.VISIBILITY.get(flags))) + + properties.forEach { property -> + val propertySignature = property.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return@forEach + + if (property.hasGetterFlags() && isInline(property.getterFlags)) { + if (!(excludePrivateAccessors && isPrivate(property.getterFlags))) { + inlineAccessors.add(propertySignature.getter) + } + } + if (property.hasSetterFlags() && isInline(property.setterFlags)) { + if (!(excludePrivateAccessors && isPrivate(property.setterFlags))) { + inlineAccessors.add(propertySignature.setter) } } } return inlineAccessors.map { - nameResolver.getString(it.name) + nameResolver.getString(it.desc) - }.toSet() + JvmMemberSignature.Method(name = nameResolver.getString(it.name), desc = nameResolver.getString(it.desc)) + } } diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/AbiSnapshotDiffService.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/AbiSnapshotDiffService.kt index 43fdca1f403..59ed70b99bc 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/AbiSnapshotDiffService.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/AbiSnapshotDiffService.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.incremental -import org.jetbrains.kotlin.incremental.ChangesCollector.Companion.getNonPrivateMemberNames import org.jetbrains.kotlin.metadata.ProtoBuf.Visibility.PRIVATE import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.name.FqName @@ -98,7 +97,8 @@ class AbiSnapshotDiffService() { when (protoData) { is ClassProtoData -> { fqNames.add(fqName) - symbols.addAll(protoData.getNonPrivateMemberNames().map { LookupSymbol(it, fqName.asString()) }) + symbols.addAll( + protoData.getNonPrivateMemberNames(includeInlineAccessors = true).map { LookupSymbol(it, fqName.asString()) }) } is PackagePartProtoData -> { symbols.addAll( diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/BasicClassInfo.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/BasicClassInfo.kt index 8872ab3230f..41403653717 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/BasicClassInfo.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/BasicClassInfo.kt @@ -12,7 +12,8 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.org.objectweb.asm.AnnotationVisitor import org.jetbrains.org.objectweb.asm.ClassReader -import org.jetbrains.org.objectweb.asm.ClassReader.* +import org.jetbrains.org.objectweb.asm.ClassReader.SKIP_CODE +import org.jetbrains.org.objectweb.asm.ClassReader.SKIP_DEBUG import org.jetbrains.org.objectweb.asm.ClassVisitor import org.jetbrains.org.objectweb.asm.Opcodes @@ -47,7 +48,8 @@ class BasicClassInfo( val innerClassesClassVisitor = InnerClassesClassVisitor(kotlinClassHeaderClassVisitor) val basicClassInfoVisitor = BasicClassInfoClassVisitor(innerClassesClassVisitor) - ClassReader(classContents).accept(basicClassInfoVisitor, SKIP_CODE or SKIP_DEBUG or SKIP_FRAMES) + // parsingOptions = (SKIP_CODE, SKIP_DEBUG) as method bodies and debug info are not important + ClassReader(classContents).accept(basicClassInfoVisitor, SKIP_CODE or SKIP_DEBUG) val className = basicClassInfoVisitor.getClassName() val innerClassesInfo = innerClassesClassVisitor.getInnerClassesInfo() diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotSerializer.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotSerializer.kt index 4a9d8a51f5e..f41bfbb8e21 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotSerializer.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotSerializer.kt @@ -186,7 +186,7 @@ internal object KotlinClassInfoExternalizer : DataExternalizer ListExternalizer(StringExternalizer).save(output, info.classHeaderStrings.toList()) NullableValueExternalizer(StringExternalizer).save(output, info.multifileClassName) LinkedHashMapExternalizer(StringExternalizer, ConstantExternalizer).save(output, info.constantsMap) - LinkedHashMapExternalizer(StringExternalizer, LongExternalizer).save(output, info.inlineFunctionsMap) + LinkedHashMapExternalizer(StringExternalizer, LongExternalizer).save(output, info.inlineFunctionsAndAccessorsMap) } override fun read(input: DataInput): KotlinClassInfo { @@ -198,7 +198,7 @@ internal object KotlinClassInfoExternalizer : DataExternalizer classHeaderStrings = ListExternalizer(StringExternalizer).read(input).toTypedArray(), multifileClassName = NullableValueExternalizer(StringExternalizer).read(input), constantsMap = LinkedHashMapExternalizer(StringExternalizer, ConstantExternalizer).read(input), - inlineFunctionsMap = LinkedHashMapExternalizer(StringExternalizer, LongExternalizer).read(input) + inlineFunctionsAndAccessorsMap = LinkedHashMapExternalizer(StringExternalizer, LongExternalizer).read(input) ) } } diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotter.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotter.kt index cbdd5cb00d4..90e1a2d5f28 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotter.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotter.kt @@ -9,10 +9,9 @@ import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildTime import org.jetbrains.kotlin.build.report.metrics.DoNothingBuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.measure -import org.jetbrains.kotlin.incremental.ChangesCollector.Companion.getNonPrivateMemberNames import org.jetbrains.kotlin.incremental.KotlinClassInfo -import org.jetbrains.kotlin.incremental.PackagePartProtoData import org.jetbrains.kotlin.incremental.classpathDiff.ClassSnapshotGranularity.CLASS_MEMBER_LEVEL +import org.jetbrains.kotlin.incremental.getNonPrivateMemberNames import org.jetbrains.kotlin.incremental.md5 import org.jetbrains.kotlin.incremental.storage.toByteArray import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.Kind.* @@ -97,7 +96,7 @@ object ClassSnapshotter { ) FILE_FACADE, MULTIFILE_CLASS_PART -> PackageFacadeKotlinClassSnapshot( classId, classAbiHash, classMemberLevelSnapshot, - packageMemberNames = (kotlinClassInfo.protoData as PackagePartProtoData).getNonPrivateMemberNames() + packageMemberNames = kotlinClassInfo.protoData.getNonPrivateMemberNames(includeInlineAccessors = true).toSet() ) MULTIFILE_CLASS -> MultifileClassKotlinClassSnapshot( classId, classAbiHash, classMemberLevelSnapshot, diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/Impact.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/Impact.kt index 5d3819a7c40..27976540cc5 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/Impact.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/Impact.kt @@ -183,7 +183,10 @@ private object ConstantsInCompanionObjectsImpact : Impact { } else null } }.toMap() - val classToCompanionObject: Map = companionObjectToConstants.keys.associateBy { it.parentClassId!! } + val classToCompanionObject: Map = companionObjectToConstants.keys.associateBy { companionObject -> + // companionObject.parentClassId should be present in `allClasses` as this is a companion object + companionObject.parentClassId!! + } return object : ImpactedSymbolsResolver { override fun getImpactedClasses(classId: ClassId): Set { @@ -211,6 +214,7 @@ private object ConstantsInCompanionObjectsImpact : Impact { return object : ImpactingClassesResolver { override fun getImpactingClasses(classId: ClassId): Set { return if (classId in companionObjects) { + // classId.parentClassId should be present in `allClasses` as this is a companion object setOf(classId.parentClassId!!) } else emptySet() } diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/JavaClassSnapshotter.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/JavaClassSnapshotter.kt index dc32d38e46f..f28e3356ac2 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/JavaClassSnapshotter.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/classpathDiff/JavaClassSnapshotter.kt @@ -28,11 +28,11 @@ object JavaClassSnapshotter { // First, collect all info. // Note the parsing options passed to ClassReader: - // - SKIP_CODE and SKIP_FRAMES are set as method bodies will not be part of the ABI of the class. - // - SKIP_DEBUG is not set as it would skip method parameters, which may be used by annotation processors like Room. - // - EXPAND_FRAMES is not needed (and not relevant when SKIP_CODE is set). + // - SKIP_CODE is set as method bodies will not be part of the ABI of the class. + // - SKIP_DEBUG seems possible but is *not* set just to be safe, so that we don't skip any info that might be important. + // - SKIP_FRAMES or EXPAND_FRAMES is not needed (and not relevant when SKIP_CODE is set). val classReader = ClassReader(classFile.contents) - classReader.accept(abiClass, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES) + classReader.accept(abiClass, ClassReader.SKIP_CODE) // Then, remove non-ABI info, which includes: // - Method bodies: Should have already been removed (see SKIP_CODE above) diff --git a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest.kt b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest.kt index d7efbb3ea8f..61cf45b6358 100644 --- a/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest.kt +++ b/compiler/incremental-compilation-impl/test/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest.kt @@ -202,6 +202,7 @@ class KotlinOnlyClasspathChangesComputerTest : ClasspathChangesComputerTest() { LookupSymbol(name = "inlineFunctionChangedSignature", scope = "com.example.SomeClass"), LookupSymbol(name = "inlineFunctionChangedImplementation", scope = "com.example.SomeClass"), + LookupSymbol(name = "inlineFunctionChangedLineNumber", scope = "com.example.SomeClass"), LookupSymbol(name = SAM_LOOKUP_NAME.asString(), scope = "com.example.SomeClass"), LookupSymbol(name = SAM_LOOKUP_NAME.asString(), scope = "com.example.SomeClass.CompanionObject"), @@ -213,6 +214,30 @@ class KotlinOnlyClasspathChangesComputerTest : ClasspathChangesComputerTest() { ).assertEquals(changes) } + @Test + fun testPropertyAccessors() { + val changes = computeClasspathChanges(File(testDataDir, "KotlinOnly/testPropertyAccessors/src"), tmpDir) + Changes( + lookupSymbols = setOf( + LookupSymbol(name = "property_ChangedType", scope = "com.example.SomeClass"), + + LookupSymbol(name = "inlineProperty_ChangedType", scope = "com.example"), + LookupSymbol(name = "inlineProperty_ChangedType_BackingField", scope = "com.example"), + LookupSymbol(name = "getInlineProperty_ChangedType", scope = "com.example"), + LookupSymbol(name = "setInlineProperty_ChangedType", scope = "com.example"), + + LookupSymbol(name = "getInlineProperty_ChangedGetterImpl", scope = "com.example"), + LookupSymbol(name = "setInlineProperty_ChangedSetterImpl", scope = "com.example"), + + LookupSymbol(name = SAM_LOOKUP_NAME.asString(), scope = "com.example.SomeClass") + ), + fqNames = setOf( + "com.example", + "com.example.SomeClass" + ) + ).assertEquals(changes) + } + /** Tests [SupertypesInheritorsImpact]. */ @Test override fun testImpactComputation_SupertypesInheritors() { diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/classes/current-classpath/com/example/SomeClass.class b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/classes/current-classpath/com/example/SomeClass.class index b7d405bb17c37da15dcb4f53ba190500095bf6e6..5e264cba77a415707ba8dda3ecc7b5d097d59c43 100644 GIT binary patch delta 740 zcmah{K~EDw7=1I-U3P~SwzXT!0;RSP5kzZMsB1;^WDS9XC({@cBL_)P|NXKL;1bpZ{Js1B zUgeLNiORyytUr3ZwefuC!PYZ@+31D{^gxNG#SbwN{T2;-QX{}rv?N!Z5@uXTlp`a5 z?mq2yrnD?dExm3>OD6_Szq+id*zJ^cUDiY>^iAvFjV(QS+x1i+YpGiYFCAiQ2;0OX zecc(--Jbr!5s(k-0uV^wd9o9IR&Vby5NU(`*{l`T2~;sle1%wIj{G#n4*5L!nIXQw z))tTWN9eVZ+rsEus<3#K_h{Y(D5SWWL}_|Jm&+X>i_t_0Us--8w#QK<#?g!_R&_3< z5+(|FR5Po7y`v&AaC&rZTh(gpZ1kNe)l|oQIr`pPlbc!O;nDX$|A{1Qfp5jjPud1s z=*7;Va2R`c5GH@*(8*(m929%AVbmfg5`XEh2=0ncnEr@U9}-338mnf+fDe~A^Hp+* z6S5#vG&bzE#i82+%A+ZZ*_2FnJv!FU34CKjpW4GIRO Ef3wI~ApigX delta 586 zcmZ8d%Ps^#6g^cn-MX7GZ5VnU7$)AY@or<-(&7hXmVQ9eiC8f!d#Mlb12$qIn8?J^ z)=&5d#Ho&W^`q`Nx6VCvZ#{NjrqjWzKbDU7CC(??!R{>gvC)hdw|*Yt7r6OaY$nvK=6cK6J7Ae;--8@7u*Qhn1!? zb4tM0&C~UO;6U7>c!OaxoEd48t4CeHGfKRzI=RFuwiqMkr+GUw4X6mS5#}OHVxABS g5vo{hK*U(Wasys$zLgkuj0^$)&V*-U^u;KB0uJRxRR910 diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/classes/previous-classpath/com/example/SomeClass.class b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/classes/previous-classpath/com/example/SomeClass.class index 27c5ceb2556cd0d21dd4f47209218a45917c7d75..548cf4ebaa2311055166c74bb0e035ba8ae82d1c 100644 GIT binary patch delta 599 zcmZutJxjw-6g@9#W79TmW1D{358GSxHw615ehog!QiYQxJr4Gll}rh z90UbvSO0~hzraBdZ_**8_}(M;o|AjeJNNzg?*hul@9R5&2DTV9K4#i5|IM;|hiS^* z=~;jOVsP9)XDANulMW(7B{|+@k1Wo=SVu~FkwA)b0hWnCuo1F;Ld7 z@we`jtRigd)oi`6b$67M%^k5^gB(p<%tEufF72*}qboYqgZC`i7(M>EcGDjSk|$kx9Q=_lw(!L8rFMY1}dob X;5E!sGawlVT8V1FXCQ1qGm!oROR7l} delta 595 zcmah`%Syvg6r6k0gfzz5chiSj8|$OKYF}0naV6vrlnR1hAlwgVf1zY0h+p7F1Pc|U zZr%6?{)P)doK#TirU~3RlT7BEGr5j@+Ow};!)E{u>f!@m@7BJI~?+i)yo zkoB+Rk(oy!42gOFQNEPVN4=ya9cjtvsAowtC`@9=8TE>0O;*K$F#Q{?<-cpgE{&9DL=de7%10Q|tR;NRqOc3?T0OtMJvcc1$HK0KcA%v!1 z(6er!Zc`h)2x*7f9Z_=mpUEWVs5{l&sk$h2x4PS%<`+Yg-f8v-?)Z2Ic1D=Pfjj}5 z(@b-TPq-xiT>N80@0v*cCgE`1;If~PITHiq9|ljNEB9=Sx7c>pJT xUS^^z9cUg_J*;{BE9)##@vwo-4urxMwmS$bSPDA|hQb^RTVX~arjSs`e*;G-JE#Bv diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/current-classpath/com/example/SomeClass.kt b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/current-classpath/com/example/SomeClass.kt index 660aeb42721..c3676ce9f7a 100644 --- a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/current-classpath/com/example/SomeClass.kt +++ b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/current-classpath/com/example/SomeClass.kt @@ -14,6 +14,8 @@ class SomeClass { inline fun inlineFunctionChangedSignature(): Long = 0 inline fun inlineFunctionChangedImplementation(): Int = 1000 + + inline fun inlineFunctionChangedLineNumber(): Int = 0 inline fun inlineFunctionChangedUnchanged(): Int = 0 private inline fun privateInlineFunctionChangedSignature(): Long = 0 } \ No newline at end of file diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/previous-classpath/com/example/SomeClass.kt b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/previous-classpath/com/example/SomeClass.kt index c75bad71253..0f4c228bd36 100644 --- a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/previous-classpath/com/example/SomeClass.kt +++ b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testConstantsAndInlineFunctions/src/previous-classpath/com/example/SomeClass.kt @@ -14,6 +14,8 @@ class SomeClass { inline fun inlineFunctionChangedSignature(): Int = 0 inline fun inlineFunctionChangedImplementation(): Int = 0 + inline fun inlineFunctionChangedLineNumber(): Int = 0 + inline fun inlineFunctionChangedUnchanged(): Int = 0 private inline fun privateInlineFunctionChangedSignature(): Int = 0 } \ No newline at end of file diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/current-classpath/com/example/SomeClass.class b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/current-classpath/com/example/SomeClass.class new file mode 100644 index 0000000000000000000000000000000000000000..6b9a84a265be0b293bc2bf03dd4b809731c56bba GIT binary patch literal 2242 zcmaJ>T~pge6g?~3vMq!y+k6u~LIN>PgMpBQ1WF0Cq$W9BzkmJ(u!I*3{Z+SKwBDQb z^Ir*>I1ohIjgQ^N@J0{nw|*mZaKd=sONwWZOD=kxD{Ann-vzl4yQ= zc84L>G;1fsITljwndNy_qeN$wHA@UrernPd=dW9iXL`2lOdgtivg#|mnZUpmFDj?p zv+8jS5r=!?k%eVxl&pGGxj}u2-|2;tR_&_f5~FW>@OX2)!{TJ_+#w13RMpdt1!rX|%tKJ%>P9a?Q%0Jg#`VyQgk~i)cSXP#tbI~I zzZ5WVJ?o%k9Wv-$EBlK~c%--gL32m+wxXNvK0W4i*>csKvy0v3-n;=ge$Ms(~#{xZ*DBVJgBK=xuq=?reBlWe6 z)L=4FA5iQeY4oe3@AovjFD{c}tnfDye@Iw~z8cX05u%P_n?|}1LXuX143UV8ASe>j zC-?y4cS>t*yvEQi?dz0aaq|A1RO7wkpN1R~Y?>JDsYsq$<}{)wEPq zXsasH{IfmxF2(rv3ommE5;m~83&!y+zT3qx zhsLqRp>pKp;1S0|4xQr(M^Zz%j?s%hAJ;;aH@{%kkiUm$;s> literal 0 HcmV?d00001 diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/current-classpath/com/example/SomeClassKt.class b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/current-classpath/com/example/SomeClassKt.class new file mode 100644 index 0000000000000000000000000000000000000000..fdf143c4ddbe832f1cfca4c80edb827ee87525a9 GIT binary patch literal 3941 zcmb7HT~`xF7=C7xkPw%!1OXEeLPR9^5!ANY21TVsqwzCHZD~uFu;NNSXlCK)oyQA* zL4QH7+l%TsJ)BB>wfb_`*tnsWcFgMbifNR$7y@&d+YG17!{XU(6=6jBp`f3n`2Ua!&fU(e zF@zVX)7hn~3=6(SZyJ_m)bljxPP=)Av)%3b_F{Pz8is`FILZ2&_9Y0;<%M;B!$m*C zK30A3D#mP^$9mcH>C77o&tN#=D|^$OO`^0PQl{8}6{BkD zmRYN&p6NX0WOh1&`L?}Se90}N62=+YUbQ`oVWc28s#(iEsGC)*Xw?n9l2dUG*?yeG z0>f|@Ko}Qjx9o}@;=k7}tNqclF4GV`NAMZ5k z?gtg)_Nb_~rhMkY1v89y3c67hQ?|Q%4XPes2CTxkkSyAKt`1{L-f;gOPw1Oa~(&tuLL_!UE&OV#G(`hz$2rcvg#kjO&O5tCDM= zlPe~}gOY2A!dkJo=XR*P2bXJGL^@cYPp*4=l})3*s&AI*O}tPm>E$)OZi;8; zWwcn^tCx%wQy>zL_NtayG1g3O66AWdTC)!rj`LJ+gS1XVh>9;Rx{HdB7}?TSf^6w@ zmM!g0YKM^!M=PbULQfOaU;G8%BKjM(3{|>{D3Bo}oth3ZOGtqYO}<0)ce+v9pf!3U zpu)<46iSGr#_2pEBT{DgSHiT)%##eA91b!|tz=2Q!?0Io9_=z>TnTYDIGtN$5?-0p zgrpMQMJC~uIo(x;igl;Vq*vw)$xtosA~WfgInz}p<<89lrC6k*FOWMxTFg!}uU2obE3s@msW4VYF-Eev@yH*N>5mvOoV*D#-ROIPq(^HI6 zsNgyc>jr5qxA=^ zl*GestLQCOy{o9uX63Q8lEhlqRrC(4UMu%V=6;)%uZf~{6-Dp_-_UG`VlzNL@y7&> zSUJ1$TEM857@}#N9cKMqO=aiu?1tDzU%1!3_Ru7=E!gi za^yHhI5dtJ$5D=F97`O_9Ag}#97zc_IZ_;b95Wm$N0=kTafIVJN1o#@#{{QuEKG6i La6IH#<9PHR)MbWY literal 0 HcmV?d00001 diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/previous-classpath/com/example/SomeClass.class b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/classes/previous-classpath/com/example/SomeClass.class new file mode 100644 index 0000000000000000000000000000000000000000..3fd854545a767050cde18231908349e93df00c45 GIT binary patch literal 2182 zcmah}T~pge6g?|{3t`K$A;c6yLmdB_~qs+;^lkKk2~C_sxuTjk(;cpVHDX66y%6RTt*Tv*B7=K z5=UnHkT|CzqCMuG$GdgPl@bpoGnUNU=8k82mg}T3b|LZRvGBN^!Zi}<9(r`F;k#nF z)u&y{@tR(joA!!^>nLR~fk}o!1R#YehEzwMXgfqw4p;`fU6E$qz>JD%e9TZ9_M$Ic z!))NjElM)NjXpBkgyw(=AB5>|YA6R`7NW!Sk(5s``M}FhXlsAqzJ79A!L>6OVS?eJ zhH4OTiH?crW79sJb!2)xx|Al#9n39sCogqwZ8S@?3V%P zh!53#=;+nZtPjokQ2lCX-iI1Kv~V@F=tIZ!jC7&Kq&Hglp)4NI+lgTV{LP>{@c(TU49wVYkJ%EQz@O?9lNnn{QjfBFH1haf1gduuLCA zoZL@PPyYms6!}8@o=Vv7sj&Q>?w|S*l1Bd)wcpU}uDnF*6P3S_{@sUdQL7RS5F_e1 z9@9t*K*-PzkS7wkA_=M?!CUCR(Sia=Ao+n*NAW7 zs9t!JltP)1X%o^i=;G>s+;b!G6=K6|)l(NK;8&Dv20tkkiJFKLLiI=;gC4w%3rZ0ulMKo!^& qND37E!99Vy0-C@B0YhL`peQgeP!_l?a7SQNU_>Aj&ixWI!?Mi$0oU`9vzWw*Vzy1br5mkoaQnivX zUg(vbvXLoPE5=e;=lqTx2V>Bl>w9{ptXo@|m5t{{iM~b{=C%wwZR87&ZIl z`qDGP7@Ln??ilMg^wPFzZ7rKdd6OYBGn;2PWgZmI@+#s;bVETmN%7B+iq7O`R~h0t z>U8$%6^8jxqc;uPHfnhqw8!q*V51>;6}^sCjl@E&hIH=aulSk%LhvdMJN^bc`3vdH zFyoKkW2@v$wI^;TJ#h=hsTg(qq>0=gui#D$NBllo7MzM0x{|bBjxtP6nNv@vI>L$0 zuiQp=2&$l)Y|wRtGsO1v@~**fB2@OKJDUuH&dY=;HeAK9Y~41iRsyHmc3bf!w~b01 zv$TP#yEb(z$gOBrGxuwzWf$$5p;xjhPUB2B=5Ur_AOH|YhW5jb=ux(aWX54>+0fb9 zRTby4kiVf#i{NCJEuVTa*$W4Zcknp=;hB3dO+p1#Rad)Rd z)d9>Pb_}hnJ>53K4|axgw30ew+D-)(E6#4e&oJ8<&jDnn$m;=M4&}kHiCl^Dm1$E_ zpoBz8qOY)Bwdqslu3_t&x~*p!l*(R&(jpU&gm{2~ZHtORjW0}5o2T05dB%SI_$ryC zzoI3QO5*6`w5Ft$dA87{eS9Sj&)-{>d;sR4| zOA!w>CuDOsHBW2F{kRTEuqwHF{9Gy7+$*`X{kZxhxL(^71dm9r zQ9oB&HjhcJaSzvPiq~t3*Xu^Sj!5uP0;jZN4wr0GC|+U~7MPfz2~XmwpXAMxClpe2 zPY{N5FpId)FpPK_-Cf3TeBT|xpt`rJbK7*1N0+LbMA}=R`_sMM%7#&Uq;HhzOMjtS z(#xxQ%@ptTkI7!M*rumw1!f6JIkAq+P$|B~((jRc zOBJOJTBa`oDy;NKp;3`l>YZC;`n)o8BtuD}j%=0b^UBO2NQTmYUuMWFbDCu6=njw> z^2(eJl%Ye~FEi$qIYTmZ1_#KDd1cN7${cZJ=7~fEv@4SRfMY_a8FGd4b|V&I1x(aK ze%zJ5N_`dT6OZK5A8?{6F77xA7D(oTq!^O#F-#GKkc;DFoow2*a+xrqtv8bGpLvIK z>wn_n2YlJ|WSJvk%=lW_3(UqnhF;fbzwpfYM zn^^v%xaL|Z$dLnDB-ekVJ}QdUH%(6|Lc2|UIs&4xH^dgw2HOwfqcT#-)`7L~sd=sP+*o~$8~$M<>skjEN+%;P8goX0wT zSp(zHv9X2;j*}cEj!lkfjxLTx4wa*qBgN6rVQ}O)u5ldZ7~mM@c*^PekK-J1ju^)w ZjxCO5j@ulg93vd#9M3rJaTGaL{s)dFbl(5~ literal 0 HcmV?d00001 diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/current-classpath/com/example/SomeClass.kt b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/current-classpath/com/example/SomeClass.kt new file mode 100644 index 00000000000..c56aeca601f --- /dev/null +++ b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/current-classpath/com/example/SomeClass.kt @@ -0,0 +1,79 @@ +package com.example + +@Suppress("RedundantGetter", "RedundantSetter") +class SomeClass { + + var property_ChangedType: Long = 0 + get() = field + set(value) { + field = value + } + + var property_ChangedGetterImpl: Int = 0 + get() { + println("Getter implementation has changed!") + return field + } + set(value) { + field = value + } + + var property_ChangedSetterImpl: Int = 0 + get() = field + set(value) { + println("Setter implementation has changed!") + field = value + } + + var property_Unchanged: Int = 0 + get() = field + set(value) { + field = value + } + + private var privateProperty_ChangedType: Long = 0 + get() = field + set(value) { + field = value + } +} + +var inlineProperty_ChangedType_BackingField: Long = 0 +var inlineProperty_ChangedGetterImpl_BackingField: Int = 0 +var inlineProperty_ChangedSetterImpl_BackingField: Int = 0 +var inlineProperty_Unchanged_BackingField: Int = 0 +private var privateInlineProperty_ChangedType_BackingField: Long = 0 + +inline var inlineProperty_ChangedType: Long + get() = inlineProperty_ChangedType_BackingField + set(value) { + inlineProperty_ChangedType_BackingField = value + } + +inline var inlineProperty_ChangedGetterImpl: Int + get() { + println("Getter implementation has changed!") + return inlineProperty_ChangedGetterImpl_BackingField + } + set(value) { + inlineProperty_ChangedGetterImpl_BackingField = value + } + +inline var inlineProperty_ChangedSetterImpl: Int + get() = inlineProperty_ChangedSetterImpl_BackingField + set(value) { + println("Setter implementation has changed!") + inlineProperty_ChangedSetterImpl_BackingField = value + } + +inline var inlineProperty_Unchanged: Int + get() = inlineProperty_Unchanged_BackingField + set(value) { + inlineProperty_Unchanged_BackingField = value + } + +private inline var privateInlineProperty_ChangedType: Long + get() = privateInlineProperty_ChangedType_BackingField + set(value) { + privateInlineProperty_ChangedType_BackingField = value + } diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/previous-classpath/com/example/SomeClass.kt b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/previous-classpath/com/example/SomeClass.kt new file mode 100644 index 00000000000..139820c572d --- /dev/null +++ b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathChangesComputerTest/KotlinOnly/testPropertyAccessors/src/previous-classpath/com/example/SomeClass.kt @@ -0,0 +1,79 @@ +package com.example + +@Suppress("RedundantGetter", "RedundantSetter") +class SomeClass { + + var property_ChangedType: Int = 0 + get() = field + set(value) { + field = value + } + + var property_ChangedGetterImpl: Int = 0 + get() { + println("Getter implementation") + return field + } + set(value) { + field = value + } + + var property_ChangedSetterImpl: Int = 0 + get() = field + set(value) { + println("Setter implementation") + field = value + } + + var property_Unchanged: Int = 0 + get() = field + set(value) { + field = value + } + + private var privateProperty_ChangedType: Int = 0 + get() = field + set(value) { + field = value + } +} + +var inlineProperty_ChangedType_BackingField: Int = 0 +var inlineProperty_ChangedGetterImpl_BackingField: Int = 0 +var inlineProperty_ChangedSetterImpl_BackingField: Int = 0 +var inlineProperty_Unchanged_BackingField: Int = 0 +private var privateInlineProperty_ChangedType_BackingField: Int = 0 + +inline var inlineProperty_ChangedType: Int + get() = inlineProperty_ChangedType_BackingField + set(value) { + inlineProperty_ChangedType_BackingField = value + } + +inline var inlineProperty_ChangedGetterImpl: Int + get() { + println("Getter implementation") + return inlineProperty_ChangedGetterImpl_BackingField + } + set(value) { + inlineProperty_ChangedGetterImpl_BackingField = value + } + +inline var inlineProperty_ChangedSetterImpl: Int + get() = inlineProperty_ChangedSetterImpl_BackingField + set(value) { + println("Setter implementation") + inlineProperty_ChangedSetterImpl_BackingField = value + } + +inline var inlineProperty_Unchanged: Int + get() = inlineProperty_Unchanged_BackingField + set(value) { + inlineProperty_Unchanged_BackingField = value + } + +private inline var privateInlineProperty_ChangedType: Int + get() = privateInlineProperty_ChangedType_BackingField + set(value) { + privateInlineProperty_ChangedType_BackingField = value + } diff --git a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotterTest/kotlin/testSimpleClass/expected-snapshot/com/example/SimpleClass.json b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotterTest/kotlin/testSimpleClass/expected-snapshot/com/example/SimpleClass.json index 88e67fc50cb..29ab0f2dbbf 100644 --- a/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotterTest/kotlin/testSimpleClass/expected-snapshot/com/example/SimpleClass.json +++ b/compiler/incremental-compilation-impl/testData/org/jetbrains/kotlin/incremental/classpathDiff/ClasspathSnapshotterTest/kotlin/testSimpleClass/expected-snapshot/com/example/SimpleClass.json @@ -44,7 +44,7 @@ "publicFunction" ], "constantsMap": {}, - "inlineFunctionsMap": {}, + "inlineFunctionsAndAccessorsMap": {}, "className$delegate": { "initializer": {}, "_value": {} diff --git a/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt b/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt index b44fc10faf8..3bcc2b79c9f 100644 --- a/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt +++ b/compiler/test-infrastructure-utils/tests/org/jetbrains/kotlin/codegen/InlineTestUtil.kt @@ -18,15 +18,15 @@ package org.jetbrains.kotlin.codegen import org.jetbrains.kotlin.backend.common.output.OutputFile import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME -import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames +import org.jetbrains.kotlin.inline.inlineFunctionsAndAccessors import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMemberSignature import org.jetbrains.org.objectweb.asm.* import org.jetbrains.org.objectweb.asm.tree.MethodNode -import java.util.* object InlineTestUtil { fun checkNoCallsToInline( @@ -57,13 +57,13 @@ object InlineTestUtil { val binaryClasses = hashMapOf() for (file in files) { val binaryClass = loadBinaryClass(file) - val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader) + val inlineFunctionsAndAccessors = inlineFunctionsAndAccessors(binaryClass.classHeader) val classVisitor = object : ClassVisitorWithName() { override fun visitMethod( access: Int, name: String, desc: String, signature: String?, exceptions: Array? ): MethodVisitor? { - if (name + desc in inlineFunctions) { + if (JvmMemberSignature.Method(name, desc) in inlineFunctionsAndAccessors) { inlineMethods.add(MethodInfo(className, name, desc)) } return null @@ -81,14 +81,14 @@ object InlineTestUtil { var doLambdaInliningCheck = true for (file in files) { val binaryClass = loadBinaryClass(file) - val inlineFunctions = inlineFunctionsJvmNames(binaryClass.classHeader) + val inlineFunctionsAndAccessors = inlineFunctionsAndAccessors(binaryClass.classHeader) //if inline function creates anonymous object then do not try to check that all lambdas are inlined val classVisitor = object : ClassVisitorWithName() { override fun visitMethod( access: Int, name: String, desc: String, signature: String?, exceptions: Array? ): MethodVisitor? { - if (name + desc in inlineFunctions) { + if (JvmMemberSignature.Method(name, desc) in inlineFunctionsAndAccessors) { return object : MethodNodeWithAnonymousObjectCheck(inlineInfo, access, name, desc, signature, exceptions) { override fun onAnonymousConstructorCallOrSingletonAccess(owner: String) { doLambdaInliningCheck = false