diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/IndexDataComparer.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/IndexDataComparer.kt new file mode 100644 index 000000000000..e5c9d453d357 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/IndexDataComparer.kt @@ -0,0 +1,102 @@ +package com.intellij.util.indexing.diagnostic.dump.output + +import com.intellij.psi.stubs.* + +object IndexDataComparer { + + fun areValuesTheSame(currentValue: V, storedValue: V): Boolean { + return if (currentValue is SerializedStubTree) { + areStubTreesTheSame(storedValue as SerializedStubTree, currentValue as SerializedStubTree) + } + else { + currentValue == storedValue + } + } + + private fun areStubTreesTheSame( + expectedTree: SerializedStubTree, + actualTree: SerializedStubTree + ): Boolean { + if (!areStubsTheSame(expectedTree.stub, actualTree.stub)) { + return false + } + + val expectedForwardIndex: MutableMap, MutableMap> = expectedTree.stubIndicesValueMap + val actualForwardIndex: Map, Map> = actualTree.stubIndicesValueMap + + // StubIndexKey-s don't have equals()\hashCode() implementations, so we have to compare them by names. + // Create helper mappings from names to StubIndexKey-s preserving the keys identity. + val expectedStubIndexKeyNameToKey: Map> = expectedForwardIndex.keys.associateBy { it.name } + val actualStubIndexKeyNameToKey: Map> = actualForwardIndex.keys.associateBy { it.name } + if (expectedStubIndexKeyNameToKey.keys != actualStubIndexKeyNameToKey.keys) { + return false + } + + for (keyName in expectedStubIndexKeyNameToKey.keys) { + val expectedStubIndexKey = expectedStubIndexKeyNameToKey.getValue(keyName) + val actualStubIndexKey = actualStubIndexKeyNameToKey.getValue(keyName) + + val expectedKeyValues: Map = expectedForwardIndex.getValue(expectedStubIndexKey) + val actualKeyValues: Map = actualForwardIndex.getValue(actualStubIndexKey) + if (expectedKeyValues.size != actualKeyValues.size) { + return false + } + + // Do not use .equals() to compare [oneKeyValues] and [twoKeyValues] + // Their internal implementation is THashMap + // with customized [TObjectHashingStrategy] for keys. + // But [THashMap.equals()] does not check equality + // via the [TObjectHashingStrategy.equals()] but uses the standard Object.equals(). + // Thus, we need to manually check for each key of the first map that the same key + // in the second map is present (and under the hood the hashing equality will be taken into account). + for ((expectedKey: Any, expectedStubList: StubIdList) in expectedKeyValues) { + val actualStubList = actualKeyValues[expectedKey] ?: return false + if (expectedStubList != actualStubList) { + return false + } + } + } + return true + } + + private fun areStubsTheSame(expectedStub: Stub, actualStub: Stub): Boolean { + // Check toString() to not rely on identity equality of [ObjectStubSerializer]s + // because [ObjectStubSerializer] does not declare equals() / hashCode(). + if (expectedStub.stubType != actualStub.stubType + && expectedStub.stubType?.toString() != actualStub.stubType?.toString() + ) { + return false + } + + // TODO: improve this comparison approach. Stubs don't have proper equals() + if (expectedStub != actualStub + && expectedStub.javaClass.name != actualStub.javaClass.name) { + return false + } + if (expectedStub is ObjectStubBase<*>) { + if (actualStub !is ObjectStubBase<*>) { + return false + } + if (expectedStub.stubId != actualStub.stubId) { + return false + } + } + + val expectedChildren: List = expectedStub.childrenStubs + val actualChildren: List = actualStub.childrenStubs + if (expectedChildren.size != actualChildren.size) { + return false + } + + for (index in expectedChildren.indices) { + val expectedChild = expectedChildren[index] + val actualChild = actualChildren[index] + if (!areStubsTheSame(expectedChild, actualChild)) { + return false + } + } + return true + } + + +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/IndexDataPresenter.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/IndexDataPresenter.kt new file mode 100644 index 000000000000..f3dff5f0e733 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/IndexDataPresenter.kt @@ -0,0 +1,64 @@ +package com.intellij.util.indexing.diagnostic.dump.output + +import com.intellij.psi.stubs.* + +object IndexDataPresenter { + + fun getPresentableIndexValue(value: V): String { + return if (value is SerializedStubTree) { + buildString { + appendln("Stub tree:") + appendln(stubToString(value.stub)) + + val stubIndicesValueMap: Map, Map> = try { + value.stubIndicesValueMap + } + catch (e: Exception) { + appendln("Failed-to-read stub tree forward index: (message = ${e.message}) (exception class = ${e.javaClass.simpleName})") + return@buildString + } + + appendln("Stub tree forward index:") + for ((stubIndexKey, stubIndexValues) in stubIndicesValueMap) { + appendln(" ${stubIndexKey.name}") + for ((key, stubIdList) in stubIndexValues) { + val stubIds = (0 until stubIdList.size()).map { stubIdList[it] } + appendln(" $key -> " + stubIds.joinToString()) + } + } + } + } + else { + value.toString() + } + } + + fun getPresentableKeyValueMap(keyValueMap: Map): String { + if (keyValueMap.isEmpty()) { + return "[]" + } + return buildString { + for ((key, value) in keyValueMap) { + appendln("$key -> ${getPresentableIndexValue(value)}") + } + } + } + + private fun stubToString(node: Stub, indent: String = " "): String = + buildString { + append(indent) + val stubType = node.stubType + if (stubType != null) { + append(stubType.toString()).append(':') + } + append(node.toString()) + if (node is ObjectStubBase<*>) { + append(" (id = ").append(node.stubId).append(")") + } + append('\n') + for (child in node.childrenStubs) { + appendln(stubToString(child, indent + " ")) + } + } + +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/PrettyWriter.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/PrettyWriter.kt new file mode 100644 index 000000000000..019a6a2294b0 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/output/PrettyWriter.kt @@ -0,0 +1,32 @@ +package com.intellij.util.indexing.diagnostic.dump.output + +import java.io.PrintStream + +class PrettyWriter(private val out: PrintStream) : AutoCloseable { + + private var indent = "" + + inner class Object { + fun writeString(s: String) { + s.lineSequence().forEach { + out.println("$indent$it") + } + } + } + + fun writeObject(name: String, block: Object.() -> Unit) { + out.println("$indent$name") + indent += " " + val obj = Object() + try { + obj.block() + } + finally { + indent = indent.removeSuffix(" ") + } + } + + override fun close() { + out.close() + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/package-info.java b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/package-info.java new file mode 100644 index 000000000000..c38397625aff --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/package-info.java @@ -0,0 +1,6 @@ +// 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. +@ApiStatus.Internal +@ApiStatus.Experimental +package com.intellij.util.indexing.diagnostic.dump; + +import org.jetbrains.annotations.ApiStatus; \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/PortableFilePath.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/PortableFilePath.kt new file mode 100644 index 000000000000..223c63c0d67b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/PortableFilePath.kt @@ -0,0 +1,74 @@ +package com.intellij.util.indexing.diagnostic.dump.paths + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.fasterxml.jackson.annotation.JsonTypeName +import com.intellij.util.indexing.diagnostic.dump.paths.providers.IdePortableFilePathProvider + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME) +sealed class PortableFilePath { + + abstract val presentablePath: String + @JsonIgnore get + + @JsonTypeName("project") + object ProjectRoot : PortableFilePath() { + override val presentablePath + get() = "" + } + + @JsonTypeName("library") + data class LibraryRoot( + val libraryName: String, + val libraryRootIndex: Int, + val inClassFiles: Boolean + ) : PortableFilePath() { + override val presentablePath + get() = "/" + + "" + } + + @JsonTypeName("jdk") + data class JdkRoot( + val jdkName: String, + val jdkRootIndex: Int, + val inClassFiles: Boolean + ) : PortableFilePath() { + override val presentablePath + get() = "/" + + "" + } + + @JsonTypeName("ide") + data class IdeRoot(val ideDirectoryType: String) : PortableFilePath() { + init { + require(ideDirectoryType in IdePortableFilePathProvider.IDE_PATHS.keys) { ideDirectoryType } + } + + override val presentablePath + get() = "" + } + + @JsonTypeName("archive") + data class ArchiveRoot(val archiveLocalPath: PortableFilePath) : PortableFilePath() { + override val presentablePath + get() = archiveLocalPath.presentablePath + "!/" + } + + @JsonTypeName("absolute") + data class AbsolutePath(val absoluteUrl: String) : PortableFilePath() { + override val presentablePath + get() = absoluteUrl + } + + @JsonTypeName("relative") + data class RelativePath(val root: PortableFilePath, val relativePath: String) : PortableFilePath() { + init { + require(!relativePath.startsWith('/')) { relativePath } + } + + override val presentablePath + get() = root.presentablePath.trimEnd('/') + '/' + relativePath + } + +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/portableFilePaths.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/portableFilePaths.kt new file mode 100644 index 000000000000..5837fc46a602 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/portableFilePaths.kt @@ -0,0 +1,54 @@ +package com.intellij.util.indexing.diagnostic.dump.paths + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem +import com.intellij.util.indexing.diagnostic.dump.paths.providers.* +import com.intellij.util.indexing.diagnostic.dump.paths.resolvers.* + +object PortableFilePaths { + + private val PROVIDERS: List = listOf( + JdkPortableFilePathProvider, + LibraryRelativePortableFilePathProvider, + IdePortableFilePathProvider, + ProjectRelativePortableFilePathProvider + ) + + private val RESOLVERS: List = listOf( + JdkRootPortableFilePathResolver, + LibraryRootPortableFilePathResolver, + ArchiveRootPortableFilePathResolver, + IdeRootPortableFilePathResolver, + ProjectRootPortableFilePathResolver, + RelativePortableFilePathResolver + ) + + fun getPortableFilePath(virtualFile: VirtualFile, project: Project): PortableFilePath = runReadAction { + PROVIDERS.asSequence().mapNotNull { it.getRelativePortableFilePath(project, virtualFile) }.firstOrNull() + ?: PortableFilePath.AbsolutePath(virtualFile.url) + } + + fun findFileByPath(portableFilePath: PortableFilePath, project: Project): VirtualFile? = runReadAction { + RESOLVERS.asSequence().mapNotNull { it.findFileByPath(project, portableFilePath) }.firstOrNull() + ?: AbsolutePortableFilePathResolver.findFileByPath(project, portableFilePath) + } + + fun isSupportedFileSystem(virtualFile: VirtualFile): Boolean = + virtualFile.isInLocalFileSystem || virtualFile.fileSystem is ArchiveFileSystem + +} + +object PortableFilePathsPersistence { + + private val jacksonMapper = jacksonObjectMapper() + + fun serializeToString(portableFilePath: PortableFilePath): String = + jacksonMapper.writeValueAsString(portableFilePath) + + fun deserializeFromString(string: String): PortableFilePath = + jacksonMapper.readValue(string) +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/IdePortableFilePathProvider.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/IdePortableFilePathProvider.kt new file mode 100644 index 000000000000..6de1e1de112e --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/IdePortableFilePathProvider.kt @@ -0,0 +1,33 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.providers + +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +object IdePortableFilePathProvider : PortableFilePathProvider { + + val IDE_PATHS: Map = mapOf( + "config" to PathManager.getConfigPath(), + "system" to PathManager.getSystemPath(), + "log" to PathManager.getLogPath(), + "plugins" to PathManager.getPluginsPath(), + "home" to PathManager.getHomePath() + ).mapValues { FileUtil.toSystemIndependentName(it.value) } + + override fun getRelativePortableFilePath(project: Project, virtualFile: VirtualFile): PortableFilePath.RelativePath? { + for ((ideDirType, ideDirPath) in IDE_PATHS) { + val relativeFilePath = ProjectRelativePortableFilePathProvider.getLocalOrArchiveRelativeFilePath( + virtualFile, + project, + ideDirPath, + PortableFilePath.IdeRoot(ideDirType) + ) + if (relativeFilePath != null) { + return relativeFilePath + } + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/JdkPortableFilePathProvider.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/JdkPortableFilePathProvider.kt new file mode 100644 index 000000000000..2e19d0fac4ce --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/JdkPortableFilePathProvider.kt @@ -0,0 +1,31 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.providers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.JdkOrderEntry +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.LibraryUtil +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +object JdkPortableFilePathProvider : PortableFilePathProvider { + override fun getRelativePortableFilePath(project: Project, virtualFile: VirtualFile): PortableFilePath.RelativePath? { + val orderEntry = LibraryUtil.findLibraryEntry(virtualFile, project) + if (orderEntry is JdkOrderEntry) { + val jdkName = orderEntry.jdkName + if (jdkName != null) { + for (rootType in listOf(OrderRootType.CLASSES, OrderRootType.SOURCES)) { + val inClassFiles = rootType == OrderRootType.CLASSES + val jdkRoots = orderEntry.getRootFiles(rootType) + for ((rootIndex, rootFile) in jdkRoots.withIndex()) { + val relativePath = VfsUtilCore.getRelativePath(virtualFile, rootFile) + if (relativePath != null) { + return PortableFilePath.RelativePath(PortableFilePath.JdkRoot(jdkName, rootIndex, inClassFiles), relativePath) + } + } + } + } + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/LibraryRelativePortableFilePathProvider.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/LibraryRelativePortableFilePathProvider.kt new file mode 100644 index 000000000000..424981a3f64a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/LibraryRelativePortableFilePathProvider.kt @@ -0,0 +1,33 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.providers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.LibraryOrderEntry +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.LibraryUtil +import com.intellij.openapi.vfs.VfsUtilCore +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +object LibraryRelativePortableFilePathProvider : PortableFilePathProvider { + override fun getRelativePortableFilePath(project: Project, virtualFile: VirtualFile): PortableFilePath.RelativePath? { + val orderEntry = LibraryUtil.findLibraryEntry(virtualFile, project) + if (orderEntry is LibraryOrderEntry) { + val libraryName = orderEntry.libraryName + if (libraryName != null) { + for (rootType in listOf(OrderRootType.CLASSES, OrderRootType.SOURCES)) { + val inClassFiles = rootType == OrderRootType.CLASSES + for ((rootIndex, rootFile) in orderEntry.getRootFiles(rootType).withIndex()) { + val relativePath = VfsUtilCore.getRelativePath(virtualFile, rootFile) + if (relativePath != null) { + return PortableFilePath.RelativePath( + PortableFilePath.LibraryRoot(libraryName, rootIndex, inClassFiles), + relativePath + ) + } + } + } + } + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/PortableFilePathProvider.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/PortableFilePathProvider.kt new file mode 100644 index 000000000000..890ea13e5f29 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/PortableFilePathProvider.kt @@ -0,0 +1,9 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.providers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +interface PortableFilePathProvider { + fun getRelativePortableFilePath(project: Project, virtualFile: VirtualFile): PortableFilePath.RelativePath? +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/ProjectRelativePortableFilePathProvider.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/ProjectRelativePortableFilePathProvider.kt new file mode 100644 index 000000000000..dcd48433a4c4 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/providers/ProjectRelativePortableFilePathProvider.kt @@ -0,0 +1,44 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.providers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.io.FileUtil +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePaths + +object ProjectRelativePortableFilePathProvider : PortableFilePathProvider { + override fun getRelativePortableFilePath(project: Project, virtualFile: VirtualFile): PortableFilePath.RelativePath? { + val projectBasePath = project.basePath ?: return null + return getLocalOrArchiveRelativeFilePath(virtualFile, project, projectBasePath, PortableFilePath.ProjectRoot) + } + + fun getLocalOrArchiveRelativeFilePath( + virtualFile: VirtualFile, + project: Project, + rootBasePath: String, + root: PortableFilePath + ): PortableFilePath.RelativePath? { + val fileSystem = virtualFile.fileSystem + if (fileSystem is ArchiveFileSystem) { + val archiveLocalFile = fileSystem.getLocalByEntry(virtualFile) ?: return null + val archiveRootFile = fileSystem.getRootByEntry(virtualFile) ?: return null + val relativePath = VfsUtil.getRelativePath(virtualFile, archiveRootFile) ?: return null + val archiveLocalPath: PortableFilePath = PortableFilePaths.getPortableFilePath(archiveLocalFile, project) + val archiveRoot = PortableFilePath.ArchiveRoot(archiveLocalPath) + return PortableFilePath.RelativePath(archiveRoot, relativePath) + } + + // Usual non-archive local pth. + val filePath = virtualFile.path + val systemIndependentBase = FileUtil.toSystemIndependentName(rootBasePath) + if (FileUtil.isAncestor(systemIndependentBase, filePath, false)) { + val relativePath = FileUtil.getRelativePath(systemIndependentBase, filePath, '/') + if (relativePath != null) { + return PortableFilePath.RelativePath(root, relativePath) + } + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/AbsolutePortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/AbsolutePortableFilePathResolver.kt new file mode 100644 index 000000000000..4dd7a66e2f2a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/AbsolutePortableFilePathResolver.kt @@ -0,0 +1,15 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +object AbsolutePortableFilePathResolver : PortableFilePathResolver { + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.AbsolutePath) { + return VirtualFileManager.getInstance().refreshAndFindFileByUrl(portableFilePath.absoluteUrl) + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/ArchiveRootPortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/ArchiveRootPortableFilePathResolver.kt new file mode 100644 index 000000000000..bcf87c16ae80 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/ArchiveRootPortableFilePathResolver.kt @@ -0,0 +1,28 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.openapi.vfs.impl.VirtualFileManagerImpl +import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePaths + +object ArchiveRootPortableFilePathResolver : PortableFilePathResolver { + + private val archiveFileSystems by lazy { + (VirtualFileManager.getInstance() as VirtualFileManagerImpl) + .physicalFileSystems + .filterIsInstance() + } + + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.ArchiveRoot) { + val archiveLocalFile = PortableFilePaths.findFileByPath(portableFilePath.archiveLocalPath, project) ?: return null + return archiveFileSystems.asSequence() + .mapNotNull { it.getRootByLocal(archiveLocalFile) } + .firstOrNull() ?: return null + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/IdeRootPortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/IdeRootPortableFilePathResolver.kt new file mode 100644 index 000000000000..3d381704cf27 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/IdeRootPortableFilePathResolver.kt @@ -0,0 +1,19 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath +import com.intellij.util.indexing.diagnostic.dump.paths.providers.IdePortableFilePathProvider +import java.nio.file.Paths + +object IdeRootPortableFilePathResolver : PortableFilePathResolver { + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.IdeRoot) { + val ideDirectoryPath = IdePortableFilePathProvider.IDE_PATHS[portableFilePath.ideDirectoryType] + checkNotNull(ideDirectoryPath) { portableFilePath.ideDirectoryType } + return VfsUtil.findFile(Paths.get(ideDirectoryPath), true) + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/JdkRootPortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/JdkRootPortableFilePathResolver.kt new file mode 100644 index 000000000000..18dafa635e92 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/JdkRootPortableFilePathResolver.kt @@ -0,0 +1,20 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.ProjectJdkTable +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +object JdkRootPortableFilePathResolver : PortableFilePathResolver { + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.JdkRoot) { + val jdk = ProjectJdkTable.getInstance().findJdk(portableFilePath.jdkName) ?: return null + val rootType = if (portableFilePath.inClassFiles) OrderRootType.CLASSES else OrderRootType.SOURCES + val roots = jdk.rootProvider.getFiles(rootType) + return roots.getOrNull(portableFilePath.jdkRootIndex) + } + return null + } + +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/LibraryRootPortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/LibraryRootPortableFilePathResolver.kt new file mode 100644 index 000000000000..97520f5d0f50 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/LibraryRootPortableFilePathResolver.kt @@ -0,0 +1,20 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +object LibraryRootPortableFilePathResolver : PortableFilePathResolver { + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.LibraryRoot) { + val libraryTable = LibraryTablesRegistrar.getInstance().getLibraryTable(project) + val library = libraryTable.getLibraryByName(portableFilePath.libraryName) ?: return null + val rootType = if (portableFilePath.inClassFiles) OrderRootType.CLASSES else OrderRootType.SOURCES + val roots = library.rootProvider.getFiles(rootType) + return roots.getOrNull(portableFilePath.libraryRootIndex) + } + return null + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/PortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/PortableFilePathResolver.kt new file mode 100644 index 000000000000..a9f469c8c570 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/PortableFilePathResolver.kt @@ -0,0 +1,9 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath + +interface PortableFilePathResolver { + fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/ProjectRootPortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/ProjectRootPortableFilePathResolver.kt new file mode 100644 index 000000000000..b0f68a707aae --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/ProjectRootPortableFilePathResolver.kt @@ -0,0 +1,18 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath +import java.nio.file.Paths + +object ProjectRootPortableFilePathResolver : PortableFilePathResolver { + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.ProjectRoot) { + val projectBasePath = project.basePath ?: return null + return VfsUtil.findFile(Paths.get(projectBasePath), true) + } + return null + } + +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/RelativePortableFilePathResolver.kt b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/RelativePortableFilePathResolver.kt new file mode 100644 index 000000000000..5e6544c6d352 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/diagnostic/dump/paths/resolvers/RelativePortableFilePathResolver.kt @@ -0,0 +1,19 @@ +package com.intellij.util.indexing.diagnostic.dump.paths.resolvers + +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.vfs.VirtualFileManager +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePath +import com.intellij.util.indexing.diagnostic.dump.paths.PortableFilePaths + +object RelativePortableFilePathResolver : PortableFilePathResolver { + override fun findFileByPath(project: Project, portableFilePath: PortableFilePath): VirtualFile? { + if (portableFilePath is PortableFilePath.RelativePath) { + val rootFile = PortableFilePaths.findFileByPath(portableFilePath.root, project) ?: return null + val fullUrl = rootFile.url.trimEnd('/') + '/' + portableFilePath.relativePath + return VirtualFileManager.getInstance().refreshAndFindFileByUrl(fullUrl) + } + return null + } + +} \ No newline at end of file