mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
[kotlin] KTIJ-25280 Scripts: reduce the use of Workspace Model to the platform interaction only
^KTIJ-25280 fixed GitOrigin-RevId: 5153283afaa8b272ce13ac8fdeb39bf264811d97
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d7995a972b
commit
4eb8e29c5c
@@ -12,8 +12,6 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.RootKindFilter
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.RootKindMatcher
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.isKotlinBinary
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptDependenciesSourcesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptsDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.util.isKotlinFileType
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
@@ -88,10 +86,11 @@ internal class RootKindMatcherImpl(private val project: Project) : RootKindMatch
|
||||
return true
|
||||
}
|
||||
|
||||
val classFileScope = when {
|
||||
correctedFilter.includeScriptDependencies -> getAllScriptsDependenciesClassFilesScope(project)
|
||||
else -> null
|
||||
}
|
||||
val classFileScope = when {
|
||||
correctedFilter.includeScriptDependencies -> ScriptConfigurationManager.getInstance(
|
||||
project).getAllScriptsDependenciesClassFilesScope()
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (classFileScope != null && classFileScope.contains(virtualFile)) {
|
||||
return true
|
||||
@@ -104,7 +103,9 @@ internal class RootKindMatcherImpl(private val project: Project) : RootKindMatch
|
||||
}
|
||||
|
||||
val sourceFileScope = when {
|
||||
correctedFilter.includeScriptDependencies -> getAllScriptDependenciesSourcesScope(project)
|
||||
correctedFilter.includeScriptDependencies -> ScriptConfigurationManager.getInstance(project)
|
||||
.getAllScriptDependenciesSourcesScope()
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ import org.jetbrains.kotlin.idea.base.scripting.projectStructure.ScriptModuleInf
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptRelatedModuleNameFile
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.isKotlinBinary
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptDependenciesSourcesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptsDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition
|
||||
import org.jetbrains.kotlin.utils.yieldIfNotNull
|
||||
@@ -48,7 +47,7 @@ internal class ScriptingModuleInfoProviderExtension : ModuleInfoProviderExtensio
|
||||
) {
|
||||
val isBinary = virtualFile.fileType.isKotlinBinary
|
||||
|
||||
if (isBinary && virtualFile in getAllScriptsDependenciesClassFilesScope(project)) {
|
||||
if (isBinary && virtualFile in ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFilesScope()) {
|
||||
if (isLibrarySource) {
|
||||
register(ScriptDependenciesSourceInfo.ForProject(project))
|
||||
} else {
|
||||
@@ -56,7 +55,7 @@ internal class ScriptingModuleInfoProviderExtension : ModuleInfoProviderExtensio
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBinary && virtualFile in getAllScriptDependenciesSourcesScope(project)) {
|
||||
if (!isBinary && virtualFile in ScriptConfigurationManager.getInstance(project).getAllScriptDependenciesSourcesScope()) {
|
||||
register(ScriptDependenciesSourceInfo.ForProject(project))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
|
||||
import org.jetbrains.kotlin.idea.base.scripting.ScriptingTargetPlatformDetector
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.KotlinScriptSearchScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptsDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getScriptDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.TargetPlatformVersion
|
||||
@@ -75,9 +73,10 @@ sealed class ScriptDependenciesInfo(override val project: Project) : IdeaModuleI
|
||||
get() {
|
||||
// TODO: this is not very efficient because KotlinSourceFilterScope already checks if the files are in scripts classpath
|
||||
val scriptKtFile = PsiManager.getInstance(project).findFile(scriptFile) as KtFile
|
||||
val scriptVFile = scriptKtFile.virtualFile ?: scriptKtFile.viewProvider.virtualFile
|
||||
return KotlinSourceFilterScope.libraryClasses(
|
||||
getScriptDependenciesClassFilesScope(project, scriptKtFile), project
|
||||
)
|
||||
ScriptConfigurationManager.getInstance(project).getScriptDependenciesClassFilesScope(scriptVFile), project
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +89,8 @@ sealed class ScriptDependenciesInfo(override val project: Project) : IdeaModuleI
|
||||
|
||||
override val contentScope: GlobalSearchScope
|
||||
get() {
|
||||
return KotlinSourceFilterScope.libraryClasses(getAllScriptsDependenciesClassFilesScope(project), project)
|
||||
return KotlinSourceFilterScope.libraryClasses(
|
||||
ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFilesScope(), project)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.IdeaModuleInfo
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.SourceForBinaryModuleInfo
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.scope.KotlinSourceFilterScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptDependenciesSourcesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
@@ -26,7 +26,7 @@ sealed class ScriptDependenciesSourceInfo(override val project: Project) : IdeaM
|
||||
// include project sources because script dependencies sources may contain roots from project
|
||||
// the main example is buildSrc for *.gradle.kts files
|
||||
override fun sourceScope(): GlobalSearchScope = KotlinSourceFilterScope.projectAndLibrarySources(
|
||||
getAllScriptDependenciesSourcesScope(project), project
|
||||
ScriptConfigurationManager.getInstance(project).getAllScriptDependenciesSourcesScope(), project
|
||||
)
|
||||
|
||||
override fun hashCode() = project.hashCode()
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModel
|
||||
import org.jetbrains.kotlin.analysis.project.structure.*
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
@@ -13,10 +12,6 @@ import org.jetbrains.kotlin.idea.base.projectStructure.KtModuleByModuleInfoBase
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.KtModuleFactory
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.toKtModuleOfType
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptId
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRootTypeId
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.listDependencies
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.scriptsAsEntities
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.nio.file.Path
|
||||
|
||||
@@ -79,15 +74,6 @@ private class KtScriptDependencyModuleByModuleInfo(
|
||||
.map { it.toNioPath() }
|
||||
}
|
||||
is ScriptDependenciesInfo.ForFile -> {
|
||||
if (scriptsAsEntities) {
|
||||
val entityStorage = WorkspaceModel.getInstance(project).currentSnapshot
|
||||
val scriptEntity = entityStorage.resolve(KotlinScriptId(moduleInfo.scriptFile.path))
|
||||
if (scriptEntity != null) {
|
||||
return scriptEntity.listDependencies(project, KotlinScriptLibraryRootTypeId.COMPILED)
|
||||
.map { it.toNioPath() }
|
||||
}
|
||||
}
|
||||
|
||||
return ScriptConfigurationManager.getInstance(project)
|
||||
.getScriptDependenciesClassFiles(moduleInfo.scriptFile)
|
||||
.map { it.toNioPath() }
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import com.intellij.openapi.util.Condition
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaFullClassNameIndex
|
||||
import com.intellij.psi.search.EverythingGlobalScope
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.stubs.StubIndex
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.util.CommonProcessors
|
||||
import com.intellij.util.Processor
|
||||
import com.intellij.util.containers.ConcurrentFactoryMap
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.KotlinScriptMarkerFileSystem
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.computeClassRoots
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.scriptsAsEntities
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinSafeClassFinder
|
||||
|
||||
internal class KotlinScriptDependenciesClassFinder(private val project: Project) : NonClasspathClassFinder(project), KotlinSafeClassFinder {
|
||||
private val useOnlyForScripts = Registry.`is`("kotlin.resolve.scripting.limit.dependency.element.finder", true)
|
||||
|
||||
/*
|
||||
PsiElementFinder's are global and can be called for any context.
|
||||
As 'KotlinScriptDependenciesClassFinder' is meant to provide additional dependencies only for scripts,
|
||||
we need to know if the caller came from a script resolution context.
|
||||
|
||||
We are doing so by checking if the given scope contains a synthetic 'KotlinScriptMarkerFileSystem.rootFile'.
|
||||
Normally, only global scopes and 'KotlinScriptScope' contains such a file.
|
||||
*/
|
||||
private fun isApplicable(scope: GlobalSearchScope): Boolean =
|
||||
!scriptsAsEntities && (!useOnlyForScripts || scope.contains(KotlinScriptMarkerFileSystem.rootFile))
|
||||
|
||||
override fun getClassRoots(scope: GlobalSearchScope?): List<VirtualFile> {
|
||||
if (scriptsAsEntities) return super.getClassRoots(scope)
|
||||
var result = super.getClassRoots(scope)
|
||||
if (scope is EverythingGlobalScope) {
|
||||
result = result + KotlinScriptMarkerFileSystem.rootFile
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun calcClassRoots(): List<VirtualFile> = if (scriptsAsEntities) emptyList() else computeClassRoots(project)
|
||||
|
||||
private val everywhereCache = CachedValuesManager.getManager(project).createCachedValue {
|
||||
CachedValueProvider.Result.create(
|
||||
ConcurrentFactoryMap.createMap { qualifiedName: String ->
|
||||
findClassNotCached(qualifiedName, GlobalSearchScope.everythingScope(project))
|
||||
},
|
||||
ScriptDependenciesModificationTracker.getInstance(project),
|
||||
PsiModificationTracker.MODIFICATION_COUNT,
|
||||
ProjectRootModificationTracker.getInstance(project),
|
||||
VirtualFileManager.getInstance()
|
||||
)
|
||||
}
|
||||
|
||||
override fun findClass(qualifiedName: String, scope: GlobalSearchScope): PsiClass? {
|
||||
return if (isApplicable(scope)) everywhereCache.value[qualifiedName]?.takeIf { isInScope(it, scope) } else null
|
||||
}
|
||||
|
||||
private fun findClassNotCached(qualifiedName: String, scope: GlobalSearchScope): PsiClass? {
|
||||
val topLevelClass = super.findClass(qualifiedName, scope)
|
||||
if (topLevelClass != null && isInScope(topLevelClass, scope)) {
|
||||
return topLevelClass
|
||||
}
|
||||
|
||||
// The following code is needed because NonClasspathClassFinder cannot find inner classes
|
||||
// JavaFullClassNameIndex cannot be used directly, because it filters only classes in source roots
|
||||
|
||||
val processor = QualifiedClassNameProcessor(qualifiedName)
|
||||
|
||||
StubIndex.getInstance().processElements(
|
||||
JavaFullClassNameIndex.getInstance().key,
|
||||
qualifiedName,
|
||||
project,
|
||||
scope.takeUnless { it is EverythingGlobalScope },
|
||||
PsiClass::class.java,
|
||||
processor
|
||||
)
|
||||
|
||||
return processor.foundValue?.takeIf { isInScope(it, scope) }
|
||||
}
|
||||
|
||||
private fun isInScope(clazz: PsiClass, scope: GlobalSearchScope): Boolean {
|
||||
if (scope is EverythingGlobalScope) {
|
||||
return true
|
||||
}
|
||||
|
||||
val file = clazz.containingFile?.virtualFile ?: return false
|
||||
val index = ProjectFileIndex.getInstance(myProject)
|
||||
return !index.isInContent(file) && !index.isInLibrary(file) && scope.contains(file)
|
||||
}
|
||||
|
||||
override fun findClasses(qualifiedName: String, scope: GlobalSearchScope): Array<PsiClass> =
|
||||
if (isApplicable(scope)) super.findClasses(qualifiedName, scope) else emptyArray()
|
||||
|
||||
override fun getSubPackages(psiPackage: PsiPackage, scope: GlobalSearchScope): Array<PsiPackage> =
|
||||
if (isApplicable(scope)) super.getSubPackages(psiPackage, scope) else emptyArray()
|
||||
|
||||
override fun getClasses(psiPackage: PsiPackage, scope: GlobalSearchScope): Array<PsiClass> =
|
||||
if (isApplicable(scope)) super.getClasses(psiPackage, scope) else emptyArray()
|
||||
|
||||
override fun getPackageFiles(psiPackage: PsiPackage, scope: GlobalSearchScope): Array<PsiFile> =
|
||||
if (isApplicable(scope)) super.getPackageFiles(psiPackage, scope) else emptyArray()
|
||||
|
||||
override fun getPackageFilesFilter(psiPackage: PsiPackage, scope: GlobalSearchScope): Condition<PsiFile>? =
|
||||
if (isApplicable(scope)) super.getPackageFilesFilter(psiPackage, scope) else null
|
||||
|
||||
override fun getClassNames(psiPackage: PsiPackage, scope: GlobalSearchScope): Set<String> =
|
||||
if (isApplicable(scope)) super.getClassNames(psiPackage, scope) else emptySet()
|
||||
|
||||
override fun processPackageDirectories(
|
||||
psiPackage: PsiPackage, scope: GlobalSearchScope,
|
||||
consumer: Processor<in PsiDirectory>, includeLibrarySources: Boolean
|
||||
): Boolean = if (isApplicable(scope)) super.processPackageDirectories(psiPackage, scope, consumer, includeLibrarySources) else true
|
||||
|
||||
private class QualifiedClassNameProcessor(private val qualifiedName: String): CommonProcessors.FindFirstProcessor<PsiClass>() {
|
||||
override fun accept(t: PsiClass?): Boolean {
|
||||
return t?.qualifiedName == qualifiedName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,8 +22,6 @@ class KotlinScriptExternalLibrariesNodesProvider: ExternalLibrariesWorkspaceMode
|
||||
override fun getWorkspaceClass(): Class<KotlinScriptEntity> = KotlinScriptEntity::class.java
|
||||
|
||||
override fun createNode(entity: KotlinScriptEntity, project: Project, settings: ViewSettings?): AbstractTreeNode<*>? {
|
||||
if (!scriptsAsEntities) return null
|
||||
|
||||
val dependencies = entity.listDependencies(project)
|
||||
val path = entity.path
|
||||
val scriptFile = VirtualFileManager.getInstance().findFileByNioPath(Path.of(path))
|
||||
|
||||
@@ -55,9 +55,6 @@ internal class IdeScriptDependenciesProvider(project: Project) : ScriptDependenc
|
||||
}
|
||||
|
||||
/**
|
||||
* **Please, note** that [ScriptConfigurationManager] should not be used directly.
|
||||
* Instead, consider using [org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptImplementationSwitcher].
|
||||
*
|
||||
* Facade for loading and caching Kotlin script files configuration.
|
||||
*
|
||||
* This service also starts indexing of new dependency roots and runs highlighting
|
||||
@@ -126,12 +123,6 @@ interface ScriptConfigurationManager {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): ScriptConfigurationManager = project.service()
|
||||
|
||||
@JvmStatic
|
||||
fun allExtraRoots(project: Project): Collection<VirtualFile> {
|
||||
val manager = getInstance(project)
|
||||
return manager.getAllScriptsDependenciesClassFiles() + manager.getAllScriptDependenciesSources()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun compositeScriptConfigurationManager(project: Project) =
|
||||
getInstance(project).cast<CompositeScriptConfigurationManager>()
|
||||
|
||||
@@ -11,14 +11,14 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.PsiShortNamesCache
|
||||
import com.intellij.psi.stubs.StubIndex
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptsDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
|
||||
// Allow searching java classes in jars in script dependencies, this is needed for stuff like completion and autoimport
|
||||
class JavaClassesInScriptDependenciesShortNameCache(private val project: Project) : PsiShortNamesCache() {
|
||||
override fun getAllClassNames() = emptyArray<String>()
|
||||
|
||||
override fun getClassesByName(name: String, scope: GlobalSearchScope): Array<out PsiClass> {
|
||||
val classpathScope = getAllScriptsDependenciesClassFilesScope(project)
|
||||
val classpathScope = ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFilesScope()
|
||||
val classes = StubIndex.getElements(
|
||||
JavaShortClassNameIndex.getInstance().key, name, project, classpathScope.intersectWith(scope), PsiClass::class.java
|
||||
)
|
||||
|
||||
@@ -2,28 +2,17 @@
|
||||
package org.jetbrains.kotlin.idea.core.script.dependencies
|
||||
|
||||
import com.intellij.java.workspaceModel.fileIndex.JvmPackageRootData
|
||||
import com.intellij.navigation.ItemPresentation
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.AdditionalLibraryRootsProvider
|
||||
import com.intellij.openapi.roots.SyntheticLibrary
|
||||
import com.intellij.openapi.roots.impl.CustomEntityProjectModelInfoProvider
|
||||
import com.intellij.openapi.roots.impl.CustomEntityProjectModelInfoProvider.LibraryRoots
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.workspaceModel.core.fileIndex.WorkspaceFileIndexContributor
|
||||
import com.intellij.workspaceModel.core.fileIndex.WorkspaceFileKind
|
||||
import com.intellij.workspaceModel.core.fileIndex.WorkspaceFileSetRegistrar
|
||||
import com.intellij.workspaceModel.core.fileIndex.impl.ModuleOrLibrarySourceRootData
|
||||
import com.intellij.workspaceModel.ide.virtualFile
|
||||
import com.intellij.workspaceModel.storage.EntityStorage
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryEntity
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptLibraryRootTypeId
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.scriptsAsEntities
|
||||
import javax.swing.Icon
|
||||
|
||||
/**
|
||||
* See recommendations for custom entities indexing
|
||||
@@ -39,7 +28,7 @@ class KotlinScriptProjectModelInfoProvider : CustomEntityProjectModelInfoProvide
|
||||
entities: Sequence<KotlinScriptLibraryEntity>,
|
||||
entityStorage: EntityStorage
|
||||
): Sequence<LibraryRoots<KotlinScriptLibraryEntity>> =
|
||||
if (!scriptsAsEntities || useWorkspaceFileContributor()) { // see KotlinScriptDependenciesLibraryRootProvider
|
||||
if (useWorkspaceFileContributor()) { // see KotlinScriptDependenciesLibraryRootProvider
|
||||
emptySequence()
|
||||
} else {
|
||||
entities.map { libEntity ->
|
||||
@@ -59,7 +48,7 @@ class KotlinScriptWorkspaceFileIndexContributor : WorkspaceFileIndexContributor<
|
||||
get() = KotlinScriptLibraryEntity::class.java
|
||||
|
||||
override fun registerFileSets(entity: KotlinScriptLibraryEntity, registrar: WorkspaceFileSetRegistrar, storage: EntityStorage) {
|
||||
if (!scriptsAsEntities || !useWorkspaceFileContributor()) return // see KotlinScriptDependenciesLibraryRootProvider
|
||||
if (!useWorkspaceFileContributor()) return // see KotlinScriptDependenciesLibraryRootProvider
|
||||
val (classes, sources) = entity.roots.partition { it.type == KotlinScriptLibraryRootTypeId.COMPILED }
|
||||
classes.forEach {
|
||||
registrar.registerFileSet(it.url, WorkspaceFileKind.EXTERNAL, entity, RootData)
|
||||
@@ -76,95 +65,3 @@ class KotlinScriptWorkspaceFileIndexContributor : WorkspaceFileIndexContributor<
|
||||
private object RootSourceData : JvmPackageRootData, ModuleOrLibrarySourceRootData
|
||||
}
|
||||
|
||||
class KotlinScriptDependenciesLibraryRootProvider : AdditionalLibraryRootsProvider() {
|
||||
|
||||
override fun getAdditionalProjectLibraries(project: Project): Collection<SyntheticLibrary> { // RootIndex & FileBasedIndexEx need it
|
||||
if (scriptsAsEntities) return emptyList() // see KotlinScriptProjectModelInfoProvider
|
||||
|
||||
val manager = ScriptConfigurationManager.getInstance(project)
|
||||
val classes = manager.getAllScriptsDependenciesClassFiles().filterValid()
|
||||
val sources = manager.getAllScriptDependenciesSources().filterValid()
|
||||
val sdkClasses = manager.getAllScriptsSdkDependenciesClassFiles().filterValid()
|
||||
val sdkSources = manager.getAllScriptSdkDependenciesSources().filterValid()
|
||||
return if (classes.isEmpty() && sources.isEmpty() && sdkClasses.isEmpty() && sdkSources.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
val library = KotlinScriptDependenciesLibrary(classes = classes, sources = sources)
|
||||
if (sdkClasses.isEmpty() && sdkSources.isEmpty()) {
|
||||
listOf(library)
|
||||
} else {
|
||||
listOf(ScriptSdk(manager.getFirstScriptsSdk(), sdkClasses, sdkSources), library)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<VirtualFile>.filterValid() = this.filterTo(LinkedHashSet(), VirtualFile::isValid)
|
||||
|
||||
override fun getRootsToWatch(project: Project): Collection<VirtualFile> = if (scriptsAsEntities) {
|
||||
emptyList()
|
||||
} else {
|
||||
ScriptConfigurationManager.allExtraRoots(project).filterValid()
|
||||
}
|
||||
|
||||
abstract class AbstractDependenciesLibrary(
|
||||
private val id: String,
|
||||
val classes: Collection<VirtualFile>,
|
||||
val sources: Collection<VirtualFile>
|
||||
) :
|
||||
SyntheticLibrary(id, null), ItemPresentation {
|
||||
|
||||
protected val gradle: Boolean by lazy { classes.hasGradleDependency() }
|
||||
|
||||
override fun getBinaryRoots(): Collection<VirtualFile> = classes
|
||||
|
||||
override fun getSourceRoots(): Collection<VirtualFile> = sources
|
||||
|
||||
override fun getIcon(unused: Boolean): Icon = if (gradle) {
|
||||
KotlinIcons.GRADLE_SCRIPT
|
||||
} else {
|
||||
KotlinIcons.SCRIPT
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as AbstractDependenciesLibrary
|
||||
|
||||
return id == other.id && classes == other.classes && sources == other.sources
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return 31 * classes.hashCode() + sources.hashCode()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private class KotlinScriptDependenciesLibrary(classes: Collection<VirtualFile>, sources: Collection<VirtualFile>) :
|
||||
AbstractDependenciesLibrary("KotlinScriptDependenciesLibrary", classes, sources) {
|
||||
|
||||
override fun getPresentableText(): String =
|
||||
if (gradle) {
|
||||
KotlinBaseScriptingBundle.message("script.name.gradle.script.dependencies")
|
||||
} else {
|
||||
KotlinBaseScriptingBundle.message("script.name.kotlin.script.dependencies")
|
||||
}
|
||||
}
|
||||
|
||||
private class ScriptSdk(val sdk: Sdk?, classes: Collection<VirtualFile>, sources: Collection<VirtualFile>) :
|
||||
AbstractDependenciesLibrary("ScriptSdk", classes, sources) {
|
||||
|
||||
override fun getPresentableText(): String =
|
||||
if (gradle) {
|
||||
sdk?.let { KotlinBaseScriptingBundle.message("script.name.gradle.script.sdk.dependencies.0", it.name) }
|
||||
?: KotlinBaseScriptingBundle.message("script.name.gradle.script.sdk.dependencies")
|
||||
} else {
|
||||
sdk?.let { KotlinBaseScriptingBundle.message("script.name.kotlin.script.sdk.dependencies.0", it.name) }
|
||||
?: KotlinBaseScriptingBundle.message("script.name.kotlin.script.sdk.dependencies")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Collection<VirtualFile>.hasGradleDependency() = any { it.name.contains("gradle") }
|
||||
@@ -13,7 +13,7 @@ import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfoOrNull
|
||||
import org.jetbrains.kotlin.idea.base.scripting.projectStructure.ScriptModuleInfo
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getScriptDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.util.isKotlinFileType
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
@@ -82,8 +82,9 @@ class KotlinScriptResolveScopeProvider : ResolveScopeProvider() {
|
||||
if (scriptDefinition is ScriptDefinition.FromConfigurationsBase ||
|
||||
scriptDefinition.asLegacyOrNull<KotlinScriptDefinitionFromAnnotatedTemplate>() != null
|
||||
) {
|
||||
val dependenciesScope = getScriptDependenciesClassFilesScope(project, ktFile)
|
||||
return KotlinScriptSearchScope(project, GlobalSearchScope.fileScope(project, file).uniteWith(dependenciesScope))
|
||||
val vFile = ktFile.virtualFile ?: ktFile.viewProvider.virtualFile
|
||||
val dependenciesScope = ScriptConfigurationManager.getInstance(project).getScriptDependenciesClassFilesScope(vFile)
|
||||
return KotlinScriptSearchScope(project, GlobalSearchScope.fileScope(project, file).uniteWith(dependenciesScope))
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -6,12 +6,8 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.ResolveScopeProvider
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.NonClasspathDirectoriesScope
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.moduleInfo.SdkInfo
|
||||
import org.jetbrains.kotlin.idea.base.projectStructure.scope.KotlinSourceFilterScope
|
||||
import org.jetbrains.kotlin.idea.base.scripting.projectStructure.ScriptDependenciesInfo
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.*
|
||||
|
||||
/**
|
||||
* @see KotlinScriptResolveScopeProvider
|
||||
@@ -29,32 +25,14 @@ class ScriptDependenciesResolveScopeProvider : ResolveScopeProvider() {
|
||||
- multiple editors can be opened (selected is only one of them)
|
||||
*/
|
||||
|
||||
if (getAllScriptsDependenciesClassFiles(project).isEmpty()) return null
|
||||
if (ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFiles().isEmpty()) return null
|
||||
|
||||
if (file !in getAllScriptsDependenciesClassFilesScope(project)
|
||||
&& file !in getAllScriptDependenciesSourcesScope(project)
|
||||
if (file !in ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFilesScope()
|
||||
&& file !in ScriptConfigurationManager.getInstance(project).getAllScriptDependenciesSourcesScope()
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (scriptsAsEntities) {
|
||||
val scripts = file.findDependentScripts(project) ?: return null
|
||||
val dependencies = scripts.flatMap { it.listDependencies(project, KotlinScriptLibraryRootTypeId.COMPILED) }.distinct()
|
||||
|
||||
var searchScope = GlobalSearchScope.union(
|
||||
arrayOf(
|
||||
GlobalSearchScope.fileScope(project, file),
|
||||
KotlinSourceFilterScope.libraryClasses(NonClasspathDirectoriesScope.compose(dependencies), project)
|
||||
)
|
||||
)
|
||||
|
||||
ScriptConfigurationManager.getInstance(project).getFirstScriptsSdk()?.let {
|
||||
searchScope = searchScope.uniteWith(SdkInfo(project, it).contentScope)
|
||||
}
|
||||
|
||||
return searchScope
|
||||
}
|
||||
|
||||
val scope = GlobalSearchScope.union(
|
||||
arrayOf(
|
||||
GlobalSearchScope.fileScope(project, file),
|
||||
|
||||
@@ -7,8 +7,7 @@ import com.intellij.psi.PsiClassOwner
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.compiled.*
|
||||
import com.intellij.psi.util.MethodSignatureUtil
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptDependenciesSources
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.getAllScriptsDependenciesClassFilesScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class ScriptDependencySourceNavigationPolicyForJavaClasses : ClsCustomNavigationPolicy {
|
||||
@@ -38,12 +37,12 @@ class ScriptDependencySourceNavigationPolicyForJavaClasses : ClsCustomNavigation
|
||||
val project = file.project
|
||||
val sourceFileName = file.classes.firstOrNull()?.safeAs<ClsClassImpl>()?.sourceFileName ?: return null
|
||||
|
||||
if (virtualFile !in getAllScriptsDependenciesClassFilesScope(project)) return null
|
||||
if (virtualFile !in ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFilesScope()) return null
|
||||
|
||||
val packageName = file.packageName
|
||||
val relativePath = if (packageName.isEmpty()) sourceFileName else packageName.replace('.', '/') + '/' + sourceFileName
|
||||
|
||||
for (root in getAllScriptDependenciesSources(project).filter { it.isValid }) {
|
||||
for (root in ScriptConfigurationManager.getInstance(project).getAllScriptDependenciesSources().filter { it.isValid }) {
|
||||
val sourceFile = root.findFileByRelativePath(relativePath)
|
||||
if (sourceFile != null && sourceFile.isValid) {
|
||||
val sourcePsi = file.manager.findFile(sourceFile)
|
||||
|
||||
@@ -101,7 +101,7 @@ class ScriptClassRootsCache(
|
||||
return HeavyScriptInfo(configuration, roots, compose(roots), sdk)
|
||||
}
|
||||
|
||||
return if (sdk == null || scriptsAsEntities) {
|
||||
return if (sdk == null) {
|
||||
heavyInfoForRoots(vfsRoots)
|
||||
} else {
|
||||
val sdkClasses = sdk.rootProvider.getFiles(OrderRootType.CLASSES).toList()
|
||||
|
||||
@@ -12,10 +12,8 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.project.ProjectManagerListener
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.AdditionalLibraryRootsListener
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import com.intellij.util.applyIf
|
||||
@@ -23,14 +21,10 @@ import com.intellij.util.ui.EDT.isCurrentThreadEdt
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModel
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.kotlin.idea.base.scripting.KotlinBaseScriptingBundle
|
||||
import org.jetbrains.kotlin.idea.base.util.CheckCanceledLock
|
||||
import org.jetbrains.kotlin.idea.core.KotlinPluginDisposable
|
||||
import org.jetbrains.kotlin.idea.core.script.KotlinScriptDependenciesClassFinder
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker
|
||||
import org.jetbrains.kotlin.idea.core.script.configuration.CompositeScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.hasGradleDependency
|
||||
import org.jetbrains.kotlin.idea.core.script.scriptingDebugLog
|
||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||
import org.jetbrains.kotlin.idea.util.FirPluginOracleService
|
||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
||||
@@ -208,71 +202,36 @@ abstract class ScriptClassRootsUpdater(
|
||||
|
||||
if (disposable.disposed) return
|
||||
|
||||
if (scriptsAsEntities) { // (updates.changed && !updates.hasNewRoots)
|
||||
val manager = VirtualFileManager.getInstance()
|
||||
val updatedScriptPaths = when (updates) {
|
||||
is ScriptClassRootsCache.IncrementalUpdates -> updates.updatedScripts
|
||||
else -> updates.cache.scriptsPaths()
|
||||
}
|
||||
|
||||
updatedScriptPaths.takeUnless { it.isEmpty() }?.asSequence()
|
||||
?.map {
|
||||
val byNioPath = manager.findFileByNioPath(Paths.get(it))
|
||||
if (byNioPath == null) { // e.g. jupyter notebooks have their .kts in memory only
|
||||
val path = it.applyIf(it.startsWith("/")) { it.replaceFirst("/", "") }
|
||||
LightVirtualFile(path)
|
||||
} else {
|
||||
byNioPath
|
||||
}
|
||||
}
|
||||
?.let { updatedScriptFiles ->
|
||||
val actualScriptPaths = updates.cache.scriptsPaths()
|
||||
val (filesToAddOrUpdate, filesToRemove) = updatedScriptFiles.partition { actualScriptPaths.contains(it.path) }
|
||||
|
||||
// Here we're sometimes under read-lock.
|
||||
// There is no way to acquire write-lock (on EDT) without releasing this thread.
|
||||
|
||||
applyDiffToModelAsync(filesToAddOrUpdate, filesToRemove)
|
||||
}
|
||||
val manager = VirtualFileManager.getInstance()
|
||||
val updatedScriptPaths = when (updates) {
|
||||
is ScriptClassRootsCache.IncrementalUpdates -> updates.updatedScripts
|
||||
else -> updates.cache.scriptsPaths()
|
||||
}
|
||||
|
||||
updatedScriptPaths.takeUnless { it.isEmpty() }?.asSequence()
|
||||
?.map {
|
||||
val byNioPath = manager.findFileByNioPath(Paths.get(it))
|
||||
if (byNioPath == null) { // e.g. jupyter notebooks have their .kts in memory only
|
||||
val path = it.applyIf(it.startsWith("/")) { it.replaceFirst("/", "") }
|
||||
LightVirtualFile(path)
|
||||
} else {
|
||||
byNioPath
|
||||
}
|
||||
}
|
||||
?.let { updatedScriptFiles ->
|
||||
val actualScriptPaths = updates.cache.scriptsPaths()
|
||||
val (filesToAddOrUpdate, filesToRemove) = updatedScriptFiles.partition { actualScriptPaths.contains(it.path) }
|
||||
|
||||
// Here we're sometimes under read-lock.
|
||||
// There is no way to acquire write-lock (on EDT) without releasing this thread.
|
||||
|
||||
applyDiffToModelAsync(filesToAddOrUpdate, filesToRemove)
|
||||
}
|
||||
|
||||
if (updates.hasNewRoots) {
|
||||
runInEdt(ModalityState.NON_MODAL) {
|
||||
runWriteAction {
|
||||
if (project.isDisposed) return@runWriteAction
|
||||
|
||||
if (!scriptsAsEntities) {
|
||||
scriptingDebugLog { "kotlin.script.dependencies from ${updates.oldRoots} to ${updates.newRoots}" }
|
||||
|
||||
val hasGradleDependency = updates.newSdkRoots.hasGradleDependency() || updates.newRoots.hasGradleDependency()
|
||||
val dependencySdkLibraryName = if (hasGradleDependency) {
|
||||
KotlinBaseScriptingBundle.message("script.name.gradle.script.sdk.dependencies")
|
||||
} else {
|
||||
KotlinBaseScriptingBundle.message("script.name.kotlin.script.sdk.dependencies")
|
||||
}
|
||||
|
||||
AdditionalLibraryRootsListener.fireAdditionalLibraryChanged(
|
||||
project,
|
||||
dependencySdkLibraryName,
|
||||
updates.oldSdkRoots,
|
||||
updates.newSdkRoots,
|
||||
dependencySdkLibraryName
|
||||
)
|
||||
|
||||
val dependencyLibraryName = if (hasGradleDependency) {
|
||||
KotlinBaseScriptingBundle.message("script.name.gradle.script.dependencies")
|
||||
} else {
|
||||
KotlinBaseScriptingBundle.message("script.name.kotlin.script.dependencies")
|
||||
}
|
||||
AdditionalLibraryRootsListener.fireAdditionalLibraryChanged(
|
||||
project,
|
||||
dependencyLibraryName,
|
||||
updates.oldRoots,
|
||||
updates.newRoots,
|
||||
dependencyLibraryName
|
||||
)
|
||||
}
|
||||
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
}
|
||||
}
|
||||
@@ -281,11 +240,6 @@ abstract class ScriptClassRootsUpdater(
|
||||
runReadAction {
|
||||
if (project.isDisposed) return@runReadAction
|
||||
|
||||
if (!scriptsAsEntities) {
|
||||
PsiElementFinder.EP.findExtensionOrFail(KotlinScriptDependenciesClassFinder::class.java, project).clearCache()
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
}
|
||||
|
||||
if (updates.hasUpdatedScripts) {
|
||||
updateHighlighting(project) { file -> updates.isScriptChanged(file.path) }
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ package org.jetbrains.kotlin.idea.core.script.ucache
|
||||
import com.intellij.ide.scratch.ScratchUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.ProjectRootManager
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import com.intellij.util.applyIf
|
||||
@@ -126,6 +125,58 @@ private fun KotlinScriptEntity.debugInfo(storage: EntityStorage): String {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused") // exists for debug purposes
|
||||
private fun managerScriptsDebugInfo(project: Project, scriptFiles: Sequence<VirtualFile>? = null): String = buildString {
|
||||
val configurationManager = ScriptConfigurationManager.getInstance(project)
|
||||
|
||||
val allSourcesSize = configurationManager.getAllScriptDependenciesSources().size
|
||||
val allSdkSourcesSize = configurationManager.getAllScriptSdkDependenciesSources().size
|
||||
|
||||
val allClassesSize = configurationManager.getAllScriptsDependenciesClassFiles().size
|
||||
val allSdkClassesSize = configurationManager.getAllScriptsSdkDependenciesClassFiles().size
|
||||
|
||||
scriptFiles?.forEach {
|
||||
val classDepSize = configurationManager.getScriptDependenciesClassFiles(it).size
|
||||
val sourceDepSize = configurationManager.getScriptDependenciesSourceFiles(it).size
|
||||
append("[${it.path}]: classes: ${classDepSize}, sources: ${sourceDepSize}\n")
|
||||
}
|
||||
insert(
|
||||
0,
|
||||
"==> ScriptConfigurationManager (classes: $allClassesSize, sdkClasses: $allSdkClassesSize, sources: $allSourcesSize, sdkSources: $allSdkSourcesSize)\n"
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("unused") // exists for debug purposes
|
||||
private fun scriptEntitiesDebugInfo(project: Project, listRoots: Boolean = false): String {
|
||||
fun List<KotlinScriptLibraryRoot>.print(indent: CharSequence = " ") = asSequence()
|
||||
.mapIndexed { i, root -> "$indent${i + 1}: ${root.url.presentableUrl}" }
|
||||
.joinToString("\n", indent)
|
||||
|
||||
return buildString {
|
||||
val entityStorage = WorkspaceModel.getInstance(project).currentSnapshot
|
||||
|
||||
val allClasses = HashSet<KotlinScriptLibraryRoot>()
|
||||
val allSources = HashSet<KotlinScriptLibraryRoot>()
|
||||
|
||||
entityStorage.entities(KotlinScriptEntity::class.java).forEachIndexed { scriptIndex, scriptEntity ->
|
||||
append("#${scriptIndex + 1}: [${scriptEntity.path}]\n")
|
||||
scriptEntity.dependencies.forEachIndexed dependencies@{ libIndex, libId ->
|
||||
val lib = entityStorage.resolve(libId) ?: return@dependencies
|
||||
|
||||
val (classes, sources) = lib.roots.partition { it.type == KotlinScriptLibraryRootTypeId.COMPILED }
|
||||
allClasses.addAll(classes)
|
||||
allSources.addAll(sources)
|
||||
append(" Lib #${libIndex + 1}: \"${lib.name}\", classes: ${classes.size}, sources: ${sources.size} \n")
|
||||
applyIf(listRoots) {
|
||||
append(" Classes:\n ${classes.print()}\n")
|
||||
append(" Sources:\n ${sources.print()}\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insert(0, "==> WorkspaceModel (unique classes: ${allClasses.size}, sources: ${allSources.size})\n")
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableEntityStorage.syncScriptEntities(
|
||||
scriptFilesToAddOrUpdate: List<VirtualFile>,
|
||||
@@ -244,7 +295,6 @@ private fun MutableEntityStorage.getActualScriptLibraries(scriptFile: VirtualFil
|
||||
|
||||
libraries.fillWithFiles(project, dependenciesClassFiles, dependenciesSourceFiles)
|
||||
libraries.fillWithIdeSpecificDependencies(project, scriptFile)
|
||||
libraries.fillWithSdkDependencies(project, scriptFile)
|
||||
|
||||
val mergedLibraries = libraries.mergeClassAndSourceRoots()
|
||||
|
||||
@@ -289,19 +339,6 @@ private fun MutableList<KotlinScriptLibraryEntity>.fillWithIdeSpecificDependenci
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<KotlinScriptLibraryEntity>.fillWithSdkDependencies(project: Project, scriptFile: VirtualFile) {
|
||||
val configurationManager = ScriptConfigurationManager.getInstance(project)
|
||||
|
||||
val scriptSdk = configurationManager.getScriptSdk(scriptFile)
|
||||
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
|
||||
|
||||
if (scriptSdk?.homePath != projectSdk?.homePath) {
|
||||
val sdkClassFiles = configurationManager.getScriptSdkDependenciesClassFiles(scriptFile)
|
||||
val sdkSourceFiles = configurationManager.getScriptSdkDependenciesSourceFiles(scriptFile)
|
||||
fillWithFiles(project, sdkClassFiles, sdkSourceFiles)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinScriptLibraryEntity.hasSameRootsAs(dependency: KotlinScriptLibraryEntity): Boolean =
|
||||
this.roots.containsAll(dependency.roots) && dependency.roots.containsAll(this.roots)
|
||||
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.core.script.ucache
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.search.NonClasspathDirectoriesScope
|
||||
import com.intellij.util.applyIf
|
||||
import com.intellij.workspaceModel.ide.WorkspaceModel
|
||||
import com.intellij.workspaceModel.storage.EntityStorage
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
const val KOTLIN_SCRIPTS_AS_ENTITIES = "kotlin.scripts.as.entities"
|
||||
|
||||
val scriptsAsEntities: Boolean
|
||||
get() = Registry.`is`(KOTLIN_SCRIPTS_AS_ENTITIES, true)
|
||||
|
||||
|
||||
/**
|
||||
* ScriptConfigurationManager or WorkspaceModel based on 'scriptsAsEntities'
|
||||
*/
|
||||
|
||||
fun getScriptDependenciesClassFilesScope(project: Project, ktFile: KtFile): GlobalSearchScope {
|
||||
val vFile = ktFile.virtualFile ?: ktFile.viewProvider.virtualFile
|
||||
require(ktFile.isScript()) { "argument must be a script: ${vFile.path}" }
|
||||
|
||||
return if (scriptsAsEntities) {
|
||||
val entityStorage = WorkspaceModel.getInstance(project).currentSnapshot
|
||||
val scriptEntity = entityStorage.resolve(KotlinScriptId(vFile.path))
|
||||
|
||||
if (scriptEntity == null) {
|
||||
// WorkspaceModel doesn't know about the file yet. But once the latest sync is over it will.
|
||||
// We cannot synchronously call its syncScriptEntities() because it requires platform write-lock acquisition and this function
|
||||
// is called under platform read-lock.
|
||||
ScriptConfigurationManager.getInstance(project).getScriptDependenciesClassFilesScope(vFile)
|
||||
} else {
|
||||
NonClasspathDirectoriesScope.compose(scriptEntity.listDependencies(project, KotlinScriptLibraryRootTypeId.COMPILED))
|
||||
}
|
||||
} else {
|
||||
ScriptConfigurationManager.getInstance(project).getScriptDependenciesClassFilesScope(vFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllScriptsDependenciesClassFilesScope(project: Project): GlobalSearchScope =
|
||||
// calculation based on WS model is inefficient and leads to freezes
|
||||
ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFilesScope()
|
||||
|
||||
fun getAllScriptDependenciesSourcesScope(project: Project): GlobalSearchScope =
|
||||
// calculation based on WS model is inefficient and leads to freezes
|
||||
ScriptConfigurationManager.getInstance(project).getAllScriptDependenciesSourcesScope()
|
||||
|
||||
fun getAllScriptsDependenciesClassFiles(project: Project): Collection<VirtualFile> =
|
||||
// calculation based on WS model is inefficient and leads to delays
|
||||
ScriptConfigurationManager.getInstance(project).getAllScriptsDependenciesClassFiles()
|
||||
|
||||
fun getAllScriptDependenciesSources(project: Project): Collection<VirtualFile> =
|
||||
// calculation based on WS model is inefficient and leads to freezes
|
||||
ScriptConfigurationManager.getInstance(project).getAllScriptDependenciesSources()
|
||||
|
||||
fun computeClassRoots(project: Project): List<VirtualFile> {
|
||||
return if (scriptsAsEntities) {
|
||||
val entityStorage = WorkspaceModel.getInstance(project).currentSnapshot
|
||||
entityStorage.listDependenciesOfAllScriptEntities(project, KotlinScriptLibraryRootTypeId.COMPILED).toList()
|
||||
} else {
|
||||
val manager = ScriptConfigurationManager.getInstance(project)
|
||||
(manager.getAllScriptsDependenciesClassFiles() + manager.getAllScriptsSdkDependenciesClassFiles()).filter { it.isValid }
|
||||
}
|
||||
}
|
||||
|
||||
private fun EntityStorage.listDependenciesOfAllScriptEntities(
|
||||
project: Project,
|
||||
rootTypeId: KotlinScriptLibraryRootTypeId
|
||||
): Collection<VirtualFile> =
|
||||
entities(KotlinScriptEntity::class.java)
|
||||
.flatMap { it.listDependencies(project, rootTypeId) }
|
||||
.toSet()
|
||||
|
||||
@Suppress("unused") // exists for debug purposes
|
||||
internal fun scriptEntitiesDebugInfo(project: Project, listRoots: Boolean = false): String {
|
||||
fun List<KotlinScriptLibraryRoot>.print(indent: CharSequence = " ") = asSequence()
|
||||
.mapIndexed { i, root -> "$indent${i + 1}: ${root.url.presentableUrl}" }
|
||||
.joinToString("\n", indent)
|
||||
|
||||
return buildString {
|
||||
val entityStorage = WorkspaceModel.getInstance(project).currentSnapshot
|
||||
|
||||
val allClasses = HashSet<KotlinScriptLibraryRoot>()
|
||||
val allSources = HashSet<KotlinScriptLibraryRoot>()
|
||||
|
||||
entityStorage.entities(KotlinScriptEntity::class.java).forEachIndexed { scriptIndex, scriptEntity ->
|
||||
append("#${scriptIndex + 1}: [${scriptEntity.path}]\n")
|
||||
scriptEntity.dependencies.forEachIndexed { libIndex, libId ->
|
||||
val lib = entityStorage.resolve(libId) ?: return@forEachIndexed
|
||||
|
||||
val (classes, sources) = lib.roots.partition { it.type == KotlinScriptLibraryRootTypeId.COMPILED }
|
||||
allClasses.addAll(classes)
|
||||
allSources.addAll(sources)
|
||||
append(" Lib #${libIndex + 1}: \"${lib.name}\", classes: ${classes.size}, sources: ${sources.size} \n")
|
||||
applyIf(listRoots) {
|
||||
append(" Classes:\n ${classes.print()}\n")
|
||||
append(" Sources:\n ${sources.print()}\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insert(0, "==> WorkspaceModel (unique classes: ${allClasses.size}, sources: ${allSources.size})\n")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused") // exists for debug purposes
|
||||
internal fun managerScriptsDebugInfo(project: Project, scriptFiles: Sequence<VirtualFile>? = null): String = buildString {
|
||||
val configurationManager = ScriptConfigurationManager.getInstance(project)
|
||||
|
||||
val allSourcesSize = configurationManager.getAllScriptDependenciesSources().size
|
||||
val allSdkSourcesSize = configurationManager.getAllScriptSdkDependenciesSources().size
|
||||
|
||||
val allClassesSize = configurationManager.getAllScriptsDependenciesClassFiles().size
|
||||
val allSdkClassesSize = configurationManager.getAllScriptsSdkDependenciesClassFiles().size
|
||||
|
||||
scriptFiles?.forEach {
|
||||
val classDepSize = configurationManager.getScriptDependenciesClassFiles(it).size
|
||||
val sourceDepSize = configurationManager.getScriptDependenciesSourceFiles(it).size
|
||||
append("[${it.path}]: classes: ${classDepSize}, sources: ${sourceDepSize}\n")
|
||||
}
|
||||
insert(
|
||||
0,
|
||||
"==> ScriptConfigurationManager (classes: $allClassesSize, sdkClasses: $allSdkClassesSize, sources: $allSourcesSize, sdkSources: $allSdkSourcesSize)\n"
|
||||
)
|
||||
}
|
||||
@@ -5,7 +5,6 @@ package org.jetbrains.kotlin.idea.codeInsight.gradle
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.testFramework.runInEdtAndWait
|
||||
@@ -13,7 +12,6 @@ import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ucache.KOTLIN_SCRIPTS_AS_ENTITIES
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.plugins.gradle.extensions.cloneWithCorruptedRoots
|
||||
import org.jetbrains.plugins.gradle.extensions.rootsFiles
|
||||
@@ -21,44 +19,10 @@ import org.jetbrains.plugins.gradle.extensions.rootsUrls
|
||||
import org.jetbrains.plugins.gradle.tooling.annotation.TargetVersions
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExternalResource
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
abstract class GradleBuildFileHighlightingTest : KotlinGradleImportingTestCase() {
|
||||
|
||||
companion object {
|
||||
private val GRADLE_VERSION_AND_SCRIPT_FLAG = SUPPORTED_GRADLE_VERSIONS
|
||||
.map { listOf(arrayOf(it, false), arrayOf(it, true)) }
|
||||
.flatten()
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("ACCIDENTAL_OVERRIDE")
|
||||
@Parameterized.Parameters(name = "{index}: with Gradle-{0}, scriptsAsEntities-{1}")
|
||||
fun testInputData(): List<Array<out Any>> = GRADLE_VERSION_AND_SCRIPT_FLAG
|
||||
}
|
||||
|
||||
|
||||
@JvmField
|
||||
@Parameterized.Parameter(1)
|
||||
var scriptsAsEntities: Boolean? = null
|
||||
|
||||
@JvmField
|
||||
@Rule
|
||||
val setRegistryFlag = RegistryFlagRule()
|
||||
|
||||
inner class RegistryFlagRule : ExternalResource() {
|
||||
override fun before() {
|
||||
Registry.get(KOTLIN_SCRIPTS_AS_ENTITIES).setValue(scriptsAsEntities!!)
|
||||
}
|
||||
|
||||
override fun after() {
|
||||
Registry.get(KOTLIN_SCRIPTS_AS_ENTITIES).resetToDefault()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KtsInJsProject2114 : GradleBuildFileHighlightingTest() {
|
||||
@TargetVersions("4.8 <=> 6.0")
|
||||
@Test
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.intellij.build.SyncViewManager
|
||||
import com.intellij.build.events.BuildEvent
|
||||
import com.intellij.build.events.MessageEvent
|
||||
import com.intellij.build.events.impl.MessageEventImpl
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.replaceService
|
||||
@@ -58,8 +57,6 @@ abstract class GradleKtsImportTest : KotlinGradleImportingTestCase() {
|
||||
@Test
|
||||
@TargetVersions("6.0.1+")
|
||||
fun testWorkspaceModelInSyncAfterImport() {
|
||||
Registry.get("kotlin.scripts.as.entities").setValue(true)
|
||||
|
||||
configureByFiles()
|
||||
importProject()
|
||||
|
||||
@@ -71,7 +68,6 @@ abstract class GradleKtsImportTest : KotlinGradleImportingTestCase() {
|
||||
val ktsFile = KtsFixture(fileName).virtualFile
|
||||
|
||||
val (managerClassFiles, managerSourceFiles) = getDependenciesFromManager(ktsFile)
|
||||
val (sdkClasses, sdkSources) = getSdkDependencies(ktsFile)
|
||||
|
||||
val entityStorage = WorkspaceModel.getInstance(myProject).currentSnapshot
|
||||
val scriptEntity = entityStorage.entities(KotlinScriptEntity::class.java).find { it.path.contains(fileName) }
|
||||
@@ -80,8 +76,8 @@ abstract class GradleKtsImportTest : KotlinGradleImportingTestCase() {
|
||||
val entityClassFiles = scriptEntity.listDependencies(myProject, KotlinScriptLibraryRootTypeId.COMPILED)
|
||||
val entitySourceFiles = scriptEntity.listDependencies(myProject, KotlinScriptLibraryRootTypeId.SOURCES)
|
||||
|
||||
assertEquals("Class dependencies for $fileName are not equivalent", entityClassFiles, managerClassFiles + sdkClasses)
|
||||
assertEquals("Source dependencies for $fileName are not equivalent", entitySourceFiles, managerSourceFiles + sdkSources)
|
||||
assertEquals("Class dependencies for $fileName are not equivalent", entityClassFiles, managerClassFiles)
|
||||
assertEquals("Source dependencies for $fileName are not equivalent", entitySourceFiles, managerSourceFiles)
|
||||
}
|
||||
|
||||
// classes, sources
|
||||
@@ -90,13 +86,6 @@ abstract class GradleKtsImportTest : KotlinGradleImportingTestCase() {
|
||||
val managerSourceFiles = scriptConfigurationManager.getScriptDependenciesSourceFiles(file)
|
||||
return Pair(managerClassFiles, managerSourceFiles)
|
||||
}
|
||||
|
||||
// classes, sources
|
||||
private fun getSdkDependencies(file: VirtualFile): Pair<Collection<VirtualFile>, Collection<VirtualFile>> {
|
||||
val managerClassFiles = scriptConfigurationManager.getScriptSdkDependenciesClassFiles(file)
|
||||
val managerSourceFiles = scriptConfigurationManager.getScriptSdkDependenciesSourceFiles(file)
|
||||
return Pair(managerClassFiles, managerSourceFiles)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ class RegisteredFindersTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
|
||||
fun testKnownNonClasspathFinder() {
|
||||
val expectedFindersNames = setOf(
|
||||
"GantClassFinder",
|
||||
"KotlinScriptDependenciesClassFinder"
|
||||
"GantClassFinder"
|
||||
).toMutableSet()
|
||||
|
||||
val optionalFindersNames = setOf(
|
||||
|
||||
@@ -414,7 +414,6 @@ fun checkExtract(files: ExtractTestFiles, checkAdditionalAfterdata: Boolean = fa
|
||||
try {
|
||||
runInEdtAndWait {
|
||||
runReadAction {
|
||||
// To make extraction work in `kotlin.scripts.as.entities=true` mode it's crucial to load dependencies in advance
|
||||
ScriptConfigurationManager.updateScriptDependenciesSynchronously(files.mainFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,11 +57,8 @@
|
||||
|
||||
<postStartupActivity implementation="org.jetbrains.kotlin.idea.core.script.LoadScriptDefinitionsStartupActivity" order="last"/>
|
||||
|
||||
<java.elementFinder implementation="org.jetbrains.kotlin.idea.core.script.KotlinScriptDependenciesClassFinder" order="last"/>
|
||||
|
||||
<java.shortNamesCache implementation="org.jetbrains.kotlin.idea.core.script.dependencies.JavaClassesInScriptDependenciesShortNameCache"/>
|
||||
|
||||
<additionalLibraryRootsProvider implementation="org.jetbrains.kotlin.idea.core.script.dependencies.KotlinScriptDependenciesLibraryRootProvider"/>
|
||||
|
||||
<psi.clsCustomNavigationPolicy implementation="org.jetbrains.kotlin.idea.core.script.dependencies.ScriptDependencySourceNavigationPolicyForJavaClasses"/>
|
||||
|
||||
@@ -82,12 +79,6 @@
|
||||
<!--suppress PluginXmlValidity -->
|
||||
<indexableEntityProvider implementation="org.jetbrains.kotlin.idea.core.script.ucache.KotlinScriptDependencyIndexableEntityProvider"/>
|
||||
|
||||
<registryKey
|
||||
key="kotlin.scripts.as.entities"
|
||||
description="Enables explicit script dependencies support"
|
||||
defaultValue="true"
|
||||
restartRequired="true"/>
|
||||
|
||||
<registryKey
|
||||
key="kotlin.scripting.support.warning"
|
||||
description="Show Kotlin scripting support warning"
|
||||
|
||||
Reference in New Issue
Block a user