diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt index f35770f11ac..e766d984ea7 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/FirIdeSessionProvider.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.api.impl.barebone.annotations.Immutable import org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache import org.jetbrains.kotlin.analysis.project.structure.KtModule +import org.jetbrains.kotlin.analysis.project.structure.NoCacheForModuleException import org.jetbrains.kotlin.fir.FirModuleData import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSessionProvider @@ -26,7 +27,8 @@ class LLFirSessionProvider internal constructor( moduleToSession[module] internal fun getModuleCache(module: KtModule): ModuleFileCache = - moduleToSession.getValue(module).cache + moduleToSession[module]?.cache + ?: throw NoCacheForModuleException(module, moduleToSession.keys) val allSessions: Collection get() = moduleToSession.values diff --git a/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/NoCacheForModuleException.kt b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/NoCacheForModuleException.kt new file mode 100644 index 00000000000..54d937a9cb9 --- /dev/null +++ b/analysis/project-structure/src/org/jetbrains/kotlin/analysis/project/structure/NoCacheForModuleException.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.analysis.project.structure + +/** + * Exception to signal that no [org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder.ModuleFileCache] was + * found for [missingModule] by [org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSessionProvider]. + * + * TODO: This can be caused by the problem described in KT-51240. When the problem is fixed, this exception will probably become redundant. + */ +public class NoCacheForModuleException( + private val missingModule: KtModule, + private val existingModules: Set +) : NoSuchElementException() { + override val message: String + get() = "No cache was found for module '${missingModule.moduleDescription}'! " + + "Caches exist for the following modules: ${existingModules.map { it.moduleDescription }}" +} \ No newline at end of file diff --git a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt index ab220786000..769ca4f02a6 100644 --- a/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt +++ b/analysis/symbol-light-classes/src/org/jetbrains/kotlin/light/classes/symbol/classes/firLightClassUtils.kt @@ -10,6 +10,7 @@ import com.intellij.psi.PsiModifier import com.intellij.psi.PsiReferenceList import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager +import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import org.jetbrains.kotlin.analysis.api.symbols.* import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers @@ -21,6 +22,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.getKtModuleOfTypeSafe +import org.jetbrains.kotlin.analysis.project.structure.NoCacheForModuleException import org.jetbrains.kotlin.asJava.builder.LightMemberOriginForDeclaration import org.jetbrains.kotlin.asJava.classes.* import org.jetbrains.kotlin.asJava.elements.KtLightField @@ -433,19 +435,39 @@ internal fun KtSymbolWithMembers.createInnerClasses( return result } -internal fun KtClassOrObject.checkIsInheritor(baseClassOrigin: KtClassOrObject, checkDeep: Boolean): Boolean { - return analyseForLightClasses(this) { - val subClassSymbol = this@checkIsInheritor.getClassOrObjectSymbol() - val superClassSymbol = baseClassOrigin.getClassOrObjectSymbol() +internal fun KtClassOrObject.checkIsInheritor(superClassOrigin: KtClassOrObject, checkDeep: Boolean): Boolean { + val subClassOrigin = this - if (subClassSymbol == superClassSymbol) return@analyseForLightClasses false + fun KtAnalysisSession.check(): Boolean { + val subClassSymbol = subClassOrigin.getClassOrObjectSymbol() + val superClassSymbol = superClassOrigin.getClassOrObjectSymbol() - if (checkDeep) { + if (subClassSymbol == superClassSymbol) return false + + return if (checkDeep) { subClassSymbol.isSubClassOf(superClassSymbol) } else { subClassSymbol.isDirectSubClassOf(superClassSymbol) } } + + // Due to the KT-51240 we cannot be sure which PSI element is better to analyse, so we try both. + // + // We specifically catch NoCacheForModuleException as a sign that LLFirSessionProvider.getModuleCache could not + // find a cache for the passed module. This means that `module(subClassOrigin)` does not have `module(superClassOrigin)` as + // its dependency, and we should try the other way around. + // + // Note, however, that the second call might also fail, since the modules can be completely independent. + // We can only hope that, since this code is invoked from the light classes, the passed PSI classes are + // relatively close to each other syntactically, meaning that there is some dependency between the modules + // they reside in. + // + // TODO: Avoid this hack when KT-51240 is fixed + return try { + analyseForLightClasses(subClassOrigin) { check() } + } catch (e: NoCacheForModuleException) { + analyseForLightClasses(superClassOrigin) { check() } + } } private val KtSymbolWithTypeParameters.hasReifiedParameters: Boolean