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 e45f86ffaa1..2828ccc9d07 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 @@ -227,10 +227,12 @@ abstract class KtLightClassForSourceDeclaration( isAbstract() || isSealed() -> { psiModifiers.add(PsiModifier.ABSTRACT) } + isEnum -> { // Enum class should not be `final`, since its enum entries extend it. // It could be either `abstract` w/o ctor, or empty modality w/ private ctor. } + !(classOrObject.hasModifier(OPEN_KEYWORD)) -> { val descriptor = lazy { getDescriptor() } var modifier = PsiModifier.FINAL @@ -314,11 +316,14 @@ abstract class KtLightClassForSourceDeclaration( } if (classOrObject.hasInterfaceDefaultImpls && jvmDefaultMode != JvmDefaultMode.ALL_INCOMPATIBLE) { - result.add(KtLightClassForInterfaceDefaultImpls(classOrObject)) + result.add(createClassForInterfaceDefaultImpls()) } + return result } + protected open fun createClassForInterfaceDefaultImpls(): PsiClass = KtLightClassForInterfaceDefaultImpls(classOrObject) + override fun getUseScope(): SearchScope = kotlinOrigin.useScope override fun getElementType(): IStubElementType, *>? = classOrObject.elementType @@ -398,6 +403,7 @@ abstract class KtLightClassForSourceDeclaration( return when { !classOrObject.safeIsLocal() && containingScript != null -> KtLightClassForScript.getLightClassCachedValue(containingScript).value + else -> getLightClassCachedValue(classOrObject).value } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraLightClassForInterfaceDefaultImpls.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraLightClassForInterfaceDefaultImpls.kt new file mode 100644 index 00000000000..e8967307333 --- /dev/null +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtUltraLightClassForInterfaceDefaultImpls.kt @@ -0,0 +1,153 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.asJava.classes + +import com.intellij.psi.* +import com.intellij.psi.impl.PsiClassImplUtil +import com.intellij.psi.util.CachedValue +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.util.IncorrectOperationException +import org.jetbrains.annotations.NotNull +import org.jetbrains.kotlin.asJava.elements.KtLightField +import org.jetbrains.kotlin.asJava.elements.KtLightMethod +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.psi.KtClassOrObject +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtPropertyAccessor +import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +class KtUltraLightClassForInterfaceDefaultImpls(classOrObject: KtClassOrObject, support: KtUltraLightSupport) : + KtUltraLightClass(classOrObject, support) { + override fun getQualifiedName(): String? = containingClass?.qualifiedName?.let { "$it.${JvmAbi.DEFAULT_IMPLS_CLASS_NAME}" } + override fun getName() = JvmAbi.DEFAULT_IMPLS_CLASS_NAME + override fun getParent() = containingClass + override fun copy(): KtUltraLightClassForInterfaceDefaultImpls = KtUltraLightClassForInterfaceDefaultImpls( + classOrObject.copy() as KtClassOrObject, + support, + ) + + override fun getInterfaces(): Array = emptyArray() + + override fun createExtendsList(): PsiReferenceList? = null + override fun createImplementsList(): PsiReferenceList? = null + override fun getSuperClass(): PsiClass? = PsiClassImplUtil.getSuperClass(this) + override fun getSupers(): Array = PsiClassImplUtil.getSuperClass(this)?.let { arrayOf(it) } ?: emptyArray() + override fun getSuperTypes(): Array = arrayOf(PsiType.getJavaLangObject(manager, resolveScope)) + + override fun getTypeParameterList(): PsiTypeParameterList? = null + override fun getTypeParameters(): Array = emptyArray() + override fun computeModifiers(): Set = publicStaticFinal + + override fun getOwnFields(): List = emptyList() + override fun isInterface(): Boolean = false + + override fun isDeprecated(): Boolean = false + override fun isAnnotationType(): Boolean = false + override fun isEnum(): Boolean = false + override fun isFinal(isFinalByPsi: Boolean): Boolean = true + override fun hasTypeParameters(): Boolean = false + override fun isInheritor(baseClass: PsiClass, checkDeep: Boolean): Boolean = + baseClass.qualifiedName == CommonClassNames.JAVA_LANG_OBJECT + + override fun setName(name: String): PsiElement = + throw IncorrectOperationException("Impossible to rename ${JvmAbi.DEFAULT_IMPLS_CLASS_NAME}") + + override fun getContainingClass(): KtLightClassForSourceDeclaration? = create(classOrObject, jvmDefaultMode) + + override fun getOwnInnerClasses() = emptyList() + override fun getOwnMethods(): List = _ownMethods.value + + private val membersBuilder by lazyPub { + UltraLightMembersCreator( + this, + false, + classOrObject.hasModifier(KtTokens.SEALED_KEYWORD), + mangleInternalFunctions = true, + support = support, + ) + } + + + private fun ownMethods(): List { + val interfaceType by lazy { + JavaPsiFacade.getElementFactory(project).createType(containingClass!!) + } + + val result = mutableListOf() + fun processClass(psiClass: PsiClass) { + val declarations = psiClass.safeAs() + ?.kotlinOrigin + ?.declarations + ?.filterNot { it.isHiddenByDeprecation(support) } + .orEmpty() + + for (declaration in declarations) { + when (declaration) { + is KtNamedFunction -> { + if (declaration.hasBody()) { + result.addAll( + membersBuilder.createMethods(declaration, forceStatic = true, forceNonFinal = true) { + KtUltraLightReceiverParameterForDefaultImpls(support, it) { interfaceType } + } + ) + } + } + + is KtProperty -> { + if (declaration.accessors.any(KtPropertyAccessor::hasBody)) { + result.addAll( + membersBuilder.propertyAccessors( + declaration, + declaration.isVar, + forceStatic = true, + onlyJvmStatic = false, + forceNonFinal = true, + ) { + KtUltraLightReceiverParameterForDefaultImpls(support, it) { interfaceType } + } + ) + } + } + } + } + + for (superClass in psiClass.interfaces) { + processClass(superClass) + } + } + + containingClass?.let { processClass(it) } + + return result + } + + private val _ownMethods: CachedValue> = CachedValuesManager.getManager(project).createCachedValue( + /* provider = */ + { + CachedValueProvider.Result.create( + ownMethods(), + classOrObject.getExternalDependencies() + ) + }, + /* trackValue = */ false, + ) +} + +internal class KtUltraLightReceiverParameterForDefaultImpls( + support: KtUltraLightSupport, + method: KtUltraLightMethod, + private val typeGetter: () -> PsiType, +) : KtUltraLightParameter(AsmUtil.THIS_IN_DEFAULT_IMPLS, null, support, method) { + override fun getType(): PsiType = typeGetter() + override fun isVarArgs(): Boolean = false + override val qualifiedNameForNullabilityAnnotation: String = NotNull::class.java.name +} + +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/ultraLightClass.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt index 0ef9d5d6796..7200a073b1b 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightClass.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -521,6 +521,8 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor superOwnInnerClasses } + override fun createClassForInterfaceDefaultImpls(): PsiClass = KtUltraLightClassForInterfaceDefaultImpls(classOrObject, support) + private val shouldGenerateRepeatableAnnotationContainer: Boolean get() = isAnnotationType && classOrObject.hasAnnotation(StandardNames.FqNames.repeatable) && diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt index 21dab9cb3ab..566bca7213f 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMembersCreator.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.elements.KtLightField import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.asJava.elements.convertToLightAnnotationMemberValue -import org.jetbrains.kotlin.builtins.StandardNames.DEFAULT_VALUE_PARAMETER import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotated @@ -80,6 +79,7 @@ internal class UltraLightMembersCreator( val declaration = property?.setter ?: variable declaration.simpleVisibility() } + else -> PsiModifier.PRIVATE } val modifiers = hashSetOf(visibility) @@ -115,7 +115,9 @@ internal class UltraLightMembersCreator( fun createMethods( ktFunction: KtFunction, forceStatic: Boolean, - forcePrivate: Boolean = false + forcePrivate: Boolean = false, + forceNonFinal: Boolean = false, + additionalReceiverParameter: ((KtUltraLightMethod) -> KtUltraLightParameter)? = null, ): Collection { if (ktFunction.hasExpectModifier() @@ -124,7 +126,14 @@ internal class UltraLightMembersCreator( ) return emptyList() var methodIndex = METHOD_INDEX_BASE - val basicMethod = asJavaMethod(ktFunction, forceStatic, forcePrivate, methodIndex = methodIndex) + val basicMethod = asJavaMethod( + ktFunction, + forceStatic, + forcePrivate, + methodIndex = methodIndex, + forceNonFinal = forceNonFinal, + additionalReceiverParameter = additionalReceiverParameter, + ) val result = mutableListOf(basicMethod) @@ -138,7 +147,9 @@ internal class UltraLightMembersCreator( forceStatic, forcePrivate, numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd, - methodIndex = methodIndex + methodIndex = methodIndex, + forceNonFinal = forceNonFinal, + additionalReceiverParameter = additionalReceiverParameter, ) ) } @@ -174,7 +185,9 @@ internal class UltraLightMembersCreator( forceStatic: Boolean, forcePrivate: Boolean, numberOfDefaultParametersToAdd: Int = -1, - methodIndex: Int + methodIndex: Int, + forceNonFinal: Boolean = false, + additionalReceiverParameter: ((KtUltraLightMethod) -> KtUltraLightParameter)? = null, ): KtLightMethod { ProgressManager.checkCanceled() val isConstructor = ktFunction is KtConstructor<*> @@ -182,8 +195,13 @@ internal class UltraLightMembersCreator( if (isConstructor) containingClass.name else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR) - val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate) + val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate, forceNonFinal) val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, containingClass, methodIndex) + additionalReceiverParameter?.let { + val receiver = it(wrapper) + method.addParameter(receiver) + } + addReceiverParameter(ktFunction, wrapper, method) var remainingNumberOfDefaultParametersToAdd = @@ -259,7 +277,8 @@ internal class UltraLightMembersCreator( private val accessedProperty: KtProperty?, private val outerDeclaration: KtDeclaration, private val forceStatic: Boolean, - private val forcePrivate: Boolean = false + private val forcePrivate: Boolean = false, + private val forceNonFinal: Boolean = false, ) : LightModifierList(declaration.manager, declaration.language) { override fun hasModifierProperty(name: String): Boolean { @@ -301,10 +320,13 @@ internal class UltraLightMembersCreator( } return when (name) { - PsiModifier.FINAL -> !containingClass.isInterface && outerDeclaration !is KtConstructor<*> && isFinal(outerDeclaration) + PsiModifier.FINAL -> + !forceNonFinal && !containingClass.isInterface && outerDeclaration !is KtConstructor<*> && isFinal(outerDeclaration) + PsiModifier.ABSTRACT -> containingClass.isInterface || outerDeclaration.hasModifier(ABSTRACT_KEYWORD) - PsiModifier.STATIC -> forceStatic || containingClassIsNamedObject && (outerDeclaration.isJvmStatic(support) || declaration - .isJvmStatic(support)) + PsiModifier.STATIC -> + forceStatic || containingClassIsNamedObject && (outerDeclaration.isJvmStatic(support) || declaration.isJvmStatic(support)) + PsiModifier.STRICTFP -> declaration is KtFunction && declaration.hasAnnotation(STRICTFP_ANNOTATION_FQ_NAME) PsiModifier.SYNCHRONIZED -> declaration is KtFunction && declaration.hasAnnotation(SYNCHRONIZED_ANNOTATION_FQ_NAME) PsiModifier.NATIVE -> declaration is KtFunction && declaration.hasModifier(EXTERNAL_KEYWORD) @@ -329,7 +351,8 @@ internal class UltraLightMembersCreator( name: String, declaration: KtDeclaration, forceStatic: Boolean, - forcePrivate: Boolean = false + forcePrivate: Boolean = false, + forceNonFinal: Boolean = false, ): LightMethodBuilder { val accessedProperty = if (declaration is KtPropertyAccessor) declaration.property else null val outer = accessedProperty ?: declaration @@ -340,7 +363,7 @@ internal class UltraLightMembersCreator( return LightMethodBuilder( manager, language, name, LightParameterListBuilder(manager, language), - UltraLightModifierListForMember(declaration, accessedProperty, outer, forceStatic, forcePrivate) + UltraLightModifierListForMember(declaration, accessedProperty, outer, forceStatic, forcePrivate, forceNonFinal) ).setConstructor(declaration is KtConstructor<*>) } @@ -410,6 +433,8 @@ internal class UltraLightMembersCreator( onlyJvmStatic: Boolean, createAsAnnotationMethod: Boolean = false, isJvmRecord: Boolean = false, + forceNonFinal: Boolean = false, + additionalReceiverParameter: ((KtUltraLightMethod) -> KtUltraLightParameter)? = null, ): List { val propertyName = declaration.name ?: return emptyList() @@ -460,18 +485,28 @@ internal class UltraLightMembersCreator( val defaultGetterName = if (createAsAnnotationMethod || isJvmRecord) propertyName else JvmAbi.getterName(propertyName) val getterName = computeMethodName(auxiliaryOrigin, defaultGetterName, MethodType.GETTER) - val getterPrototype = lightMethod(getterName, auxiliaryOrigin, forceStatic = onlyJvmStatic || forceStatic) + val getterPrototype = lightMethod( + getterName, + auxiliaryOrigin, + forceStatic = onlyJvmStatic || forceStatic, + forceNonFinal = forceNonFinal, + ) + val getterWrapper = KtUltraLightMethodForSourceDeclaration( getterPrototype, lightMemberOrigin, support, containingClass, forceToSkipNullabilityAnnotation = createAsAnnotationMethod, - methodIndex = METHOD_INDEX_FOR_GETTER + methodIndex = METHOD_INDEX_FOR_GETTER, ) val getterType: PsiType by lazyPub { methodReturnType(declaration, getterWrapper, isSuspendFunction = false) } getterPrototype.setMethodReturnType { getterType } + additionalReceiverParameter?.invoke(getterWrapper)?.let { + getterPrototype.addParameter(it) + } + addReceiverParameter(declaration, getterWrapper, getterPrototype) val defaultExpression = if (createAsAnnotationMethod && declaration is KtParameter) declaration.defaultValue else null @@ -491,16 +526,25 @@ internal class UltraLightMembersCreator( ) val setterName = computeMethodName(auxiliaryOrigin, JvmAbi.setterName(propertyName), MethodType.SETTER) - val setterPrototype = lightMethod(setterName, auxiliaryOrigin, forceStatic = onlyJvmStatic || forceStatic) - .setMethodReturnType(PsiType.VOID) + val setterPrototype = lightMethod( + setterName, + auxiliaryOrigin, + forceStatic = onlyJvmStatic || forceStatic, + forceNonFinal = forceNonFinal, + ).setMethodReturnType(PsiType.VOID) val setterWrapper = KtUltraLightMethodForSourceDeclaration( setterPrototype, lightMemberOrigin, support, containingClass, - methodIndex = METHOD_INDEX_FOR_SETTER + methodIndex = METHOD_INDEX_FOR_SETTER, ) + + additionalReceiverParameter?.invoke(setterWrapper)?.let { + setterPrototype.addParameter(it) + } + addReceiverParameter(declaration, setterWrapper, setterPrototype) val setterParameter = ktSetter?.parameter setterPrototype.addParameter( diff --git a/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.fir.java b/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.fir.java index 7447a290ee6..ec5c0ee2dd8 100644 --- a/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.fir.java +++ b/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.fir.java @@ -1,10 +1,10 @@ -public abstract interface B /* p.B*/ extends p.A { +public abstract interface C /* p.C*/ extends p.B { @org.jetbrains.annotations.NotNull() - public abstract java.lang.String b();// b() + public abstract java.lang.String c();// c() -public static final class DefaultImpls /* p.B.DefaultImpls*/ extends p.A { +public static final class DefaultImpls /* p.C.DefaultImpls*/ extends p.B { @org.jetbrains.annotations.NotNull() - public java.lang.String b();// b() + public java.lang.String c();// c() -}} +}} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.java b/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.java index 44105c60b2d..c4391759c9f 100644 --- a/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.java +++ b/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.java @@ -1,13 +1,16 @@ -public abstract interface B /* p.B*/ extends p.A { +public abstract interface C /* p.C*/ extends p.B { @org.jetbrains.annotations.NotNull() - public abstract java.lang.String b();// b() + public abstract java.lang.String c();// c() -public static final class DefaultImpls /* p.B.DefaultImpls*/ { +public static final class DefaultImpls /* p.C.DefaultImpls*/ { @org.jetbrains.annotations.NotNull() - public static java.lang.String a(@org.jetbrains.annotations.NotNull() p.B);// a(p.B) + public static java.lang.String a(@org.jetbrains.annotations.NotNull() p.C);// a(p.C) @org.jetbrains.annotations.NotNull() - public static java.lang.String b(@org.jetbrains.annotations.NotNull() p.B);// b(p.B) + public static java.lang.String b(@org.jetbrains.annotations.NotNull() p.C);// b(p.C) + + @org.jetbrains.annotations.NotNull() + public static java.lang.String c(@org.jetbrains.annotations.NotNull() p.C);// c(p.C) }} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.kt b/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.kt index 6450d565069..c8849b23a2b 100644 --- a/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.kt +++ b/compiler/testData/asJava/lightClasses/ExtendingInterfaceWithDefaultImpls.kt @@ -1,4 +1,4 @@ -// p.B +// p.C package p interface A { @@ -9,6 +9,10 @@ interface B: A { fun b() = "b" } +interface C : B { + fun c() = "c" +} + // TODO: could be lazy // see KT-22819 // LAZINESS:NoLaziness \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/compilationErrors/PrivateInTrait.java b/compiler/testData/asJava/lightClasses/compilationErrors/PrivateInTrait.java index 6d322675405..7fcabbd4787 100644 --- a/compiler/testData/asJava/lightClasses/compilationErrors/PrivateInTrait.java +++ b/compiler/testData/asJava/lightClasses/compilationErrors/PrivateInTrait.java @@ -1,10 +1,10 @@ public abstract interface PrivateInTrait /* PrivateInTrait*/ { public static final class DefaultImpls /* PrivateInTrait.DefaultImpls*/ { - private static java.lang.String getN(PrivateInTrait);// getN(PrivateInTrait) + private static java.lang.String getN(@org.jetbrains.annotations.NotNull() PrivateInTrait);// getN(PrivateInTrait) - private static java.lang.String getNn(PrivateInTrait);// getNn(PrivateInTrait) + private static java.lang.String getNn(@org.jetbrains.annotations.NotNull() PrivateInTrait);// getNn(PrivateInTrait) - private static void setNn(PrivateInTrait, java.lang.String);// setNn(PrivateInTrait, java.lang.String) + private static void setNn(@org.jetbrains.annotations.NotNull() PrivateInTrait, java.lang.String);// setNn(PrivateInTrait, java.lang.String) }} \ No newline at end of file