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:
+20
@@ -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);
|
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")
|
@TestMetadata("Delegation.kt")
|
||||||
public void testDelegation() throws Exception {
|
public void testDelegation() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
|
||||||
|
|||||||
+2
-3
@@ -47,6 +47,7 @@ import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper
|
|||||||
import org.jetbrains.kotlin.idea.stubindex.*
|
import org.jetbrains.kotlin.idea.stubindex.*
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles
|
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -70,12 +71,10 @@ class IDELightClassGenerationSupport(private val project: Project) : LightClassG
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val hasDelegatedMembers = classOrObject.superTypeListEntries.any { it is KtDelegatedSuperTypeEntry }
|
|
||||||
val dummyContextProvider = { IDELightClassContexts.lightContextForClassOrObject(classOrObject) }
|
|
||||||
LazyLightClassDataHolder.ForClass(
|
LazyLightClassDataHolder.ForClass(
|
||||||
builder,
|
builder,
|
||||||
exactContextProvider = { IDELightClassContexts.contextForNonLocalClassOrObject(classOrObject) },
|
exactContextProvider = { IDELightClassContexts.contextForNonLocalClassOrObject(classOrObject) },
|
||||||
dummyContextProvider = if (!hasDelegatedMembers) dummyContextProvider else null
|
dummyContextProvider = { IDELightClassContexts.lightContextForClassOrObject(classOrObject) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-2
@@ -125,7 +125,9 @@ object IDELightClassContexts {
|
|||||||
return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, EXACT)
|
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))
|
val resolveSession = setupAdHocResolve(classOrObject.project, classOrObject.getResolutionFacade().moduleDescriptor, listOf(classOrObject.containingKtFile))
|
||||||
|
|
||||||
ForceResolveUtil.forceResolveAllContents(resolveSession.resolveToDescriptor(classOrObject))
|
ForceResolveUtil.forceResolveAllContents(resolveSession.resolveToDescriptor(classOrObject))
|
||||||
@@ -133,6 +135,24 @@ object IDELightClassContexts {
|
|||||||
return IDELightClassConstructionContext(resolveSession.bindingContext, resolveSession.moduleDescriptor, LIGHT)
|
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 {
|
fun lightContextForFacade(files: List<KtFile>): LightClassConstructionContext {
|
||||||
val representativeFile = files.first()
|
val representativeFile = files.first()
|
||||||
val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files)
|
val resolveSession = setupAdHocResolve(representativeFile.project, representativeFile.getResolutionFacade().moduleDescriptor, files)
|
||||||
@@ -329,6 +349,6 @@ object IDELightClassContexts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val notImplemented: Nothing
|
private val notImplemented: Nothing
|
||||||
get() = error("Should not be called")
|
get() = error("Should not be called")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -38,12 +38,13 @@ import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
|||||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
|
||||||
typealias LightClassContextProvider = () -> LightClassConstructionContext
|
typealias ExactLightClassContextProvider = () -> LightClassConstructionContext
|
||||||
|
typealias DummyLightClassContextProvider = (() -> LightClassConstructionContext?)?
|
||||||
|
|
||||||
sealed class LazyLightClassDataHolder(
|
sealed class LazyLightClassDataHolder(
|
||||||
builder: LightClassBuilder,
|
builder: LightClassBuilder,
|
||||||
exactContextProvider: LightClassContextProvider,
|
exactContextProvider: ExactLightClassContextProvider,
|
||||||
dummyContextProvider: LightClassContextProvider?
|
dummyContextProvider: DummyLightClassContextProvider
|
||||||
) : LightClassDataHolder {
|
) : LightClassDataHolder {
|
||||||
|
|
||||||
private val exactResultLazyValue = lazyPub { builder(exactContextProvider()) }
|
private val exactResultLazyValue = lazyPub { builder(exactContextProvider()) }
|
||||||
@@ -51,7 +52,7 @@ sealed class LazyLightClassDataHolder(
|
|||||||
private val exactResult: LightClassBuilderResult by exactResultLazyValue
|
private val exactResult: LightClassBuilderResult by exactResultLazyValue
|
||||||
|
|
||||||
private val lazyInexactResult by lazyPub {
|
private val lazyInexactResult by lazyPub {
|
||||||
dummyContextProvider?.let { builder.invoke(it()) }
|
dummyContextProvider?.let { provider -> provider()?.let { context -> builder.invoke(context) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val inexactResult: LightClassBuilderResult?
|
private val inexactResult: LightClassBuilderResult?
|
||||||
@@ -67,7 +68,7 @@ sealed class LazyLightClassDataHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ForClass(
|
class ForClass(
|
||||||
builder: LightClassBuilder, exactContextProvider: LightClassContextProvider, dummyContextProvider: LightClassContextProvider?
|
builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider
|
||||||
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForClass {
|
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForClass {
|
||||||
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
|
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
|
||||||
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
|
LazyLightClassData(relyOnDummySupertypes = classOrObject.getSuperTypeList() == null) { lightClassBuilderResult ->
|
||||||
@@ -76,7 +77,7 @@ sealed class LazyLightClassDataHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ForFacade(
|
class ForFacade(
|
||||||
builder: LightClassBuilder, exactContextProvider: LightClassContextProvider, dummyContextProvider: LightClassContextProvider?
|
builder: LightClassBuilder, exactContextProvider: ExactLightClassContextProvider, dummyContextProvider: DummyLightClassContextProvider
|
||||||
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade
|
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider), LightClassDataHolder.ForFacade
|
||||||
|
|
||||||
private inner class LazyLightClassData(
|
private inner class LazyLightClassData(
|
||||||
|
|||||||
+12
@@ -42,6 +42,18 @@ public class IdeCompiledLightClassTestGenerated extends AbstractIdeCompiledLight
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("Delegation.kt")
|
||||||
public void testDelegation() throws Exception {
|
public void testDelegation() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
|
||||||
|
|||||||
@@ -42,6 +42,18 @@ public class IdeLightClassTestGenerated extends AbstractIdeLightClassTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("Delegation.kt")
|
||||||
public void testDelegation() throws Exception {
|
public void testDelegation() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/asJava/lightClasses/Delegation.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user