Kotlin meta-annotation converter for UL-annotations
This commit is contained in:
+18
-8
@@ -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<KtLightAbstractAnnotation> = annotations.map { KtUltraLightAnnotationForDescriptor(it, ultraLightSupport, parent) }
|
||||
): List<KtLightAbstractAnnotation> = annotations.map { it.toLightAnnotation(ultraLightSupport, parent) }
|
||||
|
||||
class KtUltraLightAnnotationForDescriptor(
|
||||
private val annotationDescriptor: AnnotationDescriptor,
|
||||
class KtUltraLightSimpleAnnotation(
|
||||
private val annotationFqName: String?,
|
||||
private val argumentsList: List<Pair<String, ConstantValue<*>>>,
|
||||
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<PsiNameValuePair> 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 ->
|
||||
|
||||
@@ -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<String>
|
||||
) :
|
||||
KtUltraLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
|
||||
KtUltraLightModifierList<KtLightClassForSourceDeclaration>(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)
|
||||
|
||||
@@ -35,7 +35,7 @@ private class KtUltraLightSimpleModifierListField(
|
||||
private val declaration: KtNamedDeclaration,
|
||||
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>,
|
||||
private val modifiers: Set<String>
|
||||
) : 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)
|
||||
|
||||
+9
-15
@@ -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<PsiAnnotationMemberValue>
|
||||
) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue {
|
||||
override fun getInitializers(): Array<PsiAnnotationMemberValue> = 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()
|
||||
|
||||
}
|
||||
|
||||
+46
-40
@@ -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<out T : KtLightElement<KtModifierListOwner, P
|
||||
|
||||
override fun toString() = "Light modifier list of $owner"
|
||||
|
||||
protected open fun nonSourceAnnotations(sourceAnnotationNames: Set<String>): List<KtLightAbstractAnnotation> {
|
||||
protected open fun nonSourceAnnotationsForAnnotationType(sourceAnnotations: List<PsiAnnotation>): List<KtLightAbstractAnnotation> {
|
||||
|
||||
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<KtLightAbstractAnnotation> {
|
||||
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<out T : KtLightElement<KtModifierListOwner, P
|
||||
}
|
||||
return annotationsForEntries
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class KtUltraLightSimpleModifierList(
|
||||
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>, private val modifiers: Set<String>
|
||||
) : KtUltraLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner) {
|
||||
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>,
|
||||
private val modifiers: Set<String>,
|
||||
private val support: KtUltraLightSupport
|
||||
) : KtUltraLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(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<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner: T) :
|
||||
KtLightModifierList<T>(owner) {
|
||||
abstract class KtUltraLightModifierList<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(
|
||||
owner: T,
|
||||
private val support: KtUltraLightSupport
|
||||
) : KtLightModifierList<T>(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<out T : KtLightElement<KtModifierListOwn
|
||||
|
||||
override fun addAnnotation(qualifiedName: String): PsiAnnotation = throwInvalidOperation()
|
||||
|
||||
override fun nonSourceAnnotations(sourceAnnotationNames: Set<String>): List<KtLightAbstractAnnotation> {
|
||||
return emptyList()
|
||||
override fun nonSourceAnnotationsForAnnotationType(sourceAnnotations: List<PsiAnnotation>): List<KtLightAbstractAnnotation> {
|
||||
|
||||
if (sourceAnnotations.isEmpty()) return listOf(createRetentionRuntimeAnnotation(support, this))
|
||||
|
||||
return mutableListOf<KtLightAbstractAnnotation>().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<AnnotationDescriptor> {
|
||||
private fun getAnnotationDescriptors(
|
||||
declaration: KtAnnotated,
|
||||
annotatedLightElement: KtLightElement<*, *>
|
||||
): List<AnnotationDescriptor> {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
+130
@@ -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<String>? =
|
||||
attributes.firstOrNull { it.attributeName == attributeName }
|
||||
?.let { it as? PsiNameValuePair }
|
||||
?.let { (it.value as? PsiArrayInitializerMemberValue) }
|
||||
?.let { arrayInitializer ->
|
||||
arrayInitializer.initializers.filterIsInstance<KtLightPsiLiteral>()
|
||||
.map { it.value }
|
||||
.filterIsInstance<Pair<ClassId, Name>>()
|
||||
.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
|
||||
)
|
||||
}
|
||||
+92
-41
@@ -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<PsiNameValuePair> by lazyPub {
|
||||
this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArguments.map { makeLightPsiNameValuePair(it as KtValueArgument) }
|
||||
.toTypedArray<PsiNameValuePair>()
|
||||
}
|
||||
private fun checkIfToArrayConversionExpected(callEntry: Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>): 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<ValueParameterDescriptor, ResolvedValueArgument>
|
||||
): 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<ValueParameterDescriptor, ResolvedValueArgument>
|
||||
): 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<PsiNameValuePair> 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<PsiNameValuePair> = _attributes
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user