Refactor: move utils related to expect/actual declarations and MPPs

Move them to 'idea-analysis' module
This commit is contained in:
Pavel V. Talanov
2018-03-14 17:03:03 +01:00
parent 3aee544f02
commit 9c9cdee7f0
27 changed files with 240 additions and 215 deletions
@@ -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