[FE, Java resolve] Support inheritors of sealed Java type without permits clause

This fixes a false negative NO_ELSE_IN_WHEN in K2 and incidentally
also fixes a false positive NO_ELSE_IN_WHEN in K1 since the fix is in
the common code.

#KT-62491 Fixed
This commit is contained in:
Kirill Rakhman
2023-10-24 10:00:18 +02:00
committed by Space Team
parent 15d3bf5e25
commit ac203591e5
22 changed files with 291 additions and 21 deletions
@@ -19,7 +19,9 @@ package org.jetbrains.kotlin.load.java.structure.impl
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElementFactory
import com.intellij.psi.PsiTypeParameter
import com.intellij.psi.SyntaxTraverser
import com.intellij.psi.search.SearchScope
import org.jetbrains.kotlin.asJava.KtLightClassMarker
import org.jetbrains.kotlin.asJava.isSyntheticValuesOrValueOfMethod
@@ -68,9 +70,18 @@ class JavaClassImpl(psiClassSource: JavaElementPsiSource<PsiClass>) : JavaClassi
override val isSealed: Boolean
get() = JavaElementUtil.isSealed(this)
override val permittedTypes: Collection<JavaClassifierType>
get() = psi.permitsListTypes.convertIndexed { index, _ ->
JavaClassifierTypeImpl(sourceFactory.createPermittedTypeSource(psiElementSource, index))
override val permittedTypes: Sequence<JavaClassifierType>
get() {
if (!isSealed) return emptySequence()
val permitsListTypes = psi.permitsListTypes
return if (permitsListTypes.isNotEmpty()) {
permitsListTypes.convertIndexed { index, _ ->
JavaClassifierTypeImpl(sourceFactory.createPermittedTypeSource(psiElementSource, index))
}.asSequence()
} else {
lazilyComputePermittedTypesInSameFile(psiElementSource)
}
}
override val isRecord: Boolean
@@ -163,3 +174,19 @@ class JavaClassImpl(psiClassSource: JavaElementPsiSource<PsiClass>) : JavaClassi
private val LOGGER = Logger.getInstance(JavaClassImpl::class.java)
}
}
private fun lazilyComputePermittedTypesInSameFile(psiElementSource: JavaElementPsiSource<PsiClass>): Sequence<JavaClassifierType> {
return Sequence {
// Don't capture PSI directly but only via psiElementSource
val psi = psiElementSource.psi
val elementFactory = PsiElementFactory.getInstance(psi.project)
SyntaxTraverser.psiTraverser(psi.containingFile)
.filter(PsiClass::class.java)
// isInheritor can lead to resolution which can cause contract violations,
// that's why we compute it lazily only when the sequence is iterated.
.filter { it.isInheritor(psi, /* checkDeep: */ false) }
.map { JavaClassifierTypeImpl(psiElementSource.factory.createTypeSource(elementFactory.createType(it))) }
.iterator()
}
}
@@ -79,8 +79,10 @@ class BinaryJavaClass(
override val lightClassOriginKind: LightClassOriginKind? get() = null
override val isSealed: Boolean get() = permittedTypes.isNotEmpty()
override val permittedTypes = arrayListOf<JavaClassifierType>()
private val permittedTypesList: ArrayList<JavaClassifierType> = arrayListOf()
override val isSealed: Boolean get() = permittedTypesList.isNotEmpty()
override val permittedTypes: Sequence<JavaClassifierType>
get() = permittedTypesList.asSequence()
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = false
@@ -258,6 +260,6 @@ class BinaryJavaClass(
}
override fun visitPermittedSubclass(permittedSubclass: String?) {
permittedTypes.addIfNotNull(permittedSubclass?.convertInternalNameToClassifierType())
permittedTypesList.addIfNotNull(permittedSubclass?.convertInternalNameToClassifierType())
}
}