diff --git a/compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt b/compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt new file mode 100644 index 00000000000..7bf9591fe73 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/DataClassWithCustomImplementedMembers.kt @@ -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 \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/DelegatedNested.java b/compiler/testData/asJava/lightClasses/DelegatedNested.java new file mode 100644 index 00000000000..7430267544e --- /dev/null +++ b/compiler/testData/asJava/lightClasses/DelegatedNested.java @@ -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 */ } + } +} diff --git a/compiler/testData/asJava/lightClasses/DelegatedNested.kt b/compiler/testData/asJava/lightClasses/DelegatedNested.kt new file mode 100644 index 00000000000..59b11dc52aa --- /dev/null +++ b/compiler/testData/asJava/lightClasses/DelegatedNested.kt @@ -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 \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java index fb200b945e5..6b3d1037a2a 100644 --- a/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/asJava/CompilerLightClassTestGenerated.java @@ -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"); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index cfd087cf6fa..98075e0522a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.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) } ) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt index 3c7da12b4ef..49626c6fd89 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/IDELightClassContexts.kt @@ -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().any { + isGeneratedForDataClass(it.nameAsSafeName) + } + return !hasDelegatedMembers && !dataClassWithGeneratedMembersOverridden + && classOrObject.declarations.filterIsInstance().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): 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") } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt index 0c308bddc3b..c163b91392f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/lightClasses/LazyLightClassDataHolder.kt @@ -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( diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java index 9de9c49d2a2..bf6b5af616e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeCompiledLightClassTestGenerated.java @@ -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"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java index d5900f4ca6a..534cdfabc5e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/IdeLightClassTestGenerated.java @@ -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");