1 // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.util.indexing.diagnostic.dump
4 import com.intellij.openapi.application.runReadAction
5 import com.intellij.openapi.progress.ProgressIndicator
6 import com.intellij.openapi.project.Project
7 import com.intellij.openapi.roots.impl.FilePropertyPusher
8 import com.intellij.openapi.vfs.VirtualFile
9 import com.intellij.util.containers.ConcurrentBitSet
10 import com.intellij.util.indexing.*
11 import com.intellij.util.indexing.diagnostic.dump.paths.IndexedFilePath
12 import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePaths
13 import kotlin.streams.asSequence
15 object IndexContentDiagnosticDumper {
17 fun getIndexContentDiagnostic(project: Project, indicator: ProgressIndicator): IndexContentDiagnostic {
18 val providers = (FileBasedIndex.getInstance() as FileBasedIndexImpl).getOrderedIndexableFilesProviders(project)
19 val visitedFiles = ConcurrentBitSet()
21 indicator.text = IndexingBundle.message("index.content.diagnostic.dumping")
22 indicator.isIndeterminate = false
23 indicator.fraction = 0.0
25 val indexedFilePaths = arrayListOf<IndexedFilePath>()
26 val providerNameToOriginalFileIds = hashMapOf<String, MutableSet<Int>>()
27 val filesFromUnsupportedFileSystem = arrayListOf<IndexedFilePath>()
29 for ((index, provider) in providers.withIndex()) {
30 indicator.text2 = provider.debugName
31 val providerFileIds = hashSetOf<Int>()
32 providerNameToOriginalFileIds[provider.debugName] = providerFileIds
33 provider.iterateFiles(project, { fileOrDir ->
34 if (!fileOrDir.isDirectory) {
35 val indexedFilePath = createIndexedFilePath(fileOrDir, project)
36 if (PortableFilePaths.isSupportedFileSystem(fileOrDir)) {
37 indexedFilePaths += indexedFilePath
38 providerFileIds += indexedFilePath.originalFileSystemId
41 // TODO: consider not excluding any file systems.
42 filesFromUnsupportedFileSystem += indexedFilePath
43 return@iterateFiles true
48 indicator.fraction = (index + 1).toDouble() / providers.size
50 return IndexContentDiagnostic(
52 filesFromUnsupportedFileSystem,
53 providerNameToOriginalFileIds
57 fun doesFileHaveProvidedIndex(file: VirtualFile, extension: FileBasedIndexExtension<*, *>, project: Project): Boolean {
58 val fileId = FileBasedIndex.getFileId(file)
59 return FileBasedIndexInfrastructureExtension.EP_NAME.extensions().asSequence()
60 .mapNotNull { it.createFileIndexingStatusProcessor(project) }
61 .any { it.hasIndexForFile(file, fileId, extension) }
64 fun createIndexedFilePath(fileOrDir: VirtualFile, project: Project): IndexedFilePath {
65 val fileId = FileBasedIndex.getFileId(fileOrDir)
66 val fileUrl = fileOrDir.url
67 val fileType = if (fileOrDir.isDirectory) null else fileOrDir.fileType.name
68 val substitutedFileType = if (fileOrDir.isDirectory) {
73 SubstitutedFileType.substituteFileType(fileOrDir, fileOrDir.fileType, project).name.takeIf { it != fileType }
76 val fileSize = if (fileOrDir.isDirectory) null else fileOrDir.length
77 val portableFilePath = PortableFilePaths.getPortableFilePath(fileOrDir, project)
78 val resolvedFile = PortableFilePaths.findFileByPath(portableFilePath, project)
79 val allPusherValues = dumpFilePropertyPusherValues(fileOrDir, project).mapValues { it.value?.toString() ?: "<null-value>" }
80 val indexedFilePath = IndexedFilePath(
89 check(fileUrl == resolvedFile?.url) {
91 appendln("File cannot be resolved")
92 appendln("Original URL: $fileUrl")
93 appendln("Resolved URL: ${resolvedFile?.url}")
94 appendln(indexedFilePath.toString())
97 return indexedFilePath
100 fun dumpFilePropertyPusherValues(file: VirtualFile, project: Project): Map<String, Any?> {
101 val map = hashMapOf<String, Any?>()
102 FilePropertyPusher.EP_NAME.forEachExtensionSafe { pusher ->
103 if (file.isDirectory && pusher.acceptsDirectory(file, project)
104 || !file.isDirectory && pusher.acceptsFile(file, project)
106 map[pusher.pusherName] = pusher.getImmediateValue(project, file)
112 private val FilePropertyPusher<*>.pusherName: String
113 get() = javaClass.name
114 .removePrefix("com.")
115 .removePrefix("intellij.")
116 .removePrefix("jetbrains.")
117 .replace("util.", "")
118 .replace("impl.", "")