shared-indexes: move PortableFilePaths and other classes to intellij.lang.impl module to make StoreIndices command independent of shared-indexes plugin.

StoreIndices command is declared in PerformanceTesting plugin.
StoreIndices references PortableFilePaths and other classes that were declared in shared-indexes-plugin.
But StoreIndices command can be run without shared-indexes plugin enabled so NoSuchClassError did occur.

GitOrigin-RevId: 172ab6de1067cb7eb980724c36afb087974f2b95
This commit is contained in:
Sergey Patrikeev
2020-04-28 20:55:03 +00:00
committed by intellij-monorepo-bot
parent 7364ac3fb1
commit e3d0698dab
19 changed files with 630 additions and 0 deletions
@@ -0,0 +1,102 @@
package com.intellij.util.indexing.diagnostic.dump.output
import com.intellij.psi.stubs.*
object IndexDataComparer {
fun <V> 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<StubIndexKey<*, *>, MutableMap<Any, StubIdList>> = expectedTree.stubIndicesValueMap
val actualForwardIndex: Map<StubIndexKey<*, *>, Map<Any, StubIdList>> = 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<String, StubIndexKey<*, *>> = expectedForwardIndex.keys.associateBy { it.name }
val actualStubIndexKeyNameToKey: Map<String, StubIndexKey<*, *>> = 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<Any, StubIdList> = expectedForwardIndex.getValue(expectedStubIndexKey)
val actualKeyValues: Map<Any, StubIdList> = actualForwardIndex.getValue(actualStubIndexKey)
if (expectedKeyValues.size != actualKeyValues.size) {
return false
}
// Do not use .equals() to compare [oneKeyValues] and [twoKeyValues]
// Their internal implementation is THashMap<Any, StubIdList>
// 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<Stub> = expectedStub.childrenStubs
val actualChildren: List<Stub> = 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
}
}
@@ -0,0 +1,64 @@
package com.intellij.util.indexing.diagnostic.dump.output
import com.intellij.psi.stubs.*
object IndexDataPresenter {
fun <V> getPresentableIndexValue(value: V): String {
return if (value is SerializedStubTree) {
buildString {
appendln("Stub tree:")
appendln(stubToString(value.stub))
val stubIndicesValueMap: Map<StubIndexKey<*, *>, Map<Any, StubIdList>> = 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 <K, V> getPresentableKeyValueMap(keyValueMap: Map<K, V>): 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 + " "))
}
}
}
@@ -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()
}
}
@@ -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;
@@ -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() = "<project home>"
}
@JsonTypeName("library")
data class LibraryRoot(
val libraryName: String,
val libraryRootIndex: Int,
val inClassFiles: Boolean
) : PortableFilePath() {
override val presentablePath
get() = "<library $libraryName>/" +
"<library " + (if (inClassFiles) "class" else "source") + " root #$libraryRootIndex>"
}
@JsonTypeName("jdk")
data class JdkRoot(
val jdkName: String,
val jdkRootIndex: Int,
val inClassFiles: Boolean
) : PortableFilePath() {
override val presentablePath
get() = "<jdk $jdkName>/" +
"<jdk " + (if (inClassFiles) "class" else "source") + " root #$jdkRootIndex>"
}
@JsonTypeName("ide")
data class IdeRoot(val ideDirectoryType: String) : PortableFilePath() {
init {
require(ideDirectoryType in IdePortableFilePathProvider.IDE_PATHS.keys) { ideDirectoryType }
}
override val presentablePath
get() = "<ide $ideDirectoryType dir>"
}
@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
}
}
@@ -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<PortableFilePathProvider> = listOf(
JdkPortableFilePathProvider,
LibraryRelativePortableFilePathProvider,
IdePortableFilePathProvider,
ProjectRelativePortableFilePathProvider
)
private val RESOLVERS: List<PortableFilePathResolver> = 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<PortableFilePath>(string)
}
@@ -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<String, String> = 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
}
}
@@ -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
}
}
@@ -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
}
}
@@ -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?
}
@@ -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
}
}
@@ -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
}
}
@@ -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<ArchiveFileSystem>()
}
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
}
}
@@ -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
}
}
@@ -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
}
}
@@ -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
}
}
@@ -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?
}
@@ -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
}
}
@@ -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
}
}