mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-250821 fix ModuleFilesIteratorImpl misses files under inner CONTENT_NON_INDEXABLE filesets
WorkspaceFileIndexImpl.processContentUnderDirectory calls getFileInfo to find filesets. It searches for both CONTENT and CONTENT_NON_INDEXABLE filesets However, ModuleFilesIteratorImpl passes fileset filter, checking that filesets belong to the module. When inner non-indexable root does not belong to the module (almost always), the iterator skip file as not indexable, instead of taking it (cherry picked from commit e7e69a64d85b0426175376ec5a4cc4796d00da1a) GitOrigin-RevId: 260a2a9503338bd83fdc11d4d818854cb7f0d09f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d6ff41aa4e
commit
febef8303a
@@ -16,8 +16,12 @@ import com.intellij.workspaceModel.core.fileIndex.WorkspaceFileIndex.Companion.g
|
||||
import com.intellij.workspaceModel.core.fileIndex.WorkspaceFileSetWithCustomData
|
||||
import com.intellij.workspaceModel.core.fileIndex.impl.ModuleRelatedRootData
|
||||
import com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexEx
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.VisibleForTesting
|
||||
|
||||
internal class ModuleFilesIteratorImpl(
|
||||
@ApiStatus.Internal
|
||||
@VisibleForTesting
|
||||
class ModuleFilesIteratorImpl(
|
||||
private val module: Module,
|
||||
private val root: VirtualFile,
|
||||
private val recursive: Boolean,
|
||||
@@ -61,7 +65,12 @@ internal class ModuleFilesIteratorImpl(
|
||||
val myWorkspaceFileIndex = getInstance(project) as WorkspaceFileIndexEx
|
||||
|
||||
return if (recursive) {
|
||||
iterateContentUnderDirectory(root, processorEx, fileFilter, myWorkspaceFileIndex)
|
||||
val customFilter = VirtualFileFilter { file ->
|
||||
val info = myWorkspaceFileIndex.getFileInfo(file, true, true, false, false, false ,false, false)
|
||||
info.findFileSet { it.kind.isIndexable && (it.data as? ModuleRelatedRootData)?.module == module } != null
|
||||
}.and(fileFilter) // run `fileFilter` second, so if it is deduplication filter, it won't be invoked on files outside module
|
||||
val fileSetFilter: (WorkspaceFileSetWithCustomData<*>) -> Boolean = { fileSet -> !isScopeDisposed() && fileSet.kind.isContent }
|
||||
myWorkspaceFileIndex.processContentUnderDirectory(root, processorEx, customFilter, fileSetFilter)
|
||||
}
|
||||
else {
|
||||
fileFilter.accept(root) && processorEx.processFileEx(root) != TreeNodeProcessingResult.STOP
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.roots.impl.indexing
|
||||
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.readAction
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.roots.ContentIterator
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileFilter
|
||||
import com.intellij.platform.backend.workspace.toVirtualFileUrl
|
||||
import com.intellij.platform.backend.workspace.workspaceModel
|
||||
import com.intellij.platform.workspace.jps.entities.ContentRootEntity
|
||||
import com.intellij.platform.workspace.jps.entities.ModuleEntity
|
||||
import com.intellij.platform.workspace.storage.url.VirtualFileUrl
|
||||
import com.intellij.testFramework.IndexingTestUtil
|
||||
import com.intellij.testFramework.junit5.TestApplication
|
||||
import com.intellij.testFramework.rules.ProjectModelExtension
|
||||
import com.intellij.testFramework.rules.TempDirectoryExtension
|
||||
import com.intellij.testFramework.workspaceModel.update
|
||||
import com.intellij.util.indexing.roots.IndexableFilesIterator
|
||||
import com.intellij.util.indexing.roots.ModuleFilesIteratorImpl
|
||||
import com.intellij.util.indexing.testEntities.NonIndexableKindFileSetTestContributor
|
||||
import com.intellij.util.indexing.testEntities.NonIndexableTestEntity
|
||||
import com.intellij.workspaceModel.core.fileIndex.impl.WorkspaceFileIndexImpl
|
||||
import com.intellij.workspaceModel.ide.NonPersistentEntitySource
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
|
||||
@TestApplication
|
||||
internal class ModuleFilesIteratorImplTest {
|
||||
@RegisterExtension
|
||||
private val projectModel = ProjectModelExtension()
|
||||
|
||||
@RegisterExtension
|
||||
private val tempDir = TempDirectoryExtension()
|
||||
|
||||
|
||||
private val disposable: Disposable get() = projectModel.disposableRule.disposable
|
||||
|
||||
private val project get() = projectModel.project
|
||||
private val workspaceModel get() = project.workspaceModel
|
||||
private val virtualFileUrlManager get() = workspaceModel.getVirtualFileUrlManager()
|
||||
|
||||
private lateinit var module: Module
|
||||
private lateinit var moduleRoot: VirtualFile
|
||||
private lateinit var innerRoot: VirtualFile
|
||||
|
||||
@BeforeEach
|
||||
fun setUp(): Unit = runBlocking {
|
||||
WorkspaceFileIndexImpl.EP_NAME.point.registerExtension(NonIndexableKindFileSetTestContributor(), disposable)
|
||||
|
||||
moduleRoot = tempDir.newVirtualDirectory("root")
|
||||
tempDir.newVirtualFile("root/root.txt")
|
||||
innerRoot = tempDir.newVirtualDirectory("root/inner")
|
||||
tempDir.newVirtualFile("root/inner/inner.txt")
|
||||
|
||||
workspaceModel.update { storage ->
|
||||
storage.addEntity(ModuleEntity("module", emptyList(), NonPersistentEntitySource) {
|
||||
contentRoots = listOf(ContentRootEntity(moduleRoot.toVirtualFileUrl(), emptyList(), NonPersistentEntitySource))
|
||||
})
|
||||
}
|
||||
|
||||
IndexingTestUtil.waitUntilIndexesAreReady(project)
|
||||
|
||||
module = ModuleManager.getInstance(project).modules.single()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterates module root without an inner non-indexable fileset`(): Unit = runBlocking {
|
||||
assertIteratesModuleRoot()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `iterates module root with an inner non-indexable fileset`(): Unit = runBlocking {
|
||||
workspaceModel.update { storage ->
|
||||
storage.addEntity(NonIndexableTestEntity(innerRoot.toVirtualFileUrl(), NonPersistentEntitySource))
|
||||
}
|
||||
IndexingTestUtil.waitUntilIndexesAreReady(project)
|
||||
|
||||
assertIteratesModuleRoot()
|
||||
}
|
||||
|
||||
private suspend fun assertIteratesModuleRoot() {
|
||||
val files = readAction {
|
||||
val result = mutableListOf<VirtualFile>()
|
||||
val fullyProcessed = moduleFilesIterator().iterateFiles(
|
||||
project,
|
||||
ContentIterator { file ->
|
||||
result.add(file)
|
||||
true
|
||||
},
|
||||
VirtualFileFilter.ALL,
|
||||
)
|
||||
assertThat(fullyProcessed).isTrue()
|
||||
result
|
||||
}
|
||||
|
||||
assertThat(relativePaths(files)).containsExactlyInAnyOrder("", "root.txt", "inner", "inner/inner.txt")
|
||||
}
|
||||
|
||||
private fun moduleFilesIterator(): IndexableFilesIterator =
|
||||
ModuleFilesIteratorImpl(module, moduleRoot, true, true)
|
||||
|
||||
private fun relativePaths(files: Collection<VirtualFile>): Set<String> {
|
||||
return files.mapTo(linkedSetOf()) { file ->
|
||||
VfsUtilCore.getRelativePath(file, moduleRoot, '/') ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun VirtualFile.toVirtualFileUrl(): VirtualFileUrl = this.toVirtualFileUrl(virtualFileUrlManager)
|
||||
}
|
||||
Reference in New Issue
Block a user