diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java index adaf67bcd59..9bccca502fb 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/FakeLightClassForFileOfPackage.java @@ -23,12 +23,15 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.impl.light.AbstractLightClass; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation; import org.jetbrains.kotlin.asJava.finder.JavaElementFinder; import org.jetbrains.kotlin.idea.KotlinLanguage; import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind; import org.jetbrains.kotlin.psi.KtClassOrObject; import org.jetbrains.kotlin.psi.KtFile; +import java.util.List; + /** * This class serves as a workaround for usages of {@link JavaElementFinder#findClasses} which eventually only need names of files * containing the class. When queried for a package class (e.g. test/TestPackage), {@code findClasses} along with a @@ -111,4 +114,10 @@ public class FakeLightClassForFileOfPackage extends AbstractLightClass implement public LightClassOriginKind getOriginKind() { return LightClassOriginKind.SOURCE; } + + @Nullable + @Override + public List getGivenAnnotations() { + return null; + } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt index df2fc73f96b..eb9ff23f2ef 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightAnnotations.kt @@ -2,9 +2,22 @@ package org.jetbrains.kotlin.asJava.classes import com.intellij.lang.jvm.JvmModifier import com.intellij.psi.* +import com.intellij.psi.impl.PsiImplUtil +import com.intellij.psi.impl.light.LightIdentifier +import com.intellij.psi.impl.light.LightTypeElement +import com.intellij.psi.impl.source.PsiClassReferenceType +import com.intellij.psi.meta.PsiMetaData import org.jetbrains.annotations.NotNull import org.jetbrains.annotations.Nullable +import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation +import org.jetbrains.kotlin.asJava.elements.KtLightElementBase import org.jetbrains.kotlin.asJava.elements.KtLightNullabilityAnnotation +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor +import org.jetbrains.kotlin.load.kotlin.TypeMappingMode +import org.jetbrains.kotlin.psi.KtCallElement +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.resolve.constants.* import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.isError @@ -35,6 +48,140 @@ class KtUltraLightNullabilityAnnotation( } } +fun DeclarationDescriptor.obtainLightAnnotations( + ultraLightSupport: UltraLightSupport, + parent: PsiElement +): List = annotations.map { KtUltraLightAnnotationForDescriptor(it, ultraLightSupport, parent) } + +class KtUltraLightAnnotationForDescriptor( + private val annotationDescriptor: AnnotationDescriptor, + private val ultraLightSupport: UltraLightSupport, + parent: PsiElement +) : KtLightAbstractAnnotation(parent, { error("clsDelegate for annotation based on descriptor: $annotationDescriptor") }) { + override fun getNameReferenceElement(): PsiJavaCodeReferenceElement? = null + + override fun getMetaData(): PsiMetaData? = null + + private val parameterList = ParameterListImpl() + + override fun getParameterList(): PsiAnnotationParameterList = parameterList + + override val kotlinOrigin: KtCallElement? get() = null + + override fun setDeclaredAttributeValue(p0: String?, p1: T?) = cannotModify() + + override fun findAttributeValue(attributeName: String?): PsiAnnotationMemberValue? = + PsiImplUtil.findAttributeValue(this, attributeName) + + override fun findDeclaredAttributeValue(attributeName: String?) = + PsiImplUtil.findDeclaredAttributeValue(this, attributeName) + + override fun getQualifiedName() = annotationDescriptor.fqName?.asString() + + private inner class ParameterListImpl : KtLightElementBase(this@KtUltraLightAnnotationForDescriptor), PsiAnnotationParameterList { + private val _attributes: Array by lazyPub { + annotationDescriptor.allValueArguments.map { + PsiNameValuePairForAnnotationArgument(it.key.asString(), it.value, ultraLightSupport, this) + }.toTypedArray() + } + + override fun getAttributes(): Array = _attributes + + override val kotlinOrigin: KtElement? get() = null + } + + override fun getText() = "@$qualifiedName(" + parameterList.attributes.joinToString { it.name + "=" + it.value?.text } + ")" +} + +private class PsiNameValuePairForAnnotationArgument( + private val _name: String = "", + private val constantValue: ConstantValue<*>, + private val ultraLightSupport: UltraLightSupport, + parent: PsiElement +) : KtLightElementBase(parent), PsiNameValuePair { + override val kotlinOrigin: KtElement? get() = null + + private val _value by lazyPub { + constantValue.toAnnotationMemberValue(this, ultraLightSupport) + } + + override fun setValue(p0: PsiAnnotationMemberValue) = cannotModify() + + override fun getNameIdentifier() = LightIdentifier(parent.manager, _name) + + override fun getValue(): PsiAnnotationMemberValue? = _value + + override fun getLiteralValue(): String? = (value as? PsiLiteralExpression)?.value?.toString() + + override fun getName() = _name +} + +private fun ConstantValue<*>.toAnnotationMemberValue( + parent: PsiElement, ultraLightSupport: UltraLightSupport +): PsiAnnotationMemberValue? = when (this) { + + is AnnotationValue -> KtUltraLightAnnotationForDescriptor(value, ultraLightSupport, parent) + + is ArrayValue -> + KtUltraLightPsiArrayInitializerMemberValue(lightParent = parent) { arrayLiteralParent -> + this.value.mapNotNull { element -> element.toAnnotationMemberValue(arrayLiteralParent, ultraLightSupport) } + } + + is KClassValue -> KtUltraLightPsiClassObjectAccessExpression(this, ultraLightSupport, parent) + + is ErrorValue -> null + + else -> KtUltraLightPsiLiteralForConstantValue(this, ultraLightSupport, parent) +} + +private class KtUltraLightPsiArrayInitializerMemberValue( + val lightParent: PsiElement, + private val arguments: (KtUltraLightPsiArrayInitializerMemberValue) -> List +) : KtLightElementBase(lightParent), PsiArrayInitializerMemberValue { + + override val kotlinOrigin: KtElement? get() = null + + override fun getInitializers(): Array = arguments(this).toTypedArray() + + override fun getParent(): PsiElement = lightParent + override fun isPhysical(): Boolean = false + + override fun getText(): String = "{" + initializers.joinToString { it.text } + "}" +} + +private open class KtUltraLightPsiLiteralForConstantValue( + private val constantValue: ConstantValue<*>, + private val ultraLightSupport: UltraLightSupport, + lightParent: PsiElement +) : KtLightElementBase(lightParent), PsiLiteralExpression { + override val kotlinOrigin: KtElement? get() = null + + override fun getValue(): Any? = constantValue.value + + override fun getType() = + constantValue.getType(ultraLightSupport.moduleDescriptor).asPsiType(ultraLightSupport, TypeMappingMode.DEFAULT, this) + + override fun getText() = when (constantValue) { + is NullValue -> "" + is StringValue -> "\"${value.toString()}\"" + is EnumValue -> constantValue.enumClassId.shortClassName.asString() + "." + constantValue.enumEntryName.asString() + else -> value.toString() + } +} + +private class KtUltraLightPsiClassObjectAccessExpression( + kClassValue: KClassValue, + ultraLightSupport: UltraLightSupport, + parent: PsiElement +) : KtUltraLightPsiLiteralForConstantValue(kClassValue, ultraLightSupport, parent), PsiClassObjectAccessExpression { + override fun getOperand(): PsiTypeElement { + val argument = (type as? PsiClassReferenceType)?.parameters?.getOrNull(0) + return LightTypeElement(parent.manager, argument ?: type) + } + + override fun getText() = operand.text + ".class" +} + fun PsiModifierListOwner.isPrivateOrParameterInPrivateMethod(): Boolean { if (hasModifier(JvmModifier.PRIVATE)) return true if (this !is PsiParameter) return false diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethod.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethod.kt index cf13aacd87a..c49b813151b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethod.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethod.kt @@ -12,6 +12,7 @@ import com.intellij.psi.impl.light.LightMethodBuilder import com.intellij.psi.impl.light.LightTypeParameterListBuilder import org.jetbrains.annotations.NonNls import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration +import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl import org.jetbrains.kotlin.asJava.elements.KtLightSimpleModifierList @@ -109,12 +110,15 @@ internal class KtUltraLightMethodForDescriptor( override val kotlinTypeForNullabilityAnnotation: KotlinType? get() = descriptor.returnType + + override val givenAnnotations: List + get() = descriptor.obtainLightAnnotations(support, this) } internal abstract class KtUltraLightParameter( name: String, override val kotlinOrigin: KtDeclaration?, - private val support: UltraLightSupport, + protected val support: UltraLightSupport, method: KtLightMethod ) : org.jetbrains.kotlin.asJava.elements.LightParameter( name, @@ -246,4 +250,7 @@ internal class KtUltraLightParameterForDescriptor( override fun computeContainingDescriptor() = descriptor.containingDeclaration as? CallableMemberDescriptor override fun isVarArgs() = (descriptor as? ValueParameterDescriptor)?.varargElementType != null + + override val givenAnnotations: List + get() = descriptor.obtainLightAnnotations(support, this) } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt index c88180f679a..c68d72d9043 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightPsi.kt @@ -670,6 +670,7 @@ interface UltraLightSupport { fun isTooComplexForUltraLightGeneration(element: KtClassOrObject): Boolean val deprecationResolver: DeprecationResolver val typeMapper: KotlinTypeMapper + val moduleDescriptor: ModuleDescriptor } interface KtUltraLightElementWithNullabilityAnnotation : KtLightDeclaration, diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt index 60f4db191a5..35b052c424b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightUtils.kt @@ -144,7 +144,15 @@ internal fun UltraLightSupport.mapType( ): PsiType { val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) mapTypeToSignatureWriter(typeMapper, signatureWriter) - val signature = StringCharacterIterator(signatureWriter.toString()) + val canonicalSignature = signatureWriter.toString() + return createTypeFromCanonicalText(canonicalSignature, psiContext) +} + +fun createTypeFromCanonicalText( + canonicalSignature: String, + psiContext: PsiElement +): PsiType { + val signature = StringCharacterIterator(canonicalSignature) val javaType = SignatureParsing.parseTypeString(signature, StubBuildingVisitor.GUESSING_MAPPER) val typeInfo = TypeInfo.fromString(javaType, false) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt index 49beb6ba892..70608ee9a9f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightElements.kt @@ -27,6 +27,8 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind interface KtLightElement : PsiElement { val kotlinOrigin: T? + val givenAnnotations: List? get() = null + val clsDelegate: D } @@ -46,4 +48,4 @@ interface KtLightMethod : PsiAnnotationMethod, KtLightMember { || lightMemberOrigin?.originKind == JvmDeclarationOriginKind.CLASS_MEMBER_DELEGATION_TO_DEFAULT_IMPL val isMangled: Boolean -} \ No newline at end of file +} diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt index 124df015e11..7b1f149acde 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightModifierList.kt @@ -66,7 +66,8 @@ abstract class KtLightModifierList { - val annotationsForEntries = lightAnnotationsForEntries(this) + val annotationsForEntries = + owner.givenAnnotations ?: lightAnnotationsForEntries(this) val modifierListOwner = parent if (modifierListOwner is KtLightClassForSourceDeclaration && modifierListOwner.isAnnotationType) { val sourceAnnotationNames = annotationsForEntries.mapTo(mutableSetOf()) { it.qualifiedName } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightTypeParameter.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightTypeParameter.java index d8e71cb77f3..4a288edbddc 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightTypeParameter.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightTypeParameter.java @@ -28,6 +28,8 @@ import org.jetbrains.kotlin.idea.KotlinLanguage; import org.jetbrains.kotlin.psi.KtTypeParameter; import org.jetbrains.kotlin.psi.KtTypeParameterListOwner; +import java.util.List; + public class KtLightTypeParameter extends AbstractLightClass implements PsiTypeParameter, KtLightDeclaration { private final PsiTypeParameterListOwner owner; @@ -172,4 +174,10 @@ public class KtLightTypeParameter } return false; } + + @Nullable + @Override + public List getGivenAnnotations() { + return null; + } } diff --git a/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java new file mode 100644 index 00000000000..1feac1d5b9b --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.java @@ -0,0 +1,42 @@ +@java.lang.annotation.Retention(null=java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface SimpleAnn /* SimpleAnn*/ { + @null() + public abstract java.lang.String value(); + +} + +@java.lang.annotation.Retention(null=java.lang.annotation.RetentionPolicy.RUNTIME) +public abstract @interface Ann /* Ann*/ { + @null() + public abstract SimpleAnn[] t(); + + @null() + public abstract java.lang.Class z(); + + @null() + public abstract java.lang.Class[] e(); + + @null() + public abstract java.lang.String y(); + + @null() + public abstract kotlin.DeprecationLevel depr(); + + public abstract int x(); + +} + +public abstract interface Base /* Base*/ { + @Ann(null=1, null="134", null=String::class, null=arrayOf(Int::class, Double::class), null=DeprecationLevel.WARNING, null=SimpleAnn("243"), null=SimpleAnn("4324")) + public abstract void foo(@Ann(null=2, null="324", null=Ann::class, null=arrayOf(Byte::class, Base::class), null=DeprecationLevel.WARNING, null=SimpleAnn("687"), null=SimpleAnn("78")) @org.jetbrains.annotations.NotNull() java.lang.String); + +} + +public final class Derived /* Derived*/ implements Base { + @Ann(x=1, y="134", z=String.class, e={Integer.class, Double.class}, depr=DeprecationLevel.WARNING, t={@SimpleAnn(value="243"), @SimpleAnn(value="4324")}) + public void foo(@Ann(x=2, y="324", z=Ann.class, e={Byte.class, Base.class}, depr=DeprecationLevel.WARNING, t={@SimpleAnn(value="687"), @SimpleAnn(value="78")}) @org.jetbrains.annotations.NotNull() java.lang.String); + + @null() + public Derived(@org.jetbrains.annotations.NotNull() Base); + +} diff --git a/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt new file mode 100644 index 00000000000..d0b4393ecb9 --- /dev/null +++ b/compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt @@ -0,0 +1,25 @@ +import kotlin.reflect.KClass + +/** should load cls */ +annotation class SimpleAnn(val value: String) + +/** should load cls */ +annotation class Ann( + val x: Int, + val y: String, + val z: KClass<*>, + val e: Array>, + val depr: DeprecationLevel + vararg val t: SimpleAnn +) + +interface Base { + @Ann(1, "134", String::class, arrayOf(Int::class, Double::class), DeprecationLevel.WARNING, SimpleAnn("243"), SimpleAnn("4324")) + fun foo( + @Ann(2, "324", Ann::class, arrayOf(Byte::class, Base::class), DeprecationLevel.WARNING, SimpleAnn("687"), SimpleAnn("78")) x: String + ) +} + +class Derived(b: Base) : Base by b { + +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index 7f95cb87008..e0a3dc5558d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -90,8 +90,11 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG return false } + override val moduleDescriptor by lazyPub { + element.getResolutionFacade().moduleDescriptor + } + override val moduleName: String by lazyPub { - val moduleDescriptor = element.getResolutionFacade().moduleDescriptor JvmCodegenUtil.getModuleName(moduleDescriptor) } diff --git a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java index cbc5f733fe5..de841a0e22d 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/asJava/classes/UltraLightClassLoadingTestGenerated.java @@ -54,6 +54,11 @@ public class UltraLightClassLoadingTestGenerated extends AbstractUltraLightClass runTest("compiler/testData/asJava/ultraLightClasses/dataClasses.kt"); } + @TestMetadata("delegatesWithAnnotations.kt") + public void testDelegatesWithAnnotations() throws Exception { + runTest("compiler/testData/asJava/ultraLightClasses/delegatesWithAnnotations.kt"); + } + @TestMetadata("delegatingToInterfaces.kt") public void testDelegatingToInterfaces() throws Exception { runTest("compiler/testData/asJava/ultraLightClasses/delegatingToInterfaces.kt");