KtLightElements: make light annotations lazier
Allow to get annotation list and to invoke `findAnnotation` without building delegate
Introduce KtLightNullabilityAnnotation which holds nullability information and is built
before delegate is built
This commit is contained in:
+3
-1
@@ -40,7 +40,7 @@ class KtLightClassForInterfaceDefaultImpls(classOrObject: KtClassOrObject)
|
||||
override fun getTypeParameterList(): PsiTypeParameterList? = null
|
||||
override fun getTypeParameters(): Array<PsiTypeParameter> = emptyArray()
|
||||
|
||||
override fun computeModifiers(): Array<String> = arrayOf(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL)
|
||||
override fun computeModifiers() = publicStaticFinal
|
||||
|
||||
override fun isInterface(): Boolean = false
|
||||
override fun isDeprecated(): Boolean = false
|
||||
@@ -58,3 +58,5 @@ class KtLightClassForInterfaceDefaultImpls(classOrObject: KtClassOrObject)
|
||||
|
||||
override fun getOwnInnerClasses() = emptyList<PsiClass>()
|
||||
}
|
||||
|
||||
private val publicStaticFinal = setOf(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL)
|
||||
+4
-4
@@ -44,8 +44,8 @@ import org.jetbrains.kotlin.asJava.builder.LightClassData
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassDataProviderForClassOrObject
|
||||
import org.jetbrains.kotlin.asJava.elements.FakeFileForLightClass
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightSimpleModifierList
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightModifierListWithExplicitModifiers
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightPsiReferenceList
|
||||
import org.jetbrains.kotlin.asJava.hasInterfaceDefaultImpls
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
@@ -180,11 +180,11 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
||||
|
||||
override fun getName(): String? = classOrObject.nameAsName?.asString()
|
||||
|
||||
private val _modifierList: PsiModifierList by lazyPub { KtLightModifierListWithExplicitModifiers(this@KtLightClassForSourceDeclaration, computeModifiers()) }
|
||||
private val _modifierList: PsiModifierList by lazyPub { KtLightSimpleModifierList(this@KtLightClassForSourceDeclaration, computeModifiers()) }
|
||||
|
||||
override fun getModifierList(): PsiModifierList? = _modifierList
|
||||
|
||||
protected open fun computeModifiers(): Array<String> {
|
||||
protected open fun computeModifiers(): Set<String> {
|
||||
val psiModifiers = hashSetOf<String>()
|
||||
|
||||
// PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL
|
||||
@@ -218,7 +218,7 @@ abstract class KtLightClassForSourceDeclaration(protected val classOrObject: KtC
|
||||
psiModifiers.add(PsiModifier.STATIC)
|
||||
}
|
||||
|
||||
return psiModifiers.toTypedArray()
|
||||
return psiModifiers
|
||||
}
|
||||
|
||||
private fun isAbstract(): Boolean = classOrObject.hasModifier(ABSTRACT_KEYWORD) || isInterface
|
||||
|
||||
+7
-27
@@ -41,7 +41,7 @@ abstract class KtLightMemberImpl<out D : PsiMember>(
|
||||
|
||||
private val _modifierList by lazyPub {
|
||||
if (lightMemberOrigin is LightMemberOriginForDeclaration)
|
||||
KtLightModifierList(this, dummyDelegate?.modifierList)
|
||||
KtLightMemberModifierList(this, dummyDelegate?.modifierList)
|
||||
else clsDelegate.modifierList!!
|
||||
}
|
||||
|
||||
@@ -64,8 +64,6 @@ abstract class KtLightMemberImpl<out D : PsiMember>(
|
||||
override fun isDeprecated() = (clsDelegate as PsiDocCommentOwner).isDeprecated
|
||||
}
|
||||
|
||||
private val visibilityModifiers = arrayOf(PsiModifier.PRIVATE, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PUBLIC)
|
||||
|
||||
internal fun getMemberOrigin(member: PsiMember): LightMemberOriginForDeclaration? {
|
||||
if (member !is ClsRepositoryPsiElement<*>) return null
|
||||
|
||||
@@ -74,14 +72,11 @@ internal fun getMemberOrigin(member: PsiMember): LightMemberOriginForDeclaration
|
||||
return stubElement.getUserData<LightElementOrigin>(ORIGIN) as? LightMemberOriginForDeclaration ?: return null
|
||||
}
|
||||
|
||||
private val visibilityModifiers = arrayOf(PsiModifier.PRIVATE, PsiModifier.PACKAGE_LOCAL, PsiModifier.PROTECTED, PsiModifier.PUBLIC)
|
||||
|
||||
class KtLightModifierList(
|
||||
private val owner: KtLightMember<*>,
|
||||
private val dummyDelegate: PsiModifierList?
|
||||
) : LightElement(owner.manager, KotlinLanguage.INSTANCE), PsiModifierList {
|
||||
private val clsDelegate by lazyPub { owner.clsDelegate.modifierList!! }
|
||||
private val _annotations by lazyPub { computeAnnotations(this, clsDelegate) }
|
||||
|
||||
private class KtLightMemberModifierList(
|
||||
owner: KtLightMember<*>, private val dummyDelegate: PsiModifierList?
|
||||
) : KtLightModifierList<KtLightMember<*>>(owner) {
|
||||
override fun hasModifierProperty(name: String) = when {
|
||||
name == PsiModifier.ABSTRACT && isImplementationInInterface() -> false
|
||||
name == PsiModifier.DEFAULT && isImplementationInInterface() -> true
|
||||
@@ -100,21 +95,6 @@ class KtLightModifierList(
|
||||
private fun isImplementationInInterface()
|
||||
= owner.containingClass.isInterface && owner is KtLightMethod && owner.kotlinOrigin?.hasBody() ?: false
|
||||
|
||||
override fun hasExplicitModifier(name: String) = hasModifierProperty(name)
|
||||
|
||||
override fun setModifierProperty(name: String, value: Boolean) = clsDelegate.setModifierProperty(name, value)
|
||||
override fun checkSetModifierProperty(name: String, value: Boolean) = clsDelegate.checkSetModifierProperty(name, value)
|
||||
override fun addAnnotation(qualifiedName: String) = clsDelegate.addAnnotation(qualifiedName)
|
||||
override fun getApplicableAnnotations(): Array<out PsiAnnotation> = annotations
|
||||
override fun getAnnotations(): Array<out PsiAnnotation> = _annotations.value
|
||||
override fun findAnnotation(qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName }
|
||||
override fun getParent() = owner
|
||||
override fun getText(): String? = ""
|
||||
override fun getTextRange() = TextRange.EMPTY_RANGE
|
||||
override fun copy(): PsiElement = KtLightModifierList(owner, dummyDelegate)
|
||||
override fun getReferences() = PsiReference.EMPTY_ARRAY
|
||||
override fun isEquivalentTo(another: PsiElement?) =
|
||||
another is KtLightModifierList && owner == another.owner
|
||||
|
||||
override fun toString() = "Light modifier list of $owner"
|
||||
override fun copy() = KtLightMemberModifierList(owner, dummyDelegate)
|
||||
}
|
||||
|
||||
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.asJava.elements
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.light.LightElement
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
|
||||
abstract class KtLightModifierList<out T : KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(protected val owner: T)
|
||||
: LightElement(owner.manager, KotlinLanguage.INSTANCE), PsiModifierList, KtLightElement<KtModifierList, PsiModifierList> {
|
||||
override val clsDelegate by lazyPub { owner.clsDelegate.modifierList!! }
|
||||
private val _annotations by lazyPub { computeAnnotations(this) }
|
||||
override val kotlinOrigin: KtModifierList?
|
||||
get() = owner.kotlinOrigin?.modifierList
|
||||
|
||||
override fun hasExplicitModifier(name: String) = hasModifierProperty(name)
|
||||
|
||||
override fun setModifierProperty(name: String, value: Boolean) = clsDelegate.setModifierProperty(name, value)
|
||||
override fun checkSetModifierProperty(name: String, value: Boolean) = clsDelegate.checkSetModifierProperty(name, value)
|
||||
override fun addAnnotation(qualifiedName: String) = clsDelegate.addAnnotation(qualifiedName)
|
||||
override fun getApplicableAnnotations(): Array<out PsiAnnotation> = annotations
|
||||
override fun getAnnotations(): Array<out PsiAnnotation> = _annotations.toTypedArray()
|
||||
override fun findAnnotation(qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName }
|
||||
override fun getParent() = owner
|
||||
override fun getText(): String? = ""
|
||||
override fun getTextRange() = TextRange.EMPTY_RANGE
|
||||
override fun getReferences() = PsiReference.EMPTY_ARRAY
|
||||
override fun isEquivalentTo(another: PsiElement?) =
|
||||
another is KtLightModifierList<*> && owner == another.owner
|
||||
|
||||
override fun toString() = "Light modifier list of $owner"
|
||||
}
|
||||
|
||||
class KtLightSimpleModifierList(
|
||||
owner: KtLightElement<KtModifierListOwner, PsiModifierListOwner>, private val modifiers: Set<String>
|
||||
) : KtLightModifierList<KtLightElement<KtModifierListOwner, PsiModifierListOwner>>(owner) {
|
||||
override fun hasModifierProperty(name: String) = name in modifiers
|
||||
|
||||
override fun copy() = KtLightSimpleModifierList(owner, modifiers)
|
||||
}
|
||||
|
||||
private fun computeAnnotations(lightModifierList: KtLightModifierList<*>): List<PsiAnnotation> {
|
||||
val annotationsForEntries = lightAnnotationsForEntries(lightModifierList)
|
||||
val modifierListOwner = lightModifierList.parent
|
||||
if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) {
|
||||
val sourceAnnotationNames = annotationsForEntries.mapTo(mutableSetOf()) { it.qualifiedName }
|
||||
val specialAnnotationsOnAnnotationClass = modifierListOwner.clsDelegate.modifierList?.annotations.orEmpty().filter {
|
||||
it.qualifiedName !in sourceAnnotationNames
|
||||
}.map { KtLightNonSourceAnnotation(lightModifierList, it) }
|
||||
return annotationsForEntries + specialAnnotationsOnAnnotationClass
|
||||
}
|
||||
if ((modifierListOwner is KtLightMember<*> && modifierListOwner !is KtLightFieldImpl.KtLightEnumConstant)
|
||||
|| modifierListOwner is KtLightParameter) {
|
||||
return annotationsForEntries +
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
listOf(KtLightNullabilityAnnotation(modifierListOwner as KtLightElement<*, PsiModifierListOwner>, lightModifierList))
|
||||
}
|
||||
return annotationsForEntries
|
||||
}
|
||||
|
||||
private fun lightAnnotationsForEntries(lightModifierList: KtLightModifierList<*>): List<KtLightAnnotationForSourceEntry> {
|
||||
val lightModifierListOwner = lightModifierList.parent
|
||||
val annotatedKtDeclaration = lightModifierListOwner.kotlinOrigin as? KtDeclaration
|
||||
|
||||
if (annotatedKtDeclaration == null || !annotatedKtDeclaration.isValid || !hasAnnotationsInSource(annotatedKtDeclaration)) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return getAnnotationDescriptors(annotatedKtDeclaration, lightModifierListOwner)
|
||||
.mapNotNull { descriptor ->
|
||||
val fqName = descriptor.type.constructor.declarationDescriptor?.fqNameUnsafe?.asString() ?: return@mapNotNull null
|
||||
val entry = descriptor.source.getPsi() as? KtAnnotationEntry ?: return@mapNotNull null
|
||||
Pair(fqName, entry)
|
||||
}
|
||||
.groupBy({ it.first }) { it.second }
|
||||
.flatMap {
|
||||
(fqName, entries) ->
|
||||
entries.mapIndexed { index, entry ->
|
||||
KtLightAnnotationForSourceEntry(fqName, entry, lightModifierList) {
|
||||
lightModifierList.clsDelegate.annotations.filter { it.qualifiedName == fqName }.getOrNull(index)
|
||||
?: KtLightNonExistentAnnotation(lightModifierList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun getAnnotationDescriptors(declaration: KtDeclaration?, annotatedLightElement: KtLightElement<*, *>): List<AnnotationDescriptor> {
|
||||
val descriptor = declaration?.let { LightClassGenerationSupport.getInstance(it.project).resolveToDescriptor(it) }
|
||||
val annotatedDescriptor = when {
|
||||
descriptor is ClassDescriptor && annotatedLightElement is KtLightMethod && annotatedLightElement.isConstructor -> descriptor.unsubstitutedPrimaryConstructor
|
||||
descriptor !is PropertyDescriptor || annotatedLightElement !is KtLightMethod -> descriptor
|
||||
annotatedLightElement.isGetter -> descriptor.getter
|
||||
annotatedLightElement.isSetter -> descriptor.setter
|
||||
else -> descriptor
|
||||
} ?: return emptyList()
|
||||
|
||||
return annotatedDescriptor.annotations.getAllAnnotations().
|
||||
filter { it.matches(annotatedLightElement) }.
|
||||
map { it.annotation }
|
||||
}
|
||||
|
||||
private fun hasAnnotationsInSource(declaration: KtDeclaration): Boolean {
|
||||
if (declaration.annotationEntries.isNotEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (declaration is KtProperty) {
|
||||
return declaration.accessors.any { hasAnnotationsInSource(it) }
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun AnnotationWithTarget.matches(annotated: KtLightElement<*, *>): Boolean {
|
||||
if (annotated !is KtLightFieldImpl.KtLightFieldForDeclaration) return true
|
||||
|
||||
if (target == AnnotationUseSiteTarget.FIELD) return true
|
||||
|
||||
if (target != null) return false
|
||||
|
||||
val declarationSiteTargets = AnnotationChecker.applicableTargetSet(annotation)
|
||||
return KotlinTarget.FIELD in declarationSiteTargets && KotlinTarget.PROPERTY !in declarationSiteTargets
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.asJava.elements
|
||||
|
||||
import com.intellij.psi.PsiAnnotation
|
||||
import com.intellij.psi.PsiAnnotationOwner
|
||||
import com.intellij.psi.PsiModifierList
|
||||
import com.intellij.psi.impl.light.LightModifierList
|
||||
import com.intellij.psi.util.CachedValue
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.utils.indexOfFirst
|
||||
|
||||
abstract class KtLightModifierListWithExplicitModifiers(
|
||||
private val owner: KtLightElement<*, *>,
|
||||
modifiers: Array<String>
|
||||
) : LightModifierList(owner.manager, KotlinLanguage.INSTANCE, *modifiers) {
|
||||
abstract val delegate: PsiAnnotationOwner
|
||||
|
||||
private val _annotations by lazyPub { computeAnnotations(this, delegate) }
|
||||
|
||||
override fun getParent() = owner
|
||||
|
||||
override fun getAnnotations(): Array<out PsiAnnotation> = _annotations.value
|
||||
|
||||
override fun getApplicableAnnotations() = delegate.applicableAnnotations
|
||||
|
||||
override fun findAnnotation(@NonNls qualifiedName: String) = annotations.firstOrNull { it.qualifiedName == qualifiedName }
|
||||
|
||||
override fun addAnnotation(@NonNls qualifiedName: String) = delegate.addAnnotation(qualifiedName)
|
||||
}
|
||||
|
||||
internal fun computeAnnotations(lightElement: PsiModifierList,
|
||||
delegate: PsiAnnotationOwner): CachedValue<Array<out PsiAnnotation>> {
|
||||
fun doCompute(): Array<PsiAnnotation> {
|
||||
val delegateAnnotations = delegate.annotations
|
||||
if (delegateAnnotations.isEmpty()) return emptyArray()
|
||||
|
||||
val lightOwner = lightElement.parent as? KtLightElement<*, *>
|
||||
val declaration = lightOwner?.kotlinOrigin as? KtDeclaration
|
||||
if (declaration != null && !declaration.isValid) return PsiAnnotation.EMPTY_ARRAY
|
||||
val descriptor = declaration?.let { LightClassGenerationSupport.getInstance(lightElement.project).resolveToDescriptor(it) }
|
||||
val annotatedDescriptor = when {
|
||||
descriptor !is PropertyDescriptor || lightOwner !is KtLightMethod -> descriptor
|
||||
lightOwner.isGetter -> descriptor.getter
|
||||
lightOwner.isSetter -> descriptor.setter
|
||||
else -> descriptor
|
||||
}
|
||||
val ktAnnotations = annotatedDescriptor?.annotations?.getAllAnnotations() ?: emptyList()
|
||||
var nextIndex = 0
|
||||
val result = delegateAnnotations
|
||||
.map { clsAnnotation ->
|
||||
val currentIndex = ktAnnotations.indexOfFirst(nextIndex) {
|
||||
it.annotation.type.constructor.declarationDescriptor?.fqNameUnsafe?.asString() == clsAnnotation.qualifiedName
|
||||
}
|
||||
if (currentIndex >= 0) {
|
||||
nextIndex = currentIndex + 1
|
||||
val ktAnnotation = ktAnnotations[currentIndex]
|
||||
val entry = ktAnnotation.annotation.source.getPsi() as? KtAnnotationEntry ?: return@map clsAnnotation
|
||||
KtLightAnnotation(clsAnnotation, entry, lightElement)
|
||||
}
|
||||
else clsAnnotation
|
||||
}
|
||||
.toTypedArray()
|
||||
return result
|
||||
}
|
||||
|
||||
return CachedValuesManager.getManager(lightElement.project).createCachedValue<Array<out PsiAnnotation>>(
|
||||
{ CachedValueProvider.Result.create(doCompute(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) },
|
||||
false
|
||||
)
|
||||
}
|
||||
+2
-8
@@ -19,10 +19,8 @@ package org.jetbrains.kotlin.asJava.elements;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -32,6 +30,7 @@ import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class KtLightParameter extends LightParameter implements KtLightDeclaration<KtParameter, PsiParameter> {
|
||||
@@ -54,12 +53,7 @@ public class KtLightParameter extends LightParameter implements KtLightDeclarati
|
||||
this.method = method;
|
||||
|
||||
if (method.getLightMemberOrigin() instanceof LightMemberOriginForDeclaration) {
|
||||
this.modifierList = new KtLightModifierListWithExplicitModifiers(this, ArrayUtil.EMPTY_STRING_ARRAY) {
|
||||
@Override
|
||||
public PsiAnnotationOwner getDelegate() {
|
||||
return delegate.getModifierList();
|
||||
}
|
||||
};
|
||||
this.modifierList = new KtLightSimpleModifierList(this, Collections.emptySet());
|
||||
}
|
||||
else {
|
||||
this.modifierList = super.getModifierList();
|
||||
|
||||
+87
-24
@@ -19,7 +19,8 @@ package org.jetbrains.kotlin.asJava.elements
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
||||
import org.jetbrains.kotlin.asJava.classes.lazyPub
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
@@ -33,18 +34,35 @@ import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
class KtLightAnnotation(
|
||||
override val clsDelegate: PsiAnnotation,
|
||||
abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: () -> PsiAnnotation) :
|
||||
KtLightElementBase(parent), PsiAnnotation, KtLightElement<KtAnnotationEntry, PsiAnnotation> {
|
||||
override val clsDelegate by lazyPub(computeDelegate)
|
||||
|
||||
override fun getNameReferenceElement() = clsDelegate.nameReferenceElement
|
||||
|
||||
override fun getOwner() = parent as? PsiAnnotationOwner
|
||||
|
||||
override fun getMetaData() = clsDelegate.metaData
|
||||
|
||||
override fun getParameterList() = clsDelegate.parameterList
|
||||
}
|
||||
|
||||
class KtLightAnnotationForSourceEntry(
|
||||
private val qualifiedName: String,
|
||||
override val kotlinOrigin: KtAnnotationEntry,
|
||||
private val owner: PsiAnnotationOwner
|
||||
) : PsiAnnotation by clsDelegate, KtLightElement<KtAnnotationEntry, PsiAnnotation> {
|
||||
parent: KtLightElement<*, *>,
|
||||
computeDelegate: () -> PsiAnnotation
|
||||
) : KtLightAbstractAnnotation(parent, computeDelegate) {
|
||||
|
||||
override fun getQualifiedName() = qualifiedName
|
||||
|
||||
open inner class LightExpressionValue<out D : PsiExpression>(
|
||||
val delegate: D,
|
||||
private val parent: PsiElement
|
||||
) : PsiAnnotationMemberValue, PsiExpression by delegate {
|
||||
val originalExpression: PsiElement? by lazyPub {
|
||||
val nameAndValue = delegate.getStrictParentOfType<PsiNameValuePair>() ?: return@lazyPub null
|
||||
val annotationEntry = this@KtLightAnnotation.kotlinOrigin
|
||||
val annotationEntry = this@KtLightAnnotationForSourceEntry.kotlinOrigin
|
||||
val context = LightClassGenerationSupport.getInstance(project).analyze(annotationEntry)
|
||||
val resolvedCall = annotationEntry.getResolvedCall(context) ?: return@lazyPub null
|
||||
val annotationConstructor = resolvedCall.resultingDescriptor
|
||||
@@ -73,10 +91,10 @@ class KtLightAnnotation(
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun getConstantValue(): Any? {
|
||||
val expression = originalExpression as? KtExpression ?: return null
|
||||
val annotationEntry = this@KtLightAnnotation.kotlinOrigin
|
||||
val annotationEntry = this@KtLightAnnotationForSourceEntry.kotlinOrigin
|
||||
val context = LightClassGenerationSupport.getInstance(project).analyze(annotationEntry)
|
||||
return context[BindingContext.COMPILE_TIME_VALUE, expression]?.getValue(TypeUtils.NO_EXPECTED_TYPE)
|
||||
}
|
||||
@@ -102,7 +120,8 @@ class KtLightAnnotation(
|
||||
val exprToReplace =
|
||||
if (origin is KtCallExpression /*arrayOf*/) {
|
||||
unwrapArray(origin.valueArguments)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
origin as? KtExpression
|
||||
} ?: return this
|
||||
exprToReplace.replace(KtPsiFactory(this).createExpression("\"${StringUtil.escapeStringCharacters(value)}\""))
|
||||
@@ -114,7 +133,7 @@ class KtLightAnnotation(
|
||||
inner class LightStringLiteral(
|
||||
delegate: PsiLiteralExpression,
|
||||
parent: PsiElement
|
||||
): LightExpressionValue<PsiLiteralExpression>(delegate, parent), PsiLiteralExpression {
|
||||
) : LightExpressionValue<PsiLiteralExpression>(delegate, parent), PsiLiteralExpression {
|
||||
override fun getValue() = delegate.value
|
||||
}
|
||||
|
||||
@@ -150,31 +169,75 @@ class KtLightAnnotation(
|
||||
override fun isPhysical() = true
|
||||
|
||||
override fun getName() = null
|
||||
override fun setName(newName: String) = throw IncorrectOperationException()
|
||||
|
||||
override fun getOwner() = owner
|
||||
|
||||
override fun findAttributeValue(name: String?) = clsDelegate.findAttributeValue(name)?.let { wrapAnnotationValue(it, this) }
|
||||
override fun findDeclaredAttributeValue(name: String?) = clsDelegate.findDeclaredAttributeValue(name)?.let { wrapAnnotationValue(it, this) }
|
||||
|
||||
override fun getText() = kotlinOrigin.text ?: ""
|
||||
override fun getTextRange() = kotlinOrigin.textRange ?: TextRange.EMPTY_RANGE
|
||||
|
||||
override fun getParent() = owner as? PsiElement
|
||||
|
||||
override fun getLanguage() = KotlinLanguage.INSTANCE
|
||||
|
||||
override fun delete() {
|
||||
kotlinOrigin.delete()
|
||||
}
|
||||
override fun delete() = kotlinOrigin.delete()
|
||||
|
||||
override fun toString() = "@$qualifiedName"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || other::class.java != this::class.java) return false
|
||||
return kotlinOrigin == (other as KtLightAnnotation).kotlinOrigin
|
||||
return kotlinOrigin == (other as KtLightAnnotationForSourceEntry).kotlinOrigin
|
||||
}
|
||||
|
||||
override fun hashCode() = kotlinOrigin.hashCode()
|
||||
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?): T
|
||||
= clsDelegate.setDeclaredAttributeValue(attributeName, value)
|
||||
}
|
||||
|
||||
class KtLightNonSourceAnnotation(
|
||||
parent: PsiElement, clsDelegate: PsiAnnotation
|
||||
): KtLightAbstractAnnotation(parent, { clsDelegate }) {
|
||||
override val kotlinOrigin: KtAnnotationEntry? get() = null
|
||||
override fun getQualifiedName() = clsDelegate.qualifiedName
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?)
|
||||
= clsDelegate.setDeclaredAttributeValue(attributeName, value)
|
||||
override fun findAttributeValue(attributeName: String?) = clsDelegate.findAttributeValue(attributeName)
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = clsDelegate.findDeclaredAttributeValue(attributeName)
|
||||
}
|
||||
|
||||
class KtLightNonExistentAnnotation(parent: KtLightElement<*, *>) : KtLightElementBase(parent), PsiAnnotation {
|
||||
override val kotlinOrigin get() = null
|
||||
override fun toString() = this.javaClass.name
|
||||
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
|
||||
|
||||
override fun getNameReferenceElement() = null
|
||||
override fun findAttributeValue(attributeName: String?) = null
|
||||
override fun getQualifiedName() = null
|
||||
override fun getOwner() = parent as? PsiAnnotationOwner
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = null
|
||||
override fun getMetaData() = null
|
||||
override fun getParameterList() = KtLightEmptyAnnotationParameterList(this)
|
||||
}
|
||||
|
||||
class KtLightEmptyAnnotationParameterList(parent: PsiElement) : KtLightElementBase(parent), PsiAnnotationParameterList {
|
||||
override val kotlinOrigin get() = null
|
||||
override fun getAttributes(): Array<PsiNameValuePair> = emptyArray()
|
||||
}
|
||||
|
||||
class KtLightNullabilityAnnotation(member: KtLightElement<*, PsiModifierListOwner>, parent: PsiElement) : KtLightAbstractAnnotation(parent, {
|
||||
// searching for last because nullability annotations are generated after backend generates source annotations
|
||||
member.clsDelegate.modifierList?.annotations?.findLast {
|
||||
isNullabilityAnnotation(it.qualifiedName)
|
||||
} ?: KtLightNonExistentAnnotation(member)
|
||||
}) {
|
||||
override val kotlinOrigin get() = null
|
||||
override fun <T : PsiAnnotationMemberValue?> setDeclaredAttributeValue(attributeName: String?, value: T?) = cannotModify()
|
||||
|
||||
override fun findAttributeValue(attributeName: String?) = null
|
||||
|
||||
override fun getQualifiedName(): String? = clsDelegate.qualifiedName
|
||||
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = null
|
||||
}
|
||||
|
||||
private fun cannotModify(): Nothing = error("Cannot modify") // TODO: meaningful message?
|
||||
|
||||
internal fun isNullabilityAnnotation(qualifiedName: String?) = qualifiedName in backendNullabilityAnnotations
|
||||
|
||||
private val backendNullabilityAnnotations = arrayOf(Nullable::class.java.name, NotNull::class.java.name)
|
||||
@@ -20,7 +20,7 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
|
||||
import java.util.*
|
||||
|
||||
fun KtClassOrObject.toLightClass(): KtLightClass? = LightClassGenerationSupport.getInstance(project).getLightClass(this)
|
||||
|
||||
@@ -125,7 +124,7 @@ val PsiElement.unwrapped: PsiElement?
|
||||
get() = when {
|
||||
this is KtLightElement<*, *> -> kotlinOrigin
|
||||
this is KtLightIdentifier -> origin
|
||||
this is KtLightAnnotation.LightExpressionValue<*> -> originalExpression
|
||||
this is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> originalExpression
|
||||
else -> this
|
||||
}
|
||||
|
||||
@@ -153,7 +152,7 @@ fun KtAnnotationEntry.toLightAnnotation(): PsiAnnotation? {
|
||||
val ktDeclaration = getStrictParentOfType<KtModifierList>()?.parent as? KtDeclaration ?: return null
|
||||
for (lightElement in ktDeclaration.toLightElements()) {
|
||||
if (lightElement !is PsiModifierListOwner) continue
|
||||
lightElement.modifierList?.annotations?.firstOrNull { it is KtLightAnnotation && it.kotlinOrigin == this }?.let { return it }
|
||||
lightElement.modifierList?.annotations?.firstOrNull { it is KtLightAnnotationForSourceEntry && it.kotlinOrigin == this }?.let { return it }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
@kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE)
|
||||
@kotlin.annotation.Target(allowedTargets = {kotlin.annotation.AnnotationTarget.TYPE_PARAMETER})
|
||||
@kotlin.annotation.MustBeDocumented
|
||||
@kotlin.annotation.Repeatable
|
||||
@java.lang.annotation.Documented
|
||||
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
|
||||
@java.lang.annotation.Target({})
|
||||
public @interface Anno {
|
||||
int i();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Anno
|
||||
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(AnnotationTarget.TYPE_PARAMETER)
|
||||
@MustBeDocumented
|
||||
@Repeatable
|
||||
annotation class Anno(val i: Int)
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
public final class Annotations {
|
||||
@p.R(s = "a")
|
||||
@p.R(s = "b")
|
||||
@p.R(s = "c")
|
||||
public final void repeatables1() { /* compiled code */ }
|
||||
|
||||
@p.R(s = "a")
|
||||
public final void repeatables2() { /* compiled code */ }
|
||||
|
||||
@p.R(s = "a")
|
||||
@p.S(g = "b")
|
||||
@p.R(s = "c")
|
||||
@p.S(g = "D")
|
||||
@p.R(s = "f")
|
||||
public final void repeatables3() { /* compiled code */ }
|
||||
|
||||
public Annotations() { /* compiled code */ }
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// p.Annotations
|
||||
package p
|
||||
|
||||
|
||||
class Annotations {
|
||||
|
||||
@R("a") @R("b") @R("c")
|
||||
fun repeatables1() {
|
||||
|
||||
}
|
||||
|
||||
@R("a")
|
||||
fun repeatables2() {
|
||||
|
||||
}
|
||||
|
||||
@R("a") @S("b") @R("c") @S("D") @R("f")
|
||||
fun repeatables3() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Repeatable
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class S(val g: String)
|
||||
|
||||
@Repeatable
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class R(val s: String)
|
||||
@@ -138,6 +138,12 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SpecialAnnotationsOnAnnotationClass.kt")
|
||||
public void testSpecialAnnotationsOnAnnotationClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("VarArgs.kt")
|
||||
public void testVarArgs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/VarArgs.kt");
|
||||
@@ -164,6 +170,12 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("RepetableAnnotations.kt")
|
||||
public void testRepetableAnnotations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SameName.kt")
|
||||
public void testSameName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/compilationErrors/SameName.kt");
|
||||
|
||||
@@ -21,7 +21,7 @@ import com.intellij.psi.PsiConstantEvaluationHelper
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiExpression
|
||||
import com.intellij.psi.impl.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
@@ -49,7 +49,7 @@ class KotlinLightConstantExpressionEvaluator : ConstantExpressionEvaluator {
|
||||
throwExceptionOnOverflow: Boolean,
|
||||
auxEvaluator: PsiConstantEvaluationHelper.AuxEvaluator?
|
||||
): Any? {
|
||||
if (expression !is KtLightAnnotation.LightExpressionValue<*>) return null
|
||||
if (expression !is KtLightAnnotationForSourceEntry.LightExpressionValue<*>) return null
|
||||
val expressionToCompute = expression.originalExpression ?: return null
|
||||
return when (expressionToCompute) {
|
||||
is KtExpression -> {
|
||||
|
||||
@@ -471,7 +471,7 @@ private fun copyModifierListItems(from: PsiModifierList, to: PsiModifierList, wi
|
||||
}
|
||||
}
|
||||
for (annotation in from.annotations) {
|
||||
val annotationName = annotation.qualifiedName!!
|
||||
val annotationName = annotation.qualifiedName ?: continue
|
||||
|
||||
if (Retention::class.java.name != annotationName) {
|
||||
to.addAnnotation(annotationName)
|
||||
|
||||
@@ -23,13 +23,15 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.annotations.Nullable
|
||||
import org.jetbrains.kotlin.asJava.LightClassTestCommon
|
||||
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
|
||||
import org.jetbrains.kotlin.asJava.builder.StubComputationTracker
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
import org.jetbrains.kotlin.asJava.elements.*
|
||||
import org.jetbrains.kotlin.idea.KotlinDaemonAnalyzerTestCase
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.LightClassLazinessChecker.Tracker.Level.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.lightClasses.IDELightClassConstructionContext
|
||||
@@ -42,9 +44,12 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.stringValue
|
||||
import org.junit.Assert
|
||||
import java.io.File
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
abstract class AbstractIdeLightClassTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
fun doTest(testDataPath: String) {
|
||||
@@ -219,18 +224,54 @@ object LightClassLazinessChecker {
|
||||
for ((field, lightFieldInfo) in fieldsToInfo) {
|
||||
val delegate = (field as KtLightField).clsDelegate
|
||||
assertEquals(fieldInfo(delegate), lightFieldInfo)
|
||||
checkAnnotationConsistency(field)
|
||||
}
|
||||
for ((method, lightMethodInfo) in methodsToInfo) {
|
||||
val delegate = (method as KtLightMethod).clsDelegate
|
||||
assertEquals(methodInfo(delegate, lazinessMode), lightMethodInfo)
|
||||
checkAnnotationConsistency(method)
|
||||
method.parameterList.parameters.forEach {
|
||||
checkAnnotationConsistency(it as KtLightParameter)
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(classInfo(lightClass.clsDelegate), classInfo)
|
||||
checkAnnotationConsistency(lightClass)
|
||||
|
||||
innerClasses.forEach(LazinessInfo::checkConsistency)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAnnotationConsistency(modifierListOwner: KtLightElement<*, PsiModifierListOwner>) {
|
||||
if (modifierListOwner is KtLightClassForFacade) return
|
||||
|
||||
modifierListOwner.clsDelegate.modifierList!!.annotations.groupBy { delegateAnnotation ->
|
||||
delegateAnnotation.qualifiedName!!
|
||||
}.map {
|
||||
(fqName, clsAnnotations) ->
|
||||
|
||||
val lightAnnotations = (modifierListOwner as? PsiModifierListOwner)?.modifierList?.annotations?.filter { it.qualifiedName == fqName }.orEmpty()
|
||||
if (fqName != Nullable::class.java.name && fqName != NotNull::class.java.name) {
|
||||
assertEquals(clsAnnotations.size, lightAnnotations.size, "Missing $fqName annotation")
|
||||
}
|
||||
else {
|
||||
// having duplicating nullability annotations is fine
|
||||
// see KtLightNullabilityAnnotation
|
||||
assertTrue(lightAnnotations.isNotEmpty(), "Missing $fqName annotation")
|
||||
}
|
||||
clsAnnotations.zip(lightAnnotations).forEach {
|
||||
(clsAnnotation, lightAnnotation) ->
|
||||
assertNotNull(lightAnnotation!!.nameReferenceElement)
|
||||
if (lightAnnotation is KtLightAbstractAnnotation) {
|
||||
assertEquals(clsAnnotation.values(), lightAnnotation.values())
|
||||
assertEquals(clsAnnotation, lightAnnotation.clsDelegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiAnnotation.values() = parameterList.attributes.map { it.value.stringValue() }
|
||||
|
||||
private data class ClassInfo(
|
||||
val fieldNames: Collection<String>,
|
||||
val methodNames: Collection<String>,
|
||||
@@ -247,6 +288,8 @@ object LightClassLazinessChecker {
|
||||
)
|
||||
|
||||
private fun fieldInfo(field: PsiField) = with(field) {
|
||||
modifierList?.annotations // check getting annotations list doesn't trigger exact resolve
|
||||
|
||||
FieldInfo(
|
||||
name!!, PsiModifier.MODIFIERS.asList().filter { modifierList!!.hasModifierProperty(it) }
|
||||
)
|
||||
@@ -261,6 +304,8 @@ object LightClassLazinessChecker {
|
||||
)
|
||||
|
||||
private fun methodInfo(method: PsiMethod, lazinessMode: Mode) = with(method) {
|
||||
modifierList.annotations // check getting annotations list doesn't trigger exact resolve
|
||||
|
||||
MethodInfo(
|
||||
name, relevantModifiers(lazinessMode),
|
||||
isConstructor, method.parameterList.parametersCount, isVarArgs
|
||||
|
||||
+6
@@ -138,6 +138,12 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SpecialAnnotationsOnAnnotationClass.kt")
|
||||
public void testSpecialAnnotationsOnAnnotationClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("VarArgs.kt")
|
||||
public void testVarArgs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/VarArgs.kt");
|
||||
|
||||
@@ -138,6 +138,12 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SpecialAnnotationsOnAnnotationClass.kt")
|
||||
public void testSpecialAnnotationsOnAnnotationClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("VarArgs.kt")
|
||||
public void testVarArgs() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/VarArgs.kt");
|
||||
@@ -164,6 +170,12 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("RepetableAnnotations.kt")
|
||||
public void testRepetableAnnotations() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("SameName.kt")
|
||||
public void testSameName() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/compilationErrors/SameName.kt");
|
||||
|
||||
@@ -40,7 +40,7 @@ object PsiElementChecker {
|
||||
}
|
||||
|
||||
private fun checkPsiElement(element: PsiElement) {
|
||||
if (element !is KtLightElement<*, *> && element !is KtLightModifierList) return
|
||||
if (element !is KtLightElement<*, *> && element !is KtLightModifierList<*>) return
|
||||
|
||||
if (element is PsiModifierListOwner) {
|
||||
val modifierList = element.modifierList
|
||||
|
||||
-1
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.annotation.processing
|
||||
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.findFacadeClass
|
||||
import org.jetbrains.kotlin.asJava.toLightClass
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ public final class Test {
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final java.lang.String getF()
|
||||
|
||||
@org.jetbrains.annotations.NotNull
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final void a()
|
||||
|
||||
|
||||
+3
-3
@@ -20,7 +20,7 @@ import com.intellij.psi.*
|
||||
import com.intellij.psi.PsiModifier.*
|
||||
import com.intellij.psi.impl.PsiSubstitutorImpl
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||
import javax.lang.model.element.Modifier
|
||||
|
||||
private val HAS_DEFAULT by lazy {
|
||||
@@ -54,7 +54,7 @@ private fun PsiModifierList.getJavaModifiers(): Set<Modifier> {
|
||||
internal fun PsiExpression.calcConstantValue(evaluator: PsiConstantEvaluationHelper? = null): Any? {
|
||||
return when (this) {
|
||||
is PsiLiteral -> value
|
||||
is KtLightAnnotation.LightExpressionValue<*> -> getConstantValue() ?: delegate.calcConstantValue(evaluator)
|
||||
is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> getConstantValue() ?: delegate.calcConstantValue(evaluator)
|
||||
is PsiExpression -> (evaluator ?: getConstantEvaluator(this)).computeConstantExpression(this)
|
||||
else -> null
|
||||
}
|
||||
@@ -71,7 +71,7 @@ internal val PsiModifierListOwner.isFinal: Boolean
|
||||
fun PsiModifierListOwner.getJavaModifiers() = modifierList?.getJavaModifiers() ?: emptySet()
|
||||
|
||||
fun PsiModifierListOwner.getAnnotationsWithInherited(): List<PsiAnnotation> {
|
||||
val annotations = modifierList?.annotations?.toMutableList() ?: mutableListOf()
|
||||
val annotations = modifierList?.annotations?.filter { it.qualifiedName != null }?.toMutableList() ?: mutableListOf()
|
||||
|
||||
if (this is PsiClass) {
|
||||
var superClass = superClass
|
||||
|
||||
@@ -229,7 +229,7 @@ internal object KotlinConverter {
|
||||
is KtContainerNode -> element.getExpression()?.let {
|
||||
KotlinConverter.convertExpression(it, parentCallback, requiredType)
|
||||
} ?: el<UExpression> { UastEmptyExpression }
|
||||
is KtLightAnnotation.LightExpressionValue<*> -> {
|
||||
is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> {
|
||||
val expression = element.originalExpression
|
||||
when (expression) {
|
||||
is KtExpression -> KotlinConverter.convertExpression(expression, parentCallback, requiredType)
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.spring.gutter.SpringClassAnnotator
|
||||
import com.intellij.util.Function
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightIdentifier
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
|
||||
@@ -78,7 +78,7 @@ class KotlinSpringClassAnnotator : SpringClassAnnotator() {
|
||||
}
|
||||
|
||||
// Workaround for SpringClassAnnotator
|
||||
(getElementToProcess(psiElement) as? KtLightAnnotation)?.let { return super.collectNavigationMarkers(it, result) }
|
||||
(getElementToProcess(psiElement) as? KtLightAnnotationForSourceEntry)?.let { return super.collectNavigationMarkers(it, result) }
|
||||
|
||||
super.collectNavigationMarkers(psiElement, result)
|
||||
}
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ import com.intellij.spring.model.xml.beans.SpringPropertyDefinition
|
||||
import com.intellij.testFramework.UsefulTestCase.assertSameElements
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.intellij.util.xml.DomUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotation
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightAnnotationForSourceEntry
|
||||
import org.jetbrains.kotlin.idea.completion.test.assertInstanceOf
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
@@ -47,7 +47,7 @@ private fun nameBean(element: PsiElement): String {
|
||||
private fun nameProperty(element: PsiElement) = DomUtil.getDomElement(element).assertInstanceOf<SpringPropertyDefinition>().propertyName!!
|
||||
|
||||
private fun namePsi(element: PsiElement): String {
|
||||
if (element is KtLightAnnotation) return namePsi(element.kotlinOrigin.getStrictParentOfType<KtModifierListOwner>()!!)
|
||||
if (element is KtLightAnnotationForSourceEntry) return namePsi(element.kotlinOrigin.getStrictParentOfType<KtModifierListOwner>()!!)
|
||||
return SymbolPresentationUtil.getSymbolPresentableText(element)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user