[IDE] Optimize stdlib cache for non-JVM modules

Consider only dependencies of JVM modules.
Cache found/missing stdlib dependencies for modules.

As of now, non-JVM platforms use default builtins in IDE.
For any non-JVM module indexed stdlib dependency is guaranteed
to be missing, searching for it is useless and costly.

^KTIJ-5666 Fixed
See also KT-44552
This commit is contained in:
Pavel Kirpichenkov
2021-03-25 19:56:55 +03:00
committed by TeamCityServer
parent 6c11751c55
commit 36bc71121a
3 changed files with 42 additions and 13 deletions
@@ -17,11 +17,14 @@ import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.vfilefinder.KotlinStdlibIndex
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.jvm.isJvm
import java.util.concurrent.ConcurrentHashMap
// TODO(kirpichenkov): works only for JVM (see KT-44552)
interface KotlinStdlibCache {
fun isStdlib(libraryInfo: LibraryInfo): Boolean
fun isStdlibDependency(libraryInfo: LibraryInfo): Boolean
fun findStdlibInModuleDependencies(module: IdeaModuleInfo): LibraryInfo?
companion object {
fun getInstance(project: Project): KotlinStdlibCache =
@@ -35,21 +38,30 @@ interface KotlinStdlibCache {
val Disabled = object : KotlinStdlibCache {
override fun isStdlib(libraryInfo: LibraryInfo) = false
override fun isStdlibDependency(libraryInfo: LibraryInfo) = false
override fun findStdlibInModuleDependencies(module: IdeaModuleInfo): LibraryInfo? = null
}
}
}
class KotlinStdlibCacheImpl(val project: Project) : KotlinStdlibCache {
private val stdlibCache
@JvmInline
private value class StdlibDependency(val libraryInfo: LibraryInfo?)
private val isStdlibCache: MutableMap<LibraryInfo, Boolean>
get() = project.cacheInvalidatingOnRootModifications {
ConcurrentHashMap<LibraryInfo, Boolean>()
}
private val stdlibDependencyCache
private val isStdlibDependencyCache: MutableMap<LibraryInfo, Boolean>
get() = project.cacheInvalidatingOnRootModifications {
ConcurrentHashMap<LibraryInfo, Boolean>()
}
private val moduleStdlibDependencyCache: MutableMap<IdeaModuleInfo, StdlibDependency>
get() = project.cacheInvalidatingOnRootModifications {
ConcurrentHashMap<IdeaModuleInfo, StdlibDependency>()
}
private class LibraryScope(
project: Project,
private val directories: Set<VirtualFile>
@@ -76,16 +88,26 @@ class KotlinStdlibCacheImpl(val project: Project) : KotlinStdlibCache {
libraryScopeContainsIndexedFilesForNames(libraryInfo, listOf(name))
override fun isStdlib(libraryInfo: LibraryInfo): Boolean {
return stdlibCache.getOrPut(libraryInfo) {
return isStdlibCache.getOrPut(libraryInfo) {
libraryScopeContainsIndexedFilesForName(libraryInfo, KotlinStdlibIndex.KOTLIN_STDLIB_NAME)
}
}
override fun isStdlibDependency(libraryInfo: LibraryInfo): Boolean {
return stdlibDependencyCache.getOrPut(libraryInfo) {
return isStdlibDependencyCache.getOrPut(libraryInfo) {
libraryScopeContainsIndexedFilesForNames(libraryInfo, KotlinStdlibIndex.STANDARD_LIBRARY_DEPENDENCY_NAMES)
}
}
override fun findStdlibInModuleDependencies(module: IdeaModuleInfo): LibraryInfo? {
val stdlibDependency = moduleStdlibDependencyCache.getOrPut(module) {
module.dependencies().lazyClosure { it.dependencies() }.firstOrNull {
it is LibraryInfo && isStdlib(it)
}.let { StdlibDependency(it as? LibraryInfo?) }
}
return stdlibDependency.libraryInfo
}
}
fun LibraryInfo.isCoreKotlinLibrary(project: Project): Boolean =
@@ -17,8 +17,6 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.KtLightElement
import org.jetbrains.kotlin.caches.project.cacheByClassInvalidatingOnRootModifications
import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications
import org.jetbrains.kotlin.idea.caches.lightClasses.KtLightClassForDecompiledDeclaration
import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
@@ -32,7 +30,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
import org.jetbrains.kotlin.scripting.definitions.runReadAction
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.kotlin.utils.yieldIfNotNull
@@ -50,6 +47,12 @@ fun ModuleInfo.findSdkAcrossDependencies(): SdkInfo? {
return SdkInfoCache.getInstance(project).findOrGetCachedSdk(this)
}
fun IdeaModuleInfo.findJvmStdlibAcrossDependencies(): LibraryInfo? {
val project = project ?: return null
return KotlinStdlibCache.getInstance(project).findStdlibInModuleDependencies(this)
}
fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFile): IdeaModuleInfo? =
collectInfosByVirtualFile(
project, virtualFile,
@@ -164,12 +164,16 @@ class IdeaResolverForProject(
}
private fun findStdlibForModulesBuiltins(module: IdeaModuleInfo): LibraryInfo? {
if (IdeBuiltInsLoadingState.isFromClassLoader)
return null
return module.dependencies().lazyClosure { it.dependencies() }.firstOrNull {
it is LibraryInfo && it.isKotlinStdlib(projectContextFromSdkResolver.project)
} as? LibraryInfo
return when (IdeBuiltInsLoadingState.state) {
IdeBuiltInsLoadingState.IdeBuiltInsLoading.FROM_CLASSLOADER -> null
IdeBuiltInsLoadingState.IdeBuiltInsLoading.FROM_DEPENDENCIES_JVM -> {
if (module.platform.isJvm()) {
module.findJvmStdlibAcrossDependencies()
} else {
null
}
}
}
}
}