Refactor: move utils related to expect/actual declarations and MPPs
Move them to 'idea-analysis' module
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. 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.externalSystem.service.project.IdeModifiableModelsProvider
|
||||
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
|
||||
fun Module.findImplementingModules(modelsProvider: IdeModifiableModelsProvider) =
|
||||
modelsProvider.modules.filter { name in it.findImplementedModuleNames(modelsProvider) }
|
||||
|
||||
val Module.implementingModules: List<Module>
|
||||
get() = cached(CachedValueProvider {
|
||||
CachedValueProvider.Result(
|
||||
findImplementingModules(IdeModifiableModelsProviderImpl(project)),
|
||||
ProjectRootModificationTracker.getInstance(project)
|
||||
)
|
||||
})
|
||||
|
||||
private fun Module.getModuleInfo(baseModuleSourceInfo: ModuleSourceInfo): ModuleSourceInfo? =
|
||||
when (baseModuleSourceInfo) {
|
||||
is ModuleProductionSourceInfo -> productionSourceInfo()
|
||||
is ModuleTestSourceInfo -> testSourceInfo()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun Module.findImplementingModuleInfos(moduleSourceInfo: ModuleSourceInfo): List<ModuleSourceInfo> {
|
||||
val modelsProvider = IdeModifiableModelsProviderImpl(project)
|
||||
val implementingModules = findImplementingModules(modelsProvider)
|
||||
return implementingModules.mapNotNull { it.getModuleInfo(moduleSourceInfo) }
|
||||
}
|
||||
|
||||
val ModuleDescriptor.implementingDescriptors: List<ModuleDescriptor>
|
||||
get() {
|
||||
val moduleSourceInfo = getCapability(ModuleInfo.Capability) as? ModuleSourceInfo ?: return emptyList()
|
||||
val module = moduleSourceInfo.module
|
||||
return module.cached(CachedValueProvider {
|
||||
val implementingModuleInfos = module.findImplementingModuleInfos(moduleSourceInfo)
|
||||
val implementingModuleDescriptors = implementingModuleInfos.mapNotNull {
|
||||
KotlinCacheService.getInstance(module.project).getResolutionFacadeByModuleInfo(it, it.platform)?.moduleDescriptor
|
||||
}
|
||||
CachedValueProvider.Result(
|
||||
implementingModuleDescriptors,
|
||||
*(implementingModuleInfos.map { it.createModificationTracker() } +
|
||||
ProjectRootModificationTracker.getInstance(module.project)).toTypedArray()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
val ModuleDescriptor.implementedDescriptors: List<ModuleDescriptor>
|
||||
get() {
|
||||
val moduleSourceInfo = getCapability(ModuleInfo.Capability) as? ModuleSourceInfo ?: return emptyList()
|
||||
|
||||
return moduleSourceInfo.expectedBy.mapNotNull {
|
||||
KotlinCacheService.getInstance(moduleSourceInfo.module.project)
|
||||
.getResolutionFacadeByModuleInfo(it, it.platform)?.moduleDescriptor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. 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.util
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors
|
||||
import org.jetbrains.kotlin.idea.caches.project.implementingDescriptors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal fun MemberDescriptor.expectedDescriptors() = module.implementedDescriptors.mapNotNull { it.declarationOf(this) }
|
||||
|
||||
// TODO: Sort out the cases with multiple expected descriptors
|
||||
fun MemberDescriptor.expectedDescriptor() = expectedDescriptors().firstOrNull()
|
||||
|
||||
fun KtDeclaration.expectedDeclarationIfAny(): KtDeclaration? {
|
||||
val expectedDescriptor = (toDescriptor() as? MemberDescriptor)?.expectedDescriptor() ?: return null
|
||||
return DescriptorToSourceUtils.descriptorToDeclaration(expectedDescriptor) as? KtDeclaration
|
||||
}
|
||||
|
||||
fun KtDeclaration.isExpectedOrExpectedClassMember(): Boolean {
|
||||
if (hasExpectModifier()) return true
|
||||
if (this is KtClassOrObject) return this.isExpected()
|
||||
|
||||
return containingClassOrObject?.isExpected() == true
|
||||
}
|
||||
|
||||
fun KtClassOrObject.isExpected(): Boolean {
|
||||
return this.hasExpectModifier() || this.descriptor.safeAs<ClassDescriptor>()?.isExpect == true
|
||||
}
|
||||
|
||||
fun DeclarationDescriptor.liftToExpected(): DeclarationDescriptor? {
|
||||
if (this is MemberDescriptor) {
|
||||
return when {
|
||||
isExpect -> this
|
||||
isActual -> expectedDescriptor()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
if (this is ValueParameterDescriptor) {
|
||||
val containingExpectedDescriptor = containingDeclaration.liftToExpected() as? CallableDescriptor ?: return null
|
||||
return containingExpectedDescriptor.valueParameters.getOrNull(index)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun KtDeclaration.liftToExpected(): KtDeclaration? {
|
||||
val descriptor = resolveToDescriptorIfAny()
|
||||
val expectedDescriptor = descriptor?.liftToExpected() ?: return null
|
||||
return DescriptorToSourceUtils.descriptorToDeclaration(expectedDescriptor) as? KtDeclaration
|
||||
}
|
||||
|
||||
fun ModuleDescriptor.hasDeclarationOf(descriptor: MemberDescriptor) = declarationOf(descriptor) != null
|
||||
|
||||
private fun ModuleDescriptor.declarationOf(descriptor: MemberDescriptor): DeclarationDescriptor? =
|
||||
with(ExpectedActualResolver) {
|
||||
val expectedCompatibilityMap = findExpectedForActual(descriptor, this@declarationOf)
|
||||
expectedCompatibilityMap?.get(ExpectedActualResolver.Compatibility.Compatible)?.firstOrNull()
|
||||
?: expectedCompatibilityMap?.values?.flatten()?.firstOrNull()
|
||||
}
|
||||
|
||||
fun ModuleDescriptor.hasActualsFor(descriptor: MemberDescriptor) =
|
||||
actualsFor(descriptor).isNotEmpty()
|
||||
|
||||
fun ModuleDescriptor.actualsFor(descriptor: MemberDescriptor, checkCompatible: Boolean = false): List<DeclarationDescriptor> =
|
||||
with(ExpectedActualResolver) {
|
||||
if (checkCompatible) {
|
||||
descriptor.findCompatibleActualForExpected(this@actualsFor)
|
||||
} else {
|
||||
descriptor.findAnyActualForExpected(this@actualsFor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DeclarationDescriptor.actualsForExpected(): Collection<DeclarationDescriptor> {
|
||||
if (this is MemberDescriptor) {
|
||||
if (!this.isExpect) return emptyList()
|
||||
|
||||
return module.implementingDescriptors.flatMap { it.actualsFor(this) }
|
||||
}
|
||||
|
||||
if (this is ValueParameterDescriptor) {
|
||||
return containingDeclaration.actualsForExpected().mapNotNull { (it as? CallableDescriptor)?.valueParameters?.getOrNull(index) }
|
||||
}
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
// null means "any platform" here
|
||||
fun KtDeclaration.actualsForExpected(module: Module? = null): Set<KtDeclaration> =
|
||||
resolveToDescriptorIfAny(BodyResolveMode.FULL)
|
||||
?.actualsForExpected()
|
||||
?.filter { module == null || (it.module.getCapability(ModuleInfo.Capability) as? ModuleSourceInfo)?.module == module }
|
||||
?.mapNotNullTo(LinkedHashSet()) {
|
||||
DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtDeclaration
|
||||
} ?: emptySet()
|
||||
|
||||
|
||||
fun KtNamedDeclaration.isExpectDeclaration(): Boolean =
|
||||
(toDescriptor() as? MemberDescriptor)?.isExpect == true
|
||||
|
||||
fun KtNamedDeclaration.isActualDeclaration(): Boolean =
|
||||
(toDescriptor() as? MemberDescriptor)?.isActual == true
|
||||
Reference in New Issue
Block a user