Do not store ClassDescriptor in EnumValue

Only store the ClassId of the enum class and the Name of the entry, and
resolve the needed descriptor in getType() instead, which now takes the
module instance where that descriptor should be resolved
This commit is contained in:
Alexander Udalov
2017-12-29 16:45:34 +01:00
parent 9290d58ed0
commit 82574cb570
25 changed files with 99 additions and 167 deletions
@@ -438,7 +438,7 @@ public abstract class AnnotationCodegen {
}
@Nullable
private Set<ElementType> getJavaTargetList(ClassDescriptor descriptor) {
private static Set<ElementType> getJavaTargetList(ClassDescriptor descriptor) {
AnnotationDescriptor targetAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Target.class.getName()));
if (targetAnnotation != null) {
Collection<ConstantValue<?>> valueArguments = targetAnnotation.getAllValueArguments().values();
@@ -449,12 +449,9 @@ public abstract class AnnotationCodegen {
Set<ElementType> result = EnumSet.noneOf(ElementType.class);
for (ConstantValue<?> value : values) {
if (value instanceof EnumValue) {
ClassDescriptor enumEntry = ((EnumValue) value).getValue();
KotlinType classObjectType = DescriptorUtilsKt.getClassValueType(enumEntry);
if (classObjectType != null) {
if ("java/lang/annotation/ElementType".equals(typeMapper.mapType(classObjectType).getInternalName())) {
result.add(ElementType.valueOf(enumEntry.getName().asString()));
}
FqName enumClassFqName = ((EnumValue) value).getEnumClassId().asSingleFqName();
if (ElementType.class.getName().equals(enumClassFqName.asString())) {
result.add(ElementType.valueOf(((EnumValue) value).getEnumEntryName().asString()));
}
}
}
@@ -466,21 +463,18 @@ public abstract class AnnotationCodegen {
}
@NotNull
private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
private static RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
KotlinRetention retention = DescriptorUtilsKt.getAnnotationRetention(descriptor);
if (retention != null) {
return annotationRetentionMap.get(retention);
}
AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
if (retentionAnnotation != null) {
ConstantValue<?> compileTimeConstant = CollectionsKt.firstOrNull(retentionAnnotation.getAllValueArguments().values());
if (compileTimeConstant instanceof EnumValue) {
ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
KotlinType classObjectType = DescriptorUtilsKt.getClassValueType(enumEntry);
if (classObjectType != null) {
if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) {
return RetentionPolicy.valueOf(enumEntry.getName().asString());
}
ConstantValue<?> value = CollectionsKt.firstOrNull(retentionAnnotation.getAllValueArguments().values());
if (value instanceof EnumValue) {
FqName enumClassFqName = ((EnumValue) value).getEnumClassId().asSingleFqName();
if (RetentionPolicy.class.getName().equals(enumClassFqName.asString())) {
return RetentionPolicy.valueOf(((EnumValue) value).getEnumEntryName().asString());
}
}
}
@@ -59,16 +59,18 @@ class JvmStringTable(private val typeMapper: KotlinTypeMapper) : StringTable {
throw IllegalStateException("Cannot get FQ name of error class: " + descriptor)
}
// We use the following format to encode ClassId: "pkg/Outer.Inner".
// It represents a unique name, but such names don't usually appear in the constant pool, so we're writing "Lpkg/Outer$Inner;"
// instead and an instruction to drop the first and the last character in this string and replace all '$' with '.'.
// This works most of the time, except in two rare cases:
// - the name of the class or any of its outer classes contains dollars. In this case we're just storing the described
// string literally: "pkg/Outer.Inner$with$dollars"
// - the class is local or nested in local. In this case we're also storing the literal string, and also storing the fact that
// this name represents a local class in a separate list
return getClassIdIndex(descriptor.classId)
}
val classId = descriptor.classId
// We use the following format to encode ClassId: "pkg/Outer.Inner".
// It represents a unique name, but such names don't usually appear in the constant pool, so we're writing "Lpkg/Outer$Inner;"
// instead and an instruction to drop the first and the last character in this string and replace all '$' with '.'.
// This works most of the time, except in two rare cases:
// - the name of the class or any of its outer classes contains dollars. In this case we're just storing the described
// string literally: "pkg/Outer.Inner$with$dollars"
// - the class is local or nested in local. In this case we're also storing the literal string, and also storing the fact that
// this name represents a local class in a separate list
override fun getClassIdIndex(classId: ClassId): Int {
val string = classId.asString()
map[string]?.let { recordedIndex ->
@@ -108,11 +108,11 @@ public class MappingClassesForWhenByEnumCodegen {
v.putstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
for (Map.Entry<EnumValue, Integer> item : mapping.enumValuesToIntMapping()) {
EnumValue enumEntry = item.getKey();
EnumValue enumValue = item.getKey();
int mappedValue = item.getValue();
v.getstatic(cb.getThisName(), mapping.getFieldName(), MAPPINGS_FIELD_DESCRIPTOR);
v.getstatic(enumType.getInternalName(), enumEntry.getValue().getName().asString(), enumType.getDescriptor());
v.getstatic(enumType.getInternalName(), enumValue.getEnumEntryName().asString(), enumType.getDescriptor());
v.invokevirtual(enumType.getInternalName(), "ordinal", Type.getMethodDescriptor(Type.INT_TYPE), false);
v.iconst(mappedValue);
v.astore(Type.INT_TYPE);
@@ -208,7 +208,7 @@ class AnnotationChecker(
val valueArguments = targetEntryDescriptor.allValueArguments
val valueArgument = valueArguments.entries.firstOrNull()?.value as? ArrayValue ?: return null
return valueArgument.value.filterIsInstance<EnumValue>().mapNotNull {
KotlinTarget.valueOrNull(it.value.name.asString())
KotlinTarget.valueOrNull(it.enumEntryName.asString())
}.toSet()
}
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
@@ -662,7 +663,8 @@ private class ConstantExpressionEvaluatorVisitor(
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, expectedType: KotlinType?): CompileTimeConstant<*>? {
val enumDescriptor = trace.bindingContext.get(BindingContext.REFERENCE_TARGET, expression)
if (enumDescriptor != null && DescriptorUtils.isEnumEntry(enumDescriptor)) {
return ConstantValueFactory.createEnumValue(enumDescriptor as ClassDescriptor).wrap()
val enumClassId = (enumDescriptor.containingDeclaration as ClassDescriptor).classId ?: return null
return EnumValue(enumClassId, enumDescriptor.name).wrap()
}
val resolvedCall = expression.getResolvedCall(trace.bindingContext)
@@ -78,9 +78,8 @@ class AnnotationSerializer(private val stringTable: StringTable) {
override fun visitEnumValue(value: EnumValue, data: Unit) {
type = Type.ENUM
val enumEntry = value.value
classId = stringTable.getFqNameIndex(enumEntry.containingDeclaration as ClassDescriptor)
enumValueId = stringTable.getStringIndex(enumEntry.name.asString())
classId = stringTable.getClassIdIndex(value.enumClassId)
enumValueId = stringTable.getStringIndex(value.enumEntryName.asString())
}
override fun visitErrorValue(value: ErrorValue, data: Unit) {
@@ -644,19 +644,19 @@ class DescriptorSerializer private constructor(
proto.message = stringTable.getStringIndex(message)
}
val level = (args[RequireKotlinNames.LEVEL] as? EnumValue)?.value?.name?.asString()
val level = (args[RequireKotlinNames.LEVEL] as? EnumValue)?.enumEntryName?.asString()
when (level) {
DeprecationLevel.ERROR.toString() -> { /* ERROR is the default level */ }
DeprecationLevel.WARNING.toString() -> proto.level = ProtoBuf.VersionRequirement.Level.WARNING
DeprecationLevel.HIDDEN.toString() -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN
DeprecationLevel.ERROR.name -> { /* ERROR is the default level */ }
DeprecationLevel.WARNING.name -> proto.level = ProtoBuf.VersionRequirement.Level.WARNING
DeprecationLevel.HIDDEN.name -> proto.level = ProtoBuf.VersionRequirement.Level.HIDDEN
}
val versionKind = (args[RequireKotlinNames.VERSION_KIND] as? EnumValue)?.value?.name?.asString()
val versionKind = (args[RequireKotlinNames.VERSION_KIND] as? EnumValue)?.enumEntryName?.asString()
when (versionKind) {
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.toString() -> { /* LANGUAGE_VERSION is the default kind */ }
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION.toString() ->
ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION.name -> { /* LANGUAGE_VERSION is the default kind */ }
ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION.name ->
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION
ProtoBuf.VersionRequirement.VersionKind.API_VERSION.toString() ->
ProtoBuf.VersionRequirement.VersionKind.API_VERSION.name ->
proto.versionKind = ProtoBuf.VersionRequirement.VersionKind.API_VERSION
}
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.name.ClassId
import java.io.OutputStream
interface StringTable {
@@ -24,5 +25,7 @@ interface StringTable {
fun getFqNameIndex(descriptor: ClassifierDescriptorWithTypeParameters): Int
fun getClassIdIndex(classId: ClassId): Int
fun serializeTo(output: OutputStream)
}
@@ -62,7 +62,7 @@ open class StringTableImpl : StringTable {
return getClassIdIndex(classId)
}
fun getClassIdIndex(classId: ClassId): Int {
override fun getClassIdIndex(classId: ClassId): Int {
val builder = QualifiedName.newBuilder()
builder.kind = QualifiedName.Kind.CLASS
@@ -5,7 +5,7 @@ public final annotation class Anno : kotlin.Annotation {
public final val e: test.E
}
@test.Anno(e = Unresolved enum entry: test/E.ENTRY) public open class Class {
@test.Anno(e = E.ENTRY) public open class Class {
public constructor Class()
}
@@ -169,8 +169,7 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() {
it.allValueArguments.forEach {
val argument = it.value
if (argument is EnumValue) {
Assert.assertEquals("Enum entry name should be <module-name>X", "X", argument.value.name.identifier.last().toString())
checkDescriptor(argument.value, callable)
Assert.assertEquals("Enum entry name should be <module-name>X", "X", argument.enumEntryName.identifier.last().toString())
}
}
}
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.utils.Jsr305State
import org.jetbrains.kotlin.utils.ReportLevel
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
private val TYPE_QUALIFIER_NICKNAME_FQNAME = FqName("javax.annotation.meta.TypeQualifierNickname")
private val TYPE_QUALIFIER_FQNAME = FqName("javax.annotation.meta.TypeQualifier")
@@ -148,12 +147,12 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va
}
private fun ClassDescriptor.migrationAnnotationStatus(): ReportLevel? {
val stateDescriptor = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgument()?.safeAs<EnumValue>()?.value
?: return null
val enumValue = annotations.findAnnotation(MIGRATION_ANNOTATION_FQNAME)?.firstArgument() as? EnumValue
?: return null
jsr305State.migration?.let { return jsr305State.migration }
jsr305State.migration?.let { return it }
return when (stateDescriptor.name.asString()) {
return when (enumValue.enumEntryName.asString()) {
"STRICT" -> ReportLevel.STRICT
"WARN" -> ReportLevel.WARN
"IGNORE" -> ReportLevel.IGNORE
@@ -165,7 +164,7 @@ class AnnotationTypeQualifierResolver(storageManager: StorageManager, private va
when (this) {
is ArrayValue -> value.flatMap { it.mapConstantToQualifierApplicabilityTypes() }
is EnumValue -> listOfNotNull(
when (value.name.identifier) {
when (enumEntryName.identifier) {
"METHOD" -> QualifierApplicabilityType.METHOD_RETURN_TYPE
"FIELD" -> QualifierApplicabilityType.FIELD
"PARAMETER" -> QualifierApplicabilityType.VALUE_PARAMETER
@@ -124,8 +124,8 @@ class JavaTargetAnnotationDescriptor(
): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.target) {
override val allValueArguments by c.storageManager.createLazyValue {
val targetArgument = when (firstArgument) {
is JavaArrayAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(firstArgument.getElements(), c.module.builtIns)
is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(listOf(firstArgument), c.module.builtIns)
is JavaArrayAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(firstArgument.getElements())
is JavaEnumValueAnnotationArgument -> JavaAnnotationTargetMapper.mapJavaTargetArguments(listOf(firstArgument))
else -> null
}
targetArgument?.let { mapOf(JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS to it) }.orEmpty()
@@ -137,7 +137,7 @@ class JavaRetentionAnnotationDescriptor(
c: LazyJavaResolverContext
): JavaAnnotationDescriptor(c, annotation, KotlinBuiltIns.FQ_NAMES.retention) {
override val allValueArguments by c.storageManager.createLazyValue {
val retentionArgument = JavaAnnotationTargetMapper.mapJavaRetentionArgument(firstArgument, c.module.builtIns)
val retentionArgument = JavaAnnotationTargetMapper.mapJavaRetentionArgument(firstArgument)
retentionArgument?.let { mapOf(JavaAnnotationMapper.RETENTION_ANNOTATION_VALUE to it) }.orEmpty()
}
}
@@ -159,17 +159,20 @@ object JavaAnnotationTargetMapper {
fun mapJavaTargetArgumentByName(argumentName: String?): Set<KotlinTarget> = targetNameLists[argumentName] ?: emptySet()
internal fun mapJavaTargetArguments(arguments: List<JavaAnnotationArgument>, builtIns: KotlinBuiltIns): ConstantValue<*> {
internal fun mapJavaTargetArguments(arguments: List<JavaAnnotationArgument>): ConstantValue<*> {
// Map arguments: java.lang.annotation.Target -> kotlin.annotation.Target
val kotlinTargets = arguments.filterIsInstance<JavaEnumValueAnnotationArgument>()
.flatMap { mapJavaTargetArgumentByName(it.entryName?.asString()) }
.mapNotNull { builtIns.getAnnotationTargetEnumEntry(it) }
.map(::EnumValue)
val parameterDescriptor = DescriptorResolverUtils.getAnnotationParameterByName(
JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS,
builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.target)
)
return ArrayValue(kotlinTargets) { parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]") }
.map { kotlinTarget ->
EnumValue(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.annotationTarget), Name.identifier(kotlinTarget.name))
}
return ArrayValue(kotlinTargets) { module ->
val parameterDescriptor = DescriptorResolverUtils.getAnnotationParameterByName(
JavaAnnotationMapper.TARGET_ANNOTATION_ALLOWED_TARGETS,
module.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.target)
)
parameterDescriptor?.type ?: ErrorUtils.createErrorType("Error: AnnotationTarget[]")
}
}
private val retentionNameList = mapOf(
@@ -178,11 +181,11 @@ object JavaAnnotationTargetMapper {
"SOURCE" to KotlinRetention.SOURCE
)
internal fun mapJavaRetentionArgument(element: JavaAnnotationArgument?, builtIns: KotlinBuiltIns): ConstantValue<*>? {
// Map argument: java.lang.annotation.Retention -> kotlin.annotation.annotation
internal fun mapJavaRetentionArgument(element: JavaAnnotationArgument?): ConstantValue<*>? {
// Map argument: java.lang.annotation.Retention -> kotlin.annotation.Retention
return (element as? JavaEnumValueAnnotationArgument)?.let {
retentionNameList[it.entryName?.asString()]?.let {
builtIns.getAnnotationRetentionEnumEntry(it)?.let(::EnumValue)
retentionNameList[it.entryName?.asString()]?.let { retention ->
EnumValue(ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.annotationRetention), Name.identifier(retention.name))
}
}
}
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.load.java.lazy.descriptors
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.findNonGenericClassAcrossDependencies
@@ -34,6 +33,7 @@ import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
import org.jetbrains.kotlin.storage.getValue
@@ -98,21 +98,9 @@ class LazyJavaAnnotationDescriptor(
}
private fun resolveFromEnumValue(enumClassId: ClassId?, entryName: Name?): ConstantValue<*>? {
if (entryName == null) return null
if (enumClassId == null || entryName == null) return null
if (enumClassId == null) {
return ConstantValueFactory.createEnumValue(ErrorUtils.createErrorClassWithExactName(entryName))
}
val enumClass = c.module.findNonGenericClassAcrossDependencies(
enumClassId,
c.components.deserializedDescriptorResolver.components.notFoundClasses
)
val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(entryName, NoLookupLocation.FROM_JAVA_LOADER)
as? ClassDescriptor ?: return null
return ConstantValueFactory.createEnumValue(classifier)
return EnumValue(enumClassId, entryName)
}
private fun resolveFromJavaClassObjectType(javaType: JavaType): ConstantValue<*>? {
@@ -50,11 +50,11 @@ class SignatureEnhancement(
) {
private fun AnnotationDescriptor.extractNullabilityTypeFromArgument(): NullabilityQualifierWithMigrationStatus? {
val enumEntryDescriptor = firstArgument().safeAs<EnumValue>()?.value
// if no argument is specified, use default value: NOT_NULL
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
val enumValue = firstArgument() as? EnumValue
// if no argument is specified, use default value: NOT_NULL
?: return NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
return when (enumEntryDescriptor.name.asString()) {
return when (enumValue.enumEntryName.asString()) {
"ALWAYS" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NOT_NULL)
"MAYBE", "NEVER" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.NULLABLE)
"UNKNOWN" -> NullabilityQualifierWithMigrationStatus(NullabilityQualifier.FORCE_FLEXIBILITY)
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor
import org.jetbrains.kotlin.name.ClassId
@@ -29,6 +28,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.AnnotationDeserializer
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
@@ -97,7 +97,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
}
override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) {
arguments[name] = enumEntryValue(enumClassId, enumEntryName)
arguments[name] = EnumValue(enumClassId, enumEntryName)
}
override fun visitArray(name: Name): AnnotationArrayArgumentVisitor? {
@@ -109,7 +109,7 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
}
override fun visitEnum(enumClassId: ClassId, enumEntryName: Name) {
elements.add(enumEntryValue(enumClassId, enumEntryName))
elements.add(EnumValue(enumClassId, enumEntryName))
}
override fun visitEnd() {
@@ -132,18 +132,6 @@ class BinaryClassAnnotationAndConstantLoaderImpl(
}
}
// NOTE: see analogous code in AnnotationDeserializer
private fun enumEntryValue(enumClassId: ClassId, name: Name): ConstantValue<*> {
val enumClass = resolveClass(enumClassId)
if (enumClass.kind == ClassKind.ENUM_CLASS) {
val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(name, NoLookupLocation.FROM_JAVA_LOADER)
if (classifier is ClassDescriptor) {
return ConstantValueFactory.createEnumValue(classifier)
}
}
return ConstantValueFactory.createErrorValue("Unresolved enum entry: $enumClassId.$name")
}
override fun visitEnd() {
result.add(AnnotationDescriptorImpl(annotationClass.defaultType, arguments, source))
}
@@ -26,8 +26,6 @@ import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget;
import org.jetbrains.kotlin.descriptors.deserialization.AdditionalClassPartsProvider;
import org.jetbrains.kotlin.descriptors.deserialization.ClassDescriptorFactory;
import org.jetbrains.kotlin.descriptors.deserialization.PlatformDependentDeclarationFilter;
@@ -574,29 +572,6 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByName("Throwable");
}
@Nullable
private static ClassDescriptor getEnumEntry(@NotNull ClassDescriptor enumDescriptor, @NotNull String entryName) {
ClassifierDescriptor result = enumDescriptor.getUnsubstitutedInnerClassesScope().getContributedClassifier(
Name.identifier(entryName), NoLookupLocation.FROM_BUILTINS
);
return result instanceof ClassDescriptor ? (ClassDescriptor) result : null;
}
@Nullable
public ClassDescriptor getDeprecationLevelEnumEntry(@NotNull String level) {
return getEnumEntry(getBuiltInClassByName(FQ_NAMES.deprecationLevel.shortName()), level);
}
@Nullable
public ClassDescriptor getAnnotationTargetEnumEntry(@NotNull KotlinTarget target) {
return getEnumEntry(getAnnotationClassByName(FQ_NAMES.annotationTarget.shortName()), target.name());
}
@Nullable
public ClassDescriptor getAnnotationRetentionEnumEntry(@NotNull KotlinRetention retention) {
return getEnumEntry(getAnnotationClassByName(FQ_NAMES.annotationRetention.shortName()), retention.name());
}
@NotNull
public ClassDescriptor getString() {
return getBuiltInClassByName("String");
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -52,7 +53,10 @@ fun KotlinBuiltIns.createDeprecatedAnnotation(
mapOf(
DEPRECATED_MESSAGE_NAME to StringValue(message),
DEPRECATED_REPLACE_WITH_NAME to AnnotationValue(replaceWithAnnotation),
DEPRECATED_LEVEL_NAME to EnumValue(getDeprecationLevelEnumEntry(level) ?: error("Deprecation level $level not found"))
DEPRECATED_LEVEL_NAME to EnumValue(
ClassId.topLevel(KotlinBuiltIns.FQ_NAMES.deprecationLevel),
Name.identifier(level)
)
)
)
}
@@ -45,6 +45,8 @@ import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
private val RETENTION_PARAMETER_NAME = Name.identifier("value")
fun ClassDescriptor.getClassObjectReferenceTarget(): ClassDescriptor = companionObjectDescriptor ?: this
fun DeclarationDescriptor.getImportableDescriptor(): DeclarationDescriptor {
@@ -216,11 +218,10 @@ fun Annotated.isDocumentedAnnotation(): Boolean =
annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.mustBeDocumented) != null
fun Annotated.getAnnotationRetention(): KotlinRetention? {
val retentionArgumentValue = annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.retention)
?.allValueArguments
?.get(Name.identifier("value"))
as? EnumValue ?: return null
return KotlinRetention.valueOf(retentionArgumentValue.value.name.asString())
val retentionArgumentValue =
annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.retention)?.allValueArguments?.get(RETENTION_PARAMETER_NAME)
as? EnumValue ?: return null
return KotlinRetention.valueOf(retentionArgumentValue.enumEntryName.asString())
}
val DeclarationDescriptor.parentsWithSelf: Sequence<DeclarationDescriptor>
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.resolve.constants
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.types.KotlinType
@@ -47,8 +46,6 @@ object ConstantValueFactory {
fun createNullValue() = NullValue()
fun createEnumValue(enumEntryClass: ClassDescriptor): EnumValue = EnumValue(enumEntryClass)
fun createArrayValue(value: List<ConstantValue<*>>, type: KotlinType) = createArrayValue(value) { type }
fun createAnnotationValue(value: AnnotationDescriptor) = AnnotationValue(value)
@@ -17,15 +17,13 @@
package org.jetbrains.kotlin.resolve.constants
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.findClassAcrossModuleDependencies
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
@@ -111,14 +109,10 @@ class DoubleValue(value: Double) : ConstantValue<Double>(value) {
override fun toString() = "$value.toDouble()"
}
class EnumValue(value: ClassDescriptor) : ConstantValue<ClassDescriptor>(value) {
val enumClassId: ClassId get() = (value.containingDeclaration as ClassDescriptor).classId!!
val enumEntryName: Name get() = value.name
class EnumValue(val enumClassId: ClassId, val enumEntryName: Name) : ConstantValue<Pair<ClassId, Name>>(enumClassId to enumEntryName) {
override fun getType(module: ModuleDescriptor): KotlinType =
value.classValueType
?: ErrorUtils.createErrorType("Containing class for error-class based enum entry ${value.fqNameUnsafe}")
module.findClassAcrossModuleDependencies(enumClassId)?.takeIf(DescriptorUtils::isEnumClass)?.defaultType
?: ErrorUtils.createErrorType("Containing class for error-class based enum entry $enumClassId.$enumEntryName")
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitEnumValue(this, data)
@@ -368,11 +368,6 @@ public class ErrorUtils {
return new ErrorClassDescriptor(Name.special("<ERROR CLASS: " + debugMessage + ">"));
}
@NotNull
public static ClassDescriptor createErrorClassWithExactName(@NotNull Name name) {
return new ErrorClassDescriptor(name);
}
@NotNull
public static MemberScope createErrorScope(@NotNull String debugMessage) {
return createErrorScope(debugMessage, false);
@@ -21,13 +21,13 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.constants.AnnotationValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.ConstantValueFactory
import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument
import org.jetbrains.kotlin.serialization.ProtoBuf.Annotation.Argument.Value
@@ -85,7 +85,7 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n
resolveClassLiteralValue(nameResolver.getClassId(value.classId))
}
Type.ENUM -> {
resolveEnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId))
EnumValue(nameResolver.getClassId(value.classId), nameResolver.getName(value.enumValueId))
}
Type.ANNOTATION -> {
AnnotationValue(deserializeAnnotation(value.annotation, nameResolver))
@@ -137,18 +137,6 @@ class AnnotationDeserializer(private val module: ModuleDescriptor, private val n
return ConstantValueFactory.createKClassValue(type)
}
// NOTE: see analogous code in BinaryClassAnnotationAndConstantLoaderImpl
private fun resolveEnumValue(enumClassId: ClassId, enumEntryName: Name): ConstantValue<*> {
val enumClass = resolveClass(enumClassId)
if (enumClass.kind == ClassKind.ENUM_CLASS) {
val enumEntry = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(enumEntryName, NoLookupLocation.FROM_DESERIALIZATION)
if (enumEntry is ClassDescriptor) {
return ConstantValueFactory.createEnumValue(enumEntry)
}
}
return ConstantValueFactory.createErrorValue("Unresolved enum entry: $enumClassId.$enumEntryName")
}
private fun resolveArrayElementType(value: Value, nameResolver: NameResolver): SimpleType =
with(builtIns) {
when (value.type) {
@@ -197,7 +197,7 @@ private constructor(private val whenExpression: KtWhenExpression, context: Trans
): Pair<List<EntryWithConstants>, Int> {
return collectConstantEntries(
fromIndex, entries,
{ (it.toConstantValue(expectedType) as? EnumValue)?.value?.name?.identifier },
{ (it.toConstantValue(expectedType) as? EnumValue)?.enumEntryName?.identifier },
{ uniqueEnumNames.add(it) },
{ JsStringLiteral(it) }
)
@@ -17,7 +17,8 @@
package org.jetbrains.kotlin.android.synthetic.descriptors
import kotlinx.android.extensions.CacheImplementation
import kotlinx.android.extensions.CacheImplementation.*
import kotlinx.android.extensions.CacheImplementation.NO_CACHE
import kotlinx.android.extensions.CacheImplementation.valueOf
import kotlinx.android.extensions.ContainerOptions
import org.jetbrains.kotlin.android.synthetic.codegen.AndroidContainerType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
@@ -61,7 +62,7 @@ class ContainerOptionsProxy(val containerType: AndroidContainerType, val cache:
}
private fun <E : Enum<E>> AnnotationDescriptor.getEnumValue(name: String, factory: (String) -> E): E? {
val valueName = (allValueArguments[Name.identifier(name)] as? EnumValue)?.value?.name?.asString() ?: return null
val valueName = (allValueArguments[Name.identifier(name)] as? EnumValue)?.enumEntryName?.asString() ?: return null
return try {
factory(valueName)
@@ -70,4 +71,4 @@ private fun <E : Enum<E>> AnnotationDescriptor.getEnumValue(name: String, factor
// Enum.valueOf() may throw this
null
}
}
}