diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt index f0348a361ab..49a3dee7326 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation import org.jetbrains.kotlin.asJava.elements.psiType import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtCallElement import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.constants.* @@ -52,13 +53,22 @@ class KtUltraLightNullabilityAnnotation( } } +fun AnnotationDescriptor.toLightAnnotation(ultraLightSupport: KtUltraLightSupport, parent: PsiElement) = + KtUltraLightSimpleAnnotation( + fqName?.asString(), + allValueArguments.map { it.key.asString() to it.value }, + ultraLightSupport, + parent + ) + fun DeclarationDescriptor.obtainLightAnnotations( ultraLightSupport: KtUltraLightSupport, parent: PsiElement -): List = annotations.map { KtUltraLightAnnotationForDescriptor(it, ultraLightSupport, parent) } +): List = annotations.map { it.toLightAnnotation(ultraLightSupport, parent) } -class KtUltraLightAnnotationForDescriptor( - private val annotationDescriptor: AnnotationDescriptor, +class KtUltraLightSimpleAnnotation( + private val annotationFqName: String?, + private val argumentsList: List>>, private val ultraLightSupport: KtUltraLightSupport, parent: PsiElement ) : KtLightAbstractAnnotation(parent, computeDelegate = null) { @@ -80,12 +90,12 @@ class KtUltraLightAnnotationForDescriptor( override fun findDeclaredAttributeValue(attributeName: String?) = PsiImplUtil.findDeclaredAttributeValue(this, attributeName) - override fun getQualifiedName() = annotationDescriptor.fqName?.asString() + override fun getQualifiedName() = annotationFqName - private inner class ParameterListImpl : KtLightElementBase(this@KtUltraLightAnnotationForDescriptor), PsiAnnotationParameterList { + private inner class ParameterListImpl : KtLightElementBase(this@KtUltraLightSimpleAnnotation), PsiAnnotationParameterList { private val _attributes: Array by lazyPub { - annotationDescriptor.allValueArguments.map { - PsiNameValuePairForAnnotationArgument(it.key.asString(), it.value, ultraLightSupport, this) + argumentsList.map { + PsiNameValuePairForAnnotationArgument(it.first, it.second, ultraLightSupport, this) }.toTypedArray() } @@ -124,7 +134,7 @@ private fun ConstantValue<*>.toAnnotationMemberValue( parent: PsiElement, ultraLightSupport: KtUltraLightSupport ): PsiAnnotationMemberValue? = when (this) { - is AnnotationValue -> KtUltraLightAnnotationForDescriptor(value, ultraLightSupport, parent) + is AnnotationValue -> value.toLightAnnotation(ultraLightSupport, parent) is ArrayValue -> KtUltraLightPsiArrayInitializerMemberValue(lightParent = parent) { arrayLiteralParent -> diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt index 09dcc4eaf5d..7094e15a1da 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt @@ -43,15 +43,16 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor private class KtUltraLightClassModifierList( private val containingClass: KtLightClassForSourceDeclaration, + private val support: KtUltraLightSupport, private val computeModifiers: () -> Set ) : - KtUltraLightModifierList(containingClass) { + KtUltraLightModifierList(containingClass, support) { private val modifiers by lazyPub { computeModifiers() } override fun hasModifierProperty(name: String): Boolean = if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers) - override fun copy(): PsiElement = KtUltraLightClassModifierList(containingClass, computeModifiers) + override fun copy(): PsiElement = KtUltraLightClassModifierList(containingClass, support, computeModifiers) } @@ -90,7 +91,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor override fun getDelegate(): PsiClass = forTooComplex { super.getDelegate() } private val _modifierList: PsiModifierList? by lazyPub { - if (tooComplex) super.getModifierList() else KtUltraLightClassModifierList(this) { computeModifiers() } + if (tooComplex) super.getModifierList() else KtUltraLightClassModifierList(this, support) { computeModifiers() } } override fun getModifierList(): PsiModifierList? = _modifierList @@ -101,9 +102,12 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor private fun mapSupertype(supertype: KotlinType) = supertype.asPsiType(support, TypeMappingMode.SUPER_TYPE, this) as? PsiClassType - override fun createExtendsList(): PsiReferenceList? = - if (tooComplex) super.createExtendsList() - else KotlinSuperTypeListBuilder( + override fun createExtendsList(): PsiReferenceList? { + if (isAnnotationType) return KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.EXTENDS_LIST) + + if (tooComplex) return super.createExtendsList() + + return KotlinSuperTypeListBuilder( kotlinOrigin.getSuperTypeList(), manager, language, @@ -114,6 +118,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor .map(this::mapSupertype) .forEach(list::addReference) } + } private fun isTypeForExtendsList(supertype: KotlinType): Boolean { // Do not add redundant "extends java.lang.Object" anywhere @@ -128,9 +133,13 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor return !JvmCodegenUtil.isJvmInterface(supertype) } - override fun createImplementsList(): PsiReferenceList? = - if (tooComplex) super.createImplementsList() - else KotlinSuperTypeListBuilder( + override fun createImplementsList(): PsiReferenceList? { + + if (isAnnotationType) return KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.IMPLEMENTS_LIST) + + if (tooComplex) return super.createImplementsList() + + return KotlinSuperTypeListBuilder( kotlinOrigin.getSuperTypeList(), manager, language, @@ -143,6 +152,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor .forEach(list::addReference) } } + } override fun buildTypeParameterList(): PsiTypeParameterList = if (tooComplex) super.buildTypeParameterList() else buildTypeParameterList(classOrObject, this, support) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt index 931f7297a92..e764a8546ab 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightField.kt @@ -35,7 +35,7 @@ private class KtUltraLightSimpleModifierListField( private val declaration: KtNamedDeclaration, owner: KtLightElement, private val modifiers: Set -) : KtUltraLightSimpleModifierList(owner, modifiers) { +) : KtUltraLightSimpleModifierList(owner, modifiers, support) { override fun hasModifierProperty(name: String): Boolean = when (name) { PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME) PsiModifier.TRANSIENT -> hasFieldAnnotation(TRANSIENT_ANNOTATION_FQ_NAME) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotationsValues.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotationsValues.kt index abe62771a12..92be3784293 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotationsValues.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotationsValues.kt @@ -11,6 +11,7 @@ import com.intellij.psi.impl.LanguageConstantExpressionEvaluator import com.intellij.psi.impl.light.LightIdentifier import com.intellij.psi.impl.light.LightTypeElement import org.jetbrains.kotlin.asJava.LightClassGenerationSupport +import org.jetbrains.kotlin.asJava.classes.cannotModify import org.jetbrains.kotlin.asJava.classes.lazyPub import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.name.FqNameUnsafe @@ -23,7 +24,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs class KtLightPsiArrayInitializerMemberValue( override val kotlinOrigin: KtElement, - val lightParent: PsiElement, + private val lightParent: PsiElement, private val arguments: (KtLightPsiArrayInitializerMemberValue) -> List ) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue { override fun getInitializers(): Array = arguments(this).toTypedArray() @@ -35,7 +36,7 @@ class KtLightPsiArrayInitializerMemberValue( open class KtLightPsiLiteral( override val kotlinOrigin: KtExpression, - val lightParent: PsiElement + private val lightParent: PsiElement ) : KtLightElementBase(lightParent), PsiLiteralExpression { override fun getValue(): Any? = @@ -106,31 +107,24 @@ internal fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType return PsiType.getTypeByName(javaFqName, context.project, context.resolveScope) } -class KtLightPsiNameValuePair private constructor( +class KtLightPsiNameValuePair( override val kotlinOrigin: KtElement, - val valueArgument: KtValueArgument, + private val name: String, lightParent: PsiElement, private val argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue? ) : KtLightElementBase(lightParent), PsiNameValuePair { - constructor( - valueArgument: KtValueArgument, - lightParent: PsiElement, - argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue? - ) : this(valueArgument.asElement(), valueArgument, lightParent, argument) + override fun setValue(newValue: PsiAnnotationMemberValue): PsiAnnotationMemberValue = cannotModify() - override fun setValue(newValue: PsiAnnotationMemberValue): PsiAnnotationMemberValue = - throw UnsupportedOperationException("can't modify KtLightPsiNameValuePair") + override fun getNameIdentifier(): PsiIdentifier? = LightIdentifier(kotlinOrigin.manager, name) - override fun getNameIdentifier(): PsiIdentifier? = LightIdentifier(kotlinOrigin.manager, valueArgument.name) - - override fun getName(): String? = valueArgument.getArgumentName()?.asName?.asString() + override fun getName(): String? = name private val _value: PsiAnnotationMemberValue? by lazyPub { argument(this) } override fun getValue(): PsiAnnotationMemberValue? = _value - override fun getLiteralValue(): String? = (getValue() as? PsiLiteralExpression)?.value?.toString() + override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString() } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt index cd7255b9da2..34696c940de 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt @@ -1,33 +1,15 @@ /* - * Copyright 2010-2016 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. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.asJava.elements -import com.intellij.psi.PsiAnnotation -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiModifierList -import com.intellij.psi.PsiModifierListOwner +import com.intellij.psi.* import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration -import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration -import org.jetbrains.kotlin.asJava.classes.KtUltraLightElementWithNullabilityAnnotation -import org.jetbrains.kotlin.asJava.classes.KtUltraLightNullabilityAnnotation -import org.jetbrains.kotlin.asJava.classes.lazyPub -import org.jetbrains.kotlin.asJava.toLightAnnotation +import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor @@ -67,24 +49,29 @@ abstract class KtLightModifierList): List { + protected open fun nonSourceAnnotationsForAnnotationType(sourceAnnotations: List): List { val annotations = parent.clsDelegate.modifierList?.annotations if (annotations.isNullOrEmpty()) return emptyList() - return annotations - .filter { it.qualifiedName !in sourceAnnotationNames } - .map { KtLightNonSourceAnnotation(this, it) } + return annotations.map { KtLightNonSourceAnnotation(this, it) } } private fun computeAnnotations(): List { - val annotationsForEntries = - owner.givenAnnotations ?: lightAnnotationsForEntries(this) + val annotationsForEntries = owner.givenAnnotations ?: lightAnnotationsForEntries(this) val modifierListOwner = parent if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) { - val sourceAnnotationNames = annotationsForEntries.mapNotNullTo(mutableSetOf()) { it.qualifiedName } - return annotationsForEntries + nonSourceAnnotations(sourceAnnotationNames) + + val nonSourceAnnotations = nonSourceAnnotationsForAnnotationType(annotationsForEntries) + + val filteredNonSourceAnnotations = nonSourceAnnotations.filter { nonSourceAnnotation -> + annotationsForEntries.all { sourceAnnotation -> + nonSourceAnnotation.qualifiedName != sourceAnnotation.qualifiedName + } + } + + return annotationsForEntries + filteredNonSourceAnnotations } if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant) || modifierListOwner is LightParameter @@ -98,19 +85,22 @@ abstract class KtLightModifierList, private val modifiers: Set -) : KtUltraLightModifierList>(owner) { + owner: KtLightElement, + private val modifiers: Set, + private val support: KtUltraLightSupport +) : KtUltraLightModifierList>(owner, support) { override fun hasModifierProperty(name: String) = name in modifiers - override fun copy() = KtUltraLightSimpleModifierList(owner, modifiers) + override fun copy() = KtUltraLightSimpleModifierList(owner, modifiers, support) } -abstract class KtUltraLightModifierList>(owner: T) : - KtLightModifierList(owner) { +abstract class KtUltraLightModifierList>( + owner: T, + private val support: KtUltraLightSupport +) : KtLightModifierList(owner) { override val clsDelegate: PsiModifierList get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!") @@ -123,8 +113,22 @@ abstract class KtUltraLightModifierList): List { - return emptyList() + override fun nonSourceAnnotationsForAnnotationType(sourceAnnotations: List): List { + + if (sourceAnnotations.isEmpty()) return listOf(createRetentionRuntimeAnnotation(support, this)) + + return mutableListOf().also { result -> + + sourceAnnotations.mapNotNullTo(result) { sourceAnnotation -> + sourceAnnotation.tryConvertAsTarget(support) + ?: sourceAnnotation.tryConvertAsRetention(support) + ?: sourceAnnotation.tryConvertAsMustBeDocumented(support) + } + + if (!result.any { it.qualifiedName == "java.lang.annotation.Retention" }) { + result.add(createRetentionRuntimeAnnotation(support, this)) + } + } } } @@ -180,7 +184,10 @@ fun isFromSources(lightElement: KtLightElement<*, *>): Boolean { return true } -private fun getAnnotationDescriptors(declaration: KtAnnotated, annotatedLightElement: KtLightElement<*, *>): List { +private fun getAnnotationDescriptors( + declaration: KtAnnotated, + annotatedLightElement: KtLightElement<*, *> +): List { val context = LightClassGenerationSupport.getInstance(declaration.project).analyze(declaration) val descriptor = if (declaration is KtParameter && declaration.isPropertyParameter()) { @@ -227,4 +234,3 @@ private fun hasAnnotationsInSource(declaration: KtAnnotated): Boolean { return false } - diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt new file mode 100644 index 00000000000..cfb90cfe55b --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtToJvmAnnotationsConverter.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.elements + +import com.intellij.psi.CommonClassNames.JAVA_LANG_ANNOTATION_RETENTION +import com.intellij.psi.CommonClassNames.JAVA_LANG_ANNOTATION_TARGET +import com.intellij.psi.PsiAnnotation +import com.intellij.psi.PsiArrayInitializerMemberValue +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNameValuePair +import org.jetbrains.kotlin.asJava.classes.KtUltraLightSimpleAnnotation +import org.jetbrains.kotlin.asJava.classes.KtUltraLightSupport +import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.constants.ArrayValue +import org.jetbrains.kotlin.resolve.constants.EnumValue + +private const val JAVA_LANG_ANNOTATION_DOCUMENTED = "java.lang.annotation.Documented" + +private fun PsiAnnotation.extractAnnotationFqName(attributeName: String): String? { + val targetAttribute = + attributes.firstOrNull { it.attributeName == attributeName } as? KtLightPsiNameValuePair + targetAttribute ?: return null + + val valueTarget = (targetAttribute.value as? KtLightPsiLiteral)?.value as? Pair<*, *> + valueTarget ?: return null + + val classId = valueTarget.first as? ClassId + classId ?: return null + val name = valueTarget.second as? Name + name ?: return null + + return "${classId.asSingleFqName().asString()}.${name.identifier}" +} + + +private fun PsiAnnotation.extractArrayAnnotationFqNames(attributeName: String): List? = + attributes.firstOrNull { it.attributeName == attributeName } + ?.let { it as? PsiNameValuePair } + ?.let { (it.value as? PsiArrayInitializerMemberValue) } + ?.let { arrayInitializer -> + arrayInitializer.initializers.filterIsInstance() + .map { it.value } + .filterIsInstance>() + .map { "${it.first.asSingleFqName().asString()}.${it.second.identifier}" } + } + +private val javaAnnotationElementTypeId = ClassId.fromString("java.lang.annotation.ElementType") +private val targetMapping = hashMapOf( + "kotlin.annotation.AnnotationTarget.CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("TYPE")), + "kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS" to EnumValue(javaAnnotationElementTypeId, Name.identifier("ANNOTATION_TYPE")), + "kotlin.annotation.AnnotationTarget.FIELD" to EnumValue(javaAnnotationElementTypeId, Name.identifier("FIELD")), + "kotlin.annotation.AnnotationTarget.LOCAL_VARIABLE" to EnumValue(javaAnnotationElementTypeId, Name.identifier("LOCAL_VARIABLE")), + "kotlin.annotation.AnnotationTarget.VALUE_PARAMETER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("PARAMETER")), + "kotlin.annotation.AnnotationTarget.CONSTRUCTOR" to EnumValue(javaAnnotationElementTypeId, Name.identifier("CONSTRUCTOR")), + "kotlin.annotation.AnnotationTarget.FUNCTION" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")), + "kotlin.annotation.AnnotationTarget.PROPERTY_GETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")), + "kotlin.annotation.AnnotationTarget.PROPERTY_SETTER" to EnumValue(javaAnnotationElementTypeId, Name.identifier("METHOD")) +) + +internal fun PsiAnnotation.tryConvertAsTarget(support: KtUltraLightSupport): KtLightAbstractAnnotation? { + + if (FQ_NAMES.target.asString() != qualifiedName) return null + + val attributeValues = extractArrayAnnotationFqNames("allowedTargets") + ?: extractAnnotationFqName("value")?.let { listOf(it) } + + attributeValues ?: return null + + val convertedValues = attributeValues.mapNotNull { targetMapping[it] }.distinct() + + val targetAttributes = "value" to ArrayValue(convertedValues) { module -> module.builtIns.array.defaultType } + + return KtUltraLightSimpleAnnotation( + JAVA_LANG_ANNOTATION_TARGET, + listOf(targetAttributes), + support, + parent + ) +} + +private val javaAnnotationRetentionPolicyId = ClassId.fromString("java.lang.annotation.RetentionPolicy") +private val retentionMapping = hashMapOf( + "kotlin.annotation.AnnotationRetention.SOURCE" to EnumValue(javaAnnotationRetentionPolicyId, Name.identifier("SOURCE")), + "kotlin.annotation.AnnotationRetention.BINARY" to EnumValue(javaAnnotationRetentionPolicyId, Name.identifier("CLASS")), + "kotlin.annotation.AnnotationRetention.RUNTIME" to EnumValue(javaAnnotationRetentionPolicyId, Name.identifier("RUNTIME")) +) + + +internal fun createRetentionRuntimeAnnotation(support: KtUltraLightSupport, parent: PsiElement) = + KtUltraLightSimpleAnnotation( + JAVA_LANG_ANNOTATION_RETENTION, + listOf("value" to retentionMapping["kotlin.annotation.AnnotationRetention.RUNTIME"]!!), + support, + parent + ) + +internal fun PsiAnnotation.tryConvertAsRetention(support: KtUltraLightSupport): KtLightAbstractAnnotation? { + + if (FQ_NAMES.retention.asString() != qualifiedName) return null + + val convertedValue = extractAnnotationFqName("value") + ?.let { retentionMapping[it] } + ?: null + + convertedValue ?: return null + + return KtUltraLightSimpleAnnotation( + JAVA_LANG_ANNOTATION_RETENTION, + listOf("value" to convertedValue), + support, + parent + ) +} + +internal fun PsiAnnotation.tryConvertAsMustBeDocumented(support: KtUltraLightSupport): KtLightAbstractAnnotation? { + + if (FQ_NAMES.mustBeDocumented.asString() != qualifiedName) return null + + return KtUltraLightSimpleAnnotation( + JAVA_LANG_ANNOTATION_DOCUMENTED, + emptyList(), + support, + parent + ) +} \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt index 43d53cfac88..774cb10af71 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt @@ -41,8 +41,10 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getType +import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument +import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument import org.jetbrains.kotlin.resolve.descriptorUtil.declaresOrInheritsDefaultValue import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.types.KotlinType @@ -105,21 +107,22 @@ class KtLightAnnotationForSourceEntry( } private fun getAttributeValue(name: String?, useDefault: Boolean): PsiAnnotationMemberValue? { - val callEntry = getCallEntry(name ?: "value") ?: return null - val valueArgument = callEntry.value.arguments.firstOrNull() - if (valueArgument != null) { - ktLightAnnotationParameterList.attributes.find { (it as KtLightPsiNameValuePair).valueArgument === valueArgument }?.let { - return it.value - } - } + ktLightAnnotationParameterList.attributes + .find { it.name == (name ?: "value") } + ?.let { return it.value } + + if (useDefault) { + val callEntry = getCallEntry(name ?: "value") ?: return null + + if (callEntry.key.declaresOrInheritsDefaultValue()) { + when (val psiElement = callEntry.key.source.getPsi()) { + is KtParameter -> + return psiElement.defaultValue?.let { convertToLightAnnotationMemberValue(this, it) } + is PsiAnnotationMethod -> + return psiElement.defaultValue + } - if (useDefault && callEntry.key.declaresOrInheritsDefaultValue()) { - when (val psiElement = callEntry.key.source.getPsi()) { - is KtParameter -> - return psiElement.defaultValue?.let { convertToLightAnnotationMemberValue(this, it) } - is PsiAnnotationMethod -> - return psiElement.defaultValue } } return null @@ -142,44 +145,92 @@ class KtLightAnnotationForSourceEntry( PsiAnnotationParameterList { override val kotlinOrigin: KtElement? get() = null - private val _attributes: Array by lazyPub { - this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArguments.map { makeLightPsiNameValuePair(it as KtValueArgument) } - .toTypedArray() - } + private fun checkIfToArrayConversionExpected(callEntry: Map.Entry): Boolean { - private fun makeArrayInitializerIfExpected(pair: KtLightPsiNameValuePair): PsiAnnotationMemberValue? { - val valueArgument = pair.valueArgument - val name = valueArgument.name ?: "value" - val callEntry = getCallEntry(name) ?: return null - - val valueArguments = callEntry.value.arguments - val argument = valueArguments.firstOrNull()?.getArgumentExpression() ?: return null - - if (!callEntry.key.type.let { KotlinBuiltIns.isArrayOrPrimitiveArray(it) }) return null - - if (argument !is KtStringTemplateExpression && - argument !is KtConstantExpression && - argument !is KtClassLiteralExpression && - getAnnotationName(argument) == null - ) { - return null + if (!callEntry.key.isVararg) { + return false } - val parent = PsiTreeUtil.findCommonParent(valueArguments.map { it.getArgumentExpression() }) as KtElement - return KtLightPsiArrayInitializerMemberValue(parent, pair) { self -> - valueArguments.mapNotNull { - it.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) } + //Anno() + val valueArgument = callEntry.value.arguments.firstOrNull() ?: return false + + //Anno(1,2,3) + if (valueArgument is VarargValueArgument) { + return true + } + + //Anno(*[1,2,3]) + if (valueArgument is KtValueArgument && valueArgument.isSpread) { + return false + } + + //Anno(a = [1,2,3]) + return !valueArgument.isNamed() + } + + private fun getWrappedToArrayNameValuePair( + resolvedArgumentEntry: Map.Entry + ): KtLightPsiNameValuePair { + + val argumentExpressions = + resolvedArgumentEntry.value.arguments.mapNotNull { varargArgument -> varargArgument.getArgumentExpression() } + + val parent = PsiTreeUtil.findCommonParent(argumentExpressions) as? KtElement + ?: this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArgumentList + ?: this@KtLightAnnotationForSourceEntry.kotlinOrigin + + val argumentName = resolvedArgumentEntry.key.name.asString() + + return KtLightPsiNameValuePair( + parent, + argumentName, + this + ) { self -> + KtLightPsiArrayInitializerMemberValue(parent, self) { memberValue -> + argumentExpressions.map { argumentExpression -> + convertToLightAnnotationMemberValue(memberValue, argumentExpression) + } } } } - private fun makeLightPsiNameValuePair(valueArgument: KtValueArgument) = KtLightPsiNameValuePair(valueArgument, this) { self -> - makeArrayInitializerIfExpected(self) - ?: self.valueArgument.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) } + private fun getNotWrappedToArrayNameValuePair( + resolvedArgumentEntry: Map.Entry + ): KtLightPsiNameValuePair? { + + val firstArgument = resolvedArgumentEntry.value.arguments.firstOrNull() ?: return null + val argumentExpression = firstArgument.getArgumentExpression() ?: return null + + val argumentName = resolvedArgumentEntry.key.name.asString() + + return KtLightPsiNameValuePair( + firstArgument.asElement(), + argumentName, + this + ) { valuePair -> convertToLightAnnotationMemberValue(valuePair, argumentExpression) } + } + + private val _attributes: Array by lazyPub { + + if (this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArguments.isEmpty()) { + return@lazyPub emptyArray() + } + + val resolvedArguments = + this@KtLightAnnotationForSourceEntry.kotlinOrigin.getResolvedCall()?.valueArguments + + resolvedArguments ?: return@lazyPub emptyArray() + + resolvedArguments.mapNotNull { resolvedArgumentEntry -> + if (checkIfToArrayConversionExpected(resolvedArgumentEntry)) { + getWrappedToArrayNameValuePair(resolvedArgumentEntry) + } else { + getNotWrappedToArrayNameValuePair(resolvedArgumentEntry) + } + }.toTypedArray() } override fun getAttributes(): Array = _attributes - }