diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt index 9d9ac93851d..91fb68e8b37 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/annotationArgumentsImpl.kt @@ -18,6 +18,8 @@ package org.jetbrains.kotlin.load.java.structure.impl import com.intellij.psi.* import org.jetbrains.kotlin.load.java.structure.* +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name abstract class JavaAnnotationArgumentImpl( @@ -64,14 +66,17 @@ class JavaEnumValueAnnotationArgumentImpl( private val psiReference: PsiReferenceExpression, name: Name? ) : JavaAnnotationArgumentImpl(name), JavaEnumValueAnnotationArgument { - override fun resolve(): JavaField? { - val element = psiReference.resolve() - return when (element) { - null -> null - is PsiEnumConstant -> JavaFieldImpl(element) - else -> throw IllegalStateException("Reference argument should be an enum value, but was $element: ${element.text}") + override val enumClassId: ClassId? + get() { + val element = psiReference.resolve() + if (element is PsiEnumConstant) { + return JavaFieldImpl(element).containingClass.classId + } + + val fqName = (psiReference.qualifier as? PsiReferenceExpression)?.qualifiedName ?: return null + // TODO: find a way to construct a correct name (with nested classes) for unresolved enums + return ClassId.topLevel(FqName(fqName)) } - } override val entryName: Name? get() = psiReference.referenceName?.let(Name::identifier) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt index e35f34d070c..a60822e330f 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Annotations.kt @@ -127,7 +127,7 @@ class BinaryJavaAnnotation private constructor( } override val classId: ClassId? - get() = classifierResolutionResult.classifier.safeAs()?.classId() + get() = classifierResolutionResult.classifier.safeAs()?.classId ?: ClassId.topLevel(FqName(classifierResolutionResult.qualifiedName)) override fun resolve() = classifierResolutionResult.classifier as? JavaClass @@ -152,7 +152,7 @@ class BinaryJavaAnnotationVisitor( } override fun visitEnum(name: String?, desc: String, value: String) { - addArgument(PlainJavaEnumValueAnnotationArgument(name, desc, value, context)) + addArgument(PlainJavaEnumValueAnnotationArgument(name, context.mapDescToClassId(desc), value)) } override fun visit(name: String?, value: Any?) { @@ -216,23 +216,8 @@ class PlainJavaAnnotationAsAnnotationArgument( class PlainJavaEnumValueAnnotationArgument( name: String?, - private val desc: String, - entryName: String, - private val context: ClassifierResolutionContext + override val enumClassId: ClassId, + entryName: String ) : PlainJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument { override val entryName = Name.identifier(entryName) - - override fun resolve(): JavaField? { - val javaClass = context.resolveByInternalName(Type.getType(desc).internalName).classifier as? JavaClass ?: return null - return javaClass.fields.singleOrNull { it.name == entryName } - } -} - -private fun JavaClass.classId(): ClassId? { - val fqName = fqName ?: return null - if (outerClass == null) return ClassId.topLevel(fqName) - - val outerClassId = outerClass!!.classId() ?: return null - - return ClassId(outerClassId.packageFqName, outerClassId.relativeClassName.child(name), false) } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt index c1ef24ac605..9a56272f985 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/ClassifierResolutionContext.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.org.objectweb.asm.Type typealias ClassIdToJavaClass = (ClassId) -> JavaClass? @@ -117,4 +118,6 @@ class ClassifierResolutionContext private constructor( private fun createClassIdForTopLevel(internalName: String) = ClassId.topLevel(FqName(internalName.replace('/', '.'))) internal fun resolveByInternalName(c: String) = resolveClass(mapInternalNameToClassId(c)) + + internal fun mapDescToClassId(desc: String): ClassId = mapInternalNameToClassId(Type.getType(desc).internalName) } diff --git a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt index d7eb60b3479..c4569217e6e 100644 --- a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt +++ b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/symbols/symbolBasedAnnotationArguments.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.javac.wrappers.symbols import com.sun.tools.javac.code.Symbol import org.jetbrains.kotlin.javac.JavacWrapper import org.jetbrains.kotlin.load.java.structure.* +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import javax.lang.model.element.AnnotationMirror import javax.lang.model.element.AnnotationValue @@ -63,16 +64,17 @@ class SymbolBasedReferenceAnnotationArgument( name: Name, javac: JavacWrapper ) : SymbolBasedAnnotationArgument(name, javac), JavaEnumValueAnnotationArgument { - override val entryName: Name? - get() = name - - override fun resolve(): SymbolBasedField { - val containingClass = (element.enclosingElement as Symbol.ClassSymbol).let { - SymbolBasedClass(it, javac, null, it.classfile) - } - return SymbolBasedField(element, containingClass, javac) + // TODO: do not create extra objects here + private val javaField: JavaField? by lazy(LazyThreadSafetyMode.PUBLICATION) { + val containingClass = element.enclosingElement as Symbol.ClassSymbol + SymbolBasedField(element, SymbolBasedClass(containingClass, javac, null, containingClass.classfile), javac) } + override val enumClassId: ClassId? + get() = javaField?.containingClass?.classId + + override val entryName: Name? + get() = javaField?.name } class SymbolBasedClassObjectAnnotationArgument( diff --git a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/TreeBasedAnnotation.kt b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/TreeBasedAnnotation.kt index fb5127312df..49b4f5ae4fe 100644 --- a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/TreeBasedAnnotation.kt +++ b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/TreeBasedAnnotation.kt @@ -50,21 +50,26 @@ class TreeBasedLiteralAnnotationArgument(name: Name, override val value: Any?, javac: JavacWrapper) : TreeBasedAnnotationArgument(name, javac), JavaLiteralAnnotationArgument -class TreeBasedReferenceAnnotationArgument(name: Name, - private val compilationUnit: CompilationUnitTree, - private val field: JCTree.JCFieldAccess, - javac: JavacWrapper, - private val onElement: JavaElement) : TreeBasedAnnotationArgument(name, javac), JavaEnumValueAnnotationArgument { - override val entryName: Name? - get() = name +class TreeBasedReferenceAnnotationArgument( + name: Name, + private val compilationUnit: CompilationUnitTree, + private val field: JCTree.JCFieldAccess, + javac: JavacWrapper, + private val onElement: JavaElement +) : TreeBasedAnnotationArgument(name, javac), JavaEnumValueAnnotationArgument { + // TODO: do not run resolve here + private val javaField: JavaField? by lazy(LazyThreadSafetyMode.PUBLICATION) { + val javaClass = javac.resolve(field.selected, compilationUnit, onElement) as? JavaClass + val fieldName = Name.identifier(field.name.toString()) - override fun resolve(): JavaField? { - val javaClass = javac.resolve(field.selected, compilationUnit, onElement) as? JavaClass ?: return null - val fieldName = field.name.toString().let { Name.identifier(it) } - - return javaClass.fields.find { it.name == fieldName } + javaClass?.fields?.find { it.name == fieldName } } + override val enumClassId: ClassId? + get() = javaField?.containingClass?.classId + + override val entryName: Name? + get() = javaField?.name } class TreeBasedArrayAnnotationArgument(val args: List, diff --git a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/utils.kt b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/utils.kt index 55fa2ca219e..27a63db6c71 100644 --- a/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/utils.kt +++ b/compiler/javac-wrapper/src/org/jetbrains/kotlin/javac/wrappers/trees/utils.kt @@ -20,7 +20,6 @@ import com.sun.tools.javac.tree.JCTree import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedArrayAnnotationArgument -import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedField import org.jetbrains.kotlin.javac.wrappers.symbols.SymbolBasedReferenceAnnotationArgument import org.jetbrains.kotlin.load.java.JavaVisibilities import org.jetbrains.kotlin.load.java.structure.JavaAnnotation @@ -81,18 +80,16 @@ fun Collection.filterTypeAnnotations(): Collection { elementTypeArg.args.find { - val field = (it as? TreeBasedReferenceAnnotationArgument)?.resolve() as? SymbolBasedField - field?.element?.simpleName?.contentEquals("TYPE_USE") ?: false + (it as? TreeBasedReferenceAnnotationArgument)?.entryName?.asString() == "TYPE_USE" }?.let { filteredAnnotations.add(annotation) } } is TreeBasedReferenceAnnotationArgument -> { - (elementTypeArg.resolve() as? SymbolBasedField)?.let { field -> - field.element.simpleName.takeIf { it.contentEquals("TYPE_USE") } - ?.let { filteredAnnotations.add(annotation) } + if (elementTypeArg.entryName?.asString() == "TYPE_USE") { + filteredAnnotations.add(annotation) } } } } return filteredAnnotations -} \ No newline at end of file +} diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt index f56f9dbb875..2a956a7a932 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/components/JavaAnnotationMapper.kt @@ -162,7 +162,7 @@ object JavaAnnotationTargetMapper { internal fun mapJavaTargetArguments(arguments: List, builtIns: KotlinBuiltIns): ConstantValue<*> { // Map arguments: java.lang.annotation.Target -> kotlin.annotation.Target val kotlinTargets = arguments.filterIsInstance() - .flatMap { mapJavaTargetArgumentByName(it.resolve()?.name?.asString()) } + .flatMap { mapJavaTargetArgumentByName(it.entryName?.asString()) } .mapNotNull { builtIns.getAnnotationTargetEnumEntry(it) } .map(::EnumValue) val parameterDescriptor = DescriptorResolverUtils.getAnnotationParameterByName( @@ -181,7 +181,7 @@ object JavaAnnotationTargetMapper { internal fun mapJavaRetentionArgument(element: JavaAnnotationArgument?, builtIns: KotlinBuiltIns): ConstantValue<*>? { // Map argument: java.lang.annotation.Retention -> kotlin.annotation.annotation return (element as? JavaEnumValueAnnotationArgument)?.let { - retentionNameList[it.resolve()?.name?.asString()]?.let { + retentionNameList[it.entryName?.asString()]?.let { builtIns.getAnnotationRetentionEnumEntry(it)?.let(::EnumValue) } } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt index 4b8b74ca683..f213a8fcf7e 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/lazy/descriptors/LazyJavaAnnotationDescriptor.kt @@ -67,7 +67,7 @@ class LazyJavaAnnotationDescriptor( private fun resolveAnnotationArgument(argument: JavaAnnotationArgument?): ConstantValue<*>? { return when (argument) { is JavaLiteralAnnotationArgument -> ConstantValueFactory.createConstantValue(argument.value) - is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.resolve(), argument.entryName) + is JavaEnumValueAnnotationArgument -> resolveFromEnumValue(argument.enumClassId, argument.entryName) is JavaArrayAnnotationArgument -> resolveFromArray(argument.name ?: DEFAULT_ANNOTATION_MEMBER_NAME, argument.getElements()) is JavaAnnotationAsAnnotationArgument -> resolveFromAnnotation(argument.getAnnotation()) is JavaClassObjectAnnotationArgument -> resolveFromJavaClassObjectType(argument.getReferencedType()) @@ -97,17 +97,19 @@ class LazyJavaAnnotationDescriptor( return ConstantValueFactory.createArrayValue(values, arrayType) } - private fun resolveFromEnumValue(element: JavaField?, entryName: Name?): ConstantValue<*>? { - if (element == null || !element.isEnumEntry) { - if (entryName == null) return null + private fun resolveFromEnumValue(enumClassId: ClassId?, entryName: Name?): ConstantValue<*>? { + if (entryName == null) return null + + if (enumClassId == null) { return ConstantValueFactory.createEnumValue(ErrorUtils.createErrorClassWithExactName(entryName)) } - val containingJavaClass = element.containingClass + val enumClass = c.module.findNonGenericClassAcrossDependencies( + enumClassId, + c.components.deserializedDescriptorResolver.components.notFoundClasses + ) - val enumClass = c.components.moduleClassResolver.resolveClass(containingJavaClass) ?: return null - - val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(element.name, NoLookupLocation.FROM_JAVA_LOADER) + val classifier = enumClass.unsubstitutedInnerClassesScope.getContributedClassifier(entryName, NoLookupLocation.FROM_JAVA_LOADER) as? ClassDescriptor ?: return null return ConstantValueFactory.createEnumValue(classifier) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt index ce5c6db53b7..dcbc99b44cd 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/annotationArguments.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.load.java.structure +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name interface JavaAnnotationArgument { @@ -31,8 +32,8 @@ interface JavaArrayAnnotationArgument : JavaAnnotationArgument { } interface JavaEnumValueAnnotationArgument : JavaAnnotationArgument { + val enumClassId: ClassId? val entryName: Name? - fun resolve(): JavaField? } interface JavaClassObjectAnnotationArgument : JavaAnnotationArgument { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt index 1e9ecd88d6a..88c68f50f05 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/java/structure/javaElements.kt @@ -90,6 +90,9 @@ interface JavaClass : JavaClassifier, JavaTypeParameterListOwner, JavaModifierLi val constructors: Collection } +val JavaClass.classId: ClassId? + get() = outerClass?.classId?.createNestedClassId(name) ?: fqName?.let(ClassId::topLevel) + enum class LightClassOriginKind { SOURCE, BINARY } diff --git a/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/structure/ReflectJavaAnnotationArguments.kt b/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/structure/ReflectJavaAnnotationArguments.kt index 00101bc9ca7..633633668d1 100644 --- a/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/structure/ReflectJavaAnnotationArguments.kt +++ b/core/descriptors.runtime/src/kotlin/reflect/jvm/internal/structure/ReflectJavaAnnotationArguments.kt @@ -17,6 +17,7 @@ package kotlin.reflect.jvm.internal.structure import org.jetbrains.kotlin.load.java.structure.* +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name abstract class ReflectJavaAnnotationArgument( @@ -51,11 +52,12 @@ class ReflectJavaEnumValueAnnotationArgument( name: Name?, private val value: Enum<*> ) : ReflectJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument { - override fun resolve(): ReflectJavaField { - val clazz = value::class.java - val enumClass = if (clazz.isEnum) clazz else clazz.enclosingClass - return ReflectJavaField(enumClass.getDeclaredField(value.name)) - } + override val enumClassId: ClassId? + get() { + val clazz = value::class.java + val enumClass = if (clazz.isEnum) clazz else clazz.enclosingClass + return enumClass.classId + } override val entryName: Name? get() = Name.identifier(value.name) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt index 8c6436423f0..c0aee144d17 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassifierResolver import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.load.java.structure.JavaClass +import org.jetbrains.kotlin.load.java.structure.classId import org.jetbrains.kotlin.load.kotlin.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -104,7 +105,7 @@ class DirectoryBasedClassFinder( val packageDirectory: VirtualFile, val directoryPackageFqName: FqName ) : KotlinClassFinder { - override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.classId) + override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.classId!!) override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? { if (classId.packageFqName != directoryPackageFqName) { @@ -149,10 +150,3 @@ class DirectoryBasedDataFinder( return ClassDataWithSource(JvmProtoBufUtil.readClassDataFrom(data, strings), KotlinJvmBinarySourceElement(binaryClass)) } } - - -private val JavaClass.classId: ClassId - get() { - val outer = outerClass - return if (outer == null) ClassId.topLevel(fqName!!) else outer.classId.createNestedClassId(name) - }