[FIR IDE] Hack checkIsInheritor until KT-51240 is fixed
We do not know for sure if there is any dependency between the two classes passed to `checkIsInheritor`. To avoid the problem described in KT-51240, we try to analyse them both and hope that the dependency in some direction exists. `NoCacheForModuleException` is introduced to signal about this particular problem and avoid catching just any `NoSuchElementException`. This hack is mainly done to fix very annoying KT-51240 for the time being. ^KTIJ-20852 Fixed
This commit is contained in:
+3
-1
@@ -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.api.impl.barebone.annotations.Immutable
|
||||||
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.project.structure.KtModule
|
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.FirModuleData
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.FirSessionProvider
|
import org.jetbrains.kotlin.fir.FirSessionProvider
|
||||||
@@ -26,7 +27,8 @@ class LLFirSessionProvider internal constructor(
|
|||||||
moduleToSession[module]
|
moduleToSession[module]
|
||||||
|
|
||||||
internal fun getModuleCache(module: KtModule): ModuleFileCache =
|
internal fun getModuleCache(module: KtModule): ModuleFileCache =
|
||||||
moduleToSession.getValue(module).cache
|
moduleToSession[module]?.cache
|
||||||
|
?: throw NoCacheForModuleException(module, moduleToSession.keys)
|
||||||
|
|
||||||
val allSessions: Collection<LLFirModuleSession>
|
val allSessions: Collection<LLFirModuleSession>
|
||||||
get() = moduleToSession.values
|
get() = moduleToSession.values
|
||||||
|
|||||||
+21
@@ -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<KtModule>
|
||||||
|
) : NoSuchElementException() {
|
||||||
|
override val message: String
|
||||||
|
get() = "No cache was found for module '${missingModule.moduleDescription}'! " +
|
||||||
|
"Caches exist for the following modules: ${existingModules.map { it.moduleDescription }}"
|
||||||
|
}
|
||||||
+28
-6
@@ -10,6 +10,7 @@ import com.intellij.psi.PsiModifier
|
|||||||
import com.intellij.psi.PsiReferenceList
|
import com.intellij.psi.PsiReferenceList
|
||||||
import com.intellij.psi.util.CachedValueProvider
|
import com.intellij.psi.util.CachedValueProvider
|
||||||
import com.intellij.psi.util.CachedValuesManager
|
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.providers.createProjectWideOutOfBlockModificationTracker
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithMembers
|
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.api.types.KtType
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
|
import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.getKtModuleOfTypeSafe
|
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.builder.LightMemberOriginForDeclaration
|
||||||
import org.jetbrains.kotlin.asJava.classes.*
|
import org.jetbrains.kotlin.asJava.classes.*
|
||||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||||
@@ -433,19 +435,39 @@ internal fun KtSymbolWithMembers.createInnerClasses(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun KtClassOrObject.checkIsInheritor(baseClassOrigin: KtClassOrObject, checkDeep: Boolean): Boolean {
|
internal fun KtClassOrObject.checkIsInheritor(superClassOrigin: KtClassOrObject, checkDeep: Boolean): Boolean {
|
||||||
return analyseForLightClasses(this) {
|
val subClassOrigin = this
|
||||||
val subClassSymbol = this@checkIsInheritor.getClassOrObjectSymbol()
|
|
||||||
val superClassSymbol = baseClassOrigin.getClassOrObjectSymbol()
|
|
||||||
|
|
||||||
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)
|
subClassSymbol.isSubClassOf(superClassSymbol)
|
||||||
} else {
|
} else {
|
||||||
subClassSymbol.isDirectSubClassOf(superClassSymbol)
|
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
|
private val KtSymbolWithTypeParameters.hasReifiedParameters: Boolean
|
||||||
|
|||||||
Reference in New Issue
Block a user