diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt index 21d9e76a569..4758ae4a7f0 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/frontend/java/di/injection.kt @@ -125,8 +125,12 @@ fun StorageComponentContainer.configureJavaSpecificComponents( useInstance(languageVersionSettings.getFlag(JvmAnalysisFlags.javaTypeEnhancementState)) - if (useBuiltInsProvider) { - useInstance((moduleContext.module.builtIns as JvmBuiltIns).customizer) + val builtIns = moduleContext.module.builtIns + if (useBuiltInsProvider && builtIns is JvmBuiltIns) { + // TODO(dsavvinov): make sure that useBuiltInsProvider == true <=> builtIns is JvmBuiltIns + // Currently, that's not the case at least in IDE unit-tests, because they do not set-up + // dependency on SDK properly, see KT-43828 + useInstance(builtIns.customizer) useImpl() } useImpl() diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmResolverForModuleFactory.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmResolverForModuleFactory.kt index 531b53b7e27..70c045d6660 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmResolverForModuleFactory.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/JvmResolverForModuleFactory.kt @@ -17,8 +17,10 @@ package org.jetbrains.kotlin.resolve.jvm import org.jetbrains.kotlin.analyzer.* +import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsPackageFragmentProvider import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.container.get +import org.jetbrains.kotlin.container.tryGetService import org.jetbrains.kotlin.context.ModuleContext import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl @@ -36,12 +38,14 @@ import org.jetbrains.kotlin.resolve.TargetEnvironment import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension import org.jetbrains.kotlin.resolve.lazy.ResolveSession import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService +import org.jetbrains.kotlin.utils.addIfNotNull class JvmPlatformParameters( val packagePartProviderFactory: (ModuleContent<*>) -> PackagePartProvider, val moduleByJavaClass: (JavaClass) -> ModuleInfo?, // params: referenced module info of target class, context module info of current resolver val resolverForReferencedModule: ((ModuleInfo, ModuleInfo) -> ResolverForModule?)? = null, + val useBuiltinsProviderForModule: (ModuleInfo) -> Boolean ) : PlatformAnalysisParameters @@ -111,17 +115,16 @@ class JvmResolverForModuleFactory( packagePartProvider, languageVersionSettings, sealedInheritorsProvider = sealedInheritorsProvider, - useBuiltInsProvider = false // TODO: load built-ins from module dependencies in IDE + useBuiltInsProvider = platformParameters.useBuiltinsProviderForModule(moduleInfo) ) - val resolveSession = container.get() - val javaDescriptorResolver = container.get() - val providersForModule = arrayListOf( - resolveSession.packageFragmentProvider, - javaDescriptorResolver.packageFragmentProvider + container.get().packageFragmentProvider, + container.get().packageFragmentProvider, ) + providersForModule.addIfNotNull(container.tryGetService(JvmBuiltInsPackageFragmentProvider::class.java)) + providersForModule += PackageFragmentProviderExtension.getInstances(project) .mapNotNull { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ModuleInfoUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ModuleInfoUtils.kt index c5031a94500..bd316e16640 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ModuleInfoUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/analyzer/ModuleInfoUtils.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analyzer +import org.jetbrains.kotlin.descriptors.ModuleCapability import org.jetbrains.kotlin.descriptors.ModuleDescriptor val ModuleDescriptor.moduleInfo: ModuleInfo? @@ -23,3 +24,8 @@ internal fun collectAllExpectedByModules(entryModule: ModuleInfo): Set("IsJdk") + +val ModuleDescriptor.hasJdkCapability: Boolean + get() = getCapability(JDK_CAPABILITY) == true diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index 903e79cfd1e..9377e498c7b 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.backend.jvm +import org.jetbrains.kotlin.analyzer.hasJdkCapability import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrPluginContextImpl @@ -115,6 +116,13 @@ class JvmIrCodegenFactory(private val phaseConfig: PhaseConfig) : CodegenFactory val dependencies = psi2irContext.moduleDescriptor.allDependencyModules.map { val kotlinLibrary = (it.getCapability(KlibModuleOrigin.CAPABILITY) as? DeserializedKlibModuleOrigin)?.library + if (it.hasJdkCapability) { + // For IDE environment only, i.e. when compiling for debugger + // Deserializer for built-ins module should exist because built-in types returned from SDK belong to that module, + // but JDK's built-ins module might not be in current module's dependencies + // We have to ensure that deserializer for built-ins module is created + irLinker.deserializeIrModuleHeader(it.builtIns.builtInsModule, null) + } irLinker.deserializeIrModuleHeader(it, kotlinLibrary) } val irProviders = listOf(irLinker) diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/lazy/lazyResolveTestUtils.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/lazy/lazyResolveTestUtils.kt index e7d7e747a99..2ab9791add6 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/lazy/lazyResolveTestUtils.kt +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/resolve/lazy/lazyResolveTestUtils.kt @@ -20,7 +20,6 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.ModificationTracker import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analyzer.* -import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.load.kotlin.PackagePartProvider @@ -44,7 +43,8 @@ fun createResolveSessionForFiles( TestModule(project, addBuiltIns) val platformParameters = JvmPlatformParameters( packagePartProviderFactory = { PackagePartProvider.Empty }, - moduleByJavaClass = { testModule } + moduleByJavaClass = { testModule }, + useBuiltinsProviderForModule = { false } ) val resolverForProject = ResolverForSingleModuleProject( diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt index 1e449e6e4bc..9d5e6eb84f7 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/MultiModuleJavaAnalysisCustomTest.kt @@ -88,7 +88,8 @@ class MultiModuleJavaAnalysisCustomTest : KtUsefulTestCase() { moduleByJavaClass = { javaClass -> val moduleName = javaClass.name.asString().toLowerCase().first().toString() modules.first { it._name == moduleName } - } + }, + useBuiltinsProviderForModule = { false } ) val resolverForProject = object : AbstractResolverForProject( diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt index 67306bf3b4f..66c388b4f40 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltIns.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.getValue import org.jetbrains.kotlin.utils.sure -class JvmBuiltIns(storageManager: StorageManager, kind: Kind) : KotlinBuiltIns(storageManager) { +class JvmBuiltIns(storageManager: StorageManager, val kind: Kind) : KotlinBuiltIns(storageManager) { /** * Where built-ins should be loaded from. */ diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltInsPackageFragmentProvider.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltInsPackageFragmentProvider.kt index cc59de310c2..93c56cd61d4 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltInsPackageFragmentProvider.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/builtins/jvm/JvmBuiltInsPackageFragmentProvider.kt @@ -60,4 +60,8 @@ class JvmBuiltInsPackageFragmentProvider( finder.findBuiltInsData(fqName)?.let { inputStream -> BuiltInsPackageFragmentImpl.create(fqName, storageManager, moduleDescriptor, inputStream, isFallback = false) } + + companion object { + const val DOT_BUILTINS_METADATA_FILE_EXTENSION = ".kotlin_builtins" + } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java index 8c65ca36014..03b0b070a70 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/KotlinBuiltIns.java @@ -39,6 +39,7 @@ import static org.jetbrains.kotlin.resolve.DescriptorUtils.getFqName; public abstract class KotlinBuiltIns { private ModuleDescriptorImpl builtInsModule; + private NotNullLazyValue postponedBuiltInsModule; private final NotNullLazyValue primitives; private final NotNullLazyValue> builtInPackagesImportedByDefault; @@ -56,10 +57,10 @@ public abstract class KotlinBuiltIns { @Override public Collection invoke() { return Arrays.asList( - builtInsModule.getPackage(BUILT_INS_PACKAGE_FQ_NAME), - builtInsModule.getPackage(COLLECTIONS_PACKAGE_FQ_NAME), - builtInsModule.getPackage(RANGES_PACKAGE_FQ_NAME), - builtInsModule.getPackage(ANNOTATION_PACKAGE_FQ_NAME) + getBuiltInsModule().getPackage(BUILT_INS_PACKAGE_FQ_NAME), + getBuiltInsModule().getPackage(COLLECTIONS_PACKAGE_FQ_NAME), + getBuiltInsModule().getPackage(RANGES_PACKAGE_FQ_NAME), + getBuiltInsModule().getPackage(ANNOTATION_PACKAGE_FQ_NAME) ); } }); @@ -123,6 +124,10 @@ public abstract class KotlinBuiltIns { }); } + public void setPostponedBuiltinsModuleComputation(@NotNull Function0 computation) { + postponedBuiltInsModule = storageManager.createLazyValue(computation); + } + @NotNull protected AdditionalClassPartsProvider getAdditionalClassPartsProvider() { return AdditionalClassPartsProvider.None.INSTANCE; @@ -135,7 +140,8 @@ public abstract class KotlinBuiltIns { @NotNull protected Iterable getClassDescriptorFactories() { - return Collections.singletonList(new BuiltInFictitiousFunctionClassFactory(storageManager, builtInsModule)); + return Collections.singletonList( + new BuiltInFictitiousFunctionClassFactory(storageManager, getBuiltInsModule())); } @NotNull @@ -161,6 +167,10 @@ public abstract class KotlinBuiltIns { @NotNull public ModuleDescriptorImpl getBuiltInsModule() { + assert builtInsModule != null || postponedBuiltInsModule != null : "Uninitialized built-ins module"; + if (builtInsModule == null) { + builtInsModule = postponedBuiltInsModule.invoke(); + } return builtInsModule; } @@ -198,12 +208,12 @@ public abstract class KotlinBuiltIns { @NotNull public MemberScope getBuiltInsPackageScope() { - return builtInsModule.getPackage(BUILT_INS_PACKAGE_FQ_NAME).getMemberScope(); + return getBuiltInsModule().getPackage(BUILT_INS_PACKAGE_FQ_NAME).getMemberScope(); } @NotNull public ClassDescriptor getBuiltInClassByFqName(@NotNull FqName fqName) { - ClassDescriptor descriptor = DescriptorUtilKt.resolveClassByFqName(builtInsModule, fqName, NoLookupLocation.FROM_BUILTINS); + ClassDescriptor descriptor = DescriptorUtilKt.resolveClassByFqName(getBuiltInsModule(), fqName, NoLookupLocation.FROM_BUILTINS); assert descriptor != null : "Can't find built-in class " + fqName; return descriptor; } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CommonPlatformKindResolution.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CommonPlatformKindResolution.kt index 1e193ce59b4..c5e41764aa8 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CommonPlatformKindResolution.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CommonPlatformKindResolution.kt @@ -53,13 +53,15 @@ class CommonPlatformKindResolution : IdePlatformKindResolution { override val kind get() = CommonIdePlatformKind - override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey = BuiltInsCacheKey.DefaultBuiltInsKey + override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey = + BuiltInsCacheKey.DefaultBuiltInsKey override fun createBuiltIns( moduleInfo: IdeaModuleInfo, projectContext: ProjectContext, resolverForProject: ResolverForProject, - sdkDependency: SdkInfo? + sdkDependency: SdkInfo?, + stdlibDependency: LibraryInfo?, ): KotlinBuiltIns { return DefaultBuiltIns.Instance } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CompositeResolverForModuleFactory.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CompositeResolverForModuleFactory.kt index 18104ec0db3..d6d9fdf7947 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CompositeResolverForModuleFactory.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/CompositeResolverForModuleFactory.kt @@ -8,9 +8,11 @@ package org.jetbrains.kotlin.caches.resolve import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.containers.addIfNotNull import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters import org.jetbrains.kotlin.analyzer.common.configureCommonSpecificComponents +import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsPackageFragmentProvider import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.container.* import org.jetbrains.kotlin.context.ModuleContext @@ -22,6 +24,7 @@ import org.jetbrains.kotlin.frontend.di.configureModule import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents import org.jetbrains.kotlin.frontend.java.di.configureJavaSpecificComponents import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents +import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState import org.jetbrains.kotlin.idea.project.IdeaEnvironment import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolverImpl @@ -32,6 +35,7 @@ import org.jetbrains.kotlin.platform.* import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.js.isJs import org.jetbrains.kotlin.platform.jvm.JvmPlatform +import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.konan.NativePlatform import org.jetbrains.kotlin.platform.konan.NativePlatforms import org.jetbrains.kotlin.resolve.* @@ -130,8 +134,14 @@ class CompositeResolverForModuleFactory( return listOfNotNull(metadataProvider, klibMetadataProvider) } + @OptIn(ExperimentalStdlibApi::class) private fun getJvmProvidersIfAny(container: StorageComponentContainer): List = - if (targetPlatform.has()) listOf(container.get().packageFragmentProvider) else emptyList() + buildList { + if (targetPlatform.has()) add(container.get().packageFragmentProvider) + + // Use JVM built-ins only for completely-JVM modules + addIfNotNull(container.tryGetService(JvmBuiltInsPackageFragmentProvider::class.java)) + } private fun getNativeProvidersIfAny(moduleInfo: ModuleInfo, container: StorageComponentContainer): List { if (!targetPlatform.has()) return emptyList() @@ -191,9 +201,11 @@ class CompositeResolverForModuleFactory( // JVM-specific if (targetPlatform.has()) { configureJavaSpecificComponents( - moduleContext, moduleClassResolver!!, languageVersionSettings, configureJavaClassFinder = null, + moduleContext, moduleClassResolver!!, + languageVersionSettings, + configureJavaClassFinder = null, javaClassTracker = null, - useBuiltInsProvider = false + useBuiltInsProvider = IdeBuiltInsLoadingState.isFromDependenciesForJvm && targetPlatform.isJvm() // use JVM BuiltIns only for completely JVM modules ) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/IdePlatformKindResolution.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/IdePlatformKindResolution.kt index 3e0e51e0144..c3ae5171e8c 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/IdePlatformKindResolution.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/IdePlatformKindResolution.kt @@ -42,12 +42,13 @@ import org.jetbrains.kotlin.storage.StorageManager interface IdePlatformKindResolution { val kind: IdePlatformKind<*> - fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey + fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey fun createBuiltIns( moduleInfo: IdeaModuleInfo, projectContext: ProjectContext, resolverForProject: ResolverForProject, - sdkDependency: SdkInfo? + sdkDependency: SdkInfo?, + stdlibDependency: LibraryInfo? ): KotlinBuiltIns fun createResolverForModuleFactory( diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JsPlatformKindResolution.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JsPlatformKindResolution.kt index 28a99bcefb2..72d2057f034 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JsPlatformKindResolution.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JsPlatformKindResolution.kt @@ -51,7 +51,7 @@ class JsPlatformKindResolution : IdePlatformKindResolution { override val kind get() = JsIdePlatformKind - override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey { + override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey { return BuiltInsCacheKey.DefaultBuiltInsKey } @@ -59,7 +59,8 @@ class JsPlatformKindResolution : IdePlatformKindResolution { moduleInfo: IdeaModuleInfo, projectContext: ProjectContext, resolverForProject: ResolverForProject, - sdkDependency: SdkInfo? + sdkDependency: SdkInfo?, + stdlibDependency: LibraryInfo?, ): KotlinBuiltIns { return DefaultBuiltIns.Instance } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt index 7494a075a35..6c096c5a615 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/caches/resolve/JvmPlatformKindResolution.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.caches.resolve +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.libraries.Library @@ -18,10 +19,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.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo 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.configuration.IdeBuiltInsLoadingState import org.jetbrains.kotlin.idea.caches.resolve.supportsAdditionalBuiltInsMembers import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind @@ -30,6 +33,8 @@ import org.jetbrains.kotlin.resolve.TargetEnvironment import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory +private val LOG = Logger.getInstance(JvmPlatformKindResolution::class.java) + class JvmPlatformKindResolution : IdePlatformKindResolution { override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean { return false // TODO: No library kind for JVM @@ -51,32 +56,80 @@ class JvmPlatformKindResolution : IdePlatformKindResolution { override val kind get() = JvmIdePlatformKind - override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey { - return if (sdkInfo != null) CacheKeyBySdk(sdkInfo.sdk) else BuiltInsCacheKey.DefaultBuiltInsKey + override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey { + if (IdeBuiltInsLoadingState.isFromClassLoader && stdlibInfo != null) { + LOG.error("Standard library ${stdlibInfo.displayedName} provided for built-ins, but loading from dependencies is disabled") + } + + return if (sdkInfo != null) + CacheKeyByBuiltInsDependencies(sdkInfo.sdk, stdlibInfo) + else BuiltInsCacheKey.DefaultBuiltInsKey } override fun createBuiltIns( moduleInfo: IdeaModuleInfo, projectContext: ProjectContext, resolverForProject: ResolverForProject, - sdkDependency: SdkInfo? + sdkDependency: SdkInfo?, + stdlibDependency: LibraryInfo?, ): KotlinBuiltIns { - return if (sdkDependency != null) - JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER).apply { - setPostponedSettingsComputation { - // SDK should be present, otherwise we wouldn't have created JvmBuiltIns in createBuiltIns - val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency) - - val isAdditionalBuiltInsFeaturesSupported = - moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project) - JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported) - } - } - else - DefaultBuiltIns.Instance + return when { + sdkDependency == null -> DefaultBuiltIns.Instance + stdlibDependency == null || moduleInfo is SdkInfo -> + createBuiltInsFromClassLoader(moduleInfo, projectContext, resolverForProject, sdkDependency) + else -> createBuiltinsFromModuleDependencies(moduleInfo, projectContext, resolverForProject, sdkDependency, stdlibDependency) + } } - data class CacheKeyBySdk(val sdk: Sdk) : BuiltInsCacheKey + private fun createBuiltInsFromClassLoader( + moduleInfo: IdeaModuleInfo, + projectContext: ProjectContext, + resolverForProject: ResolverForProject, + sdkDependency: SdkInfo, + ): JvmBuiltIns { + return JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER).apply { + setPostponedSettingsComputation { + // SDK should be present, otherwise we wouldn't have created JvmBuiltIns in createBuiltIns + val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency) + + val isAdditionalBuiltInsFeaturesSupported = + moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project) + JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported) + } + } + } + + private fun createBuiltinsFromModuleDependencies( + moduleInfo: IdeaModuleInfo, + projectContext: ProjectContext, + resolverForProject: ResolverForProject, + sdkDependency: SdkInfo, + stdlibDependency: LibraryInfo, + ): JvmBuiltIns { + if (IdeBuiltInsLoadingState.isFromClassLoader) { + LOG.error("Incorrect attempt to create built-ins from module dependencies") + } + + return JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_DEPENDENCIES).apply { + setPostponedBuiltinsModuleComputation { + val stdlibDescriptor = resolverForProject.descriptorForModule(stdlibDependency) + + @Suppress("unchecked_cast") + stdlibDescriptor as ModuleDescriptorImpl + } + + setPostponedSettingsComputation { + val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency) + + val isAdditionalBuiltInsFeaturesSupported = + moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project) + + JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported) + } + } + } + + data class CacheKeyByBuiltInsDependencies(val sdk: Sdk, val stdlib: LibraryInfo?) : BuiltInsCacheKey } class JvmLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt index 5b621042f59..0d15a2642ab 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.module.Module import com.intellij.openapi.module.impl.scopes.LibraryScopeBase import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.* import com.intellij.openapi.roots.impl.libraries.LibraryEx @@ -23,10 +24,7 @@ import com.intellij.util.SmartList import com.intellij.util.containers.ContainerUtil import org.jetbrains.jps.model.java.JavaSourceRootType import org.jetbrains.jps.model.module.JpsModuleSourceRootType -import org.jetbrains.kotlin.analyzer.CombinedModuleInfo -import org.jetbrains.kotlin.analyzer.LibraryModuleInfo -import org.jetbrains.kotlin.analyzer.ModuleInfo -import org.jetbrains.kotlin.analyzer.TrackableModuleInfo +import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.caches.project.cacheByClassInvalidatingOnRootModifications import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications import org.jetbrains.kotlin.caches.resolve.resolution @@ -37,8 +35,10 @@ import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle import org.jetbrains.kotlin.idea.caches.resolve.util.enlargedSearchScope import org.jetbrains.kotlin.idea.caches.trackers.KotlinModuleOutOfCodeBlockModificationTracker import org.jetbrains.kotlin.idea.configuration.BuildSystemType +import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState import org.jetbrains.kotlin.idea.configuration.getBuildSystemType import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware +import org.jetbrains.kotlin.idea.framework.KotlinSdkType import org.jetbrains.kotlin.idea.framework.effectiveKind import org.jetbrains.kotlin.idea.framework.platform import org.jetbrains.kotlin.idea.klib.AbstractKlibLibraryInfo @@ -48,11 +48,8 @@ import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected import org.jetbrains.kotlin.idea.util.rootManager import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.platform.DefaultIdeTargetPlatformKindProvider -import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.* import org.jetbrains.kotlin.platform.compat.toOldPlatform -import org.jetbrains.kotlin.platform.idePlatformKind -import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.js.isJs import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.isJvm @@ -356,7 +353,25 @@ abstract class LibraryInfo(override val project: Project, val library: Library) val (libraries, sdks) = LibraryDependenciesCache.getInstance(project).getLibrariesAndSdksUsedWith(this) result.addAll(sdks) - result.addAll(libraries) + + /* + * When built-ins are created from module dependencies (as opposed to loading them from classloader) + * we must resolve Kotlin standard library containing some of the built-ins declarations in the same + * resolver for project as JDK. This comes from the following requirements: + * - JvmBuiltins need JDK and standard library descriptors -> resolver for project should be able to + * resolve them + * - Builtins are created in BuiltinsCache -> module descriptors should be resolved under lock of the + * SDK resolver to prevent deadlocks + * This means we have to maintain dependencies of the standard library manually or effectively drop + * resolver for SDK otherwise. Libraries depend on superset of their actual dependencies because of + * the inability to get real dependencies from IDEA model. So moving stdlib with all dependencies + * down is a questionable option. + */ + if (!IdeBuiltInsLoadingState.isFromClassLoader && this.isCoreKotlinLibrary(project)) { + libraries.filterTo(result) { it.isCoreKotlinLibrary(project) } + } else { + result.addAll(libraries) + } return result.toList() } @@ -432,10 +447,19 @@ data class SdkInfo(override val project: Project, val sdk: Sdk) : IdeaModuleInfo override fun dependencies(): List = listOf(this) override val platform: TargetPlatform - get() = JvmPlatforms.unspecifiedJvmPlatform // TODO(dsavvinov): provide proper target version + get() = when { + sdk.sdkType is KotlinSdkType -> CommonPlatforms.defaultCommonPlatform + else -> JvmPlatforms.unspecifiedJvmPlatform // TODO(dsavvinov): provide proper target version + } override val analyzerServices: PlatformDependentAnalyzerServices get() = JvmPlatformAnalyzerServices + + override val capabilities: Map, Any?> + get() = when (this.sdk.sdkType) { + is JavaSdk -> super.capabilities + mapOf(JDK_CAPABILITY to true) + else -> super.capabilities + } } object NotUnderContentRootModuleInfo : IdeaModuleInfo { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/KotlinStdlibCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/KotlinStdlibCache.kt new file mode 100644 index 00000000000..dde135a3188 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/KotlinStdlibCache.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2020 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.idea.caches.project + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.search.DelegatingGlobalSearchScope +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.util.indexing.FileBasedIndex +import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications +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 java.util.concurrent.ConcurrentHashMap + +interface KotlinStdlibCache { + fun isStdlib(libraryInfo: LibraryInfo): Boolean + fun isStdlibDependency(libraryInfo: LibraryInfo): Boolean + + companion object { + fun getInstance(project: Project): KotlinStdlibCache = + if (IdeBuiltInsLoadingState.isFromClassLoader) { + Disabled + } else { + ServiceManager.getService(project, KotlinStdlibCache::class.java) + ?: error("Failed to load service ${KotlinStdlibCache::class.java.name}") + } + + val Disabled = object : KotlinStdlibCache { + override fun isStdlib(libraryInfo: LibraryInfo) = false + override fun isStdlibDependency(libraryInfo: LibraryInfo) = false + } + } +} + +class KotlinStdlibCacheImpl(val project: Project) : KotlinStdlibCache { + private val stdlibCache = project.cacheInvalidatingOnRootModifications { + ConcurrentHashMap() + } + + private val stdlibDependencyCache = project.cacheInvalidatingOnRootModifications { + ConcurrentHashMap() + } + + private class LibraryScope( + project: Project, + private val directories: Set + ) : DelegatingGlobalSearchScope(GlobalSearchScope.allScope(project)) { + private val fileSystems = directories.mapTo(hashSetOf(), VirtualFile::getFileSystem) + + override fun contains(file: VirtualFile): Boolean = + file.fileSystem in fileSystems && generateSequence(file, VirtualFile::getParent).any { it in directories } + + override fun toString() = "All files under: $directories" + } + + private fun libraryScopeContainsIndexedFilesForNames(libraryInfo: LibraryInfo, names: Collection) = runReadAction { + names.any { name -> + FileBasedIndex.getInstance().getContainingFiles( + KotlinStdlibIndex.KEY, + name, + LibraryScope(project, libraryInfo.library.rootProvider.getFiles(OrderRootType.CLASSES).toSet()) + ).isNotEmpty() + } + } + + private fun libraryScopeContainsIndexedFilesForName(libraryInfo: LibraryInfo, name: FqName) = + libraryScopeContainsIndexedFilesForNames(libraryInfo, listOf(name)) + + override fun isStdlib(libraryInfo: LibraryInfo): Boolean { + return stdlibCache.getOrPut(libraryInfo) { + libraryScopeContainsIndexedFilesForName(libraryInfo, KotlinStdlibIndex.KOTLIN_STDLIB_NAME) + } + } + + override fun isStdlibDependency(libraryInfo: LibraryInfo): Boolean { + return stdlibDependencyCache.getOrPut(libraryInfo) { + libraryScopeContainsIndexedFilesForNames(libraryInfo, KotlinStdlibIndex.STANDARD_LIBRARY_DEPENDENCY_NAMES) + } + } +} + +fun LibraryInfo.isCoreKotlinLibrary(project: Project): Boolean = + isKotlinStdlib(project) || isKotlinStdlibDependency(project) + +fun LibraryInfo.isKotlinStdlib(project: Project): Boolean = + KotlinStdlibCache.getInstance(project).isStdlib(this) + +fun LibraryInfo.isKotlinStdlibDependency(project: Project): Boolean = + KotlinStdlibCache.getInstance(project).isStdlibDependency(this) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/LibraryDependenciesCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/LibraryDependenciesCache.kt index 2744803b322..c12a7514054 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/LibraryDependenciesCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/LibraryDependenciesCache.kt @@ -74,8 +74,8 @@ class LibraryDependenciesCacheImpl(private val project: Project) : LibraryDepend val otherLibrary = libraryOrderEntry.library if (otherLibrary is LibraryEx && !otherLibrary.isDisposed) { val otherLibraryInfos = createLibraryInfo(project, otherLibrary) - otherLibraryInfos.firstOrNull()?.platform?.let { otherLibraryPlatform -> - if (compatiblePlatforms(platform, otherLibraryPlatform)) { + otherLibraryInfos.firstOrNull()?.let { otherLibraryInfo -> + if (compatiblePlatforms(platform, otherLibraryInfo.platform)) { libraries.addAll(otherLibraryInfos) } } @@ -84,7 +84,10 @@ class LibraryDependenciesCacheImpl(private val project: Project) : LibraryDepend override fun visitJdkOrderEntry(jdkOrderEntry: JdkOrderEntry, value: Unit) { val jdk = jdkOrderEntry.jdk ?: return - sdks += SdkInfo(project, jdk) + SdkInfo(project, jdk).also { sdkInfo -> + if (compatiblePlatforms(platform, sdkInfo.platform)) + sdks += sdkInfo + } } }, Unit) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt index 62b83cabb50..056d108b458 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IdeaResolverForProject.kt @@ -6,14 +6,12 @@ package org.jetbrains.kotlin.idea.caches.resolve import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.util.ModificationTracker import org.jetbrains.kotlin.analyzer.* import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.caches.resolve.CompositeAnalyzerServices -import org.jetbrains.kotlin.caches.resolve.CompositeResolverForModuleFactory -import org.jetbrains.kotlin.caches.resolve.KotlinCacheService -import org.jetbrains.kotlin.caches.resolve.resolution +import org.jetbrains.kotlin.caches.resolve.* import org.jetbrains.kotlin.context.ProjectContext import org.jetbrains.kotlin.context.withModule import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -22,6 +20,7 @@ import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider +import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState import org.jetbrains.kotlin.idea.project.IdeaEnvironment import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider import org.jetbrains.kotlin.idea.project.findAnalyzerServices @@ -101,6 +100,9 @@ class IdeaResolverForProject( "Unexpected modules passed through JvmPlatformParameters to IDE resolver ($targetModuleInfo, $referencingModuleInfo)" } tryGetResolverForModuleWithResolutionAnchorFallback(targetModuleInfo, referencingModuleInfo) + }, + useBuiltinsProviderForModule = { + IdeBuiltInsLoadingState.isFromDependenciesForJvm && it is LibraryInfo && it.isKotlinStdlib(projectContext.project) } ) @@ -132,18 +134,28 @@ class IdeaResolverForProject( fun getOrCreateIfNeeded(module: IdeaModuleInfo): KotlinBuiltIns = projectContextFromSdkResolver.storageManager.compute { val sdk = resolverForSdk.sdkDependency(module) + val stdlib = findStdlibForModulesBuiltins(module) - val key = module.platform.idePlatformKind.resolution.getKeyForBuiltIns(module, sdk) + val key = module.platform.idePlatformKind.resolution.getKeyForBuiltIns(module, sdk, stdlib) val cachedBuiltIns = cache[key] if (cachedBuiltIns != null) return@compute cachedBuiltIns module.platform.idePlatformKind.resolution - .createBuiltIns(module, projectContextFromSdkResolver, resolverForSdk, sdk) + .createBuiltIns(module, projectContextFromSdkResolver, resolverForSdk, sdk, stdlib) .also { // TODO: MemoizedFunction should be used here instead, but for proper we also need a module (for LV settings) that is not contained in the key cache[key] = it } } + + 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 + } } private fun tryGetResolverForModuleWithResolutionAnchorFallback( diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index 8f32bfb3d6a..ca4cf51cfab 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -43,6 +43,7 @@ import org.jetbrains.kotlin.context.GlobalContextImpl import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo +import org.jetbrains.kotlin.idea.caches.resolve.util.GlobalFacadeModuleFilters import org.jetbrains.kotlin.idea.caches.resolve.util.contextWithCompositeExceptionTracker import org.jetbrains.kotlin.idea.caches.trackers.outOfBlockModificationCount import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider @@ -174,13 +175,13 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { ) } - private inner class GlobalFacade(settings: PlatformAnalysisSettings) { private val sdkContext = GlobalContext(resolverForSdkName) + private val moduleFilters = GlobalFacadeModuleFilters(project) val facadeForSdk = ProjectResolutionFacade( "facadeForSdk", "$resolverForSdkName with settings=$settings", project, sdkContext, settings, - moduleFilter = { it is SdkInfo }, + moduleFilter = moduleFilters::sdkFacadeFilter, dependencies = listOf( LibraryModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project) @@ -194,7 +195,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { "facadeForLibraries", "$resolverForLibrariesName with settings=$settings", project, librariesContext, settings, reuseDataFrom = facadeForSdk, - moduleFilter = { it is LibraryInfo }, + moduleFilter = moduleFilters::libraryFacadeFilter, invalidateOnOOCB = false, dependencies = listOf( LibraryModificationTracker.getInstance(project), @@ -207,7 +208,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { "facadeForModules", "$resolverForModulesName with settings=$settings", project, modulesContext, settings, reuseDataFrom = facadeForLibraries, - moduleFilter = { !it.isLibraryClasses() }, + moduleFilter = moduleFilters::moduleFacadeFilter, dependencies = listOf( LibraryModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/ideBuiltInsUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/ideBuiltInsUtils.kt new file mode 100644 index 00000000000..32e2d78166e --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/util/ideBuiltInsUtils.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2020 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.idea.caches.resolve.util + +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.caches.project.* +import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState + +internal interface ModuleFilters { + fun sdkFacadeFilter(module: IdeaModuleInfo): Boolean + fun libraryFacadeFilter(module: IdeaModuleInfo): Boolean + fun moduleFacadeFilter(module: IdeaModuleInfo): Boolean +} + +private object ClassLoaderBuiltInsModuleFilters : ModuleFilters { + override fun sdkFacadeFilter(module: IdeaModuleInfo): Boolean = module is SdkInfo + override fun libraryFacadeFilter(module: IdeaModuleInfo): Boolean = module is LibraryInfo + override fun moduleFacadeFilter(module: IdeaModuleInfo): Boolean = !module.isLibraryClasses() +} + +private class DependencyBuiltinsModuleFilters(private val project: Project) : ModuleFilters { + override fun sdkFacadeFilter(module: IdeaModuleInfo): Boolean = + module is SdkInfo || module is LibraryInfo && module.isCoreKotlinLibrary(project) + + override fun libraryFacadeFilter(module: IdeaModuleInfo): Boolean = + module is LibraryInfo && !module.isCoreKotlinLibrary(project) + + override fun moduleFacadeFilter(module: IdeaModuleInfo): Boolean = !module.isLibraryClasses() +} + +internal class GlobalFacadeModuleFilters(project: Project) : ModuleFilters { + private val impl = when (IdeBuiltInsLoadingState.state) { + IdeBuiltInsLoadingState.IdeBuiltInsLoading.FROM_CLASSLOADER -> ClassLoaderBuiltInsModuleFilters + IdeBuiltInsLoadingState.IdeBuiltInsLoading.FROM_DEPENDENCIES_JVM -> DependencyBuiltinsModuleFilters(project) + } + + override fun sdkFacadeFilter(module: IdeaModuleInfo): Boolean = impl.sdkFacadeFilter(module) + override fun libraryFacadeFilter(module: IdeaModuleInfo): Boolean = impl.libraryFacadeFilter(module) + override fun moduleFacadeFilter(module: IdeaModuleInfo): Boolean = impl.moduleFacadeFilter(module) +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/configuration/IdeBuiltInsLoadingState.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/configuration/IdeBuiltInsLoadingState.kt new file mode 100644 index 00000000000..c834414d5f2 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/configuration/IdeBuiltInsLoadingState.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2020 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.idea.configuration + +object IdeBuiltInsLoadingState { + val state: IdeBuiltInsLoading = IdeBuiltInsLoading.FROM_DEPENDENCIES_JVM + + enum class IdeBuiltInsLoading { + FROM_CLASSLOADER, + FROM_DEPENDENCIES_JVM; + } + + val isFromDependenciesForJvm: Boolean + get() = state == IdeBuiltInsLoading.FROM_DEPENDENCIES_JVM + + val isFromClassLoader: Boolean + get() = state == IdeBuiltInsLoading.FROM_CLASSLOADER +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/IDEVirtualFileFinder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/IDEVirtualFileFinder.kt index 155c9da0eb5..814cf62b3de 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/IDEVirtualFileFinder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/IDEVirtualFileFinder.kt @@ -18,7 +18,7 @@ import java.io.InputStream class IDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileFinder() { override fun findMetadata(classId: ClassId): InputStream? { - val file = findVirtualFileWithHeader(classId, KotlinMetadataFileIndex.KEY) ?: return null + val file = findVirtualFileWithHeader(classId.asSingleFqName(), KotlinMetadataFileIndex.KEY) ?: return null return try { file.inputStream @@ -29,8 +29,8 @@ class IDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileFi override fun hasMetadataPackage(fqName: FqName): Boolean = KotlinMetadataFilePackageIndex.hasSomethingInPackage(fqName, scope) - // TODO: load built-ins metadata from scope - override fun findBuiltInsData(packageFqName: FqName): InputStream? = null + override fun findBuiltInsData(packageFqName: FqName): InputStream? = + findVirtualFileWithHeader(packageFqName, KotlinBuiltInsMetadataIndex.KEY)?.inputStream init { if (scope != GlobalSearchScope.EMPTY_SCOPE && scope.project == null) { @@ -38,10 +38,11 @@ class IDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileFi } } - override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? = findVirtualFileWithHeader(classId, KotlinClassFileIndex.KEY) + override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? = + findVirtualFileWithHeader(classId.asSingleFqName(), KotlinClassFileIndex.KEY) - private fun findVirtualFileWithHeader(classId: ClassId, key: ID): VirtualFile? = - FileBasedIndex.getInstance().getContainingFiles(key, classId.asSingleFqName(), scope).firstOrNull() + private fun findVirtualFileWithHeader(fqName: FqName, key: ID): VirtualFile? = + FileBasedIndex.getInstance().getContainingFiles(key, fqName, scope).firstOrNull() companion object { private val LOG = Logger.getInstance(IDEVirtualFileFinder::class.java) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt index d871317b3a3..e050ca84153 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt @@ -11,6 +11,7 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.util.indexing.* import com.intellij.util.io.IOUtil import com.intellij.util.io.KeyDescriptor +import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsPackageFragmentProvider import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.idea.decompiler.builtIns.BuiltInDefinitionFile import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType @@ -25,10 +26,12 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment import org.jetbrains.kotlin.serialization.deserialization.getClassId import org.jetbrains.kotlin.utils.JsMetadataVersion +import org.jetbrains.lang.manifest.ManifestFileType import java.io.ByteArrayInputStream import java.io.DataInput import java.io.DataOutput import java.util.* +import java.util.jar.Manifest abstract class KotlinFileIndexBase(classOfIndex: Class) : ScalarIndexExtension() { val KEY: ID = ID.create(classOfIndex.canonicalName) @@ -142,6 +145,54 @@ object KotlinMetadataFilePackageIndex : KotlinMetadataFileIndexBase(KotlinBuiltInsMetadataIndex::class.java) { + override fun getIndexer() = INDEXER + + override fun getInputFilter() = FileBasedIndex.InputFilter { file -> file.fileType == KotlinBuiltInFileType } + + override fun getVersion() = VERSION + + private val VERSION = 1 + + private val INDEXER = indexer { fileContent -> + if (fileContent.fileType == KotlinBuiltInFileType && + fileContent.fileName.endsWith(JvmBuiltInsPackageFragmentProvider.DOT_BUILTINS_METADATA_FILE_EXTENSION)) { + val builtins = BuiltInDefinitionFile.read(fileContent.content, fileContent.file.parent) + (builtins as? BuiltInDefinitionFile)?.packageFqName + } else null + } +} + +object KotlinStdlibIndex : KotlinFileIndexBase(KotlinStdlibIndex::class.java) { + private const val LIBRARY_NAME_MANIFEST_ATTRIBUTE = "Implementation-Title" + private const val STDLIB_TAG_MANIFEST_ATTRIBUTE = "Kotlin-Runtime-Component" + val KOTLIN_STDLIB_NAME = FqName("kotlin-stdlib") + val KOTLIN_STDLIB_COMMON_NAME = FqName("kotlin-stdlib-common") + + val STANDARD_LIBRARY_DEPENDENCY_NAMES = setOf( + KOTLIN_STDLIB_COMMON_NAME, + ) + + override fun getIndexer() = INDEXER + + override fun getInputFilter() = FileBasedIndex.InputFilter { file -> file.fileType is ManifestFileType } + + override fun getVersion() = VERSION + + private val VERSION = 1 + + // TODO: refactor [KotlinFileIndexBase] and get rid of FqName here, it's never a proper fully qualified name, just a String wrapper + private val INDEXER = indexer { fileContent -> + if (fileContent.fileType is ManifestFileType) { + val manifest = Manifest(ByteArrayInputStream(fileContent.content)) + val attributes = manifest.mainAttributes + attributes.getValue(STDLIB_TAG_MANIFEST_ATTRIBUTE) ?: return@indexer null + val libraryName = attributes.getValue(LIBRARY_NAME_MANIFEST_ATTRIBUTE) ?: return@indexer null + FqName(libraryName) + } else null + } +} + object KlibMetaFileIndex : KotlinFileIndexBase(KlibMetaFileIndex::class.java) { override fun getIndexer() = INDEXER diff --git a/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/NativePlatformKindResolution.kt b/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/NativePlatformKindResolution.kt index a289bd935c5..494d93bd35f 100644 --- a/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/NativePlatformKindResolution.kt +++ b/idea/idea-native/src/org/jetbrains/kotlin/ide/konan/NativePlatformKindResolution.kt @@ -94,13 +94,14 @@ class NativePlatformKindResolution : IdePlatformKindResolution { override val kind get() = NativeIdePlatformKind - override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?): BuiltInsCacheKey = NativeBuiltInsCacheKey + override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey = NativeBuiltInsCacheKey override fun createBuiltIns( moduleInfo: IdeaModuleInfo, projectContext: ProjectContext, resolverForProject: ResolverForProject, - sdkDependency: SdkInfo? + sdkDependency: SdkInfo?, + stdlibDependency: LibraryInfo?, ) = createKotlinNativeBuiltIns(moduleInfo, projectContext) private fun createKotlinNativeBuiltIns(moduleInfo: ModuleInfo, projectContext: ProjectContext): KotlinBuiltIns { diff --git a/idea/resources/META-INF/caches.xml b/idea/resources/META-INF/caches.xml index 280077a634e..f57fdfc9eaf 100644 --- a/idea/resources/META-INF/caches.xml +++ b/idea/resources/META-INF/caches.xml @@ -27,6 +27,9 @@ + + diff --git a/idea/resources/META-INF/indexes.xml b/idea/resources/META-INF/indexes.xml index 7a33e25f2c1..9241a167702 100644 --- a/idea/resources/META-INF/indexes.xml +++ b/idea/resources/META-INF/indexes.xml @@ -38,6 +38,8 @@ + + diff --git a/idea/testData/multiplatform/builtinsAndStdlib/jvm/jvm.kt b/idea/testData/multiplatform/builtinsAndStdlib/jvm/jvm.kt index 50d41176a72..9335de4e8d0 100644 --- a/idea/testData/multiplatform/builtinsAndStdlib/jvm/jvm.kt +++ b/idea/testData/multiplatform/builtinsAndStdlib/jvm/jvm.kt @@ -20,7 +20,7 @@ fun getKCallable(): KCallable<*> = ::jvmFun fun main() { val ref = ::jvmFun val typedRef: KCallable<*> = getKCallable() - ref.call() + ref.call() typedRef.call() foo(Foo::bar) }