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
This commit is contained in:
+46
-28
@@ -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<LibraryModificationTracker>())!!
|
||||
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<VFileEvent>) {
|
||||
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<VFileEvent>) {
|
||||
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<VFileEvent>, 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
|
||||
Reference in New Issue
Block a user