Light classes: do not rely on dummy context when data class autogenerated members conflict with declared members

Fix related issues with nested classes
This commit is contained in:
Pavel V. Talanov
2017-04-05 20:49:32 +03:00
parent 69c250a1b7
commit 2f159bb64b
9 changed files with 115 additions and 11 deletions
@@ -0,0 +1,20 @@
// p.Wrapper
package p
class Wrapper {
data class Equals(val code: G) {
override fun equals(other: Any?): Boolean = true
}
data class HashCode(val code: G) {
override fun hashCode() = 3
}
data class ToString(val code: G) {
override fun toString() = "b"
}
}
class G
// LAZINESS:NoLaziness
@@ -0,0 +1,13 @@
public final class B {
public B() { /* compiled code */ }
public static final class A implements p.I {
private final p.I f;
public A(@org.jetbrains.annotations.NotNull p.I f) { /* compiled code */ }
public void f() { /* compiled code */ }
public void g() { /* compiled code */ }
}
}
@@ -0,0 +1,15 @@
// p.B
package p
class B {
class A(private val f: I) : I by f {
}
}
interface I {
fun g()
fun f()
}
// LAZINESS:NoLaziness
@@ -42,6 +42,18 @@ public class CompilerLightClassTestGenerated extends AbstractCompilerLightClassT
doTest(fileName);
}
@TestMetadata("DataClassWithCustomImplementedMembers.kt")
public void testDataClassWithCustomImplementedMembers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt");
doTest(fileName);
}
@TestMetadata("DelegatedNested.kt")
public void testDelegatedNested() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/DelegatedNested.kt");
doTest(fileName);
}
@TestMetadata("Delegation.kt")
public void testDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
@@ -70,12 +71,10 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
)
}
else {
val hasDelegatedMembers = classOrObject.superTypeListEntries.any { it is KtDelegatedSuperTypeEntry }
val dummyContextProvider = { IDELightClassContexts.lightContextForClassOrObject(classOrObject) }
LazyLightClassDataHolder.ForClass(
builder,
exactContextProvider = { IDELightClassContexts.contextForNonLocalClassOrObject(classOrObject) },
dummyContextProvider = if (!hasDelegatedMembers) dummyContextProvider else null
dummyContextProvider = { IDELightClassContexts.lightContextForClassOrObject(classOrObject) }
)
}
}
@@ -125,7 +125,9 @@ object IDELightClassContexts {
return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, EXACT)
}
fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext? {
if (!isDummyResolveApplicable(classOrObject)) return null
val resolveSession = setupAdHocResolve(classOrObject.project, classOrObject.getResolutionFacade().moduleDescriptor, listOf(classOrObject.containingKtFile))
ForceResolveUtil.forceResolveAllContents(resolveSession.resolveToDescriptor(classOrObject))
@@ -133,6 +135,24 @@ object IDELightClassContexts {
return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, LIGHT)
}
private fun isDummyResolveApplicable(classOrObject: KtClassOrObject): Boolean {
val hasDelegatedMembers = classOrObject.superTypeListEntries.any { it is KtDelegatedSuperTypeEntry }
val dataClassWithGeneratedMembersOverridden = classOrObject.declarations.filterIsInstance<KtFunction>().any {
isGeneratedForDataClass(it.nameAsSafeName)
}
return !hasDelegatedMembers && !dataClassWithGeneratedMembersOverridden
&& classOrObject.declarations.filterIsInstance<KtClassOrObject>().all { isDummyResolveApplicable(it) }
}
private fun isGeneratedForDataClass(name: Name): Boolean {
return name == DataClassDescriptorResolver.EQUALS_METHOD_NAME ||
// known failure is related to equals override, checking for other methods 'just in case'
name == DataClassDescriptorResolver.COPY_METHOD_NAME ||
name == DataClassDescriptorResolver.HASH_CODE_METHOD_NAME ||
name == DataClassDescriptorResolver.TO_STRING_METHOD_NAME ||
DataClassDescriptorResolver.isComponentLike(name)
}
fun lightContextForFacade(files: List<KtFile>): LightClassConstructionContext {
val representativeFile = files.first()
val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files)
@@ -329,6 +349,6 @@ object IDELightClassContexts {
}
private val notImplemented: Nothing
get() = error("Should not be called")
get() = error("Should not be called")
}
@@ -38,12 +38,13 @@ import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtNamedDeclaration
typealias LightClassContextProvider = () -> LightClassConstructionContext
typealias ExactLightClassContextProvider = () -> LightClassConstructionContext
typealias DummyLightClassContextProvider = (() -> LightClassConstructionContext?)?
sealed class LazyLightClassDataHolder(
builder: LightClassBuilder,
exactContextProvider: LightClassContextProvider,
dummyContextProvider: LightClassContextProvider?
exactContextProvider: ExactLightClassContextProvider,
dummyContextProvider: DummyLightClassContextProvider
) : LightClassDataHolder {
private val exactResultLazyValue = lazyPub { builder(exactContextProvider()) }
@@ -51,7 +52,7 @@ sealed class LazyLightClassDataHolder(
private val exactResult: LightClassBuilderResult by exactResultLazyValue
private val lazyInexactResult by lazyPub {
dummyContextProvider?.let { builder.invoke(it()) }
dummyContextProvider?.let { provider -> provider()?.let { context -> builder.invoke(context) } }
}
private val inexactResult: LightClassBuilderResult?
@@ -67,7 +68,7 @@ sealed class LazyLightClassDataHolder(
}
class ForClass(
builder: LightClassBuilder, exactContextProvider: LightClassContextProvider, dummyContextProvider: LightClassContextProvider?
builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForClass {
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
@@ -76,7 +77,7 @@ sealed class LazyLightClassDataHolder(
}
class ForFacade(
builder: LightClassBuilder, exactContextProvider: LightClassContextProvider, dummyContextProvider: LightClassContextProvider?
builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade
private inner class LazyLightClassData(
@@ -42,6 +42,18 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight
doTest(fileName);
}
@TestMetadata("DataClassWithCustomImplementedMembers.kt")
public void testDataClassWithCustomImplementedMembers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt");
doTest(fileName);
}
@TestMetadata("DelegatedNested.kt")
public void testDelegatedNested() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/DelegatedNested.kt");
doTest(fileName);
}
@TestMetadata("Delegation.kt")
public void testDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
@@ -42,6 +42,18 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest {
doTest(fileName);
}
@TestMetadata("DataClassWithCustomImplementedMembers.kt")
public void testDataClassWithCustomImplementedMembers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt");
doTest(fileName);
}
@TestMetadata("DelegatedNested.kt")
public void testDelegatedNested() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/DelegatedNested.kt");
doTest(fileName);
}
@TestMetadata("Delegation.kt")
public void testDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");