From 170277573878298c3b8c49c3e864060281c87e36 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Tue, 7 Nov 2017 12:37:34 +0300 Subject: [PATCH] Introduce JavaClassesSerializerExtension It will be used to track java classes changes for incremental compilation #KT-17621 In Progress --- .../JavaClassesSerializerExtension.kt | 81 +++++++++++++++++++ .../serialization/DescriptorSerializer.kt | 63 +++++++++------ .../serialization/SerializerExtension.kt | 9 +++ 3 files changed, 127 insertions(+), 26 deletions(-) create mode 100644 build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt diff --git a/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt new file mode 100644 index 00000000000..9c1ef527a13 --- /dev/null +++ b/build-common/src/org/jetbrains/kotlin/incremental/JavaClassesSerializerExtension.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.incremental + +import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.load.java.JavaVisibilities +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.serialization.DescriptorSerializer +import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase +import org.jetbrains.kotlin.serialization.ProtoBuf +import org.jetbrains.kotlin.serialization.java.JavaClassProtoBuf + +// It uses BuiltInSerializerProtocol for annotations serialization +class JavaClassesSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) { + override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) { + super.serializeClass(descriptor, proto) + if (descriptor.visibility == JavaVisibilities.PACKAGE_VISIBILITY) { + proto.setExtension(JavaClassProtoBuf.isPackagePrivateClass, true) + } + } + + override fun serializeConstructor(descriptor: ConstructorDescriptor, proto: ProtoBuf.Constructor.Builder) { + super.serializeConstructor(descriptor, proto) + if (descriptor.visibility == JavaVisibilities.PACKAGE_VISIBILITY) { + proto.setExtension(JavaClassProtoBuf.isPackagePrivateConstructor, true) + } + } + + override fun serializeFunction(descriptor: FunctionDescriptor, proto: ProtoBuf.Function.Builder) { + super.serializeFunction(descriptor, proto) + if (descriptor.visibility == JavaVisibilities.PACKAGE_VISIBILITY) { + proto.setExtension(JavaClassProtoBuf.isPackagePrivateMethod, true) + } + + if (descriptor.dispatchReceiverParameter == null) { + proto.setExtension(JavaClassProtoBuf.isStaticMethod, true) + } + } + + override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder) { + super.serializeProperty(descriptor, proto) + if (descriptor.visibility == JavaVisibilities.PACKAGE_VISIBILITY) { + proto.setExtension(JavaClassProtoBuf.isPackagePrivateField, true) + } + + if (descriptor.dispatchReceiverParameter == null) { + proto.setExtension(JavaClassProtoBuf.isStaticField, true) + } + } + + override fun shouldUseNormalizedVisibility() = true + + override val customClassMembersProducer = + object : ClassMembersProducer { + override fun getCallableMembers(classDescriptor: ClassDescriptor) = + arrayListOf().apply { + addAll(classDescriptor.unsubstitutedMemberScope.getSortedCallableDescriptors()) + addAll(classDescriptor.staticScope.getSortedCallableDescriptors()) + } + } + + private fun MemberScope.getSortedCallableDescriptors(): Collection = + DescriptorUtils.getAllDescriptors(this).filterIsInstance() + .let { DescriptorSerializer.sort(it) } +} diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index 13482c98db1..ece8ed5b2f7 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -71,7 +71,7 @@ class DescriptorSerializer private constructor( val builder = ProtoBuf.Class.newBuilder() val flags = Flags.getClassFlags( - hasAnnotations(classDescriptor), classDescriptor.visibility, classDescriptor.modality, classDescriptor.kind, + hasAnnotations(classDescriptor), normalizeVisibility(classDescriptor), classDescriptor.modality, classDescriptor.kind, classDescriptor.isInner, classDescriptor.isCompanionObject, classDescriptor.isData, classDescriptor.isExternal, classDescriptor.isExpect ) @@ -101,18 +101,24 @@ class DescriptorSerializer private constructor( builder.addConstructor(constructorProto(descriptor)) } - for (descriptor in sort(DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope))) { - if (descriptor is CallableMemberDescriptor) { - if (descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue + val callableMembers = + extension.customClassMembersProducer?.getCallableMembers(classDescriptor) + ?: sort( + DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope) + .filterIsInstance() + ) - when (descriptor) { - is PropertyDescriptor -> builder.addProperty(propertyProto(descriptor)) - is FunctionDescriptor -> builder.addFunction(functionProto(descriptor)) - } + for (descriptor in callableMembers) { + if (descriptor.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue + + when (descriptor) { + is PropertyDescriptor -> builder.addProperty(propertyProto(descriptor)) + is FunctionDescriptor -> builder.addFunction(functionProto(descriptor)) } } - for (descriptor in sort(DescriptorUtils.getAllDescriptors(classDescriptor.unsubstitutedInnerClassesScope))) { + val nestedClassifiers = sort(DescriptorUtils.getAllDescriptors(classDescriptor.unsubstitutedInnerClassesScope)) + for (descriptor in nestedClassifiers) { if (descriptor is TypeAliasDescriptor) { builder.addTypeAlias(typeAliasProto(descriptor)) } @@ -168,7 +174,7 @@ class DescriptorSerializer private constructor( val hasAnnotations = descriptor.annotations.getAllAnnotations().isNotEmpty() - val propertyFlags = Flags.getAccessorFlags(hasAnnotations, descriptor.visibility, descriptor.modality, false, false, false) + val propertyFlags = Flags.getAccessorFlags(hasAnnotations, normalizeVisibility(descriptor), descriptor.modality, false, false, false) val getter = descriptor.getter if (getter != null) { @@ -196,7 +202,7 @@ class DescriptorSerializer private constructor( } val flags = Flags.getPropertyFlags( - hasAnnotations, descriptor.visibility, descriptor.modality, descriptor.kind, descriptor.isVar, + hasAnnotations, normalizeVisibility(descriptor), descriptor.modality, descriptor.kind, descriptor.isVar, hasGetter, hasSetter, hasConstant, descriptor.isConst, descriptor.isLateInit, descriptor.isExternal, @Suppress("DEPRECATION") descriptor.isDelegated, descriptor.isExpect ) @@ -240,13 +246,20 @@ class DescriptorSerializer private constructor( return builder } + private fun normalizeVisibility(descriptor: DeclarationDescriptorWithVisibility) = + // It can be necessary for Java classes serialization having package-private visibility + if (extension.shouldUseNormalizedVisibility()) + descriptor.visibility.normalize() + else + descriptor.visibility + fun functionProto(descriptor: FunctionDescriptor): ProtoBuf.Function.Builder { val builder = ProtoBuf.Function.newBuilder() val local = createChildSerializer(descriptor) val flags = Flags.getFunctionFlags( - hasAnnotations(descriptor), descriptor.visibility, descriptor.modality, descriptor.kind, descriptor.isOperator, + hasAnnotations(descriptor), normalizeVisibility(descriptor), descriptor.modality, descriptor.kind, descriptor.isOperator, descriptor.isInfix, descriptor.isInline, descriptor.isTailrec, descriptor.isExternal, descriptor.isSuspend, descriptor.isExpect ) @@ -308,7 +321,7 @@ class DescriptorSerializer private constructor( val local = createChildSerializer(descriptor) - val flags = Flags.getConstructorFlags(hasAnnotations(descriptor), descriptor.visibility, !descriptor.isPrimary) + val flags = Flags.getConstructorFlags(hasAnnotations(descriptor), normalizeVisibility(descriptor), !descriptor.isPrimary) if (flags != builder.flags) { builder.flags = flags } @@ -344,7 +357,7 @@ class DescriptorSerializer private constructor( val builder = ProtoBuf.TypeAlias.newBuilder() val local = createChildSerializer(descriptor) - val flags = Flags.getTypeAliasFlags(hasAnnotations(descriptor), descriptor.visibility) + val flags = Flags.getTypeAliasFlags(hasAnnotations(descriptor), normalizeVisibility(descriptor)) if (flags != builder.flags) { builder.flags = flags } @@ -664,7 +677,16 @@ class DescriptorSerializer private constructor( private fun getTypeParameterId(descriptor: TypeParameterDescriptor): Int = typeParameters.intern(descriptor) - + private fun getAccessorFlags(accessor: PropertyAccessorDescriptor): Int { + return Flags.getAccessorFlags( + hasAnnotations(accessor), + normalizeVisibility(accessor), + accessor.modality, + !accessor.isDefault, + accessor.isExternal, + accessor.isInline + ) + } companion object { @JvmStatic @@ -704,17 +726,6 @@ class DescriptorSerializer private constructor( return serializer } - private fun getAccessorFlags(accessor: PropertyAccessorDescriptor): Int { - return Flags.getAccessorFlags( - hasAnnotations(accessor), - accessor.visibility, - accessor.modality, - !accessor.isDefault, - accessor.isExternal, - accessor.isInline - ) - } - private fun variance(variance: Variance): ProtoBuf.TypeParameter.Variance = when (variance) { Variance.INVARIANT -> ProtoBuf.TypeParameter.Variance.INV Variance.IN_VARIANCE -> ProtoBuf.TypeParameter.Variance.IN diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt index 9da320b774f..7f3d3391027 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtension.kt @@ -27,6 +27,15 @@ abstract class SerializerExtension { val annotationSerializer by lazy { AnnotationSerializer(stringTable) } open fun shouldUseTypeTable(): Boolean = false + open fun shouldUseNormalizedVisibility(): Boolean = false + + interface ClassMembersProducer { + fun getCallableMembers(classDescriptor: ClassDescriptor): Collection + } + + open val customClassMembersProducer: ClassMembersProducer? + get() = null + open fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) { }