Add IDE support for common klibs
This commit is contained in:
+95
-3
@@ -5,27 +5,40 @@
|
||||
|
||||
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.vfs.VirtualFile
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
|
||||
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
|
||||
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
|
||||
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.KotlinBuiltIns
|
||||
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.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.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class CommonPlatformKindResolution : IdePlatformKindResolution {
|
||||
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<*>?
|
||||
@@ -39,6 +52,20 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
|
||||
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(
|
||||
settings: PlatformAnalysisParameters,
|
||||
environment: TargetEnvironment,
|
||||
@@ -51,4 +78,69 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
|
||||
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 org.jetbrains.kotlin.analyzer.*
|
||||
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.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.container.*
|
||||
import org.jetbrains.kotlin.context.ModuleContext
|
||||
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.idea.project.IdeaEnvironment
|
||||
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.ModuleClassResolverImpl
|
||||
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.KonanPlatforms
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExperimentalMarkerDeclarationAnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
|
||||
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.js.KotlinJavascriptSerializationUtil
|
||||
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.utils.KotlinJavascriptMetadataUtils
|
||||
|
||||
@@ -108,7 +113,7 @@ class CompositeResolverForModuleFactory(
|
||||
val packageFragmentProviders = sequence {
|
||||
yield(container.get<ResolveSession>().packageFragmentProvider)
|
||||
|
||||
yieldAll(getCommonProvidersIfAny(container))
|
||||
yieldAll(getCommonProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container)) // todo: module context
|
||||
yieldAll(getJsProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container))
|
||||
yieldAll(getJvmProvidersIfAny(container))
|
||||
yieldAll(getKonanProvidersIfAny(moduleInfo, container))
|
||||
@@ -117,8 +122,45 @@ class CompositeResolverForModuleFactory(
|
||||
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
|
||||
}
|
||||
|
||||
private fun getCommonProvidersIfAny(container: StorageComponentContainer): List<PackageFragmentProvider> =
|
||||
if (targetPlatform.isCommon()) listOf(container.get<MetadataPackageFragmentProvider>()) else emptyList()
|
||||
private fun getCommonProvidersIfAny(
|
||||
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> =
|
||||
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.findAnalyzerServices
|
||||
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.util.isInSourceContentWithoutInjected
|
||||
import org.jetbrains.kotlin.idea.util.rootManager
|
||||
@@ -122,10 +123,14 @@ private fun ideaModelDependencies(
|
||||
platform: TargetPlatform
|
||||
): List<IdeaModuleInfo> {
|
||||
fun TargetPlatform.canDependOn(other: TargetPlatform): Boolean {
|
||||
return this.isJvm() && other.isJvm() ||
|
||||
this.isJs() && other.isJs() ||
|
||||
this.isNative() && other.isNative() ||
|
||||
this.isCommon() && other.isCommon()
|
||||
return if (module.isHMPPEnabled) {
|
||||
other.componentPlatforms.containsAll(this.componentPlatforms)
|
||||
} else {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user