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
|
val primary = classOrObject.primaryConstructor
|
||||||
if (primary != null && shouldGenerateNoArgOverload(primary)) {
|
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
|
return result
|
||||||
}
|
}
|
||||||
@@ -425,15 +425,20 @@ open class KtUltraLightClass(classOrObject: KtClassOrObject, internal val suppor
|
|||||||
classOrObject is KtEnumEntry -> PsiModifier.PACKAGE_LOCAL
|
classOrObject is KtEnumEntry -> PsiModifier.PACKAGE_LOCAL
|
||||||
else -> PsiModifier.PUBLIC
|
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(
|
KtUltraLightMethodForSourceDeclaration(
|
||||||
LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility),
|
LightMethodBuilder(manager, language, name.orEmpty()).setConstructor(true).addModifier(visibility),
|
||||||
declaration,
|
declaration,
|
||||||
support,
|
support,
|
||||||
this
|
this,
|
||||||
|
methodIndex
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun isHiddenByDeprecation(declaration: KtDeclaration): Boolean {
|
private fun isHiddenByDeprecation(declaration: KtDeclaration): Boolean {
|
||||||
|
|||||||
+34
-11
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.asJava.classes
|
package org.jetbrains.kotlin.asJava.classes
|
||||||
|
|
||||||
import com.intellij.lang.Language
|
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.light.LightMethodBuilder
|
import com.intellij.psi.impl.light.LightMethodBuilder
|
||||||
import com.intellij.psi.impl.light.LightModifierList
|
import com.intellij.psi.impl.light.LightModifierList
|
||||||
@@ -123,19 +122,22 @@ internal class UltraLightMembersCreator(
|
|||||||
return emptyList()
|
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)
|
val result = mutableListOf(basicMethod)
|
||||||
|
|
||||||
if (ktFunction.hasAnnotation(JVM_OVERLOADS_FQ_NAME)) {
|
if (ktFunction.hasAnnotation(JVM_OVERLOADS_FQ_NAME)) {
|
||||||
val numberOfDefaultParameters = ktFunction.valueParameters.count(KtParameter::hasDefaultValue)
|
val numberOfDefaultParameters = ktFunction.valueParameters.count(KtParameter::hasDefaultValue)
|
||||||
for (numberOfDefaultParametersToAdd in numberOfDefaultParameters - 1 downTo 0) {
|
for (numberOfDefaultParametersToAdd in numberOfDefaultParameters - 1 downTo 0) {
|
||||||
|
methodIndex++
|
||||||
result.add(
|
result.add(
|
||||||
asJavaMethod(
|
asJavaMethod(
|
||||||
ktFunction,
|
ktFunction,
|
||||||
forceStatic,
|
forceStatic,
|
||||||
forcePrivate,
|
forcePrivate,
|
||||||
numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd
|
numberOfDefaultParametersToAdd = numberOfDefaultParametersToAdd,
|
||||||
|
methodIndex = methodIndex
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -145,7 +147,7 @@ internal class UltraLightMembersCreator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class KtUltraLightAnnotationMethod(
|
internal class KtUltraLightAnnotationMethod(
|
||||||
psiMethod: KtLightMethod,
|
private val psiMethod: KtLightMethod,
|
||||||
expression: KtExpression
|
expression: KtExpression
|
||||||
) : KtLightMethod by psiMethod,
|
) : KtLightMethod by psiMethod,
|
||||||
PsiAnnotationMethod {
|
PsiAnnotationMethod {
|
||||||
@@ -154,14 +156,23 @@ internal class UltraLightMembersCreator(
|
|||||||
convertToLightAnnotationMemberValue(psiMethod, expression)
|
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 getDefaultValue(): PsiAnnotationMemberValue? = value
|
||||||
|
|
||||||
|
override fun getSourceElement(): PsiElement? = psiMethod.sourceElement
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun asJavaMethod(
|
private fun asJavaMethod(
|
||||||
ktFunction: KtFunction,
|
ktFunction: KtFunction,
|
||||||
forceStatic: Boolean,
|
forceStatic: Boolean,
|
||||||
forcePrivate: Boolean,
|
forcePrivate: Boolean,
|
||||||
numberOfDefaultParametersToAdd: Int = -1
|
numberOfDefaultParametersToAdd: Int = -1,
|
||||||
|
methodIndex: Int
|
||||||
): KtLightMethod {
|
): KtLightMethod {
|
||||||
val isConstructor = ktFunction is KtConstructor<*>
|
val isConstructor = ktFunction is KtConstructor<*>
|
||||||
val name =
|
val name =
|
||||||
@@ -169,7 +180,7 @@ internal class UltraLightMembersCreator(
|
|||||||
else computeMethodName(ktFunction, ktFunction.name ?: SpecialNames.NO_NAME_PROVIDED.asString(), MethodType.REGULAR)
|
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)
|
||||||
val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, containingClass)
|
val wrapper = KtUltraLightMethodForSourceDeclaration(method, ktFunction, support, containingClass, methodIndex)
|
||||||
addReceiverParameter(ktFunction, wrapper, method)
|
addReceiverParameter(ktFunction, wrapper, method)
|
||||||
|
|
||||||
var remainingNumberOfDefaultParametersToAdd =
|
var remainingNumberOfDefaultParametersToAdd =
|
||||||
@@ -266,7 +277,9 @@ internal class UltraLightMembersCreator(
|
|||||||
if (forcePrivate || declaration.isPrivate() || accessedProperty?.isPrivate() == true) {
|
if (forcePrivate || declaration.isPrivate() || accessedProperty?.isPrivate() == true) {
|
||||||
return name == PsiModifier.PRIVATE
|
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
|
return name == PsiModifier.PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +297,8 @@ internal class UltraLightMembersCreator(
|
|||||||
return when (name) {
|
return when (name) {
|
||||||
PsiModifier.FINAL -> !containingClass.isInterface && outerDeclaration !is KtConstructor<*> && isFinal(outerDeclaration)
|
PsiModifier.FINAL -> !containingClass.isInterface && outerDeclaration !is KtConstructor<*> && isFinal(outerDeclaration)
|
||||||
PsiModifier.ABSTRACT -> containingClass.isInterface || outerDeclaration.hasModifier(KtTokens.ABSTRACT_KEYWORD)
|
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.STRICTFP -> declaration is KtFunction && declaration.hasAnnotation(STRICTFP_ANNOTATION_FQ_NAME)
|
||||||
PsiModifier.SYNCHRONIZED -> declaration is KtFunction && declaration.hasAnnotation(SYNCHRONIZED_ANNOTATION_FQ_NAME)
|
PsiModifier.SYNCHRONIZED -> declaration is KtFunction && declaration.hasAnnotation(SYNCHRONIZED_ANNOTATION_FQ_NAME)
|
||||||
PsiModifier.NATIVE -> declaration is KtFunction && declaration.hasModifier(EXTERNAL_KEYWORD)
|
PsiModifier.NATIVE -> declaration is KtFunction && declaration.hasModifier(EXTERNAL_KEYWORD)
|
||||||
@@ -408,7 +422,9 @@ internal class UltraLightMembersCreator(
|
|||||||
if (declaration is KtProperty && declaration.hasDelegate()) {
|
if (declaration is KtProperty && declaration.hasDelegate()) {
|
||||||
return true
|
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
|
return false
|
||||||
}
|
}
|
||||||
if (!isPrivate || accessor?.hasBody() == true) {
|
if (!isPrivate || accessor?.hasBody() == true) {
|
||||||
@@ -436,7 +452,8 @@ internal class UltraLightMembersCreator(
|
|||||||
lightMemberOrigin,
|
lightMemberOrigin,
|
||||||
support,
|
support,
|
||||||
containingClass,
|
containingClass,
|
||||||
forceToSkipNullabilityAnnotation = createAsAnnotationMethod
|
forceToSkipNullabilityAnnotation = createAsAnnotationMethod,
|
||||||
|
methodIndex = METHOD_INDEX_FOR_GETTER
|
||||||
)
|
)
|
||||||
|
|
||||||
val getterType: PsiType by lazyPub { methodReturnType(declaration, getterWrapper, isSuspendFunction = false) }
|
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)
|
val setterPrototype = lightMethod(setterName, auxiliaryOrigin, forceStatic = onlyJvmStatic || forceStatic)
|
||||||
.setMethodReturnType(PsiType.VOID)
|
.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)
|
addReceiverParameter(declaration, setterWrapper, setterPrototype)
|
||||||
val setterParameter = ktSetter?.parameter
|
val setterParameter = ktSetter?.parameter
|
||||||
setterPrototype.addParameter(
|
setterPrototype.addParameter(
|
||||||
|
|||||||
+34
-7
@@ -27,11 +27,19 @@ import org.jetbrains.kotlin.psi.KtProperty
|
|||||||
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
import org.jetbrains.kotlin.psi.KtTypeParameterListOwner
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
|
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 abstract class KtUltraLightMethod(
|
||||||
internal val delegate: PsiMethod,
|
internal val delegate: PsiMethod,
|
||||||
lightMemberOrigin: LightMemberOrigin?,
|
lightMemberOrigin: LightMemberOrigin?,
|
||||||
protected val support: KtUltraLightSupport,
|
protected val support: KtUltraLightSupport,
|
||||||
containingClass: KtLightClass
|
containingClass: KtLightClass,
|
||||||
|
private val methodIndex: Int
|
||||||
) : KtLightMethodImpl(
|
) : KtLightMethodImpl(
|
||||||
{ delegate },
|
{ delegate },
|
||||||
lightMemberOrigin,
|
lightMemberOrigin,
|
||||||
@@ -104,7 +112,15 @@ internal abstract class KtUltraLightMethod(
|
|||||||
override fun findSuperMethods(parentClass: PsiClass?): Array<out PsiMethod> =
|
override fun findSuperMethods(parentClass: PsiClass?): Array<out PsiMethod> =
|
||||||
PsiSuperMethodImplUtil.findSuperMethods(this, parentClass)
|
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()
|
override fun hashCode(): Int = name.hashCode()
|
||||||
|
|
||||||
@@ -116,19 +132,29 @@ internal class KtUltraLightMethodForSourceDeclaration(
|
|||||||
lightMemberOrigin: LightMemberOrigin?,
|
lightMemberOrigin: LightMemberOrigin?,
|
||||||
support: KtUltraLightSupport,
|
support: KtUltraLightSupport,
|
||||||
containingClass: KtLightClass,
|
containingClass: KtLightClass,
|
||||||
private val forceToSkipNullabilityAnnotation: Boolean = false
|
private val forceToSkipNullabilityAnnotation: Boolean = false,
|
||||||
|
methodIndex: Int
|
||||||
) : KtUltraLightMethod(
|
) : KtUltraLightMethod(
|
||||||
delegate,
|
delegate,
|
||||||
lightMemberOrigin,
|
lightMemberOrigin,
|
||||||
support,
|
support,
|
||||||
containingClass
|
containingClass,
|
||||||
|
methodIndex
|
||||||
) {
|
) {
|
||||||
constructor(
|
constructor(
|
||||||
delegate: PsiMethod,
|
delegate: PsiMethod,
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
support: KtUltraLightSupport,
|
support: KtUltraLightSupport,
|
||||||
containingClass: KtLightClass
|
containingClass: KtLightClass,
|
||||||
) : this(delegate, LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER), support, containingClass)
|
methodIndex: Int
|
||||||
|
) : this(
|
||||||
|
delegate,
|
||||||
|
LightMemberOriginForDeclaration(declaration, JvmDeclarationOriginKind.OTHER),
|
||||||
|
support,
|
||||||
|
containingClass,
|
||||||
|
forceToSkipNullabilityAnnotation = false,
|
||||||
|
methodIndex
|
||||||
|
)
|
||||||
|
|
||||||
override val qualifiedNameForNullabilityAnnotation: String?
|
override val qualifiedNameForNullabilityAnnotation: String?
|
||||||
get() {
|
get() {
|
||||||
@@ -161,7 +187,8 @@ internal class KtUltraLightMethodForDescriptor(
|
|||||||
delegate,
|
delegate,
|
||||||
lightMemberOrigin,
|
lightMemberOrigin,
|
||||||
support,
|
support,
|
||||||
containingClass
|
containingClass,
|
||||||
|
METHOD_INDEX_FOR_NON_ORIGIN_METHOD
|
||||||
) {
|
) {
|
||||||
// This is greedy realization of UL class.
|
// 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.
|
// 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.Conditions
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.impl.light.LightElement
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
|
||||||
import com.intellij.testFramework.UsefulTestCase
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
import com.intellij.util.PairProcessor
|
import com.intellij.util.PairProcessor
|
||||||
import com.intellij.util.ref.DebugReflectionUtil
|
import com.intellij.util.ref.DebugReflectionUtil
|
||||||
@@ -81,6 +79,13 @@ object UltraLightChecker {
|
|||||||
val gold = KtLightClassForSourceDeclaration.createNoCache(ktClass, forceUsingOldLightClasses = true)
|
val gold = KtLightClassForSourceDeclaration.createNoCache(ktClass, forceUsingOldLightClasses = true)
|
||||||
val ultraLightClass = LightClassGenerationSupport.getInstance(ktClass.project).createUltraLightClass(ktClass) ?: return null
|
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)
|
checkClassEquivalenceByRendering(gold, ultraLightClass)
|
||||||
|
|
||||||
return ultraLightClass
|
return ultraLightClass
|
||||||
|
|||||||
Reference in New Issue
Block a user