From 5151659006f18d0c86489ff597e4b0fd2ad31c8f Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 5 Aug 2019 18:20:14 +0300 Subject: [PATCH] Do not use dummy resolving for light data classes which extend other classes When using dummy resolving for creating stubs of data classes we do not have overriding information which is needed to determine whether we need to generate synthetic members or not. As a result of that, we may have two different versions of member scope: the first one is resolved by dummy resolving and the second one resolved via an ordinary one. As light methods depend on the index of them in the class body, we can have two different methods with the same index which breaks mapping from dummy resolved methods to normal ones. This behaviour can be reproduced when having data class which extends other class with some synthetic members overridden and marked as final like described in #KT-32969 #KT-32969 fixed --- .../lightClasses/IDELightClassContexts.kt | 7 ++++++ .../kotlin/asJava/LightClassFromTextTest.kt | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt index ee119fe75c1..684993bf0d0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt @@ -187,6 +187,8 @@ internal object IDELightClassContexts { if (isDataClassWithGeneratedMembersOverridden(classOrObject)) return false + if (isDataClassWhichExtendsOtherClass(classOrObject)) return false + if (hasMembersOverridingInternalMembers(classOrObject)) return false if (hasSerializationLikeAnnotations(classOrObject)) return false @@ -232,6 +234,11 @@ internal object IDELightClassContexts { DataClassDescriptorResolver.isComponentLike(name) } + private fun isDataClassWhichExtendsOtherClass(classOrObject: KtClassOrObject): Boolean { + return classOrObject.hasModifier(KtTokens.DATA_KEYWORD) && + classOrObject.superTypeListEntries.isNotEmpty() + } + private fun hasMembersOverridingInternalMembers(classOrObject: KtClassOrObject): Boolean { return classOrObject.declarations.filterIsInstance().any { possiblyOverridesInternalMember(it) diff --git a/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt b/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt index e8e86183a14..15b65ac27b5 100644 --- a/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt +++ b/idea/tests/org/jetbrains/kotlin/asJava/LightClassFromTextTest.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiClass import com.intellij.psi.PsiClassType import com.intellij.psi.PsiType import com.intellij.testFramework.LightProjectDescriptor +import org.jetbrains.kotlin.asJava.elements.KtLightMethod import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor import org.jetbrains.kotlin.idea.test.PluginTestCaseBase @@ -104,6 +105,27 @@ class LightClassFromTextTest : KotlinLightCodeInsightFixtureTestCase() { assertEquals(exampleClass, (f.returnType as PsiClassType).resolve()) } + // KT-32969 + fun testDataClassWhichExtendsAbstractWithFinalToString() { + myFixture.configureByText( + "A.kt", + """ + abstract class A { + final override fun toString() = "nya" + } + """.trimIndent() + ) as KtFile + val dataClass = classesFromText("data class D(val x: Int): A()").single() + + for (method in dataClass.methods) { + if (method is KtLightMethod) { + // LazyLightClassMemberMatchingError$WrongMatch will be thrown + // if memberIndex conflict will be found + method.clsDelegate + } + } + } + fun testHeaderDeclarations() { val contextFile = myFixture.configureByText("Header.kt", "header class Foo\n\nheader fun foo()\n") as KtFile val headerClass = contextFile.declarations.single { it is KtClassOrObject }