Add IDE support for common klibs
This commit is contained in:
+95
-3
@@ -5,27 +5,40 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.caches.resolve
|
package org.jetbrains.kotlin.caches.resolve
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.OrderRootType
|
||||||
|
import com.intellij.openapi.roots.libraries.Library
|
||||||
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.util.PathUtil
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
|
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
|
||||||
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
|
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
|
||||||
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
|
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
|
||||||
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.metadataVersion
|
||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.context.ProjectContext
|
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.project.SdkInfo
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
|
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
|
||||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||||
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
|
import org.jetbrains.kotlin.library.*
|
||||||
|
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
|
||||||
|
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||||
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
|
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
|
||||||
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
|
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class CommonPlatformKindResolution : IdePlatformKindResolution {
|
class CommonPlatformKindResolution : IdePlatformKindResolution {
|
||||||
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
|
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
|
||||||
return virtualFile.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION
|
return virtualFile.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION || virtualFile.isMetadataKlib
|
||||||
}
|
}
|
||||||
|
|
||||||
override val libraryKind: PersistentLibraryKind<*>?
|
override val libraryKind: PersistentLibraryKind<*>?
|
||||||
@@ -39,6 +52,20 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
|
|||||||
return DefaultBuiltIns.Instance
|
return DefaultBuiltIns.Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> {
|
||||||
|
val klibFiles = library.getFiles(OrderRootType.CLASSES).filter { it.isMetadataKlib }
|
||||||
|
|
||||||
|
return if (klibFiles.isNotEmpty()) {
|
||||||
|
klibFiles.mapNotNull {
|
||||||
|
val path = PathUtil.getLocalPath(it) ?: return@mapNotNull null
|
||||||
|
CommonKlibLibraryInfo(project, library, path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No klib files <=> old metadata-library <=> create usual LibraryInfo
|
||||||
|
listOf(LibraryInfo(project, library))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun createResolverForModuleFactory(
|
override fun createResolverForModuleFactory(
|
||||||
settings: PlatformAnalysisParameters,
|
settings: PlatformAnalysisParameters,
|
||||||
environment: TargetEnvironment,
|
environment: TargetEnvironment,
|
||||||
@@ -51,4 +78,69 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
|
|||||||
shouldCheckExpectActual = true
|
shouldCheckExpectActual = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(dsavvinov): unify with NativeLibraryInfo
|
||||||
|
class CommonKlibLibraryInfo(project: Project, library: Library, val libraryRoot: String) : LibraryInfo(project, library) {
|
||||||
|
|
||||||
|
sealed class MetadataInfo {
|
||||||
|
abstract val isCompatible: Boolean
|
||||||
|
|
||||||
|
object Compatible : MetadataInfo() {
|
||||||
|
override val isCompatible get() = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class Incompatible(val isOlder: Boolean) : MetadataInfo() {
|
||||||
|
override val isCompatible get() = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonLibrary = createKotlinLibrary(File(libraryRoot))
|
||||||
|
|
||||||
|
val metadataInfo by lazy {
|
||||||
|
val metadataVersion = commonLibrary.safeMetadataVersion
|
||||||
|
when {
|
||||||
|
metadataVersion == null -> MetadataInfo.Incompatible(true) // too old KLIB format, even doesn't have metadata version
|
||||||
|
!metadataVersion.isCompatible() -> MetadataInfo.Incompatible(!metadataVersion.isAtLeast(KlibMetadataVersion.INSTANCE))
|
||||||
|
else -> MetadataInfo.Compatible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLibraryRoots() = listOf(libraryRoot)
|
||||||
|
|
||||||
|
override val platform: TargetPlatform
|
||||||
|
get() = CommonPlatforms.defaultCommonPlatform
|
||||||
|
|
||||||
|
override fun toString() = "Common" + super.toString()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
internal val KotlinLibrary.safeMetadataVersion get() = this.readSafe(null) { metadataVersion }
|
||||||
|
|
||||||
|
private fun <T> KotlinLibrary.readSafe(defaultValue: T, action: KotlinLibrary.() -> T) = try {
|
||||||
|
action()
|
||||||
|
} catch (_: IOException) {
|
||||||
|
defaultValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val VirtualFile.isMetadataKlib: Boolean
|
||||||
|
get() {
|
||||||
|
val extension = extension
|
||||||
|
if (!extension.isNullOrEmpty() && extension != KLIB_FILE_EXTENSION) return false
|
||||||
|
|
||||||
|
val manifestFile = findChild(KLIB_MANIFEST_FILE_NAME)?.takeIf { !it.isDirectory } ?: return false
|
||||||
|
|
||||||
|
// native libraries
|
||||||
|
val irFile = findChild(KLIB_IR_FOLDER_NAME)
|
||||||
|
if (irFile != null && irFile.children.isNotEmpty()) return false
|
||||||
|
|
||||||
|
val manifestProperties = try {
|
||||||
|
manifestFile.inputStream.use { Properties().apply { load(it) } }
|
||||||
|
} catch (_: IOException) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return manifestProperties.containsKey(KLIB_PROPERTY_UNIQUE_NAME)
|
||||||
|
}
|
||||||
+47
-5
@@ -10,9 +10,10 @@ package org.jetbrains.kotlin.caches.resolve
|
|||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.analyzer.*
|
import org.jetbrains.kotlin.analyzer.*
|
||||||
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
|
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
|
||||||
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
|
|
||||||
import org.jetbrains.kotlin.analyzer.common.configureCommonSpecificComponents
|
import org.jetbrains.kotlin.analyzer.common.configureCommonSpecificComponents
|
||||||
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.container.*
|
import org.jetbrains.kotlin.container.*
|
||||||
import org.jetbrains.kotlin.context.ModuleContext
|
import org.jetbrains.kotlin.context.ModuleContext
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
@@ -25,6 +26,8 @@ import org.jetbrains.kotlin.frontend.java.di.configureJavaSpecificComponents
|
|||||||
import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents
|
import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents
|
||||||
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
|
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
|
||||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||||
|
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||||
|
import org.jetbrains.kotlin.library.metadata.parseModuleHeader
|
||||||
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
|
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
|
||||||
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolverImpl
|
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolverImpl
|
||||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||||
@@ -39,7 +42,6 @@ import org.jetbrains.kotlin.platform.jvm.JvmPlatform
|
|||||||
import org.jetbrains.kotlin.platform.konan.KonanPlatform
|
import org.jetbrains.kotlin.platform.konan.KonanPlatform
|
||||||
import org.jetbrains.kotlin.platform.konan.KonanPlatforms
|
import org.jetbrains.kotlin.platform.konan.KonanPlatforms
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
|
||||||
import org.jetbrains.kotlin.resolve.checkers.ExperimentalMarkerDeclarationAnnotationChecker
|
import org.jetbrains.kotlin.resolve.checkers.ExperimentalMarkerDeclarationAnnotationChecker
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
|
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
|
||||||
@@ -50,6 +52,9 @@ import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmen
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
|
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
|
||||||
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
|
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
|
||||||
import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider
|
import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider
|
||||||
|
import org.jetbrains.kotlin.serialization.konan.NullFlexibleTypeDeserializer
|
||||||
|
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
|
||||||
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
|
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
|
||||||
|
|
||||||
@@ -108,7 +113,7 @@ class CompositeResolverForModuleFactory(
|
|||||||
val packageFragmentProviders = sequence {
|
val packageFragmentProviders = sequence {
|
||||||
yield(container.get<ResolveSession>().packageFragmentProvider)
|
yield(container.get<ResolveSession>().packageFragmentProvider)
|
||||||
|
|
||||||
yieldAll(getCommonProvidersIfAny(container))
|
yieldAll(getCommonProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container)) // todo: module context
|
||||||
yieldAll(getJsProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container))
|
yieldAll(getJsProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container))
|
||||||
yieldAll(getJvmProvidersIfAny(container))
|
yieldAll(getJvmProvidersIfAny(container))
|
||||||
yieldAll(getKonanProvidersIfAny(moduleInfo, container))
|
yieldAll(getKonanProvidersIfAny(moduleInfo, container))
|
||||||
@@ -117,8 +122,45 @@ class CompositeResolverForModuleFactory(
|
|||||||
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
|
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCommonProvidersIfAny(container: StorageComponentContainer): List<PackageFragmentProvider> =
|
private fun getCommonProvidersIfAny(
|
||||||
if (targetPlatform.isCommon()) listOf(container.get<MetadataPackageFragmentProvider>()) else emptyList()
|
moduleInfo: ModuleInfo,
|
||||||
|
moduleContext: ModuleContext,
|
||||||
|
moduleDescriptor: ModuleDescriptor,
|
||||||
|
container: StorageComponentContainer
|
||||||
|
): List<PackageFragmentProvider> {
|
||||||
|
if (!targetPlatform.isCommon()) return emptyList()
|
||||||
|
val metadataProvder = container.get<MetadataPackageFragmentProvider>()
|
||||||
|
var klibMetadataProvider: PackageFragmentProvider? = null
|
||||||
|
|
||||||
|
if (moduleInfo is CommonKlibLibraryInfo && moduleInfo.metadataInfo == CommonKlibLibraryInfo.MetadataInfo.Compatible) {
|
||||||
|
val library = moduleInfo.commonLibrary
|
||||||
|
val languageVersionSettings = container.get<LanguageVersionSettings>()
|
||||||
|
|
||||||
|
val packageFragmentNames = parseModuleHeader(library.moduleHeaderData).packageFragmentNameList
|
||||||
|
|
||||||
|
val MetadataFactories = KlibMetadataFactories(
|
||||||
|
{ DefaultBuiltIns.Instance },
|
||||||
|
NullFlexibleTypeDeserializer
|
||||||
|
)
|
||||||
|
|
||||||
|
val klibMetadataModuleDescriptorFactory = KlibMetadataModuleDescriptorFactoryImpl(
|
||||||
|
MetadataFactories.DefaultDescriptorFactory,
|
||||||
|
MetadataFactories.DefaultPackageFragmentsFactory,
|
||||||
|
MetadataFactories.flexibleTypeDeserializer
|
||||||
|
)
|
||||||
|
|
||||||
|
klibMetadataProvider = klibMetadataModuleDescriptorFactory.createPackageFragmentProvider(
|
||||||
|
library,
|
||||||
|
packageAccessHandler = null,
|
||||||
|
packageFragmentNames = packageFragmentNames,
|
||||||
|
storageManager = moduleContext.storageManager,
|
||||||
|
moduleDescriptor = moduleDescriptor,
|
||||||
|
configuration = CompilerDeserializationConfiguration(languageVersionSettings),
|
||||||
|
compositePackageFragmentAddend = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return listOfNotNull(metadataProvder, klibMetadataProvider)
|
||||||
|
}
|
||||||
|
|
||||||
private fun getJvmProvidersIfAny(container: StorageComponentContainer): List<PackageFragmentProvider> =
|
private fun getJvmProvidersIfAny(container: StorageComponentContainer): List<PackageFragmentProvider> =
|
||||||
if (targetPlatform.has<JvmPlatform>()) listOf(container.get<JavaDescriptorResolver>().packageFragmentProvider) else emptyList()
|
if (targetPlatform.has<JvmPlatform>()) listOf(container.get<JavaDescriptorResolver>().packageFragmentProvider) else emptyList()
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.idea.framework.getLibraryPlatform
|
|||||||
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
|
||||||
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
|
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
|
||||||
import org.jetbrains.kotlin.idea.project.getStableName
|
import org.jetbrains.kotlin.idea.project.getStableName
|
||||||
|
import org.jetbrains.kotlin.idea.project.isHMPPEnabled
|
||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
||||||
import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected
|
import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected
|
||||||
import org.jetbrains.kotlin.idea.util.rootManager
|
import org.jetbrains.kotlin.idea.util.rootManager
|
||||||
@@ -122,10 +123,14 @@ private fun ideaModelDependencies(
|
|||||||
platform: TargetPlatform
|
platform: TargetPlatform
|
||||||
): List<IdeaModuleInfo> {
|
): List<IdeaModuleInfo> {
|
||||||
fun TargetPlatform.canDependOn(other: TargetPlatform): Boolean {
|
fun TargetPlatform.canDependOn(other: TargetPlatform): Boolean {
|
||||||
return this.isJvm() && other.isJvm() ||
|
return if (module.isHMPPEnabled) {
|
||||||
this.isJs() && other.isJs() ||
|
other.componentPlatforms.containsAll(this.componentPlatforms)
|
||||||
this.isNative() && other.isNative() ||
|
} else {
|
||||||
this.isCommon() && other.isCommon()
|
this.isJvm() && other.isJvm() ||
|
||||||
|
this.isJs() && other.isJs() ||
|
||||||
|
this.isNative() && other.isNative() ||
|
||||||
|
this.isCommon() && other.isCommon()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOTE: lib dependencies can be processed several times during recursive traversal
|
//NOTE: lib dependencies can be processed several times during recursive traversal
|
||||||
|
|||||||
Reference in New Issue
Block a user