[kotlin] Read kotlin binary and buildins files

#KTIJ-24889

GitOrigin-RevId: 1ec9c298293c564418c10e46c2b39ba3ab21bc3c
This commit is contained in:
Vladimir Dolzhenko
2023-03-09 18:18:00 +00:00
committed by intellij-monorepo-bot
parent 173ddafc89
commit abfbfcbaa8
2 changed files with 101 additions and 51 deletions
@@ -15,35 +15,34 @@ import java.util.concurrent.ConcurrentHashMap
class ShortNamesCacheService(private val project: Project) {
@Volatile
private var shortNamesCache =
CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result.create(
ConcurrentHashMap<String, Set<String>>(),
LibraryModificationTracker.getInstance(project),
ProjectRootModificationTracker.getInstance(project),
KotlinCodeBlockModificationListener.getInstance(project).kotlinOutOfCodeBlockTracker
private val shortNamesCache =
CachedValuesManager.getManager(project).createCachedValue(
{
CachedValueProvider.Result.create(
ConcurrentHashMap<String, Set<String>>(),
LibraryModificationTracker.getInstance(project),
ProjectRootModificationTracker.getInstance(project),
KotlinCodeBlockModificationListener.getInstance(project).kotlinOutOfCodeBlockTracker
)
},
/* trackValue = */ false
)
},
/* trackValue = */ false
)
fun getShortNameCandidates(name: String): Set<String> =
shortNamesCache.value.computeIfAbsent(name) {
val scope = GlobalSearchScope.everythingScope(project)
val fqNames = mutableSetOf<String>()
FileBasedIndex.getInstance().processValues(
KotlinShortClassNameFileIndex.NAME, name, null,
FileBasedIndex.ValueProcessor { _, names ->
fqNames += names
true
}, scope
)
fqNames
fun getShortNameCandidates(name: String): Set<String> =
shortNamesCache.value.getOrPut(name) {
val scope = GlobalSearchScope.everythingScope(project)
val fqNames = hashSetOf<String>()
FileBasedIndex.getInstance().processValues(
KotlinShortClassNameFileIndex.NAME, name, null,
FileBasedIndex.ValueProcessor { _, names ->
fqNames += names
true
}, scope
)
fqNames
}
companion object {
fun getInstance(project: Project): ShortNamesCacheService = project.service()
}
companion object {
fun getInstance(project: Project): ShortNamesCacheService = project.service()
}
}
@@ -1,17 +1,26 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.vfilefinder
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.util.indexing.DataIndexer
import com.intellij.util.indexing.DefaultFileTypeSpecificInputFilter
import com.intellij.util.indexing.FileBasedIndexExtension
import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.ID
import com.intellij.util.io.DataExternalizer
import com.intellij.util.io.EnumeratorStringDescriptor
import org.jetbrains.kotlin.analysis.decompiler.psi.BuiltInDefinitionFile
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInFileType
import org.jetbrains.kotlin.analysis.decompiler.stub.file.ClsKotlinBinaryClassCache
import org.jetbrains.kotlin.analysis.decompiler.stub.file.KotlinMetadataStubBuilder
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import java.io.DataInput
import java.io.DataOutput
class KotlinShortClassNameFileIndex : FileBasedIndexExtension<String, Collection<String>>() {
companion object {
@@ -24,38 +33,80 @@ class KotlinShortClassNameFileIndex : FileBasedIndexExtension<String, Collection
override fun getKeyDescriptor(): EnumeratorStringDescriptor = EnumeratorStringDescriptor.INSTANCE
override fun getValueExternalizer() = StringSetExternalizer
override fun getValueExternalizer() = StringListExternalizer
override fun getInputFilter(): DefaultFileTypeSpecificInputFilter =
DefaultFileTypeSpecificInputFilter(KotlinFileType.INSTANCE)
DefaultFileTypeSpecificInputFilter(
KotlinFileType.INSTANCE,
KotlinBuiltInFileType,
JavaClassFileType.INSTANCE
)
override fun getVersion() = 1
override fun getVersion() = 2
override fun traceKeyHashToVirtualFileMapping(): Boolean = true
override fun getIndexer() = DataIndexer<String, Collection<String>, FileContent> { fileContent ->
val ktFile = fileContent.psiFile as? KtFile ?: return@DataIndexer emptyMap()
val map = hashMapOf<String, Collection<String>>()
ktFile.acceptChildren(object : KtTreeVisitorVoid() {
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
add(enumEntry.name, enumEntry.fqName?.asString())
super.visitEnumEntry(enumEntry)
}
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
add(classOrObject.name, classOrObject.fqName?.asString())
super.visitClassOrObject(classOrObject)
}
private fun add(name: String?, fqName: String?) {
if (name != null && fqName != null) {
val fqNames = map.computeIfAbsent(name) {
hashSetOf()
} as HashSet
fqNames += fqName
when (fileContent.fileType) {
JavaClassFileType.INSTANCE -> {
val kotlinBinaryClass = ClsKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(fileContent.file, fileContent.content)
if (kotlinBinaryClass != null) {
val classId = kotlinBinaryClass.classId
map[classId.shortClassName.asString()] = listOf(classId.asFqNameString())
}
}
})
KotlinBuiltInFileType -> {
val builtins: KotlinMetadataStubBuilder.FileWithMetadata? = BuiltInDefinitionFile.read(fileContent.content, fileContent.file.parent)
if (builtins is KotlinMetadataStubBuilder.FileWithMetadata.Compatible) {
for (classProto in builtins.classesToDecompile) {
val classId = builtins.nameResolver.getClassId(classProto.fqName)
map[classId.shortClassName.asString()] = listOf(classId.asFqNameString())
}
}
}
KotlinFileType.INSTANCE -> {
val ktFile = fileContent.psiFile as? KtFile ?: return@DataIndexer emptyMap()
ktFile.acceptChildren(object : KtTreeVisitorVoid() {
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
add(enumEntry.name, enumEntry.fqName?.asString())
super.visitEnumEntry(enumEntry)
}
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
add(classOrObject.name, classOrObject.fqName?.asString())
super.visitClassOrObject(classOrObject)
}
private fun add(name: String?, fqName: String?) {
if (name != null && fqName != null) {
val fqNames = map.getOrPut(name) {
ArrayList()
} as ArrayList
fqNames += fqName
}
}
})
}
}
map
}
}
}
object StringListExternalizer : DataExternalizer<Collection<String>> {
private val ELEMENTS_SERIALIZER = EnumeratorStringDescriptor()
override fun read(input: DataInput): List<String> {
val size = input.readInt()
return arrayListOf<String>().apply {
repeat(size) {
add(ELEMENTS_SERIALIZER.read(input))
}
}
}
override fun save(output: DataOutput, value: Collection<String>) {
output.writeInt(value.size)
value.toList().forEach { ELEMENTS_SERIALIZER.save(output, it) }
}
}