Update index on definition/import files changes

This commit is contained in:
Ilya Chernikov
2016-04-29 14:33:46 +02:00
parent 1a98c5eb0e
commit 0d7ecee6ee
2 changed files with 53 additions and 30 deletions
@@ -77,16 +77,18 @@ private fun findCandidateDeclarationsInIndex(
project: Project, project: Project,
referencedDescriptor: DeclarationDescriptor referencedDescriptor: DeclarationDescriptor
): Collection<KtDeclaration?> { ): Collection<KtDeclaration?> {
val scope = GlobalSearchScope.union( val libraryClassFilesScope = KotlinSourceFilterScope.libraryClassFiles(GlobalSearchScope.allScope(project), project)
arrayOf<GlobalSearchScope>( // NOTE: using this scope here and getNoScopeWrap below is hopefully temporary and will be removed after refactoring
KotlinSourceFilterScope.libraryClassFiles(GlobalSearchScope.allScope(project), project), // of searching logic
// NOTE: using this scope here and getNoScopeWrap below is hopefully temporary and will be removed after refactoring val scriptsScope = KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspathScope()
// of searching logic val scope = scriptsScope?.let { GlobalSearchScope.union( arrayOf(libraryClassFilesScope, it)) } ?: libraryClassFilesScope
KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspathScope()))
val containingClass = DescriptorUtils.getParentOfType(referencedDescriptor, ClassDescriptor::class.java, false) val containingClass = DescriptorUtils.getParentOfType(referencedDescriptor, ClassDescriptor::class.java, false)
if (containingClass != null) { 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) val topLevelDeclaration = DescriptorUtils.getParentOfType(referencedDescriptor, PropertyDescriptor::class.java, false)
@@ -19,9 +19,9 @@ package org.jetbrains.kotlin.idea.script
import com.intellij.openapi.components.AbstractProjectComponent import com.intellij.openapi.components.AbstractProjectComponent
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.roots.ex.ProjectRootManagerEx
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.util.EmptyRunnable
import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.*
import com.intellij.openapi.vfs.newvfs.BulkFileListener import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.VFileEvent import com.intellij.openapi.vfs.newvfs.events.VFileEvent
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
@@ -31,11 +31,14 @@ import org.jetbrains.kotlin.idea.caches.resolve.FileLibraryScope
import org.jetbrains.kotlin.script.* import org.jetbrains.kotlin.script.*
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.InputStream
import java.io.OutputStream
@Suppress("unused") // project component @Suppress("unused") // project component
class KotlinScriptConfigurationManager(private val project: Project, class KotlinScriptConfigurationManager(private val project: Project,
private val scriptDefinitionProvider: KotlinScriptDefinitionProvider, private val scriptDefinitionProvider: KotlinScriptDefinitionProvider,
private val scriptExtraImportsProvider: KotlinScriptExtraImportsProvider? private val scriptExtraImportsProvider: KotlinScriptExtraImportsProvider?,
private val kotlinScriptDependenciesIndexableSetContributor: KotlinScriptDependenciesIndexableSetContributor?
) : AbstractProjectComponent(project) { ) : AbstractProjectComponent(project) {
private val kotlinEnvVars: Map<String, List<String>> by lazy { generateKotlinScriptClasspathEnvVarsForIdea(myProject) } private val kotlinEnvVars: Map<String, List<String>> by lazy { generateKotlinScriptClasspathEnvVarsForIdea(myProject) }
@@ -45,6 +48,7 @@ class KotlinScriptConfigurationManager(private val project: Project,
val conn = myProject.messageBus.connect() val conn = myProject.messageBus.connect()
conn.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() { conn.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() {
override fun after(events: List<VFileEvent>) { override fun after(events: List<VFileEvent>) {
var anyScriptExtraImportsChanged = false
var anyScriptDefinitionChanged = false var anyScriptDefinitionChanged = false
events.filter { it is VFileEvent }.forEach { events.filter { it is VFileEvent }.forEach {
it.file?.let { it.file?.let {
@@ -54,6 +58,9 @@ class KotlinScriptConfigurationManager(private val project: Project,
scriptExtraImportsProvider?.run { scriptExtraImportsProvider?.run {
if (isExtraImportsConfig(it)) { if (isExtraImportsConfig(it)) {
invalidateExtraImports(it) invalidateExtraImports(it)
if (!anyScriptExtraImportsChanged) {
anyScriptExtraImportsChanged = true
}
} }
} }
} }
@@ -61,17 +68,23 @@ class KotlinScriptConfigurationManager(private val project: Project,
if (anyScriptDefinitionChanged) { if (anyScriptDefinitionChanged) {
reloadScriptDefinitions() reloadScriptDefinitions()
} }
if (anyScriptExtraImportsChanged) {
ProjectRootManagerEx.getInstanceEx(project)?.makeRootsChange(EmptyRunnable.getInstance(), false, true)
}
} }
}) })
} }
// TODO: cache private val scriptClasspathCache = hashMapOf<VirtualFile, List<VirtualFile>>()
fun getScriptClasspath(file: VirtualFile): List<VirtualFile> = private var allScriptsClasspathCache: List<VirtualFile>? = null
getScriptClasspathRaw(file)
.mapNotNull { StandardFileSystems.local().findFileByPath(it) } fun getScriptClasspath(file: VirtualFile): List<VirtualFile> =
.distinct() scriptClasspathCache.getOrPut(file, {
getScriptClasspathRaw(file)
.mapNotNull { StandardFileSystems.local().findFileByPath(it) }
.distinct()
})
// TODO: cache
fun getAllScriptsClasspath(): List<VirtualFile> { fun getAllScriptsClasspath(): List<VirtualFile> {
fun<R> VirtualFile.vfsWalkFiles(onFile: (VirtualFile) -> List<R>?): List<R> { fun<R> VirtualFile.vfsWalkFiles(onFile: (VirtualFile) -> List<R>?): List<R> {
assert(isDirectory) assert(isDirectory)
@@ -80,19 +93,26 @@ class KotlinScriptConfigurationManager(private val project: Project,
else -> onFile(it) ?: emptyList() else -> onFile(it) ?: emptyList()
} } } }
} }
return project.baseDir.vfsWalkFiles { getScriptClasspathRaw(it) } if (allScriptsClasspathCache == null) {
.distinct() allScriptsClasspathCache = project.baseDir.vfsWalkFiles { getScriptClasspathRaw(it) }
.mapNotNull { .distinct()
if (File(it).isDirectory) .mapNotNull {
StandardFileSystems.local()?.findFileByPath(it) ?: throw FileNotFoundException("Classpath entry points to a non-existent location: $it") if (File(it).isDirectory)
else StandardFileSystems.local()?.findFileByPath(it) ?: throw FileNotFoundException("Classpath entry points to a non-existent location: $it")
StandardFileSystems.jar()?.findFileByPath(it + URLUtil.JAR_SEPARATOR) ?: throw FileNotFoundException("Classpath entry points to a file that is not a JAR archive: $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 = fun getAllScriptsClasspathScope(): GlobalSearchScope? {
GlobalSearchScope.union(getAllScriptsClasspath().map { FileLibraryScope(project, it) }.toTypedArray()) return getAllScriptsClasspath().let { cp ->
if (cp.isEmpty()) null
else GlobalSearchScope.union(cp.map { FileLibraryScope(project, it) }.toTypedArray())
}
}
private fun getScriptClasspathRaw(file: VirtualFile): List<String> = private fun getScriptClasspathRaw(file: VirtualFile): List<String> =
scriptDefinitionProvider.findScriptDefinition(file)?.getScriptDependenciesClasspath()?.let { scriptDefinitionProvider.findScriptDefinition(file)?.getScriptDependenciesClasspath()?.let {
@@ -118,9 +138,10 @@ class KotlinScriptConfigurationManager(private val project: Project,
class KotlinScriptDependenciesIndexableSetContributor : IndexableSetContributor() { class KotlinScriptDependenciesIndexableSetContributor : IndexableSetContributor() {
override fun getAdditionalProjectRootsToIndex(project: Project): Set<VirtualFile> = override fun getAdditionalProjectRootsToIndex(project: Project): Set<VirtualFile> {
super.getAdditionalProjectRootsToIndex(project) + return super.getAdditionalProjectRootsToIndex(project) +
KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspath() KotlinScriptConfigurationManager.getInstance(project).getAllScriptsClasspath()
}
override fun getAdditionalRootsToIndex(): Set<VirtualFile> = emptySet() override fun getAdditionalRootsToIndex(): Set<VirtualFile> = emptySet()
} }