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 6e406362b46..f5c3f1d4224 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 @@ -403,7 +403,7 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor } val primary = classOrObject.primaryConstructor if (primary != null && shouldGenerateNoArgOverload(primary)) { - result.add(noArgConstructor(primary.simpleVisibility(), primary)) + result.add(noArgConstructor(primary.simpleVisibility(), primary, METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR)) } return result } @@ -425,15 +425,20 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor classOrObject is KtEnumEntry -> PsiModifier.PACKAGE_LOCAL else -> PsiModifier.PUBLIC } - return noArgConstructor(visibility, classOrObject) + return noArgConstructor(visibility, classOrObject, METHOD_INDEX_FOR_DEFAULT_CTOR) } - private fun noArgConstructor(visibility: String, declaration: KtDeclaration): KtUltraLightMethod = + private fun noArgConstructor( + visibility: String, + declaration: KtDeclaration, + methodIndex: Int + ): KtUltraLightMethod = KtUltraLightMethodForSourceDeclaration( LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility), declaration, support, - this + this, + methodIndex ) private fun isHiddenByDeprecation(declaration: KtDeclaration): Boolean { 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 9040725f20e..c259de5981d 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 @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.asJava.classes -import com.intellij.lang.Language import com.intellij.psi.* import com.intellij.psi.impl.light.LightMethodBuilder import com.intellij.psi.impl.light.LightModifierList @@ -123,19 +122,22 @@ internal class UltraLightMembersCreator( return emptyList() } - val basicMethod = asJavaMethod(ktFunction, forceStatic, forcePrivate) + var methodIndex = METHOD_INDEX_BASE + val basicMethod = asJavaMethod(ktFunction, forceStatic, forcePrivate, methodIndex = methodIndex) val result = mutableListOf(basicMethod) if (ktFunction.hasAnnotation(JVM_OVERLOADS_FQ_NAME)) { val numberOfDefaultParameters = ktFunction.valueParameters.count(KtParameter::hasDefaultValue) for (numberOfDefaultParametersToAdd in numberOfDefaultParameters - 1 downTo 0) { + methodIndex++ result.add( asJavaMethod( ktFunction, forceStatic, forcePrivate, - numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd + numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd, + methodIndex = methodIndex ) ) } @@ -145,7 +147,7 @@ internal class UltraLightMembersCreator( } internal class KtUltraLightAnnotationMethod( - psiMethod: KtLightMethod, + private val psiMethod: KtLightMethod, expression: KtExpression ) : KtLightMethod by psiMethod, PsiAnnotationMethod { @@ -154,14 +156,23 @@ internal class UltraLightMembersCreator( convertToLightAnnotationMemberValue(psiMethod, expression) } + override fun equals(other: Any?): Boolean = psiMethod == (other as? KtUltraLightAnnotationMethod)?.psiMethod + + override fun hashCode(): Int = psiMethod.hashCode() + + override fun toString(): String = psiMethod.toString() + override fun getDefaultValue(): PsiAnnotationMemberValue? = value + + override fun getSourceElement(): PsiElement? = psiMethod.sourceElement } private fun asJavaMethod( ktFunction: KtFunction, forceStatic: Boolean, forcePrivate: Boolean, - numberOfDefaultParametersToAdd: Int = -1 + numberOfDefaultParametersToAdd: Int = -1, + methodIndex: Int ): KtLightMethod { val isConstructor = ktFunction is KtConstructor<*> val name = @@ -169,7 +180,7 @@ internal class UltraLightMembersCreator( else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR) val method = lightMethod(name.orEmpty(), ktFunction, forceStatic, forcePrivate) - val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, containingClass) + val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, containingClass, methodIndex) addReceiverParameter(ktFunction, wrapper, method) var remainingNumberOfDefaultParametersToAdd = @@ -266,7 +277,9 @@ internal class UltraLightMembersCreator( if (forcePrivate || declaration.isPrivate() || accessedProperty?.isPrivate() == true) { return name == PsiModifier.PRIVATE } - if (declaration.hasModifier(KtTokens.PROTECTED_KEYWORD) || accessedProperty?.hasModifier(KtTokens.PROTECTED_KEYWORD) == true) { + if (declaration.hasModifier(KtTokens.PROTECTED_KEYWORD) || accessedProperty + ?.hasModifier(KtTokens.PROTECTED_KEYWORD) == true + ) { return name == PsiModifier.PROTECTED } @@ -284,7 +297,8 @@ internal class UltraLightMembersCreator( return when (name) { PsiModifier.FINAL -> !containingClass.isInterface && outerDeclaration !is KtConstructor<*> && isFinal(outerDeclaration) PsiModifier.ABSTRACT -> containingClass.isInterface || outerDeclaration.hasModifier(KtTokens.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) @@ -408,7 +422,9 @@ internal class UltraLightMembersCreator( if (declaration is KtProperty && declaration.hasDelegate()) { return true } - if (accessor?.hasModifier(KtTokens.PRIVATE_KEYWORD) == true || accessor?.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) == true) { + if (accessor?.hasModifier(KtTokens.PRIVATE_KEYWORD) == true || accessor + ?.hasAnnotation(JVM_SYNTHETIC_ANNOTATION_FQ_NAME) == true + ) { return false } if (!isPrivate || accessor?.hasBody() == true) { @@ -436,7 +452,8 @@ internal class UltraLightMembersCreator( lightMemberOrigin, support, containingClass, - forceToSkipNullabilityAnnotation = createAsAnnotationMethod + forceToSkipNullabilityAnnotation = createAsAnnotationMethod, + methodIndex = METHOD_INDEX_FOR_GETTER ) val getterType: PsiType by lazyPub { methodReturnType(declaration, getterWrapper, isSuspendFunction = false) } @@ -463,7 +480,13 @@ internal class UltraLightMembersCreator( val setterPrototype = lightMethod(setterName, auxiliaryOrigin, forceStatic = onlyJvmStatic || forceStatic) .setMethodReturnType(PsiType.VOID) - val setterWrapper = KtUltraLightMethodForSourceDeclaration(setterPrototype, lightMemberOrigin, support, containingClass) + val setterWrapper = KtUltraLightMethodForSourceDeclaration( + setterPrototype, + lightMemberOrigin, + support, + containingClass, + methodIndex = METHOD_INDEX_FOR_SETTER + ) addReceiverParameter(declaration, setterWrapper, setterPrototype) val setterParameter = ktSetter?.parameter setterPrototype.addParameter( diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt index 0f7bd4488c2..f8dd2265000 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/ultraLightMethods.kt @@ -27,11 +27,19 @@ import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtTypeParameterListOwner import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind +internal const val METHOD_INDEX_FOR_GETTER = 1 +internal const val METHOD_INDEX_FOR_SETTER = 2 +internal const val METHOD_INDEX_FOR_DEFAULT_CTOR = 3 +internal const val METHOD_INDEX_FOR_NO_ARG_OVERLOAD_CTOR = 4 +internal const val METHOD_INDEX_FOR_NON_ORIGIN_METHOD = 5 +internal const val METHOD_INDEX_BASE = 6 + internal abstract class KtUltraLightMethod( internal val delegate: PsiMethod, lightMemberOrigin: LightMemberOrigin?, protected val support: KtUltraLightSupport, - containingClass: KtLightClass + containingClass: KtLightClass, + private val methodIndex: Int ) : KtLightMethodImpl( { delegate }, lightMemberOrigin, @@ -104,7 +112,15 @@ internal abstract class KtUltraLightMethod( override fun findSuperMethods(parentClass: PsiClass?): Array = PsiSuperMethodImplUtil.findSuperMethods(this, parentClass) - override fun equals(other: Any?): Boolean = this === other + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is KtUltraLightMethod) return false + if (methodIndex != other.methodIndex) return false + if (this.javaClass != other.javaClass) return false + if (containingClass != other.containingClass) return false + if (kotlinOrigin === null || other.kotlinOrigin === null) return false + return kotlinOrigin == other.kotlinOrigin + } override fun hashCode(): Int = name.hashCode() @@ -116,19 +132,29 @@ internal class KtUltraLightMethodForSourceDeclaration( lightMemberOrigin: LightMemberOrigin?, support: KtUltraLightSupport, containingClass: KtLightClass, - private val forceToSkipNullabilityAnnotation: Boolean = false + private val forceToSkipNullabilityAnnotation: Boolean = false, + methodIndex: Int ) : KtUltraLightMethod( delegate, lightMemberOrigin, support, - containingClass + containingClass, + methodIndex ) { constructor( delegate: PsiMethod, declaration: KtDeclaration, support: KtUltraLightSupport, - containingClass: KtLightClass - ) : this(delegate, LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER), support, containingClass) + containingClass: KtLightClass, + methodIndex: Int + ) : this( + delegate, + LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER), + support, + containingClass, + forceToSkipNullabilityAnnotation = false, + methodIndex + ) override val qualifiedNameForNullabilityAnnotation: String? get() { @@ -161,7 +187,8 @@ internal class KtUltraLightMethodForDescriptor( delegate, lightMemberOrigin, support, - containingClass + containingClass, + METHOD_INDEX_FOR_NON_ORIGIN_METHOD ) { // This is greedy realization of UL class. // This means that all data that depends on descriptor evaluated in ctor so the descriptor will be released on the end. diff --git a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt index 2473348483f..727d7562c9d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/perf/UltraLightChecker.kt @@ -11,9 +11,7 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.Conditions import com.intellij.openapi.util.Disposer import com.intellij.psi.* -import com.intellij.psi.impl.light.LightElement import com.intellij.psi.search.GlobalSearchScope -import com.intellij.psi.util.PsiTreeUtil import com.intellij.testFramework.UsefulTestCase import com.intellij.util.PairProcessor import com.intellij.util.ref.DebugReflectionUtil @@ -81,6 +79,13 @@ object UltraLightChecker { val gold = KtLightClassForSourceDeclaration.createNoCache(ktClass, forceUsingOldLightClasses = true) val ultraLightClass = LightClassGenerationSupport.getInstance(ktClass.project).createUltraLightClass(ktClass) ?: return null + val secondULInstance = LightClassGenerationSupport.getInstance(ktClass.project).createUltraLightClass(ktClass) + Assert.assertNotNull(secondULInstance) + Assert.assertTrue(ultraLightClass !== secondULInstance) + secondULInstance!! + Assert.assertEquals(ultraLightClass.ownMethods.size, secondULInstance.ownMethods.size) + Assert.assertTrue(ultraLightClass.ownMethods.containsAll(secondULInstance.ownMethods)) + checkClassEquivalenceByRendering(gold, ultraLightClass) return ultraLightClass