Clean up API of AbstractResolverForProject
Resolution anchors are IDE-specific. Creating dedicated methods for them in AbstractResolverForProject leads to meaningless implementation in non-IDE resolvers. Now this method is implemented only for IDE resolver and accessed through JvmPlatformParameters. #KT-24309 In Progress
This commit is contained in:
+22
-13
@@ -38,7 +38,9 @@ import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
|
|||||||
|
|
||||||
class JvmPlatformParameters(
|
class JvmPlatformParameters(
|
||||||
val packagePartProviderFactory: (ModuleContent<*>) -> PackagePartProvider,
|
val packagePartProviderFactory: (ModuleContent<*>) -> PackagePartProvider,
|
||||||
val moduleByJavaClass: (JavaClass) -> ModuleInfo?
|
val moduleByJavaClass: (JavaClass) -> ModuleInfo?,
|
||||||
|
// params: referenced module info of target class, context module info of current resolver
|
||||||
|
val resolverForReferencedModule: ((ModuleInfo, ModuleInfo) -> ResolverForModule?)? = null,
|
||||||
) : PlatformAnalysisParameters
|
) : PlatformAnalysisParameters
|
||||||
|
|
||||||
|
|
||||||
@@ -63,14 +65,21 @@ class JvmResolverForModuleFactory(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val moduleClassResolver = ModuleClassResolverImpl { javaClass ->
|
val moduleClassResolver = ModuleClassResolverImpl { javaClass ->
|
||||||
val referencedClassModule = (platformParameters as JvmPlatformParameters).moduleByJavaClass(javaClass)
|
val referencedClassModule = platformParameters.moduleByJavaClass(javaClass)
|
||||||
// We don't have full control over idea resolve api so we allow for a situation which should not happen in Kotlin.
|
// A type in a java library can reference a class declared in a source root (is valid but rare case).
|
||||||
// For example, type in a java library can reference a class declared in a source root (is valid but rare case)
|
// Resolving such a class with Kotlin resolver for libraries is guaranteed to fail, as libraries can't
|
||||||
// Providing a fallback strategy in this case can hide future problems, so we should at least log to be able to diagnose those
|
// have dependencies on the source roots. The chain of resolvers (sources -> libraries -> sdk) exists to prevent
|
||||||
|
// potentially slow repetitive analysis of the same libraries after modifications in sources. The only way to mitigate
|
||||||
|
// this restriction currently is to manually configure resolution anchors for known source-dependent libraries in a project.
|
||||||
|
// See also KT-24309
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val resolverForReferencedModule = referencedClassModule?.let {
|
val resolverForReferencedModule = referencedClassModule?.let { referencedModuleInfo ->
|
||||||
resolverForProject.tryGetResolverForModuleWithResolutionAnchorFallback(it as M, moduleInfo)
|
if (platformParameters.resolverForReferencedModule != null) {
|
||||||
|
platformParameters.resolverForReferencedModule.invoke(referencedModuleInfo, moduleInfo)
|
||||||
|
} else {
|
||||||
|
resolverForProject.tryGetResolverForModule(referencedModuleInfo as M)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val resolverForModule = resolverForReferencedModule?.takeIf {
|
val resolverForModule = resolverForReferencedModule?.takeIf {
|
||||||
@@ -111,12 +120,12 @@ class JvmResolverForModuleFactory(
|
|||||||
)
|
)
|
||||||
|
|
||||||
providersForModule +=
|
providersForModule +=
|
||||||
PackageFragmentProviderExtension.getInstances(project)
|
PackageFragmentProviderExtension.getInstances(project)
|
||||||
.mapNotNull {
|
.mapNotNull {
|
||||||
it.getPackageFragmentProvider(
|
it.getPackageFragmentProvider(
|
||||||
project, moduleDescriptor, moduleContext.storageManager, trace, moduleInfo, lookupTracker
|
project, moduleDescriptor, moduleContext.storageManager, trace, moduleInfo, lookupTracker
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResolverForModule(CompositePackageFragmentProvider(providersForModule), container)
|
return ResolverForModule(CompositePackageFragmentProvider(providersForModule), container)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,9 +64,6 @@ abstract class AbstractResolverForProject<M : ModuleInfo>(
|
|||||||
return resolverForModuleDescriptor(doGetDescriptorForModule(moduleInfo))
|
return resolverForModuleDescriptor(doGetDescriptorForModule(moduleInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryGetResolverForModuleWithResolutionAnchorFallback(targetModuleInfo: M, referencingModuleInfo: M): ResolverForModule? =
|
|
||||||
tryGetResolverForModule(targetModuleInfo)
|
|
||||||
|
|
||||||
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
|
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
|
||||||
moduleDescriptor.setDependencies(
|
moduleDescriptor.setDependencies(
|
||||||
LazyModuleDependencies(
|
LazyModuleDependencies(
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class ResolverForModule(
|
|||||||
abstract class ResolverForProject<M : ModuleInfo> {
|
abstract class ResolverForProject<M : ModuleInfo> {
|
||||||
fun resolverForModule(moduleInfo: M): ResolverForModule = resolverForModuleDescriptor(descriptorForModule(moduleInfo))
|
fun resolverForModule(moduleInfo: M): ResolverForModule = resolverForModuleDescriptor(descriptorForModule(moduleInfo))
|
||||||
abstract fun tryGetResolverForModule(moduleInfo: M): ResolverForModule?
|
abstract fun tryGetResolverForModule(moduleInfo: M): ResolverForModule?
|
||||||
abstract fun tryGetResolverForModuleWithResolutionAnchorFallback(targetModuleInfo: M, referencingModuleInfo: M): ResolverForModule?
|
|
||||||
abstract fun descriptorForModule(moduleInfo: M): ModuleDescriptor
|
abstract fun descriptorForModule(moduleInfo: M): ModuleDescriptor
|
||||||
abstract fun moduleInfoForModuleDescriptor(moduleDescriptor: ModuleDescriptor): M
|
abstract fun moduleInfoForModuleDescriptor(moduleDescriptor: ModuleDescriptor): M
|
||||||
abstract fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule
|
abstract fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule
|
||||||
@@ -76,9 +75,6 @@ class EmptyResolverForProject<M : ModuleInfo> : ResolverForProject<M>() {
|
|||||||
override val allModules: Collection<M> = listOf()
|
override val allModules: Collection<M> = listOf()
|
||||||
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
|
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
|
||||||
|
|
||||||
override fun tryGetResolverForModuleWithResolutionAnchorFallback(targetModuleInfo: M, referencingModuleInfo: M) =
|
|
||||||
diagnoseUnknownModuleInfo(listOf(targetModuleInfo))
|
|
||||||
|
|
||||||
override fun moduleInfoForModuleDescriptor(descriptor: ModuleDescriptor): M {
|
override fun moduleInfoForModuleDescriptor(descriptor: ModuleDescriptor): M {
|
||||||
throw IllegalStateException("$descriptor is not contained in this resolver")
|
throw IllegalStateException("$descriptor is not contained in this resolver")
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.platform.jvm.isJvm
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider
|
import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
|
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|
||||||
|
|
||||||
class IdeaResolverForProject(
|
class IdeaResolverForProject(
|
||||||
debugName: String,
|
debugName: String,
|
||||||
@@ -96,6 +95,12 @@ class IdeaResolverForProject(
|
|||||||
moduleByJavaClass = { javaClass: JavaClass ->
|
moduleByJavaClass = { javaClass: JavaClass ->
|
||||||
val psiClass = (javaClass as JavaClassImpl).psi
|
val psiClass = (javaClass as JavaClassImpl).psi
|
||||||
psiClass.getPlatformModuleInfo(JvmPlatforms.unspecifiedJvmPlatform)?.platformModule ?: psiClass.getNullableModuleInfo()
|
psiClass.getPlatformModuleInfo(JvmPlatforms.unspecifiedJvmPlatform)?.platformModule ?: psiClass.getNullableModuleInfo()
|
||||||
|
},
|
||||||
|
resolverForReferencedModule = { targetModuleInfo, referencingModuleInfo ->
|
||||||
|
require(targetModuleInfo is IdeaModuleInfo && referencingModuleInfo is IdeaModuleInfo) {
|
||||||
|
"Unexpected modules passed through JvmPlatformParameters to IDE resolver ($targetModuleInfo, $referencingModuleInfo)"
|
||||||
|
}
|
||||||
|
tryGetResolverForModuleWithResolutionAnchorFallback(targetModuleInfo, referencingModuleInfo)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -150,7 +155,7 @@ class IdeaResolverForProject(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tryGetResolverForModuleWithResolutionAnchorFallback(
|
private fun tryGetResolverForModuleWithResolutionAnchorFallback(
|
||||||
targetModuleInfo: IdeaModuleInfo,
|
targetModuleInfo: IdeaModuleInfo,
|
||||||
referencingModuleInfo: IdeaModuleInfo,
|
referencingModuleInfo: IdeaModuleInfo,
|
||||||
): ResolverForModule? {
|
): ResolverForModule? {
|
||||||
@@ -158,9 +163,9 @@ class IdeaResolverForProject(
|
|||||||
|
|
||||||
return getResolverForProjectUsingResolutionAnchor(targetModuleInfo, referencingModuleInfo)
|
return getResolverForProjectUsingResolutionAnchor(targetModuleInfo, referencingModuleInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getResolverForProjectUsingResolutionAnchor(
|
private fun getResolverForProjectUsingResolutionAnchor(
|
||||||
targetModuleInfo: IdeaModuleInfo,
|
targetModuleInfo: IdeaModuleInfo,
|
||||||
referencingModuleInfo: IdeaModuleInfo
|
referencingModuleInfo: IdeaModuleInfo
|
||||||
): ResolverForModule? {
|
): ResolverForModule? {
|
||||||
val moduleDescriptorOfReferencingModule = descriptorByModule[referencingModuleInfo]?.moduleDescriptor
|
val moduleDescriptorOfReferencingModule = descriptorByModule[referencingModuleInfo]?.moduleDescriptor
|
||||||
@@ -173,7 +178,9 @@ class IdeaResolverForProject(
|
|||||||
?.getResolverForProject()
|
?.getResolverForProject()
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
if (resolverForProjectFromAnchorModule !is IdeaResolverForProject) return null
|
require(resolverForProjectFromAnchorModule is IdeaResolverForProject) {
|
||||||
|
"Resolution via anchor modules is expected to be used only from IDE resolvers"
|
||||||
|
}
|
||||||
|
|
||||||
return resolverForProjectFromAnchorModule.tryGetResolverForModule(targetModuleInfo)
|
return resolverForProjectFromAnchorModule.tryGetResolverForModule(targetModuleInfo)
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -21,6 +21,13 @@ import org.jetbrains.kotlin.idea.project.libraryToSourceAnalysisEnabled
|
|||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider
|
import org.jetbrains.kotlin.resolve.ResolutionAnchorProvider
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component provides capabilities for correct highlighting for projects with source-dependent libraries.
|
||||||
|
* The issue with this kind of libraries is that their declarations are resolved by ResolverForProject
|
||||||
|
* that have no access to project sources by itself. The necessary path back to project sources can be provided
|
||||||
|
* manually for the libraries in project via resolution anchors. Anchor by itself is a source module which is mapped
|
||||||
|
* to a library and used during resolution as a fallback.
|
||||||
|
*/
|
||||||
@State(name = "KotlinIdeAnchorService", storages = [Storage("anchors.xml")])
|
@State(name = "KotlinIdeAnchorService", storages = [Storage("anchors.xml")])
|
||||||
class KotlinIdeResolutionAnchorService(
|
class KotlinIdeResolutionAnchorService(
|
||||||
val project: Project
|
val project: Project
|
||||||
|
|||||||
Reference in New Issue
Block a user