MPP: analyze platform sources with expectedBy common sources
This allows to emulate current compiler behaviour Introduce CombinedModuleInfo which is a combination of several other modules intended to be analyzed together
This commit is contained in:
@@ -116,7 +116,12 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
// Protected by ("projectContext.storageManager.lock")
|
||||
private val moduleInfoByDescriptor = mutableMapOf<ModuleDescriptorImpl, M>()
|
||||
|
||||
val modules = modules.toSet()
|
||||
private val moduleInfoToResolvableInfo: Map<M, M> =
|
||||
modules.flatMap { module -> module.flatten().map { modulePart -> modulePart to module } }.toMap() as Map<M, M>
|
||||
|
||||
init {
|
||||
assert(moduleInfoToResolvableInfo.values.toSet() == modules.toSet())
|
||||
}
|
||||
|
||||
override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? {
|
||||
if (!isCorrectModuleInfo(moduleInfo)) {
|
||||
@@ -148,7 +153,7 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>()
|
||||
|
||||
override val allModules: Collection<M> by lazy {
|
||||
this.modules + delegateResolver.allModules
|
||||
this.moduleInfoToResolvableInfo.keys + delegateResolver.allModules
|
||||
}
|
||||
|
||||
override val name: String
|
||||
@@ -212,19 +217,18 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
}
|
||||
|
||||
private fun doGetDescriptorForModule(module: M): ModuleDescriptorImpl {
|
||||
if (module in modules) {
|
||||
return projectContext.storageManager.compute {
|
||||
var moduleData = descriptorByModule.getOrPut(module) {
|
||||
createModuleDescriptor(module)
|
||||
}
|
||||
if (moduleData.isOutOfDate()) {
|
||||
moduleData = recreateModuleDescriptor(module)
|
||||
}
|
||||
moduleData.moduleDescriptor
|
||||
}
|
||||
}
|
||||
val moduleFromThisResolver = moduleInfoToResolvableInfo[module]
|
||||
?: return delegateResolver.descriptorForModule(module) as ModuleDescriptorImpl
|
||||
|
||||
return delegateResolver.descriptorForModule(module) as ModuleDescriptorImpl
|
||||
return projectContext.storageManager.compute {
|
||||
var moduleData = descriptorByModule.getOrPut(moduleFromThisResolver) {
|
||||
createModuleDescriptor(moduleFromThisResolver)
|
||||
}
|
||||
if (moduleData.isOutOfDate()) {
|
||||
moduleData = recreateModuleDescriptor(moduleFromThisResolver)
|
||||
}
|
||||
moduleData.moduleDescriptor
|
||||
}
|
||||
}
|
||||
|
||||
private fun recreateModuleDescriptor(module: M): ModuleData {
|
||||
@@ -253,7 +257,7 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
}
|
||||
}
|
||||
|
||||
data class ModuleContent<out M: ModuleInfo>(
|
||||
data class ModuleContent<out M : ModuleInfo>(
|
||||
val moduleInfo: M,
|
||||
val syntheticFiles: Collection<KtFile>,
|
||||
val moduleContentScope: GlobalSearchScope
|
||||
@@ -290,6 +294,15 @@ interface ModuleInfo {
|
||||
}
|
||||
}
|
||||
|
||||
interface CombinedModuleInfo : ModuleInfo {
|
||||
val containedModules: List<ModuleInfo>
|
||||
}
|
||||
|
||||
fun ModuleInfo.flatten(): List<ModuleInfo> = when (this) {
|
||||
is CombinedModuleInfo -> listOf(this) + containedModules
|
||||
else -> listOf(this)
|
||||
}
|
||||
|
||||
interface TrackableModuleInfo : ModuleInfo {
|
||||
fun createModificationTracker(): ModificationTracker
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType
|
||||
import org.jetbrains.kotlin.analyzer.CombinedModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.TrackableModuleInfo
|
||||
import org.jetbrains.kotlin.caches.project.LibraryModuleInfo
|
||||
@@ -413,3 +414,31 @@ interface SourceForBinaryModuleInfo : IdeaModuleInfo {
|
||||
override val moduleOrigin: ModuleOrigin
|
||||
get() = ModuleOrigin.OTHER
|
||||
}
|
||||
|
||||
class PlatformModuleInfo(
|
||||
private val platformModule: ModuleSourceInfo,
|
||||
private val commonModules: List<ModuleSourceInfo>
|
||||
) : IdeaModuleInfo, CombinedModuleInfo, TrackableModuleInfo {
|
||||
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
||||
get() = platformModule.capabilities
|
||||
|
||||
override fun contentScope() = GlobalSearchScope.union(containedModules.map { it.contentScope() }.toTypedArray())
|
||||
|
||||
override val containedModules: List<ModuleSourceInfo> = listOf(platformModule) + commonModules
|
||||
|
||||
override val platform: TargetPlatform?
|
||||
get() = platformModule.platform
|
||||
|
||||
override val moduleOrigin: ModuleOrigin
|
||||
get() = platformModule.moduleOrigin
|
||||
|
||||
override fun dependencies() = platformModule.dependencies()
|
||||
|
||||
override val name: Name
|
||||
get() = Name.special("<Platform module ${platformModule.displayedName} including ${commonModules.map { it.displayedName }}>")
|
||||
|
||||
override fun createModificationTracker() = platformModule.createModificationTracker()
|
||||
}
|
||||
|
||||
fun IdeaModuleInfo.projectSourceModules(): List<ModuleSourceInfo>? =
|
||||
(this as? ModuleSourceInfo)?.let(::listOf) ?: (this as? PlatformModuleInfo)?.containedModules
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected
|
||||
import org.jetbrains.kotlin.idea.util.isKotlinBinary
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.script.getScriptDefinition
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
@@ -61,7 +62,7 @@ fun getLibrarySourcesModuleInfos(project: Project, virtualFile: VirtualFile) =
|
||||
virtualFile
|
||||
)
|
||||
|
||||
fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
|
||||
fun collectAllModuleInfosFromIdeaModel(project: Project, platform: TargetPlatform): List<IdeaModuleInfo> {
|
||||
val ideaModules = ModuleManager.getInstance(project).modules.toList()
|
||||
val modulesSourcesInfos = ideaModules.flatMap(Module::correspondingModuleInfos)
|
||||
|
||||
@@ -87,9 +88,29 @@ fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
|
||||
)
|
||||
}
|
||||
|
||||
return modulesSourcesInfos + librariesInfos + sdksInfos
|
||||
return mergePlatformModules(modulesSourcesInfos, platform) + librariesInfos + sdksInfos
|
||||
}
|
||||
|
||||
private fun mergePlatformModules(
|
||||
allModules: List<IdeaModuleInfo>,
|
||||
platform: TargetPlatform
|
||||
): List<IdeaModuleInfo> {
|
||||
if (platform == TargetPlatform.Common) return allModules
|
||||
|
||||
val platformModules =
|
||||
allModules.flatMap { module ->
|
||||
if (module is ModuleSourceInfo && module.platform == platform && module.expectedBy.isNotEmpty())
|
||||
listOf(module to module.expectedBy)
|
||||
else emptyList()
|
||||
}.map { (module, expectedBys) ->
|
||||
PlatformModuleInfo(module, expectedBys)
|
||||
}
|
||||
|
||||
val rest = allModules - platformModules.flatMap { it.containedModules }
|
||||
return rest + platformModules
|
||||
}
|
||||
|
||||
|
||||
fun getScriptRelatedModuleInfo(project: Project, virtualFile: VirtualFile): ModuleSourceInfo? {
|
||||
val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project)
|
||||
|
||||
|
||||
+9
-2
@@ -40,7 +40,11 @@ private fun Module.findImplementingModuleInfos(moduleSourceInfo: ModuleSourceInf
|
||||
|
||||
val ModuleDescriptor.implementingDescriptors: List<ModuleDescriptor>
|
||||
get() {
|
||||
val moduleSourceInfo = getCapability(ModuleInfo.Capability) as? ModuleSourceInfo ?: return emptyList()
|
||||
val moduleInfo = getCapability(ModuleInfo.Capability)
|
||||
if (moduleInfo is PlatformModuleInfo) {
|
||||
return listOf(this)
|
||||
}
|
||||
val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return emptyList()
|
||||
val module = moduleSourceInfo.module
|
||||
return module.cached(CachedValueProvider {
|
||||
val implementingModuleInfos = module.findImplementingModuleInfos(moduleSourceInfo)
|
||||
@@ -57,7 +61,10 @@ val ModuleDescriptor.implementingDescriptors: List<ModuleDescriptor>
|
||||
|
||||
val ModuleDescriptor.implementedDescriptors: List<ModuleDescriptor>
|
||||
get() {
|
||||
val moduleSourceInfo = getCapability(ModuleInfo.Capability) as? ModuleSourceInfo ?: return emptyList()
|
||||
val moduleInfo = getCapability(ModuleInfo.Capability)
|
||||
if (moduleInfo is PlatformModuleInfo) return listOf(this)
|
||||
|
||||
val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return emptyList()
|
||||
|
||||
return moduleSourceInfo.expectedBy.mapNotNull {
|
||||
KotlinCacheService.getInstance(moduleSourceInfo.module.project)
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ internal class ProjectResolutionFacade(
|
||||
globalContext
|
||||
)
|
||||
|
||||
val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project)).toMutableSet()
|
||||
val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project, settings.platform)).toMutableSet()
|
||||
|
||||
val syntheticFilesByModule = syntheticFiles.groupBy(KtFile::getModuleInfo)
|
||||
val syntheticFilesModules = syntheticFilesByModule.keys
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.analyzer.PackageOracleFactory
|
||||
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleOrigin
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.projectSourceModules
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.isSubpackageOf
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
@@ -37,11 +37,11 @@ class IdePackageOracleFactory(val project: Project) : PackageOracleFactory {
|
||||
return when (moduleInfo.platform) {
|
||||
JvmPlatform -> when (moduleInfo.moduleOrigin) {
|
||||
ModuleOrigin.LIBRARY -> JavaPackagesOracle(moduleInfo, project)
|
||||
ModuleOrigin.MODULE -> JvmSourceOracle(moduleInfo as ModuleSourceInfo, project)
|
||||
ModuleOrigin.MODULE -> JvmSourceOracle(moduleInfo, project)
|
||||
ModuleOrigin.OTHER -> PackageOracle.Optimistic
|
||||
}
|
||||
else -> when (moduleInfo.moduleOrigin) {
|
||||
ModuleOrigin.MODULE -> KotlinSourceFilesOracle(moduleInfo as ModuleSourceInfo)
|
||||
ModuleOrigin.MODULE -> KotlinSourceFilesOracle(moduleInfo, project)
|
||||
else -> PackageOracle.Optimistic // binaries for non-jvm platform need some oracles based on their structure
|
||||
}
|
||||
}
|
||||
@@ -54,17 +54,18 @@ class IdePackageOracleFactory(val project: Project) : PackageOracleFactory {
|
||||
override fun packageExists(fqName: FqName) = facade.findPackage(fqName.asString(), scope) != null
|
||||
}
|
||||
|
||||
private class KotlinSourceFilesOracle(private val moduleInfo: ModuleSourceInfo) : PackageOracle {
|
||||
private val cacheService = ServiceManager.getService(moduleInfo.module.project, PerModulePackageCacheService::class.java)
|
||||
private class KotlinSourceFilesOracle(moduleInfo: IdeaModuleInfo, private val project: Project) : PackageOracle {
|
||||
private val cacheService = ServiceManager.getService(project, PerModulePackageCacheService::class.java)
|
||||
private val sourceModules = moduleInfo.projectSourceModules()
|
||||
|
||||
override fun packageExists(fqName: FqName): Boolean {
|
||||
return cacheService.packageExists(fqName, moduleInfo)
|
||||
return sourceModules?.any { cacheService.packageExists(fqName, it) } ?: false
|
||||
}
|
||||
}
|
||||
|
||||
private class JvmSourceOracle(moduleInfo: ModuleSourceInfo, project: Project) : PackageOracle {
|
||||
private class JvmSourceOracle(moduleInfo: IdeaModuleInfo, project: Project) : PackageOracle {
|
||||
private val javaPackagesOracle = JavaPackagesOracle(moduleInfo, project)
|
||||
private val kotlinSourceOracle = KotlinSourceFilesOracle(moduleInfo)
|
||||
private val kotlinSourceOracle = KotlinSourceFilesOracle(moduleInfo, project)
|
||||
|
||||
override fun packageExists(fqName: FqName) =
|
||||
javaPackagesOracle.packageExists(fqName)
|
||||
|
||||
+5
-2
@@ -23,7 +23,9 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.stubs.StubIndex
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.projectSourceModules
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinExactPackagesIndex
|
||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||
import org.jetbrains.kotlin.idea.stubindex.SubpackagesIndexService
|
||||
@@ -62,8 +64,9 @@ class PluginDeclarationProviderFactory(
|
||||
|
||||
private fun stubBasedPackageExists(name: FqName): Boolean {
|
||||
// We're only looking for source-based declarations
|
||||
val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return false
|
||||
return PerModulePackageCacheService.getInstance(project).packageExists(name, moduleInfo)
|
||||
return (moduleInfo as? IdeaModuleInfo)?.projectSourceModules()
|
||||
?.any { PerModulePackageCacheService.getInstance(project).packageExists(name, it) }
|
||||
?: false
|
||||
}
|
||||
|
||||
private fun getStubBasedPackageMemberDeclarationProvider(name: FqName): PackageMemberDeclarationProvider? {
|
||||
|
||||
+3
-2
@@ -19,7 +19,8 @@ package org.jetbrains.kotlin.idea.stubindex.resolve
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleOrigin
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
||||
@@ -35,7 +36,7 @@ class PluginDeclarationProviderFactoryService : DeclarationProviderFactoryServic
|
||||
filesScope: GlobalSearchScope,
|
||||
moduleInfo: ModuleInfo
|
||||
): DeclarationProviderFactory {
|
||||
if (syntheticFiles.isEmpty() && moduleInfo !is ModuleSourceInfo) {
|
||||
if (syntheticFiles.isEmpty() && (moduleInfo as IdeaModuleInfo).moduleOrigin != ModuleOrigin.MODULE) {
|
||||
// No actual source declarations for libraries
|
||||
// Even in case of libraries sources they should be obtained through the classpath with subsequent decompiling
|
||||
// Anyway, we'll filter them out with `KotlinSourceFilterScope.sources` call below
|
||||
|
||||
@@ -6,10 +6,11 @@ expect class <error descr="[NO_ACTUAL_FOR_EXPECT] Expected class 'His' has no ac
|
||||
|
||||
}
|
||||
|
||||
// NOTE: can declare expect and actual in platform module
|
||||
expect class Their {
|
||||
|
||||
}
|
||||
|
||||
actual class <error descr="[ACTUAL_WITHOUT_EXPECT] Actual class 'Their' has no corresponding expected declaration">Their</error> {
|
||||
actual class Their {
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user