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.asJava.elements.psiType
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtCallElement
|
import org.jetbrains.kotlin.psi.KtCallElement
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
import org.jetbrains.kotlin.resolve.constants.*
|
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(
|
fun DeclarationDescriptor.obtainLightAnnotations(
|
||||||
ultraLightSupport: KtUltraLightSupport,
|
ultraLightSupport: KtUltraLightSupport,
|
||||||
parent: PsiElement
|
parent: PsiElement
|
||||||
): List<KtLightAbstractAnnotation> = annotations.map { KtUltraLightAnnotationForDescriptor(it, ultraLightSupport, parent) }
|
): List<KtLightAbstractAnnotation> = annotations.map { it.toLightAnnotation(ultraLightSupport, parent) }
|
||||||
|
|
||||||
class KtUltraLightAnnotationForDescriptor(
|
class KtUltraLightSimpleAnnotation(
|
||||||
private val annotationDescriptor: AnnotationDescriptor,
|
private val annotationFqName: String?,
|
||||||
|
private val argumentsList: List<Pair<String, ConstantValue<*>>>,
|
||||||
private val ultraLightSupport: KtUltraLightSupport,
|
private val ultraLightSupport: KtUltraLightSupport,
|
||||||
parent: PsiElement
|
parent: PsiElement
|
||||||
) : KtLightAbstractAnnotation(parent, computeDelegate = null) {
|
) : KtLightAbstractAnnotation(parent, computeDelegate = null) {
|
||||||
@@ -80,12 +90,12 @@ class KtUltraLightAnnotationForDescriptor(
|
|||||||
override fun findDeclaredAttributeValue(attributeName: String?) =
|
override fun findDeclaredAttributeValue(attributeName: String?) =
|
||||||
PsiImplUtil.findDeclaredAttributeValue(this, attributeName)
|
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 {
|
private val _attributes: Array<PsiNameValuePair> by lazyPub {
|
||||||
annotationDescriptor.allValueArguments.map {
|
argumentsList.map {
|
||||||
PsiNameValuePairForAnnotationArgument(it.key.asString(), it.value, ultraLightSupport, this)
|
PsiNameValuePairForAnnotationArgument(it.first, it.second, ultraLightSupport, this)
|
||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +134,7 @@ private fun ConstantValue<*>.toAnnotationMemberValue(
|
|||||||
parent: PsiElement, ultraLightSupport: KtUltraLightSupport
|
parent: PsiElement, ultraLightSupport: KtUltraLightSupport
|
||||||
): PsiAnnotationMemberValue? = when (this) {
|
): PsiAnnotationMemberValue? = when (this) {
|
||||||
|
|
||||||
is AnnotationValue -> KtUltraLightAnnotationForDescriptor(value, ultraLightSupport, parent)
|
is AnnotationValue -> value.toLightAnnotation(ultraLightSupport, parent)
|
||||||
|
|
||||||
is ArrayValue ->
|
is ArrayValue ->
|
||||||
KtUltraLightPsiArrayInitializerMemberValue(lightParent = parent) { arrayLiteralParent ->
|
KtUltraLightPsiArrayInitializerMemberValue(lightParent = parent) { arrayLiteralParent ->
|
||||||
|
|||||||
@@ -43,15 +43,16 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
|
|
||||||
private class KtUltraLightClassModifierList(
|
private class KtUltraLightClassModifierList(
|
||||||
private val containingClass: KtLightClassForSourceDeclaration,
|
private val containingClass: KtLightClassForSourceDeclaration,
|
||||||
|
private val support: KtUltraLightSupport,
|
||||||
private val computeModifiers: () -> Set<String>
|
private val computeModifiers: () -> Set<String>
|
||||||
) :
|
) :
|
||||||
KtUltraLightModifierList<KtLightClassForSourceDeclaration>(containingClass) {
|
KtUltraLightModifierList<KtLightClassForSourceDeclaration>(containingClass, support) {
|
||||||
private val modifiers by lazyPub { computeModifiers() }
|
private val modifiers by lazyPub { computeModifiers() }
|
||||||
|
|
||||||
override fun hasModifierProperty(name: String): Boolean =
|
override fun hasModifierProperty(name: String): Boolean =
|
||||||
if (name != PsiModifier.FINAL) name in modifiers else owner.isFinal(PsiModifier.FINAL in modifiers)
|
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() }
|
override fun getDelegate(): PsiClass = forTooComplex { super.getDelegate() }
|
||||||
|
|
||||||
private val _modifierList: PsiModifierList? by lazyPub {
|
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
|
override fun getModifierList(): PsiModifierList? = _modifierList
|
||||||
@@ -101,9 +102,12 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
private fun mapSupertype(supertype: KotlinType) =
|
private fun mapSupertype(supertype: KotlinType) =
|
||||||
supertype.asPsiType(support, TypeMappingMode.SUPER_TYPE, this) as? PsiClassType
|
supertype.asPsiType(support, TypeMappingMode.SUPER_TYPE, this) as? PsiClassType
|
||||||
|
|
||||||
override fun createExtendsList(): PsiReferenceList? =
|
override fun createExtendsList(): PsiReferenceList? {
|
||||||
if (tooComplex) super.createExtendsList()
|
if (isAnnotationType) return KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.EXTENDS_LIST)
|
||||||
else KotlinSuperTypeListBuilder(
|
|
||||||
|
if (tooComplex) return super.createExtendsList()
|
||||||
|
|
||||||
|
return KotlinSuperTypeListBuilder(
|
||||||
kotlinOrigin.getSuperTypeList(),
|
kotlinOrigin.getSuperTypeList(),
|
||||||
manager,
|
manager,
|
||||||
language,
|
language,
|
||||||
@@ -114,6 +118,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
.map(this::mapSupertype)
|
.map(this::mapSupertype)
|
||||||
.forEach(list::addReference)
|
.forEach(list::addReference)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun isTypeForExtendsList(supertype: KotlinType): Boolean {
|
private fun isTypeForExtendsList(supertype: KotlinType): Boolean {
|
||||||
// Do not add redundant "extends java.lang.Object" anywhere
|
// 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)
|
return !JvmCodegenUtil.isJvmInterface(supertype)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createImplementsList(): PsiReferenceList? =
|
override fun createImplementsList(): PsiReferenceList? {
|
||||||
if (tooComplex) super.createImplementsList()
|
|
||||||
else KotlinSuperTypeListBuilder(
|
if (isAnnotationType) return KotlinLightReferenceListBuilder(manager, language, PsiReferenceList.Role.IMPLEMENTS_LIST)
|
||||||
|
|
||||||
|
if (tooComplex) return super.createImplementsList()
|
||||||
|
|
||||||
|
return KotlinSuperTypeListBuilder(
|
||||||
kotlinOrigin.getSuperTypeList(),
|
kotlinOrigin.getSuperTypeList(),
|
||||||
manager,
|
manager,
|
||||||
language,
|
language,
|
||||||
@@ -143,6 +152,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
.forEach(list::addReference)
|
.forEach(list::addReference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun buildTypeParameterList(): PsiTypeParameterList =
|
override fun buildTypeParameterList(): PsiTypeParameterList =
|
||||||
if (tooComplex) super.buildTypeParameterList() else buildTypeParameterList(classOrObject, this, support)
|
if (tooComplex) super.buildTypeParameterList() else buildTypeParameterList(classOrObject, this, support)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ private class KtUltraLightSimpleModifierListField(
|
|||||||
private val declaration: KtNamedDeclaration,
|
private val declaration: KtNamedDeclaration,
|
||||||
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>,
|
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>,
|
||||||
private val modifiers: Set<String>
|
private val modifiers: Set<String>
|
||||||
) : KtUltraLightSimpleModifierList(owner, modifiers) {
|
) : KtUltraLightSimpleModifierList(owner, modifiers, support) {
|
||||||
override fun hasModifierProperty(name: String): Boolean = when (name) {
|
override fun hasModifierProperty(name: String): Boolean = when (name) {
|
||||||
PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME)
|
PsiModifier.VOLATILE -> hasFieldAnnotation(VOLATILE_ANNOTATION_FQ_NAME)
|
||||||
PsiModifier.TRANSIENT -> hasFieldAnnotation(TRANSIENT_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.LightIdentifier
|
||||||
import com.intellij.psi.impl.light.LightTypeElement
|
import com.intellij.psi.impl.light.LightTypeElement
|
||||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||||
|
import org.jetbrains.kotlin.asJava.classes.cannotModify
|
||||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
@@ -23,7 +24,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|||||||
|
|
||||||
class KtLightPsiArrayInitializerMemberValue(
|
class KtLightPsiArrayInitializerMemberValue(
|
||||||
override val kotlinOrigin: KtElement,
|
override val kotlinOrigin: KtElement,
|
||||||
val lightParent: PsiElement,
|
private val lightParent: PsiElement,
|
||||||
private val arguments: (KtLightPsiArrayInitializerMemberValue) -> List<PsiAnnotationMemberValue>
|
private val arguments: (KtLightPsiArrayInitializerMemberValue) -> List<PsiAnnotationMemberValue>
|
||||||
) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue {
|
) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue {
|
||||||
override fun getInitializers(): Array<PsiAnnotationMemberValue> = arguments(this).toTypedArray()
|
override fun getInitializers(): Array<PsiAnnotationMemberValue> = arguments(this).toTypedArray()
|
||||||
@@ -35,7 +36,7 @@ class KtLightPsiArrayInitializerMemberValue(
|
|||||||
|
|
||||||
open class KtLightPsiLiteral(
|
open class KtLightPsiLiteral(
|
||||||
override val kotlinOrigin: KtExpression,
|
override val kotlinOrigin: KtExpression,
|
||||||
val lightParent: PsiElement
|
private val lightParent: PsiElement
|
||||||
) : KtLightElementBase(lightParent), PsiLiteralExpression {
|
) : KtLightElementBase(lightParent), PsiLiteralExpression {
|
||||||
|
|
||||||
override fun getValue(): Any? =
|
override fun getValue(): Any? =
|
||||||
@@ -106,31 +107,24 @@ internal fun psiType(kotlinFqName: String, context: PsiElement, boxPrimitiveType
|
|||||||
return PsiType.getTypeByName(javaFqName, context.project, context.resolveScope)
|
return PsiType.getTypeByName(javaFqName, context.project, context.resolveScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
class KtLightPsiNameValuePair private constructor(
|
class KtLightPsiNameValuePair(
|
||||||
override val kotlinOrigin: KtElement,
|
override val kotlinOrigin: KtElement,
|
||||||
val valueArgument: KtValueArgument,
|
private val name: String,
|
||||||
lightParent: PsiElement,
|
lightParent: PsiElement,
|
||||||
private val argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
|
private val argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
|
||||||
) : KtLightElementBase(lightParent),
|
) : KtLightElementBase(lightParent),
|
||||||
PsiNameValuePair {
|
PsiNameValuePair {
|
||||||
|
|
||||||
constructor(
|
override fun setValue(newValue: PsiAnnotationMemberValue): PsiAnnotationMemberValue = cannotModify()
|
||||||
valueArgument: KtValueArgument,
|
|
||||||
lightParent: PsiElement,
|
|
||||||
argument: (KtLightPsiNameValuePair) -> PsiAnnotationMemberValue?
|
|
||||||
) : this(valueArgument.asElement(), valueArgument, lightParent, argument)
|
|
||||||
|
|
||||||
override fun setValue(newValue: PsiAnnotationMemberValue): PsiAnnotationMemberValue =
|
override fun getNameIdentifier(): PsiIdentifier? = LightIdentifier(kotlinOrigin.manager, name)
|
||||||
throw UnsupportedOperationException("can't modify KtLightPsiNameValuePair")
|
|
||||||
|
|
||||||
override fun getNameIdentifier(): PsiIdentifier? = LightIdentifier(kotlinOrigin.manager, valueArgument.name)
|
override fun getName(): String? = name
|
||||||
|
|
||||||
override fun getName(): String? = valueArgument.getArgumentName()?.asName?.asString()
|
|
||||||
|
|
||||||
private val _value: PsiAnnotationMemberValue? by lazyPub { argument(this) }
|
private val _value: PsiAnnotationMemberValue? by lazyPub { argument(this) }
|
||||||
|
|
||||||
override fun getValue(): PsiAnnotationMemberValue? = _value
|
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.
|
* 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.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.asJava.elements
|
package org.jetbrains.kotlin.asJava.elements
|
||||||
|
|
||||||
import com.intellij.psi.PsiAnnotation
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import com.intellij.psi.PsiModifierList
|
|
||||||
import com.intellij.psi.PsiModifierListOwner
|
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||||
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
|
import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
import org.jetbrains.kotlin.asJava.classes.*
|
||||||
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.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
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"
|
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
|
val annotations = parent.clsDelegate.modifierList?.annotations
|
||||||
|
|
||||||
if (annotations.isNullOrEmpty()) return emptyList()
|
if (annotations.isNullOrEmpty()) return emptyList()
|
||||||
|
|
||||||
return annotations
|
return annotations.map { KtLightNonSourceAnnotation(this, it) }
|
||||||
.filter { it.qualifiedName !in sourceAnnotationNames }
|
|
||||||
.map { KtLightNonSourceAnnotation(this, it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeAnnotations(): List<KtLightAbstractAnnotation> {
|
private fun computeAnnotations(): List<KtLightAbstractAnnotation> {
|
||||||
val annotationsForEntries =
|
val annotationsForEntries = owner.givenAnnotations ?: lightAnnotationsForEntries(this)
|
||||||
owner.givenAnnotations ?: lightAnnotationsForEntries(this)
|
|
||||||
val modifierListOwner = parent
|
val modifierListOwner = parent
|
||||||
if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) {
|
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)
|
if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant)
|
||||||
|| modifierListOwner is LightParameter
|
|| modifierListOwner is LightParameter
|
||||||
@@ -98,19 +85,22 @@ abstract class KtLightModifierList<out T : KtLightElement<KtModifierListOwner, P
|
|||||||
}
|
}
|
||||||
return annotationsForEntries
|
return annotationsForEntries
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open class KtUltraLightSimpleModifierList(
|
open class KtUltraLightSimpleModifierList(
|
||||||
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>, private val modifiers: Set<String>
|
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>,
|
||||||
) : KtUltraLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner) {
|
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 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) :
|
abstract class KtUltraLightModifierList<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(
|
||||||
KtLightModifierList<T>(owner) {
|
owner: T,
|
||||||
|
private val support: KtUltraLightSupport
|
||||||
|
) : KtLightModifierList<T>(owner) {
|
||||||
|
|
||||||
override val clsDelegate: PsiModifierList
|
override val clsDelegate: PsiModifierList
|
||||||
get() = throw IllegalStateException("Cls delegate shouldn't be loaded for ultra-light PSI!")
|
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 addAnnotation(qualifiedName: String): PsiAnnotation = throwInvalidOperation()
|
||||||
|
|
||||||
override fun nonSourceAnnotations(sourceAnnotationNames: Set<String>): List<KtLightAbstractAnnotation> {
|
override fun nonSourceAnnotationsForAnnotationType(sourceAnnotations: List<PsiAnnotation>): List<KtLightAbstractAnnotation> {
|
||||||
return emptyList()
|
|
||||||
|
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
|
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 context = LightClassGenerationSupport.getInstance(declaration.project).analyze(declaration)
|
||||||
|
|
||||||
val descriptor = if (declaration is KtParameter && declaration.isPropertyParameter()) {
|
val descriptor = if (declaration is KtParameter && declaration.isPropertyParameter()) {
|
||||||
@@ -227,4 +234,3 @@ private fun hasAnnotationsInSource(declaration: KtAnnotated): Boolean {
|
|||||||
|
|
||||||
return false
|
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.CompileTimeConstantUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
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.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
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.descriptorUtil.declaresOrInheritsDefaultValue
|
||||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -105,21 +107,22 @@ class KtLightAnnotationForSourceEntry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getAttributeValue(name: String?, useDefault: Boolean): PsiAnnotationMemberValue? {
|
private fun getAttributeValue(name: String?, useDefault: Boolean): PsiAnnotationMemberValue? {
|
||||||
val callEntry = getCallEntry(name ?: "value") ?: return null
|
|
||||||
|
|
||||||
val valueArgument = callEntry.value.arguments.firstOrNull()
|
ktLightAnnotationParameterList.attributes
|
||||||
if (valueArgument != null) {
|
.find { it.name == (name ?: "value") }
|
||||||
ktLightAnnotationParameterList.attributes.find { (it as KtLightPsiNameValuePair).valueArgument === valueArgument }?.let {
|
?.let { return it.value }
|
||||||
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
|
return null
|
||||||
@@ -142,44 +145,92 @@ class KtLightAnnotationForSourceEntry(
|
|||||||
PsiAnnotationParameterList {
|
PsiAnnotationParameterList {
|
||||||
override val kotlinOrigin: KtElement? get() = null
|
override val kotlinOrigin: KtElement? get() = null
|
||||||
|
|
||||||
private val _attributes: Array<PsiNameValuePair> by lazyPub {
|
private fun checkIfToArrayConversionExpected(callEntry: Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>): Boolean {
|
||||||
this@KtLightAnnotationForSourceEntry.kotlinOrigin.valueArguments.map { makeLightPsiNameValuePair(it as KtValueArgument) }
|
|
||||||
.toTypedArray<PsiNameValuePair>()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun makeArrayInitializerIfExpected(pair: KtLightPsiNameValuePair): PsiAnnotationMemberValue? {
|
if (!callEntry.key.isVararg) {
|
||||||
val valueArgument = pair.valueArgument
|
return false
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val parent = PsiTreeUtil.findCommonParent(valueArguments.map { it.getArgumentExpression() }) as KtElement
|
//Anno()
|
||||||
return KtLightPsiArrayInitializerMemberValue(parent, pair) { self ->
|
val valueArgument = callEntry.value.arguments.firstOrNull() ?: return false
|
||||||
valueArguments.mapNotNull {
|
|
||||||
it.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
|
//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 ->
|
private fun getNotWrappedToArrayNameValuePair(
|
||||||
makeArrayInitializerIfExpected(self)
|
resolvedArgumentEntry: Map.Entry<ValueParameterDescriptor, ResolvedValueArgument>
|
||||||
?: self.valueArgument.getArgumentExpression()?.let { convertToLightAnnotationMemberValue(self, it) }
|
): 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
|
override fun getAttributes(): Array<PsiNameValuePair> = _attributes
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user