HMPP. Rewrite LibraryDependenciesCache on using LibraryInfo/SdkInfo

... instead of pure IJ Library/SDK.
This commit is contained in:
Dmitriy Dolovov
2020-04-09 14:32:55 +07:00
parent 6d0e73191c
commit b67a48f220
11 changed files with 87 additions and 62 deletions
@@ -69,7 +69,7 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
}
} else {
// No klib files <=> old metadata-library <=> create usual LibraryInfo
listOf(LibraryInfo(project, library))
listOf(CommonMetadataLibraryInfo(project, library))
}
}
@@ -115,9 +115,16 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
}
}
class CommonKlibLibraryInfo(project: Project, library: Library, libraryRoot: String) :
AbstractKlibLibraryInfo(project, library, libraryRoot) {
class CommonKlibLibraryInfo(
project: Project,
library: Library,
libraryRoot: String
) : AbstractKlibLibraryInfo(project, library, libraryRoot) {
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
}
class CommonMetadataLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
}
@@ -60,7 +60,7 @@ interface IdePlatformKindResolution {
val libraryKind: PersistentLibraryKind<*>?
fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> = listOf(LibraryInfo(project, library))
fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo>
companion object : ApplicationExtensionDescriptor<IdePlatformKindResolution>(
"org.jetbrains.kotlin.idePlatformKindResolution", IdePlatformKindResolution::class.java
@@ -75,7 +75,7 @@ class JsPlatformKindResolution : IdePlatformKindResolution {
JsKlibLibraryInfo(project, library, path)
}
} else {
super.createLibraryInfo(project, library)
listOf(JsMetadataLibraryInfo(project, library))
}
}
@@ -112,3 +112,8 @@ class JsKlibLibraryInfo(project: Project, library: Library, libraryRoot: String)
override val platform: TargetPlatform
get() = JsPlatforms.defaultJsPlatform
}
class JsMetadataLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = JsPlatforms.defaultJsPlatform
}
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
@@ -15,10 +17,12 @@ import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory
@@ -39,6 +43,9 @@ class JvmPlatformKindResolution : IdePlatformKindResolution {
override val libraryKind: PersistentLibraryKind<*>?
get() = null
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> =
listOf(JvmLibraryInfo(project, library))
override val kind get() = JvmIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey {
@@ -54,3 +61,8 @@ class JvmPlatformKindResolution : IdePlatformKindResolution {
data class CacheKeyBySdk(val sdk: Sdk) : BuiltInsCacheKey
}
class JvmLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = JvmPlatforms.defaultJvmPlatform
}
@@ -38,7 +38,8 @@ import org.jetbrains.kotlin.idea.caches.trackers.KotlinModuleOutOfCodeBlockModif
import org.jetbrains.kotlin.idea.configuration.BuildSystemType
import org.jetbrains.kotlin.idea.configuration.getBuildSystemType
import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware
import org.jetbrains.kotlin.idea.framework.getLibraryPlatform
import org.jetbrains.kotlin.idea.framework.effectiveKind
import org.jetbrains.kotlin.idea.framework.platform
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
import org.jetbrains.kotlin.idea.project.getStableName
@@ -109,16 +110,20 @@ private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, for
}
}
val Project.libraryInfoCache: MutableMap<Library, List<LibraryInfo>>
private val Project.libraryInfoCache: MutableMap<Library, List<LibraryInfo>>
get() = cacheInvalidatingOnRootModifications { ContainerUtil.createConcurrentWeakMap() }
fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> {
val cache = project.libraryInfoCache
fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> =
project.libraryInfoCache.getOrPut(library) {
val approximatePlatform = if (library is LibraryEx && !library.isDisposed) {
// for Native returns 'unspecifiedNativePlatform', thus "approximate"
library.effectiveKind(project).platform
} else {
DefaultIdeTargetPlatformKindProvider.defaultPlatform
}
return cache.getOrPut(library) {
getLibraryPlatform(project, library).idePlatformKind.resolution.createLibraryInfo(project, library)
approximatePlatform.idePlatformKind.resolution.createLibraryInfo(project, library)
}
}
private fun OrderEntry.acceptAsDependency(forProduction: Boolean): Boolean {
return this !is ExportableOrderEntry
@@ -300,7 +305,7 @@ private class ModuleTestSourceScope(module: Module) : ModuleSourceScope(module)
override fun toString() = "ModuleTestSourceScope($module)"
}
open class LibraryInfo(override val project: Project, val library: Library) : IdeaModuleInfo, LibraryModuleInfo, BinaryModuleInfo {
abstract class LibraryInfo(override val project: Project, val library: Library) : IdeaModuleInfo, LibraryModuleInfo, BinaryModuleInfo {
override val moduleOrigin: ModuleOrigin
get() = ModuleOrigin.LIBRARY
@@ -315,18 +320,15 @@ open class LibraryInfo(override val project: Project, val library: Library) : Id
val result = LinkedHashSet<IdeaModuleInfo>()
result.add(this)
val (libraries, sdks) = LibraryDependenciesCache.getInstance(project).getLibrariesAndSdksUsedWith(library)
val (libraries, sdks) = LibraryDependenciesCache.getInstance(project).getLibrariesAndSdksUsedWith(this)
sdks.mapTo(result) { SdkInfo(project, it) }
libraries.filter { it is LibraryEx && !it.isDisposed }.flatMapTo(result) {
createLibraryInfo(project, it)
}
result.addAll(sdks)
result.addAll(libraries)
return result.toList()
}
override val platform: TargetPlatform
get() = getLibraryPlatform(project, library)
abstract override val platform: TargetPlatform // must override
override val analyzerServices: PlatformDependentAnalyzerServices
get() = platform.findAnalyzerServices(project)
@@ -337,7 +339,7 @@ open class LibraryInfo(override val project: Project, val library: Library) : Id
override fun getLibraryRoots(): Collection<String> =
library.getFiles(OrderRootType.CLASSES).mapNotNull(PathUtil::getLocalPath)
override fun toString() = "LibraryInfo(libraryName=${library.name})"
override fun toString() = "${this::class.simpleName}(libraryName=${library.name}, libraryRoots=${getLibraryRoots()})"
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -345,7 +347,6 @@ open class LibraryInfo(override val project: Project, val library: Library) : Id
}
override fun hashCode(): Int = 43 * library.hashCode()
}
data class LibrarySourceInfo(override val project: Project, val library: Library, override val binariesModuleInfo: BinaryModuleInfo) :
@@ -9,8 +9,8 @@ import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.*
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.util.Condition
import com.intellij.psi.util.CachedValueProvider
@@ -19,36 +19,34 @@ import com.intellij.util.containers.ContainerUtil
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.idea.core.util.CachedValue
import org.jetbrains.kotlin.idea.core.util.getValue
import org.jetbrains.kotlin.idea.framework.getLibraryPlatform
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
internal typealias LibrariesAndSdks = Pair<List<Library>, List<Sdk>>
internal typealias LibrariesAndSdks = Pair<List<LibraryInfo>, List<SdkInfo>>
interface LibraryDependenciesCache {
companion object {
fun getInstance(project: Project) = ServiceManager.getService(project, LibraryDependenciesCache::class.java)!!
}
fun getLibrariesAndSdksUsedWith(library: Library): LibrariesAndSdks
fun getLibrariesAndSdksUsedWith(libraryInfo: LibraryInfo): LibrariesAndSdks
}
class LibraryDependenciesCacheImpl(private val project: Project) : LibraryDependenciesCache {
val cache by CachedValue(project) {
private val cache by CachedValue(project) {
CachedValueProvider.Result(
ContainerUtil.createConcurrentWeakMap<Library, LibrariesAndSdks>(),
ContainerUtil.createConcurrentWeakMap<LibraryInfo, LibrariesAndSdks>(),
ProjectRootManager.getInstance(project)
)
}
override fun getLibrariesAndSdksUsedWith(library: Library): LibrariesAndSdks =
cache.getOrPut(library) { computeLibrariesAndSdksUsedWith(library) }
override fun getLibrariesAndSdksUsedWith(libraryInfo: LibraryInfo): LibrariesAndSdks =
cache.getOrPut(libraryInfo) { computeLibrariesAndSdksUsedWith(libraryInfo) }
//NOTE: used LibraryRuntimeClasspathScope as reference
private fun computeLibrariesAndSdksUsedWith(library: Library): LibrariesAndSdks {
private fun computeLibrariesAndSdksUsedWith(libraryInfo: LibraryInfo): LibrariesAndSdks {
val processedModules = HashSet<Module>()
val condition = Condition<OrderEntry> { orderEntry ->
if (orderEntry is ModuleOrderEntry) {
@@ -59,12 +57,12 @@ class LibraryDependenciesCacheImpl(private val project: Project) : LibraryDepend
}
}
val libraries = LinkedHashSet<Library>()
val sdks = LinkedHashSet<Sdk>()
val libraries = LinkedHashSet<LibraryInfo>()
val sdks = LinkedHashSet<SdkInfo>()
val platform = getLibraryPlatform(project, library)
val platform = libraryInfo.platform
for (module in getLibraryUsageIndex().modulesLibraryIsUsedIn[library]) {
for (module in getLibraryUsageIndex().modulesLibraryIsUsedIn[libraryInfo.library]) {
if (!processedModules.add(module)) continue
ModuleRootManager.getInstance(module).orderEntries().recursively().satisfying(condition).process(object : RootPolicy<Unit>() {
@@ -74,13 +72,19 @@ class LibraryDependenciesCacheImpl(private val project: Project) : LibraryDepend
override fun visitLibraryOrderEntry(libraryOrderEntry: LibraryOrderEntry, value: Unit) {
val otherLibrary = libraryOrderEntry.library
if (otherLibrary != null && compatiblePlatforms(platform, getLibraryPlatform(project, otherLibrary))) {
libraries.add(otherLibrary)
if (otherLibrary is LibraryEx && !otherLibrary.isDisposed) {
val otherLibraryInfos = createLibraryInfo(project, otherLibrary)
otherLibraryInfos.firstOrNull()?.platform?.let { otherLibraryPlatform ->
if (compatiblePlatforms(platform, otherLibraryPlatform)) {
libraries.addAll(otherLibraryInfos)
}
}
}
}
override fun visitJdkOrderEntry(jdkOrderEntry: JdkOrderEntry, value: Unit) {
sdks.addIfNotNull(jdkOrderEntry.jdk)
val jdk = jdkOrderEntry.jdk ?: return
sdks += SdkInfo(project, jdk)
}
}, Unit)
}
@@ -16,9 +16,7 @@
package org.jetbrains.kotlin.idea.framework
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.libraries.DummyLibraryProperties
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
@@ -61,13 +59,6 @@ val PersistentLibraryKind<*>?.platform: TargetPlatform
else -> DefaultIdeTargetPlatformKindProvider.defaultPlatform
}
fun getLibraryPlatform(project: Project, library: Library): TargetPlatform {
if (library !is LibraryEx) return DefaultIdeTargetPlatformKindProvider.defaultPlatform
if (library.isDisposed) return DefaultIdeTargetPlatformKindProvider.defaultPlatform
return library.effectiveKind(project).platform
}
fun detectLibraryKind(roots: Array<VirtualFile>): PersistentLibraryKind<*>? {
val jarFile = roots.firstOrNull() ?: return null
if (jarFile.fileSystem is JarFileSystem) {
@@ -27,8 +27,6 @@ abstract class AbstractKlibLibraryInfo(project: Project, library: Library, val l
final override fun getLibraryRoots() = listOf(libraryRoot)
final override fun toString() = "${this::class.simpleName}(libraryName=${library.name}, libraryRoot=$libraryRoot)"
abstract override val platform: TargetPlatform // must override
companion object {
@@ -11,7 +11,7 @@ import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
@@ -25,9 +25,11 @@ import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleTestSourceInfo
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
import org.jetbrains.kotlin.idea.framework.platform
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.util.addDependency
@@ -437,8 +439,11 @@ class IdeaModuleInfoTest : ModuleTestCase() {
private val Module.test: ModuleTestSourceInfo
get() = testSourceInfo()!!
private val Library.classes: LibraryInfo
get() = LibraryInfo(project!!, this)
private val LibraryEx.classes: LibraryInfo
get() = object : LibraryInfo(project!!, this) {
override val platform: TargetPlatform
get() = kind.platform
}
private fun module(name: String, hasProductionRoot: Boolean = true, hasTestRoot: Boolean = true): Module {
return createModuleFromTestData(createTempDirectory().absolutePath, name, StdModuleTypes.JAVA, false).apply {
@@ -467,15 +472,15 @@ class IdeaModuleInfoTest : ModuleTestCase() {
UsefulTestCase.assertSameElements(this.getDependentModules(), expected.toList())
}
private fun stdlibCommon(): Library = projectLibrary(
private fun stdlibCommon(): LibraryEx = projectLibrary(
"kotlin-stdlib-common",
ForTestCompileRuntime.stdlibCommonForTests().jarRoot,
kind = CommonLibraryKind
)
private fun stdlibJvm(): Library = projectLibrary("kotlin-stdlib", ForTestCompileRuntime.runtimeJarForTests().jarRoot)
private fun stdlibJvm(): LibraryEx = projectLibrary("kotlin-stdlib", ForTestCompileRuntime.runtimeJarForTests().jarRoot)
private fun stdlibJs(): Library = projectLibrary(
private fun stdlibJs(): LibraryEx = projectLibrary(
"kotlin-stdlib-js",
ForTestCompileRuntime.runtimeJarForTests().jarRoot,
kind = JSLibraryKind
@@ -9,6 +9,7 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
@@ -24,15 +25,15 @@ fun HeavyPlatformTestCase.projectLibrary(
classesRoot: VirtualFile? = null,
sourcesRoot: VirtualFile? = null,
kind: PersistentLibraryKind<*>? = null
): Library {
): LibraryEx {
return runWriteAction {
val modifiableModel = ProjectLibraryTable.getInstance(project).modifiableModel
val library = try {
modifiableModel.createLibrary(libraryName, kind)
modifiableModel.createLibrary(libraryName, kind) as LibraryEx
} finally {
modifiableModel.commit()
}
with (library.modifiableModel) {
with(library.modifiableModel) {
classesRoot?.let { addRoot(it, OrderRootType.CLASSES) }
sourcesRoot?.let { addRoot(it, OrderRootType.SOURCES) }
commit()
@@ -9,6 +9,7 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.impl.libraries.LibraryEx
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
@@ -24,11 +25,11 @@ fun PlatformTestCase.projectLibrary(
classesRoot: VirtualFile? = null,
sourcesRoot: VirtualFile? = null,
kind: PersistentLibraryKind<*>? = null
): Library {
): LibraryEx {
return runWriteAction {
val modifiableModel = ProjectLibraryTable.getInstance(project).modifiableModel
val library = try {
modifiableModel.createLibrary(libraryName, kind)
modifiableModel.createLibrary(libraryName, kind) as LibraryEx
} finally {
modifiableModel.commit()
}