diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt index 90df98878a3..e44a417a26a 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/elements/KtLightMemberImpl.kt @@ -110,7 +110,7 @@ class KtLightModifierList( name == PsiModifier.DEFAULT && isImplementationInInterface() -> true dummyDelegate != null -> { when { - name in visibilityModifiers && isOverride() -> + name in visibilityModifiers && isMethodOverride() -> clsDelegate.hasModifierProperty(name) else -> dummyDelegate.hasModifierProperty(name) } @@ -118,7 +118,7 @@ class KtLightModifierList( else -> clsDelegate.hasModifierProperty(name) } - private fun isOverride() = owner.kotlinOrigin?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false + private fun isMethodOverride() = owner is KtLightMethod && owner.kotlinOrigin?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false private fun isImplementationInInterface() = owner.containingClass.isInterface && owner is KtLightMethod && owner.kotlinOrigin?.hasBody() ?: false diff --git a/compiler/testData/asJava/lightClasses/InheritingInterfaceDefaultImpls.kt b/compiler/testData/asJava/lightClasses/InheritingInterfaceDefaultImpls.kt index 2b78bb02333..24d059976f7 100644 --- a/compiler/testData/asJava/lightClasses/InheritingInterfaceDefaultImpls.kt +++ b/compiler/testData/asJava/lightClasses/InheritingInterfaceDefaultImpls.kt @@ -21,6 +21,4 @@ interface I1 { interface I2 { fun bar() = "bar" -} - -// LAZINESS:NoLaziness \ No newline at end of file +} \ No newline at end of file diff --git a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt index d61bfa4fa7a..a9ac9a5d7b3 100644 --- a/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt +++ b/compiler/testData/asJava/lightClasses/nullabilityAnnotations/IntOverridesAny.kt @@ -8,6 +8,4 @@ interface Tr { class C: Tr { override fun foo() = 1 override val v = 1 -} - -// LAZINESS:NoLaziness \ No newline at end of file +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt index 41f2fe59e17..f7e93e3ddff 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AbstractIdeLightClassTest.kt @@ -194,7 +194,7 @@ object LightClassLazinessChecker { } // collect api method call results on light members that should not trigger exact context evaluation - val lazinessInfo = LazinessInfo(lightClass) + val lazinessInfo = LazinessInfo(lightClass, lazinessMode) tracker.allowLevel(EXACT) @@ -202,19 +202,19 @@ object LightClassLazinessChecker { tracker.checkLevel(EXACT) - // still running code above to catch possible exceptions - if (lazinessMode == Mode.NoConsistency) return - lazinessInfo.checkConsistency() } - private class LazinessInfo(val lightClass: KtLightClass) { + private class LazinessInfo(private val lightClass: KtLightClass, private val lazinessMode: Mode) { val classInfo = classInfo(lightClass) val fieldsToInfo = lightClass.fields.asList().keysToMap { fieldInfo(it) } - val methodsToInfo = lightClass.methods.asList().keysToMap { methodInfo(it) } - val innerClasses = lightClass.innerClasses.map { LazinessInfo(it as KtLightClass) } + val methodsToInfo = lightClass.methods.asList().keysToMap { methodInfo(it, lazinessMode) } + val innerClasses = lightClass.innerClasses.map { LazinessInfo(it as KtLightClass, lazinessMode) } fun checkConsistency() { + // still collecting data to trigger possible exceptions + if (lazinessMode == Mode.NoConsistency) return + // check collected data against delegates which should contain correct data for ((field, lightFieldInfo) in fieldsToInfo) { val delegate = (field as KtLightField).clsDelegate @@ -222,7 +222,7 @@ object LightClassLazinessChecker { } for ((method, lightMethodInfo) in methodsToInfo) { val delegate = (method as KtLightMethod).clsDelegate - assertEquals(methodInfo(delegate), lightMethodInfo) + assertEquals(methodInfo(delegate, lazinessMode), lightMethodInfo) } assertEquals(classInfo(lightClass.clsDelegate), classInfo) @@ -260,23 +260,30 @@ object LightClassLazinessChecker { val isVarargs: Boolean ) - private fun methodInfo(method: PsiMethod) = with(method) { + private fun methodInfo(method: PsiMethod, lazinessMode: Mode) = with(method) { MethodInfo( - name, relevantModifiers(), + name, relevantModifiers(lazinessMode), isConstructor, method.parameterList.parametersCount, isVarArgs ) } - private fun PsiMethod.relevantModifiers() - = when { containingClass!!.isInterface -> - PsiModifier.MODIFIERS.filter { it != PsiModifier.ABSTRACT && it != PsiModifier.DEFAULT } + private fun PsiMethod.relevantModifiers(lazinessMode: Mode) = when { + containingClass!!.isInterface -> PsiModifier.MODIFIERS.filter { + // we have custom strategy for interface members with implementation + it !in modifiersHackedForInterfaceMembersWithImplementation + } else -> PsiModifier.MODIFIERS.asList() + }.filter { + // cannot compute visibility for overrides without proper resolve, we check consistency if laziness is turned off + lazinessMode == Mode.NoLaziness || it !in visibilityModifiers }.filter { modifierList.hasModifierProperty(it) } - private fun Array.names() = mapTo(LinkedHashSet()) { it.name!! } } +private val modifiersHackedForInterfaceMembersWithImplementation = listOf(PsiModifier.ABSTRACT, PsiModifier.DEFAULT) +private val visibilityModifiers = listOf(PsiModifier.PRIVATE, PsiModifier.PROTECTED, PsiModifier.PUBLIC) + private fun String.removeLinesStartingWith(prefix: String): String { return lines().filterNot { it.trimStart().startsWith(prefix) }.joinToString(separator = "\n") }