[cls] include property constant initializer in stubs

^KTIJ-24667
this would allow building FirElements from stubs
This commit is contained in:
Anna Kozlova
2023-04-11 19:41:05 +02:00
parent 70ef87354f
commit f0af7c4228
25 changed files with 1032 additions and 80 deletions
@@ -30,7 +30,11 @@ abstract class IntegerValueConstant<out T> protected constructor(value: T) : Con
abstract class UnsignedValueConstant<out T> protected constructor(value: T) : ConstantValue<T>(value)
class AnnotationValue private constructor(value: Value) : ConstantValue<AnnotationValue.Value>(value) {
class Value(val type: KotlinTypeMarker, val argumentsMapping: Map<Name, ConstantValue<*>>)
class Value(val type: KotlinTypeMarker, val argumentsMapping: Map<Name, ConstantValue<*>>) {
override fun toString(): String {
return "Value(type=$type, argumentsMapping=$argumentsMapping)"
}
}
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D): R = visitor.visitAnnotationValue(this, data)
@@ -74,7 +74,8 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any>(
property = true,
field = true,
isConst = Flags.IS_CONST.get(proto.flags),
isMovedFromInterfaceCompanion = JvmProtoBufUtil.isMovedFromInterfaceCompanion(proto)
isMovedFromInterfaceCompanion = JvmProtoBufUtil.isMovedFromInterfaceCompanion(proto),
kotlinClassFinder = kotlinClassFinder, jvmMetadataVersion = jvmMetadataVersion
)
val kotlinClass = findClassWithAnnotationsAndInitializers(container, specialCase) ?: return null
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.TypeProjection
@@ -233,6 +234,7 @@ interface DescriptorRendererOptions {
var boldOnlyForNamesInHtml: Boolean
var includePropertyConstant: Boolean
var propertyConstantRenderer: ((ConstantValue<*>) -> String?)?
var parameterNameRenderingPolicy: ParameterNameRenderingPolicy
var withoutTypeParameters: Boolean
var receiverAfterName: Boolean
@@ -491,9 +491,10 @@ internal class DescriptorRendererImpl(
return (defaultList + argumentList).sorted()
}
private fun renderConstant(value: ConstantValue<*>): String {
private fun renderConstant(value: ConstantValue<*>): String? {
options.propertyConstantRenderer?.let { return it.invoke(value) }
return when (value) {
is ArrayValue -> value.value.joinToString(", ", "{", "}") { renderConstant(it) }
is ArrayValue -> value.value.mapNotNull { renderConstant(it) }.joinToString(", ", "{", "}")
is AnnotationValue -> renderAnnotation(value.value).removePrefix("@")
is KClassValue -> when (val classValue = value.value) {
is KClassValue.Value.LocalClass -> "${classValue.type}::class"
@@ -986,7 +987,8 @@ internal class DescriptorRendererImpl(
private fun renderInitializer(variable: VariableDescriptor, builder: StringBuilder) {
if (includePropertyConstant) {
variable.compileTimeInitializer?.let { constant ->
builder.append(" = ").append(escape(renderConstant(constant)))
val renderedConstant = renderConstant(constant)
if (renderedConstant != null) builder.append(" = ").append(escape(renderedConstant))
}
}
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.types.KotlinType
import java.lang.IllegalStateException
import java.lang.reflect.Modifier
@@ -87,6 +88,7 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions {
override var actualPropertiesInPrimaryConstructor: Boolean by property(false)
override var uninferredTypeParameterAsName by property(false)
override var includePropertyConstant by property(false)
override var propertyConstantRenderer: ((ConstantValue<*>) -> String?)? by property(null)
override var withoutTypeParameters by property(false)
override var withoutSuperTypes by property(false)
override var typeNormalizer by property<(KotlinType) -> KotlinType>({ it })
@@ -140,7 +140,8 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
property,
field,
isConst,
isMovedFromInterfaceCompanion
isMovedFromInterfaceCompanion,
kotlinClassFinder, jvmMetadataVersion
)
)
?: return listOf()
@@ -210,56 +211,6 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
}
}
// TODO: do not use KotlinClassFinder#findKotlinClass here because it traverses the file system in the compiler
// Introduce an API in KotlinJvmBinaryClass to find a class nearby instead
protected fun getSpecialCaseContainerClass(
container: ProtoContainer,
property: Boolean,
field: Boolean,
isConst: Boolean?,
isMovedFromInterfaceCompanion: Boolean
): KotlinJvmBinaryClass? {
if (property) {
checkNotNull(isConst) { "isConst should not be null for property (container=$container)" }
if (container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) {
return kotlinClassFinder.findKotlinClass(
container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)),
jvmMetadataVersion
)
}
if (isConst && container is ProtoContainer.Package) {
// Const properties in multifile classes are generated into the facade class
val facadeClassName = (container.source as? JvmPackagePartSource)?.facadeClassName
if (facadeClassName != null) {
// Converting '/' to '.' is fine here because the facade class has a top level ClassId
return kotlinClassFinder.findKotlinClass(
ClassId.topLevel(FqName(facadeClassName.internalName.replace('/', '.'))),
jvmMetadataVersion
)
}
}
}
if (field && container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.COMPANION_OBJECT) {
val outerClass = container.outerClass
if (outerClass != null &&
(outerClass.kind == ProtoBuf.Class.Kind.CLASS || outerClass.kind == ProtoBuf.Class.Kind.ENUM_CLASS ||
(isMovedFromInterfaceCompanion &&
(outerClass.kind == ProtoBuf.Class.Kind.INTERFACE ||
outerClass.kind == ProtoBuf.Class.Kind.ANNOTATION_CLASS)))
) {
// Backing fields of properties of a companion object in a class are generated in the outer class
return outerClass.toBinaryClass()
}
}
if (container is ProtoContainer.Package && container.source is JvmPackagePartSource) {
val jvmPackagePartSource = container.source as JvmPackagePartSource
return jvmPackagePartSource.knownJvmBinaryClass
?: kotlinClassFinder.findKotlinClass(jvmPackagePartSource.classId, jvmMetadataVersion)
}
return null
}
protected fun getCallableSignature(
proto: MessageLite,
nameResolver: NameResolver,
@@ -304,6 +255,58 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
abstract class AnnotationsContainer<out A> {
abstract val memberAnnotations: Map<MemberSignature, List<A>>
}
companion object {
fun getSpecialCaseContainerClass(
container: ProtoContainer,
property: Boolean,
field: Boolean,
isConst: Boolean?,
isMovedFromInterfaceCompanion: Boolean,
kotlinClassFinder: KotlinClassFinder,
jvmMetadataVersion: JvmMetadataVersion
): KotlinJvmBinaryClass? {
if (property) {
checkNotNull(isConst) { "isConst should not be null for property (container=$container)" }
if (container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) {
return kotlinClassFinder.findKotlinClass(
container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)),
jvmMetadataVersion
)
}
if (isConst && container is ProtoContainer.Package) {
// Const properties in multifile classes are generated into the facade class
val facadeClassName = (container.source as? JvmPackagePartSource)?.facadeClassName
if (facadeClassName != null) {
// Converting '/' to '.' is fine here because the facade class has a top level ClassId
return kotlinClassFinder.findKotlinClass(
ClassId.topLevel(FqName(facadeClassName.internalName.replace('/', '.'))),
jvmMetadataVersion
)
}
}
}
if (field && container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.COMPANION_OBJECT) {
val outerClass = container.outerClass
if (outerClass != null &&
(outerClass.kind == ProtoBuf.Class.Kind.CLASS || outerClass.kind == ProtoBuf.Class.Kind.ENUM_CLASS ||
(isMovedFromInterfaceCompanion &&
(outerClass.kind == ProtoBuf.Class.Kind.INTERFACE ||
outerClass.kind == ProtoBuf.Class.Kind.ANNOTATION_CLASS)))
) {
// Backing fields of properties of a companion object in a class are generated in the outer class
return (outerClass.source as? KotlinJvmBinarySourceElement)?.binaryClass
}
}
if (container is ProtoContainer.Package && container.source is JvmPackagePartSource) {
val jvmPackagePartSource = container.source as JvmPackagePartSource
return jvmPackagePartSource.knownJvmBinaryClass
?: kotlinClassFinder.findKotlinClass(jvmPackagePartSource.classId, jvmMetadataVersion)
}
return null
}
}
}
fun getPropertySignature(