From 0d7ecee6eeef0b655476171dccca8ef4d98b063b Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Fri, 29 Apr 2016 14:33:46 +0200 Subject: [PATCH] Update index on definition/import files changes --- .../navigation/findDecompiledDeclaration.kt | 16 +++-- .../KotlinScriptConfigurationManager.kt | 67 ++++++++++++------- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt index 52d8cfbea2f..d8a2084bd00 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/findDecompiledDeclaration.kt @@ -77,16 +77,18 @@ private fun findCandidateDeclarationsInIndex( project: Project, referencedDescriptor: DeclarationDescriptor ): Collection { - val scope = GlobalSearchScope.union( - arrayOf( - KotlinSourceFilterScope.libraryClassFiles(GlobalSearchScope.allScope(project), project), - // NOTE: using this scope here and getNoScopeWrap below is hopefully temporary and will be removed after refactoring - // of searching logic - KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspathScope())) + val libraryClassFilesScope = KotlinSourceFilterScope.libraryClassFiles(GlobalSearchScope.allScope(project), project) + // NOTE: using this scope here and getNoScopeWrap below is hopefully temporary and will be removed after refactoring + // of searching logic + val scriptsScope = KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspathScope() + val scope = scriptsScope?.let { GlobalSearchScope.union( arrayOf(libraryClassFilesScope, it)) } ?: libraryClassFilesScope val containingClass = DescriptorUtils.getParentOfType(referencedDescriptor, ClassDescriptor::class.java, false) if (containingClass != null) { - return KotlinFullClassNameIndex.getInstance().getNoScopeWrap(containingClass.fqNameSafe.asString(), project, scope) + return if (scriptsScope != null) + KotlinFullClassNameIndex.getInstance().getNoScopeWrap(containingClass.fqNameSafe.asString(), project, scope) + else + KotlinFullClassNameIndex.getInstance().get(containingClass.fqNameSafe.asString(), project, scope) } val topLevelDeclaration = DescriptorUtils.getParentOfType(referencedDescriptor, PropertyDescriptor::class.java, false) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/script/KotlinScriptConfigurationManager.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/script/KotlinScriptConfigurationManager.kt index b6951b21b9f..17cd99649ad 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/script/KotlinScriptConfigurationManager.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/script/KotlinScriptConfigurationManager.kt @@ -19,9 +19,9 @@ package org.jetbrains.kotlin.idea.script import com.intellij.openapi.components.AbstractProjectComponent import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project -import com.intellij.openapi.vfs.StandardFileSystems -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.openapi.roots.ex.ProjectRootManagerEx +import com.intellij.openapi.util.EmptyRunnable +import com.intellij.openapi.vfs.* import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.events.VFileEvent import com.intellij.psi.search.GlobalSearchScope @@ -31,11 +31,14 @@ import org.jetbrains.kotlin.idea.caches.resolve.FileLibraryScope import org.jetbrains.kotlin.script.* import java.io.File import java.io.FileNotFoundException +import java.io.InputStream +import java.io.OutputStream @Suppress("unused") // project component class KotlinScriptConfigurationManager(private val project: Project, private val scriptDefinitionProvider: KotlinScriptDefinitionProvider, - private val scriptExtraImportsProvider: KotlinScriptExtraImportsProvider? + private val scriptExtraImportsProvider: KotlinScriptExtraImportsProvider?, + private val kotlinScriptDependenciesIndexableSetContributor: KotlinScriptDependenciesIndexableSetContributor? ) : AbstractProjectComponent(project) { private val kotlinEnvVars: Map> by lazy { generateKotlinScriptClasspathEnvVarsForIdea(myProject) } @@ -45,6 +48,7 @@ class KotlinScriptConfigurationManager(private val project: Project, val conn = myProject.messageBus.connect() conn.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() { override fun after(events: List) { + var anyScriptExtraImportsChanged = false var anyScriptDefinitionChanged = false events.filter { it is VFileEvent }.forEach { it.file?.let { @@ -54,6 +58,9 @@ class KotlinScriptConfigurationManager(private val project: Project, scriptExtraImportsProvider?.run { if (isExtraImportsConfig(it)) { invalidateExtraImports(it) + if (!anyScriptExtraImportsChanged) { + anyScriptExtraImportsChanged = true + } } } } @@ -61,17 +68,23 @@ class KotlinScriptConfigurationManager(private val project: Project, if (anyScriptDefinitionChanged) { reloadScriptDefinitions() } + if (anyScriptExtraImportsChanged) { + ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true) + } } }) } - // TODO: cache - fun getScriptClasspath(file: VirtualFile): List = - getScriptClasspathRaw(file) - .mapNotNull { StandardFileSystems.local().findFileByPath(it) } - .distinct() + private val scriptClasspathCache = hashMapOf>() + private var allScriptsClasspathCache: List? = null + + fun getScriptClasspath(file: VirtualFile): List = + scriptClasspathCache.getOrPut(file, { + getScriptClasspathRaw(file) + .mapNotNull { StandardFileSystems.local().findFileByPath(it) } + .distinct() + }) - // TODO: cache fun getAllScriptsClasspath(): List { fun VirtualFile.vfsWalkFiles(onFile: (VirtualFile) -> List?): List { assert(isDirectory) @@ -80,19 +93,26 @@ class KotlinScriptConfigurationManager(private val project: Project, else -> onFile(it) ?: emptyList() } } } - return project.baseDir.vfsWalkFiles { getScriptClasspathRaw(it) } - .distinct() - .mapNotNull { - if (File(it).isDirectory) - StandardFileSystems.local()?.findFileByPath(it) ?: throw FileNotFoundException("Classpath entry points to a non-existent location: $it") - else - StandardFileSystems.jar()?.findFileByPath(it + URLUtil.JAR_SEPARATOR) ?: throw FileNotFoundException("Classpath entry points to a file that is not a JAR archive: $it") + if (allScriptsClasspathCache == null) { + allScriptsClasspathCache = project.baseDir.vfsWalkFiles { getScriptClasspathRaw(it) } + .distinct() + .mapNotNull { + if (File(it).isDirectory) + StandardFileSystems.local()?.findFileByPath(it) ?: throw FileNotFoundException("Classpath entry points to a non-existent location: $it") + else + StandardFileSystems.jar()?.findFileByPath(it + URLUtil.JAR_SEPARATOR) ?: throw FileNotFoundException("Classpath entry points to a file that is not a JAR archive: $it") - } + } + } + return allScriptsClasspathCache!! } - fun getAllScriptsClasspathScope(): GlobalSearchScope = - GlobalSearchScope.union(getAllScriptsClasspath().map { FileLibraryScope(project, it) }.toTypedArray()) + fun getAllScriptsClasspathScope(): GlobalSearchScope? { + return getAllScriptsClasspath().let { cp -> + if (cp.isEmpty()) null + else GlobalSearchScope.union(cp.map { FileLibraryScope(project, it) }.toTypedArray()) + } + } private fun getScriptClasspathRaw(file: VirtualFile): List = scriptDefinitionProvider.findScriptDefinition(file)?.getScriptDependenciesClasspath()?.let { @@ -118,9 +138,10 @@ class KotlinScriptConfigurationManager(private val project: Project, class KotlinScriptDependenciesIndexableSetContributor : IndexableSetContributor() { - override fun getAdditionalProjectRootsToIndex(project: Project): Set = - super.getAdditionalProjectRootsToIndex(project) + - KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspath() + override fun getAdditionalProjectRootsToIndex(project: Project): Set { + return super.getAdditionalProjectRootsToIndex(project) + + KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspath() + } override fun getAdditionalRootsToIndex(): Set = emptySet() }