Introduce components for library-to-source resolution in IDE
#KT-24309 In progress
This commit is contained in:
+38
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.ModuleResolverTracker
|
||||
import org.jetbrains.kotlin.analyzer.ResolverForProject
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.project.useAnchorServices
|
||||
|
||||
class IdeaModuleResolverTrackerImpl(private val project: Project) : ModuleResolverTracker<IdeaModuleInfo>() {
|
||||
private val resolversForModules by lazy {
|
||||
mutableMapOf<ModuleDescriptor, ResolverForProject<IdeaModuleInfo>>()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun registerModuleUpdate(
|
||||
newModule: ModuleDescriptor,
|
||||
oldModule: ModuleDescriptor?,
|
||||
resolverForProject: ResolverForProject<IdeaModuleInfo>
|
||||
) {
|
||||
if (!project.useAnchorServices) return
|
||||
|
||||
if (oldModule != null) resolversForModules.remove(oldModule)
|
||||
resolversForModules[newModule] = resolverForProject
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun findResolverForProjectByModuleDescriptor(moduleDescriptor: ModuleDescriptor): ResolverForProject<IdeaModuleInfo>? {
|
||||
if (!project.useAnchorServices) return null
|
||||
|
||||
return resolversForModules[moduleDescriptor]
|
||||
}
|
||||
}
|
||||
+32
-2
@@ -31,9 +31,10 @@ import org.jetbrains.kotlin.platform.idePlatformKind
|
||||
import org.jetbrains.kotlin.platform.isCommon
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||
import org.jetbrains.kotlin.platform.toTargetPlatform
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.AnchorProvider
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class IdeaResolverForProject(
|
||||
debugName: String,
|
||||
@@ -51,7 +52,8 @@ class IdeaResolverForProject(
|
||||
modules,
|
||||
fallbackModificationTracker,
|
||||
delegateResolver,
|
||||
ServiceManager.getService(projectContext.project, IdePackageOracleFactory::class.java)
|
||||
ServiceManager.getService(projectContext.project, IdePackageOracleFactory::class.java),
|
||||
ServiceManager.getService(projectContext.project, AnchorProvider::class.java)
|
||||
) {
|
||||
private val builtInsCache: BuiltInsCache =
|
||||
(delegateResolver as? IdeaResolverForProject)?.builtInsCache ?: BuiltInsCache(projectContext, this)
|
||||
@@ -146,6 +148,34 @@ class IdeaResolverForProject(
|
||||
return@compute newBuiltIns
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerModuleDescriptorUpdate(
|
||||
newDescriptor: ModuleDescriptor,
|
||||
oldDescriptor: ModuleDescriptor?
|
||||
) {
|
||||
ModuleResolverTracker
|
||||
.getInstance(projectContext.project)
|
||||
.safeAs<IdeaModuleResolverTrackerImpl>()
|
||||
?.registerModuleUpdate(newDescriptor, oldDescriptor, this)
|
||||
}
|
||||
|
||||
override fun tryGetResolverForModuleWithAnchorCheck(
|
||||
targetModuleInfo: IdeaModuleInfo,
|
||||
referencingModuleInfo: IdeaModuleInfo,
|
||||
): ResolverForModule? {
|
||||
tryGetResolverForModule(targetModuleInfo)?.let { return it }
|
||||
|
||||
val moduleDescriptorOfReferencingModule = descriptorByModule[referencingModuleInfo]?.moduleDescriptor
|
||||
?: error("$referencingModuleInfo is not contained in this resolver, which means incorrect use of anchor-aware search")
|
||||
|
||||
val anchorModuleDescriptor = anchorProvider.getAnchor(moduleDescriptorOfReferencingModule) ?: return null
|
||||
|
||||
val moduleResolverTracker =
|
||||
ModuleResolverTracker.getInstance(projectContext.project).safeAs<IdeaModuleResolverTrackerImpl>() ?: return null
|
||||
|
||||
return moduleResolverTracker.findResolverForProjectByModuleDescriptor(anchorModuleDescriptor)
|
||||
?.tryGetResolverForModule(targetModuleInfo)
|
||||
}
|
||||
}
|
||||
|
||||
interface BuiltInsCacheKey {
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent
|
||||
import com.intellij.openapi.components.State
|
||||
import com.intellij.openapi.components.Storage
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.analyzer.ModuleResolverTracker
|
||||
import org.jetbrains.kotlin.caches.project.cacheInvalidatingOnRootModifications
|
||||
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.project.*
|
||||
import org.jetbrains.kotlin.idea.project.useAnchorServices
|
||||
import org.jetbrains.kotlin.resolve.AnchorProvider
|
||||
|
||||
@State(name = "KotlinIdeAnchorService", storages = [Storage("anchors.xml")])
|
||||
class KotlinIdeAnchorService(
|
||||
val project: Project
|
||||
) : AnchorProvider(),
|
||||
PersistentStateComponent<KotlinIdeAnchorService.State> {
|
||||
|
||||
data class State(
|
||||
var moduleNameToAnchorName: Map<String, String> = emptyMap()
|
||||
)
|
||||
|
||||
@JvmField
|
||||
var myState: State = State()
|
||||
|
||||
private fun buildMapping(): Map<ModuleInfo, ModuleInfo> {
|
||||
val modulesByNames = getModuleInfosFromIdeaModel(project).associateBy { moduleInfo ->
|
||||
when (moduleInfo) {
|
||||
is LibraryInfo -> moduleInfo.library.name
|
||||
is ModuleSourceInfo -> moduleInfo.module.name
|
||||
else -> moduleInfo.name.asString()
|
||||
}
|
||||
}
|
||||
|
||||
return myState.moduleNameToAnchorName.entries.mapNotNull { (moduleName, anchorName) ->
|
||||
val module = modulesByNames[moduleName] ?: return@mapNotNull notFoundModule(moduleName)
|
||||
val anchor = modulesByNames[anchorName] ?: return@mapNotNull notFoundModule(moduleName)
|
||||
module to anchor
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
private fun notFoundModule(moduleName: String): Nothing? {
|
||||
logger<KotlinIdeAnchorService>().warn("Module <${moduleName}> not found in project model")
|
||||
return null
|
||||
}
|
||||
|
||||
private val moduleToAnchor: Map<ModuleInfo, ModuleInfo>
|
||||
get() = project.cacheInvalidatingOnRootModifications {
|
||||
buildMapping()
|
||||
}
|
||||
|
||||
private fun getAnchorModuleDescriptorIfAny(moduleInfo: ModuleInfo): ModuleDescriptor? {
|
||||
val mapped = moduleToAnchor[moduleInfo] ?: return null
|
||||
return KotlinCacheService.getInstance(project)
|
||||
.getResolutionFacadeByModuleInfo(mapped, mapped.platform)
|
||||
?.moduleDescriptor
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun getState(): State = myState
|
||||
|
||||
@Synchronized
|
||||
override fun loadState(state: State) {
|
||||
XmlSerializerUtil.copyBean(state, myState)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun getAnchor(moduleDescriptor: ModuleDescriptor): ModuleDescriptor? {
|
||||
if (!project.useAnchorServices) return null
|
||||
val resolver = ModuleResolverTracker.getInstance(project)
|
||||
.findResolverForProjectByModuleDescriptor(moduleDescriptor)
|
||||
?: return null
|
||||
return getAnchorModuleDescriptorIfAny(resolver.moduleInfoForModuleDescriptor(moduleDescriptor))
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -6,8 +6,10 @@
|
||||
package org.jetbrains.kotlin.idea.caches.resolve.util
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import org.jetbrains.kotlin.context.GlobalContextImpl
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.PlatformAnalysisSettings
|
||||
import org.jetbrains.kotlin.idea.project.useAnchorServices
|
||||
import org.jetbrains.kotlin.idea.project.useCompositeAnalysis
|
||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.storage.ExceptionTracker
|
||||
@@ -32,7 +34,7 @@ private fun GlobalContextImpl.contextWithNewLockAndCompositeExceptionTracker(deb
|
||||
}
|
||||
|
||||
internal fun GlobalContextImpl.contextWithCompositeExceptionTracker(project: Project, debugName: String): GlobalContextImpl =
|
||||
if (project.useCompositeAnalysis) {
|
||||
if (project.useCompositeAnalysis || project.useAnchorServices) {
|
||||
this.contextWithCompositeExceptionTracker(debugName)
|
||||
} else {
|
||||
this.contextWithNewLockAndCompositeExceptionTracker(debugName)
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.project
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
object KotlinAnchorSupportForLibraryAnalysisComponent {
|
||||
private const val anchorSupportOption = "kotlin.use.anchor.services"
|
||||
|
||||
@JvmStatic
|
||||
fun setState(project: Project, isEnabled: Boolean) {
|
||||
PropertiesComponent.getInstance(project).setValue(anchorSupportOption, isEnabled, false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isEnabled(project: Project): Boolean =
|
||||
PropertiesComponent.getInstance(project).getBoolean(anchorSupportOption)
|
||||
}
|
||||
|
||||
val Project.useAnchorServices: Boolean
|
||||
get() = KotlinAnchorSupportForLibraryAnalysisComponent.isEnabled(this)
|
||||
Reference in New Issue
Block a user