Light class test: avoid checking method visibility when NoLaziness is not specified

Allows to avoid putting NoLaziness flag on every test that mentions 'override' modifier
This commit is contained in:
Pavel V. Talanov
2017-04-05 16:59:13 +03:00
parent 32d3a1b4c9
commit 69c250a1b7
4 changed files with 25 additions and 22 deletions
@@ -110,7 +110,7 @@ class KtLightModifierList(
name == PsiModifier.DEFAULT && isImplementationInInterface() -> true name == PsiModifier.DEFAULT && isImplementationInInterface() -> true
dummyDelegate != null -> { dummyDelegate != null -> {
when { when {
name in visibilityModifiers && isOverride() -> name in visibilityModifiers && isMethodOverride() ->
clsDelegate.hasModifierProperty(name) clsDelegate.hasModifierProperty(name)
else -> dummyDelegate.hasModifierProperty(name) else -> dummyDelegate.hasModifierProperty(name)
} }
@@ -118,7 +118,7 @@ class KtLightModifierList(
else -> clsDelegate.hasModifierProperty(name) 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() private fun isImplementationInInterface()
= owner.containingClass.isInterface && owner is KtLightMethod && owner.kotlinOrigin?.hasBody() ?: false = owner.containingClass.isInterface && owner is KtLightMethod && owner.kotlinOrigin?.hasBody() ?: false
@@ -21,6 +21,4 @@ interface I1 {
interface I2 { interface I2 {
fun bar() = "bar" fun bar() = "bar"
} }
// LAZINESS:NoLaziness
@@ -8,6 +8,4 @@ interface Tr {
class C: Tr { class C: Tr {
override fun foo() = 1 override fun foo() = 1
override val v = 1 override val v = 1
} }
// LAZINESS:NoLaziness
@@ -194,7 +194,7 @@ object LightClassLazinessChecker {
} }
// collect api method call results on light members that should not trigger exact context evaluation // 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) tracker.allowLevel(EXACT)
@@ -202,19 +202,19 @@ object LightClassLazinessChecker {
tracker.checkLevel(EXACT) tracker.checkLevel(EXACT)
// still running code above to catch possible exceptions
if (lazinessMode == Mode.NoConsistency) return
lazinessInfo.checkConsistency() lazinessInfo.checkConsistency()
} }
private class LazinessInfo(val lightClass: KtLightClass) { private class LazinessInfo(private val lightClass: KtLightClass, private val lazinessMode: Mode) {
val classInfo = classInfo(lightClass) val classInfo = classInfo(lightClass)
val fieldsToInfo = lightClass.fields.asList().keysToMap { fieldInfo(it) } val fieldsToInfo = lightClass.fields.asList().keysToMap { fieldInfo(it) }
val methodsToInfo = lightClass.methods.asList().keysToMap { methodInfo(it) } val methodsToInfo = lightClass.methods.asList().keysToMap { methodInfo(it, lazinessMode) }
val innerClasses = lightClass.innerClasses.map { LazinessInfo(it as KtLightClass) } val innerClasses = lightClass.innerClasses.map { LazinessInfo(it as KtLightClass, lazinessMode) }
fun checkConsistency() { fun checkConsistency() {
// still collecting data to trigger possible exceptions
if (lazinessMode == Mode.NoConsistency) return
// check collected data against delegates which should contain correct data // check collected data against delegates which should contain correct data
for ((field, lightFieldInfo) in fieldsToInfo) { for ((field, lightFieldInfo) in fieldsToInfo) {
val delegate = (field as KtLightField).clsDelegate val delegate = (field as KtLightField).clsDelegate
@@ -222,7 +222,7 @@ object LightClassLazinessChecker {
} }
for ((method, lightMethodInfo) in methodsToInfo) { for ((method, lightMethodInfo) in methodsToInfo) {
val delegate = (method as KtLightMethod).clsDelegate val delegate = (method as KtLightMethod).clsDelegate
assertEquals(methodInfo(delegate), lightMethodInfo) assertEquals(methodInfo(delegate, lazinessMode), lightMethodInfo)
} }
assertEquals(classInfo(lightClass.clsDelegate), classInfo) assertEquals(classInfo(lightClass.clsDelegate), classInfo)
@@ -260,23 +260,30 @@ object LightClassLazinessChecker {
val isVarargs: Boolean val isVarargs: Boolean
) )
private fun methodInfo(method: PsiMethod) = with(method) { private fun methodInfo(method: PsiMethod, lazinessMode: Mode) = with(method) {
MethodInfo( MethodInfo(
name, relevantModifiers(), name, relevantModifiers(lazinessMode),
isConstructor, method.parameterList.parametersCount, isVarArgs isConstructor, method.parameterList.parametersCount, isVarArgs
) )
} }
private fun PsiMethod.relevantModifiers() private fun PsiMethod.relevantModifiers(lazinessMode: Mode) = when {
= when { containingClass!!.isInterface -> containingClass!!.isInterface -> PsiModifier.MODIFIERS.filter {
PsiModifier.MODIFIERS.filter { it != PsiModifier.ABSTRACT && it != PsiModifier.DEFAULT } // we have custom strategy for interface members with implementation
it !in modifiersHackedForInterfaceMembersWithImplementation
}
else -> PsiModifier.MODIFIERS.asList() 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) } }.filter { modifierList.hasModifierProperty(it) }
private fun Array<out PsiMember>.names() = mapTo(LinkedHashSet()) { it.name!! } private fun Array<out PsiMember>.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 { private fun String.removeLinesStartingWith(prefix: String): String {
return lines().filterNot { it.trimStart().startsWith(prefix) }.joinToString(separator = "\n") return lines().filterNot { it.trimStart().startsWith(prefix) }.joinToString(separator = "\n")
} }