Fix invalid equality for UL methods
Potentially fixed #KT-34796
This commit is contained in:
@@ -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 {
|
||||
|
||||
+34
-11
@@ -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(
|
||||
|
||||
+34
-7
@@ -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<out PsiMethod> =
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user