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
|
package org.jetbrains.kotlin.idea.caches.resolve
|
||||||
|
|
||||||
import com.intellij.openapi.util.SimpleModificationTracker
|
import com.intellij.ide.highlighter.ArchiveFileType
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.components.ServiceManager
|
import com.intellij.openapi.components.ServiceManager
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
import com.intellij.openapi.project.Project
|
||||||
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.roots.ProjectFileIndex
|
import com.intellij.openapi.roots.ProjectFileIndex
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager
|
import com.intellij.openapi.util.SimpleModificationTracker
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsListener
|
import com.intellij.openapi.vfs.StandardFileSystems
|
||||||
import com.intellij.psi.PsiModifierListOwner
|
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() {
|
class LibraryModificationTracker(project: Project) : SimpleModificationTracker() {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getInstance(project: Project) = ServiceManager.getService(project, javaClass<LibraryModificationTracker>())!!
|
fun getInstance(project: Project) = ServiceManager.getService(project, LibraryModificationTracker::class.java)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val connection = project.getMessageBus().connect()
|
val connection = project.messageBus.connect()
|
||||||
connection.subscribe(VirtualFileManager.VFS_CHANGES, BulkVirtualFileListenerAdapter(
|
connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener.Adapter() {
|
||||||
object : VirtualFileAdapter() {
|
override fun after(events: List<VFileEvent>) {
|
||||||
override fun fileCreated(event: VirtualFileEvent) = processEvent(event)
|
events.filter(::isRelevantEvent).let { createEvents ->
|
||||||
override fun beforeFileMovement(event: VirtualFileMoveEvent) = processEvent(event)
|
if (createEvents.isNotEmpty()) {
|
||||||
override fun beforeContentsChange(event: VirtualFileEvent) = processEvent(event)
|
ApplicationManager.getApplication().invokeLater {
|
||||||
override fun beforeFileDeletion(event: VirtualFileEvent) = processEvent(event)
|
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) {
|
private inline fun processBulk(events: List<VFileEvent>, check: (VirtualFile) -> Boolean) {
|
||||||
if (projectFileIndex.isInLibraryClasses(event.getFile())) {
|
events.forEach { event ->
|
||||||
incModificationCount()
|
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