From abfbfcbaa820f7af1c8e4aad80faad1d59e7cb73 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Thu, 9 Mar 2023 17:13:22 +0100 Subject: [PATCH] [kotlin] Read kotlin binary and buildins files #KTIJ-24889 GitOrigin-RevId: 1ec9c298293c564418c10e46c2b39ba3ab21bc3c --- .../resolve/ShortNamesCacheService.kt | 55 ++++++----- .../KotlinShortClassNameFileIndex.kt | 97 ++++++++++++++----- 2 files changed, 101 insertions(+), 51 deletions(-) diff --git a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/ShortNamesCacheService.kt b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/ShortNamesCacheService.kt index 3e76f0f863cb..e049e34f2a46 100644 --- a/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/ShortNamesCacheService.kt +++ b/plugins/kotlin/base/analysis/src/org/jetbrains/kotlin/idea/stubindex/resolve/ShortNamesCacheService.kt @@ -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>(), - LibraryModificationTracker.getInstance(project), - ProjectRootModificationTracker.getInstance(project), - KotlinCodeBlockModificationListener.getInstance(project).kotlinOutOfCodeBlockTracker + private val shortNamesCache = + CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result.create( + ConcurrentHashMap>(), + LibraryModificationTracker.getInstance(project), + ProjectRootModificationTracker.getInstance(project), + KotlinCodeBlockModificationListener.getInstance(project).kotlinOutOfCodeBlockTracker + ) + }, + /* trackValue = */ false ) - }, - /* trackValue = */ false - ) - fun getShortNameCandidates(name: String): Set = - shortNamesCache.value.computeIfAbsent(name) { - val scope = GlobalSearchScope.everythingScope(project) - val fqNames = mutableSetOf() - FileBasedIndex.getInstance().processValues( - KotlinShortClassNameFileIndex.NAME, name, null, - FileBasedIndex.ValueProcessor { _, names -> - fqNames += names - true - }, scope - ) - fqNames + fun getShortNameCandidates(name: String): Set = + shortNamesCache.value.getOrPut(name) { + val scope = GlobalSearchScope.everythingScope(project) + val fqNames = hashSetOf() + 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() - } } \ No newline at end of file diff --git a/plugins/kotlin/base/indices/src/org/jetbrains/kotlin/idea/vfilefinder/KotlinShortClassNameFileIndex.kt b/plugins/kotlin/base/indices/src/org/jetbrains/kotlin/idea/vfilefinder/KotlinShortClassNameFileIndex.kt index 7cf6b9d53639..1c1ac50832b4 100644 --- a/plugins/kotlin/base/indices/src/org/jetbrains/kotlin/idea/vfilefinder/KotlinShortClassNameFileIndex.kt +++ b/plugins/kotlin/base/indices/src/org/jetbrains/kotlin/idea/vfilefinder/KotlinShortClassNameFileIndex.kt @@ -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>() { companion object { @@ -24,38 +33,80 @@ class KotlinShortClassNameFileIndex : FileBasedIndexExtension, FileContent> { fileContent -> - val ktFile = fileContent.psiFile as? KtFile ?: return@DataIndexer emptyMap() val map = hashMapOf>() - 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 } -} \ No newline at end of file +} + +object StringListExternalizer : DataExternalizer> { + private val ELEMENTS_SERIALIZER = EnumeratorStringDescriptor() + + override fun read(input: DataInput): List { + val size = input.readInt() + return arrayListOf().apply { + repeat(size) { + add(ELEMENTS_SERIALIZER.read(input)) + } + } + } + + override fun save(output: DataOutput, value: Collection) { + output.writeInt(value.size) + value.toList().forEach { ELEMENTS_SERIALIZER.save(output, it) } + } +}