From 55006872a1c2cf7ff9d218c3f2d78b3ffd0c07e0 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Mon, 19 Oct 2015 19:24:26 +0300 Subject: [PATCH] LibraryModificationTracker Do not track external annotations Make use of BulkFileListener to avoid processing extra files Defer library classes check for newly created files: fixes a problem of indices not being updated at the time Correctly check if the file is a jar file root of a library Ther latter 2 changes fix a problem where resolve caches were not recomputed in case of deleting and readding jar files of a library --- .../resolve/LibraryModificationTracker.kt | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LibraryModificationTracker.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LibraryModificationTracker.kt index 2093291a402..1763439a6c5 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LibraryModificationTracker.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/LibraryModificationTracker.kt @@ -16,51 +16,69 @@ package org.jetbrains.kotlin.idea.caches.resolve -import com.intellij.openapi.util.SimpleModificationTracker -import com.intellij.openapi.project.Project +import com.intellij.ide.highlighter.ArchiveFileType +import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.vfs.VirtualFileManager -import com.intellij.openapi.vfs.impl.BulkVirtualFileListenerAdapter -import com.intellij.openapi.vfs.VirtualFileAdapter -import com.intellij.openapi.vfs.VirtualFileEvent -import com.intellij.openapi.vfs.VirtualFileMoveEvent +import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectFileIndex -import com.intellij.codeInsight.ExternalAnnotationsManager -import com.intellij.codeInsight.ExternalAnnotationsListener -import com.intellij.psi.PsiModifierListOwner +import com.intellij.openapi.util.SimpleModificationTracker +import com.intellij.openapi.vfs.StandardFileSystems +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.openapi.vfs.newvfs.BulkFileListener +import com.intellij.openapi.vfs.newvfs.events.VFileCopyEvent +import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent +import com.intellij.openapi.vfs.newvfs.events.VFileEvent +import com.intellij.openapi.vfs.newvfs.events.VFileMoveEvent class LibraryModificationTracker(project: Project) : SimpleModificationTracker() { companion object { @JvmStatic - fun getInstance(project: Project) = ServiceManager.getService(project, javaClass())!! + fun getInstance(project: Project) = ServiceManager.getService(project, LibraryModificationTracker::class.java)!! } init { - val connection = project.getMessageBus().connect() - connection.subscribe(VirtualFileManager.VFS_CHANGES, BulkVirtualFileListenerAdapter( - object : VirtualFileAdapter() { - override fun fileCreated(event: VirtualFileEvent) = processEvent(event) - override fun beforeFileMovement(event: VirtualFileMoveEvent) = processEvent(event) - override fun beforeContentsChange(event: VirtualFileEvent) = processEvent(event) - override fun beforeFileDeletion(event: VirtualFileEvent) = processEvent(event) + val connection = project.messageBus.connect() + connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() { + override fun after(events: List) { + events.filter(::isRelevantEvent).let { createEvents -> + if (createEvents.isNotEmpty()) { + ApplicationManager.getApplication().invokeLater { + processBulk(createEvents) { + projectFileIndex.isInLibraryClasses(it) || isLibraryArchiveRoot(it) + } + } + } } - )) - - connection.subscribe(ExternalAnnotationsManager.TOPIC, object : ExternalAnnotationsListener { - override fun afterExternalAnnotationChanging(owner: PsiModifierListOwner, annotationFQName: String, successful: Boolean) { - if (successful) incModificationCount() } - override fun externalAnnotationsChangedExternally() = incModificationCount() + override fun before(events: List) { + processBulk(events) { + projectFileIndex.isInLibraryClasses(it) + } + } }) } - val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + private val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) - fun processEvent(event: VirtualFileEvent) { - if (projectFileIndex.isInLibraryClasses(event.getFile())) { - incModificationCount() + private inline fun processBulk(events: List, check: (VirtualFile) -> Boolean) { + events.forEach { event -> + val file = event.file + if (file != null && check(file)) { + incModificationCount() + return + } } } + + // if library points to a jar, the jar does not pass isInLibraryClasses check, so we have to perform additional check for this case + private fun isLibraryArchiveRoot(virtualFile: VirtualFile): Boolean { + if (virtualFile.fileType != ArchiveFileType.INSTANCE) return false + + val archiveRoot = StandardFileSystems.getJarRootForLocalFile(virtualFile) ?: return false + return projectFileIndex.isInLibraryClasses(archiveRoot) + } } +private fun isRelevantEvent(vFileEvent: VFileEvent) = vFileEvent is VFileCreateEvent || vFileEvent is VFileMoveEvent || vFileEvent is VFileCopyEvent \ No newline at end of file