From 0571c6294350c85b62b797975561d928112d6bc0 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 24 Apr 2017 17:37:58 +0300 Subject: [PATCH] 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 --- .../KtLightClassForInterfaceDefaultImpls.kt | 4 +- .../KtLightClassForSourceDeclaration.kt | 8 +- .../asJava/elements/KtLightMemberImpl.kt | 34 +--- .../asJava/elements/KtLightModifierList.kt | 150 ++++++++++++++++++ ...tLightModifierListWithExplicitModifiers.kt | 96 ----------- .../asJava/elements/KtLightParameter.java | 10 +- ...LightAnnotation.kt => lightAnnotations.kt} | 111 ++++++++++--- .../kotlin/asJava/lightClassUtils.kt | 7 +- .../SpecialAnnotationsOnAnnotationClass.java | 10 ++ .../SpecialAnnotationsOnAnnotationClass.kt | 7 + .../RepetableAnnotations.java | 18 +++ .../compilationErrors/RepetableAnnotations.kt | 30 ++++ .../CompilerLightClassTestGenerated.java | 12 ++ .../KotlinLightConstantExpressionEvaluator.kt | 4 +- .../idea/refactoring/kotlinRefactoringUtil.kt | 2 +- .../resolve/AbstractIdeLightClassTest.kt | 49 +++++- .../IdeCompiledLightClassTestGenerated.java | 6 + .../resolve/IdeLightClassTestGenerated.java | 12 ++ .../idea/caches/resolve/PsiElementChecker.kt | 2 +- .../annotation/processing/RoundAnnotations.kt | 1 - .../kotlinWrappers/kotlinAnnotations.txt | 1 + .../java/model/internal/internalUtil.kt | 6 +- .../uast/kotlin/KotlinUastLanguagePlugin.kt | 2 +- .../lineMarking/KotlinSpringClassAnnotator.kt | 4 +- .../tests/gutter/springGutterTestUtils.kt | 4 +- 25 files changed, 411 insertions(+), 179 deletions(-) create mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt delete mode 100644 compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierListWithExplicitModifiers.kt rename compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/{KtLightAnnotation.kt => lightAnnotations.kt} (62%) create mode 100644 compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java create mode 100644 compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt create mode 100644 compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.java create mode 100644 compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt index 5e6e6586d70..8e76bf3499b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForInterfaceDefaultImpls.kt @@ -40,7 +40,7 @@ class KtLightClassForInterfaceDefaultImpls(classOrObject: KtClassOrObject) override fun getTypeParameterList(): PsiTypeParameterList? = null override fun getTypeParameters(): Array = emptyArray() - override fun computeModifiers(): Array = 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() } + +private val publicStaticFinal = setOf(PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL) \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt index 8dd04776a6d..5ff406709c5 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForSourceDeclaration.kt @@ -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 { + protected open fun computeModifiers(): Set { val psiModifiers = hashSetOf() // 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 diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt index 9fc55cc0367..5b783f1b27c 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt @@ -41,7 +41,7 @@ abstract class KtLightMemberImpl( 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( 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(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>(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 = annotations - override fun getAnnotations(): Array = _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) } + diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt new file mode 100644 index 00000000000..41848d25562 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt @@ -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>(protected val owner: T) + : LightElement(owner.manager, KotlinLanguage.INSTANCE), PsiModifierList, KtLightElement { + 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 = annotations + override fun getAnnotations(): Array = _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, private val modifiers: Set +) : KtLightModifierList>(owner) { + override fun hasModifierProperty(name: String) = name in modifiers + + override fun copy() = KtLightSimpleModifierList(owner, modifiers) +} + +private fun computeAnnotations(lightModifierList: KtLightModifierList<*>): List { + 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 { + 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 { + 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 +} diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierListWithExplicitModifiers.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierListWithExplicitModifiers.kt deleted file mode 100644 index 8dc54eef222..00000000000 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierListWithExplicitModifiers.kt +++ /dev/null @@ -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 -) : 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 = _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> { - fun doCompute(): Array { - 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>( - { CachedValueProvider.Result.create(doCompute(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT) }, - false - ) -} diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java index a48d14aac7b..936de3408f8 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightParameter.java @@ -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 { @@ -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(); diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotation.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt similarity index 62% rename from compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotation.kt rename to compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt index 0bc7f278a48..aed9e73957b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightAnnotation.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/lightAnnotations.kt @@ -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 { + 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 { + parent: KtLightElement<*, *>, + computeDelegate: () -> PsiAnnotation +) : KtLightAbstractAnnotation(parent, computeDelegate) { + + override fun getQualifiedName() = qualifiedName + open inner class LightExpressionValue( val delegate: D, private val parent: PsiElement ) : PsiAnnotationMemberValue, PsiExpression by delegate { val originalExpression: PsiElement? by lazyPub { val nameAndValue = delegate.getStrictParentOfType() ?: 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(delegate, parent), PsiLiteralExpression { + ) : LightExpressionValue(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 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 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 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 = 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 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) \ No newline at end of file diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt index ba396abcd7a..f9312643df1 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/lightClassUtils.kt @@ -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()?.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 } diff --git a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java new file mode 100644 index 00000000000..1b1dfbc0541 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.java @@ -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(); +} diff --git a/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt new file mode 100644 index 00000000000..25433768b75 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/SpecialAnnotationsOnAnnotationClass.kt @@ -0,0 +1,7 @@ +// Anno + +@Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.TYPE_PARAMETER) +@MustBeDocumented +@Repeatable +annotation class Anno(val i: Int) diff --git a/compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.java b/compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.java new file mode 100644 index 00000000000..edc1dfc214a --- /dev/null +++ b/compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.java @@ -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 */ } +} diff --git a/compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt b/compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt new file mode 100644 index 00000000000..6dc2b547b9f --- /dev/null +++ b/compiler/testData/asJava/lightClasses/compilationErrors/RepetableAnnotations.kt @@ -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) \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java index 2b0f05d3242..fa4bea1dbd5 100644 --- a/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java @@ -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"); diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt index c0c54f90978..60585bab77b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinLightConstantExpressionEvaluator.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 -> { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt index ff5029aa7ef..531f7c1e0df 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt @@ -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) diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt index f7e93e3ddff..27d0ed90b6a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt @@ -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, val methodNames: Collection, @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java index ed5563b7a6b..0a6c0a0853a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java @@ -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"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java index 69c087eacc0..4423274fac4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java @@ -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"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt index 685f61bfbc1..d4d48f5235e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.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 diff --git a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/RoundAnnotations.kt b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/RoundAnnotations.kt index 3ff87c760cd..92dc5e6429c 100644 --- a/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/RoundAnnotations.kt +++ b/plugins/annotation-processing/src/org/jetbrains/kotlin/annotation/processing/RoundAnnotations.kt @@ -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 diff --git a/plugins/annotation-processing/testData/wrappers/kotlinWrappers/kotlinAnnotations.txt b/plugins/annotation-processing/testData/wrappers/kotlinWrappers/kotlinAnnotations.txt index 17045e27fa6..39a3e2df9f7 100644 --- a/plugins/annotation-processing/testData/wrappers/kotlinWrappers/kotlinAnnotations.txt +++ b/plugins/annotation-processing/testData/wrappers/kotlinWrappers/kotlinAnnotations.txt @@ -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() diff --git a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/internalUtil.kt b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/internalUtil.kt index e63475f5011..1b2f82ea4ac 100644 --- a/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/internalUtil.kt +++ b/plugins/java-model-wrappers/src/org/jetbrains/kotlin/java/model/internal/internalUtil.kt @@ -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 { 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 { - val annotations = modifierList?.annotations?.toMutableList() ?: mutableListOf() + val annotations = modifierList?.annotations?.filter { it.qualifiedName != null }?.toMutableList() ?: mutableListOf() if (this is PsiClass) { var superClass = superClass diff --git a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt index 08782632225..32be6d5e13f 100644 --- a/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt +++ b/plugins/uast-kotlin/src/org/jetbrains/uast/kotlin/KotlinUastLanguagePlugin.kt @@ -229,7 +229,7 @@ internal object KotlinConverter { is KtContainerNode -> element.getExpression()?.let { KotlinConverter.convertExpression(it, parentCallback, requiredType) } ?: el { UastEmptyExpression } - is KtLightAnnotation.LightExpressionValue<*> -> { + is KtLightAnnotationForSourceEntry.LightExpressionValue<*> -> { val expression = element.originalExpression when (expression) { is KtExpression -> KotlinConverter.convertExpression(expression, parentCallback, requiredType) diff --git a/ultimate/src/org/jetbrains/kotlin/idea/spring/lineMarking/KotlinSpringClassAnnotator.kt b/ultimate/src/org/jetbrains/kotlin/idea/spring/lineMarking/KotlinSpringClassAnnotator.kt index 0ca9db7b907..ff9e2558e6c 100644 --- a/ultimate/src/org/jetbrains/kotlin/idea/spring/lineMarking/KotlinSpringClassAnnotator.kt +++ b/ultimate/src/org/jetbrains/kotlin/idea/spring/lineMarking/KotlinSpringClassAnnotator.kt @@ -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) } diff --git a/ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/gutter/springGutterTestUtils.kt b/ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/gutter/springGutterTestUtils.kt index 675675b90f6..daf49b2b319 100644 --- a/ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/gutter/springGutterTestUtils.kt +++ b/ultimate/tests/org/jetbrains/kotlin/idea/spring/tests/gutter/springGutterTestUtils.kt @@ -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().propertyName!! private fun namePsi(element: PsiElement): String { - if (element is KtLightAnnotation) return namePsi(element.kotlinOrigin.getStrictParentOfType()!!) + if (element is KtLightAnnotationForSourceEntry) return namePsi(element.kotlinOrigin.getStrictParentOfType()!!) return SymbolPresentationUtil.getSymbolPresentableText(element) }