[Low Level API FIR] fix invalid traverse of supertypes list

the supertypes list should not be traversed without proper locking,
otherwise some transformer may transform it concurrently

In case of looking for a declaration by class id it just should not be traversed

^KTIJ-21791
This commit is contained in:
Ilya Kirillov
2022-06-21 18:31:44 +02:00
committed by teamcity
parent 6cf085aafb
commit 0da66cc52f
3 changed files with 9 additions and 11 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.LLFirFileBui
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeOrReturnDefaultValueOnPCE import org.jetbrains.kotlin.analysis.low.level.api.fir.util.executeOrReturnDefaultValueOnPCE
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -39,9 +40,11 @@ internal class LLFirProviderHelper(
?: return@computeIfAbsent Optional.empty() ?: return@computeIfAbsent Optional.empty()
if (ktClass.getClassId() == null) return@computeIfAbsent Optional.empty() if (ktClass.getClassId() == null) return@computeIfAbsent Optional.empty()
val firFile = firFileBuilder.buildRawFirFileWithCaching(ktClass.containingKtFile) val firFile = firFileBuilder.buildRawFirFileWithCaching(ktClass.containingKtFile)
val classifier = FirElementFinder.findElementIn<FirClassLikeDeclaration>(firFile) { classifier -> val classifier = FirElementFinder.findElementIn<FirClassLikeDeclaration>(
classifier.symbol.classId == classId firFile,
} canGoInside = { it is FirRegularClass },
predicate = { it.symbol.classId == classId },
)
?: error("Classifier $classId was found in file ${ktClass.containingKtFile.virtualFilePath} but was not found in FirFile") ?: error("Classifier $classId was found in file ${ktClass.containingKtFile.virtualFilePath} but was not found in FirFile")
Optional.of(classifier) Optional.of(classifier)
}.getOrNull() }.getOrNull()
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
@@ -17,7 +16,7 @@ import org.jetbrains.kotlin.psi.KtElement
object FirElementFinder { object FirElementFinder {
inline fun <reified E : FirElement> findElementIn( inline fun <reified E : FirElement> findElementIn(
container: FirElement, container: FirElement,
crossinline goInside: (E) -> Boolean = { true }, crossinline canGoInside: (E) -> Boolean = { true },
crossinline predicate: (E) -> Boolean, crossinline predicate: (E) -> Boolean,
): E? { ): E? {
var result: E? = null var result: E? = null
@@ -31,7 +30,7 @@ object FirElementFinder {
predicate(element) -> { predicate(element) -> {
result = element result = element
} }
goInside(element) -> { canGoInside(element) -> {
element.acceptChildren(this) element.acceptChildren(this)
} }
} }
@@ -61,7 +60,4 @@ object FirElementFinder {
}) })
return result return result
} }
inline fun <reified E : FirElement> findElementByPsiIn(container: FirElement, ktElement: KtElement): E? =
findElementIn(container) { it.psi === ktElement }
} }
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.realPsi import org.jetbrains.kotlin.fir.realPsi
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
@@ -63,7 +62,7 @@ private fun KtDeclaration.findSourceOfNonLocalFirDeclarationByTraversingWholeTre
): FirDeclaration? { ): FirDeclaration? {
val firFile = containerFirFile ?: firFileBuilder.buildRawFirFileWithCaching(containingKtFile) val firFile = containerFirFile ?: firFileBuilder.buildRawFirFileWithCaching(containingKtFile)
val originalDeclaration = originalDeclaration val originalDeclaration = originalDeclaration
return FirElementFinder.findElementIn(firFile, goInside = { it is FirRegularClass }) { firDeclaration -> return FirElementFinder.findElementIn(firFile, canGoInside = { it is FirRegularClass }) { firDeclaration ->
firDeclaration.psi == this || firDeclaration.psi == originalDeclaration firDeclaration.psi == this || firDeclaration.psi == originalDeclaration
} }
} }