Fix invalid equality for UL methods

Potentially fixed #KT-34796
This commit is contained in:
Igor Yakovlev
2019-12-03 20:54:05 +03:00
parent d6fcde7316
commit 2639ed2c48
4 changed files with 84 additions and 24 deletions
@@ -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 {
@@ -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(
@@ -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