Index and locate .kotlin_metadata files in IDE

This commit is contained in:
Dmitry Jemerov
2016-12-19 17:00:23 +01:00
parent 2209631f1a
commit bc22b67995
11 changed files with 70 additions and 18 deletions

View File

@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.builtins.BuiltInsSerializerExtension
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment.Companion.METADATA_FILE_EXTENSION
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment.Companion.DOT_METADATA_FILE_EXTENSION
import org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
import java.io.ByteArrayOutputStream
import java.io.DataOutputStream
@@ -132,10 +132,10 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
private fun getPackageFilePath(packageFqName: FqName, fileName: String): String =
packageFqName.asString().replace('.', '/') + "/" +
PackagePartClassUtils.getPartClassName(fileName.substringBeforeLast(".kt")) + METADATA_FILE_EXTENSION
PackagePartClassUtils.getPartClassName(fileName.substringBeforeLast(".kt")) + DOT_METADATA_FILE_EXTENSION
private fun getClassFilePath(classId: ClassId): String =
classId.asSingleFqName().asString().replace('.', '/') + METADATA_FILE_EXTENSION
classId.asSingleFqName().asString().replace('.', '/') + DOT_METADATA_FILE_EXTENSION
protected inner class PackageSerializer(
private val classes: Collection<DeclarationDescriptor>,

View File

@@ -39,13 +39,13 @@ class JvmCliVirtualFileFinder(
override fun findMetadata(classId: ClassId): InputStream? {
assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" }
return findBinaryClass(classId, classId.shortClassName.asString() + MetadataPackageFragment.METADATA_FILE_EXTENSION)?.inputStream
return findBinaryClass(classId, classId.shortClassName.asString() + MetadataPackageFragment.DOT_METADATA_FILE_EXTENSION)?.inputStream
}
override fun hasMetadataPackage(fqName: FqName): Boolean {
var found = false
index.traverseDirectoriesInPackage(fqName, continueSearch = { dir, _ ->
found = found or dir.children.any { it.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION.substring(1) }
found = found or dir.children.any { it.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION }
!found
})
return found

View File

@@ -132,6 +132,7 @@ class MetadataPackageFragment(
}
companion object {
val METADATA_FILE_EXTENSION = ".kotlin_metadata"
val DOT_METADATA_FILE_EXTENSION = ".kotlin_metadata"
val METADATA_FILE_EXTENSION = "kotlin_metadata"
}
}

View File

@@ -34,5 +34,6 @@
<orderEntry type="module" module-name="idea-core" />
<orderEntry type="module" module-name="idea-jps-common" />
<orderEntry type="module" module-name="cli-common" />
<orderEntry type="module" module-name="descriptors" />
</component>
</module>

View File

@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendere
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
import java.io.ByteArrayInputStream
@@ -91,12 +92,14 @@ fun buildDecompiledTextForBuiltIns(builtInFile: VirtualFile): DecompiledText {
sealed class BuiltInDefinitionFile {
class Incompatible(val version: BuiltInsBinaryVersion) : BuiltInDefinitionFile()
class Compatible(val proto: BuiltInsProtoBuf.BuiltIns, val packageDirectory: VirtualFile) : BuiltInDefinitionFile() {
class Compatible(val proto: BuiltInsProtoBuf.BuiltIns,
val packageDirectory: VirtualFile,
val isMetadata: Boolean) : BuiltInDefinitionFile() {
val nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
val packageFqName = nameResolver.getPackageFqName(proto.`package`.getExtension(BuiltInsProtoBuf.packageFqName))
val classesToDecompile =
if (FILTER_OUT_CLASSES_EXISTING_AS_JVM_CLASS_FILES) proto.class_List.filter { classProto ->
if (!isMetadata && FILTER_OUT_CLASSES_EXISTING_AS_JVM_CLASS_FILES) proto.class_List.filter { classProto ->
shouldDecompileBuiltInClass(nameResolver.getClassId(classProto.fqName))
}
else proto.class_List
@@ -114,7 +117,11 @@ sealed class BuiltInDefinitionFile {
@TestOnly set
fun read(file: VirtualFile): BuiltInDefinitionFile? {
val stream = ByteArrayInputStream(file.contentsToByteArray())
return read(file.contentsToByteArray(), file)
}
fun read(contents: ByteArray, file: VirtualFile): BuiltInDefinitionFile? {
val stream = ByteArrayInputStream(contents)
val version = BuiltInsBinaryVersion.readFrom(stream)
if (!version.isCompatible()) {
@@ -122,7 +129,7 @@ sealed class BuiltInDefinitionFile {
}
val proto = BuiltInsProtoBuf.BuiltIns.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry)
val result = BuiltInDefinitionFile.Compatible(proto, file.parent)
val result = BuiltInDefinitionFile.Compatible(proto, file.parent, file.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION)
if (result.classesToDecompile.isEmpty() &&
result.proto.`package`.functionCount == 0 &&
result.proto.`package`.propertyCount == 0) {

View File

@@ -56,11 +56,14 @@ class JsIDEVirtualFileFinder(private val scope: GlobalSearchScope) : JsVirtualFi
}
class JvmIDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileKotlinClassFinder(), JvmVirtualFileFinder {
// TODO
override fun findMetadata(classId: ClassId): InputStream? = null
override fun findMetadata(classId: ClassId): InputStream? {
return findVirtualFileWithHeader(classId, KotlinMetadataFileIndex.KEY, scope, LOG)?.inputStream
}
// TODO
override fun hasMetadataPackage(fqName: FqName): Boolean = false
override fun hasMetadataPackage(fqName: FqName): Boolean {
return !FileBasedIndex.getInstance().processValues(KotlinMetadataFilePackageIndex.KEY,
fqName, null, { _, _ -> false }, scope)
}
// TODO: load built-ins metadata from scope
override fun findBuiltInsData(packageFqName: FqName): InputStream? = null

View File

@@ -22,9 +22,14 @@ import com.intellij.util.indexing.*
import com.intellij.util.io.IOUtil
import com.intellij.util.io.KeyDescriptor
import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache
import org.jetbrains.kotlin.idea.decompiler.builtIns.BuiltInDefinitionFile
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType
import org.jetbrains.kotlin.idea.decompiler.js.JsMetaFileUtils
import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import java.io.DataInput
import java.io.DataOutput
import java.util.*
@@ -101,3 +106,32 @@ object KotlinJavaScriptMetaFileIndex : KotlinFileIndexBase<KotlinJavaScriptMetaF
override fun dependsOnFileContent(): Boolean = false
}
open class KotlinMetadataFileIndexBase<T>(classOfIndex: Class<T>, indexFunction: (ClassId) -> FqName) : KotlinFileIndexBase<T>(classOfIndex) {
override fun getIndexer() = INDEXER
override fun getInputFilter() = FileBasedIndex.InputFilter { file -> file.fileType == KotlinBuiltInFileType }
override fun getVersion() = VERSION
private val VERSION = 1
private val INDEXER = indexer { fileContent ->
if (fileContent.fileType == KotlinBuiltInFileType && fileContent.fileName.endsWith(MetadataPackageFragment.DOT_METADATA_FILE_EXTENSION)) {
val builtins = BuiltInDefinitionFile.read(fileContent.content, fileContent.file.parent)
(builtins as? BuiltInDefinitionFile.Compatible)?.let { builtinDefFile ->
val proto = builtinDefFile.proto
proto.class_List.singleOrNull()?.let { cls ->
indexFunction(builtinDefFile.nameResolver.getClassId(cls.fqName))
} ?: indexFunction(ClassId(builtinDefFile.packageFqName,
Name.identifier(fileContent.fileName.substringBeforeLast(MetadataPackageFragment.DOT_METADATA_FILE_EXTENSION))))
}
} else null
}
}
object KotlinMetadataFileIndex : KotlinMetadataFileIndexBase<KotlinMetadataFileIndex>(
KotlinMetadataFileIndex::class.java, ClassId::asSingleFqName)
object KotlinMetadataFilePackageIndex : KotlinMetadataFileIndexBase<KotlinMetadataFilePackageIndex>(
KotlinMetadataFilePackageIndex::class.java, ClassId::getPackageFqName)

View File

@@ -43,11 +43,13 @@ object KotlinModuleMappingIndex : FileBasedIndexExtension<String, PackageParts>(
override fun read(input: DataInput): PackageParts? =
PackageParts(IOUtil.readUTF(input)).apply {
parts.addAll(IOUtil.readStringList(input))
metadataParts.addAll(IOUtil.readStringList(input))
}
override fun save(out: DataOutput, value: PackageParts?) {
IOUtil.writeUTF(out, value!!.packageFqName)
IOUtil.writeStringList(out, value.parts)
IOUtil.writeStringList(out, value.metadataParts)
}
}
@@ -63,7 +65,7 @@ object KotlinModuleMappingIndex : FileBasedIndexExtension<String, PackageParts>(
return FileBasedIndex.InputFilter { file -> file.extension == ModuleMapping.MAPPING_FILE_EXT }
}
override fun getVersion(): Int = 2
override fun getVersion(): Int = 3
override fun getIndexer(): DataIndexer<String, PackageParts, FileContent> {
return DataIndexer<String, PackageParts, FileContent> { inputData ->

View File

@@ -662,6 +662,8 @@
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinJavaScriptAbiVersionIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinClassFileIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinJavaScriptMetaFileIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinMetadataFileIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinMetadataFilePackageIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinModuleMappingIndex"/>
<idIndexer filetype="Kotlin" implementationClass="org.jetbrains.kotlin.idea.search.KotlinIdIndexer"/>

View File

@@ -19,9 +19,11 @@ package org.jetbrains.kotlin.idea
import com.intellij.openapi.fileTypes.FileTypeConsumer
import com.intellij.openapi.fileTypes.FileTypeFactory
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
class KotlinBuiltInFileTypeFactory : FileTypeFactory() {
override fun createFileTypes(consumer: FileTypeConsumer) {
consumer.consume(KotlinBuiltInFileType, KotlinBuiltInFileType.defaultExtension)
consumer.consume(KotlinBuiltInFileType, MetadataPackageFragment.METADATA_FILE_EXTENSION)
}
}

View File

@@ -26,9 +26,7 @@ import com.intellij.openapi.vfs.VirtualFileVisitor
import com.intellij.openapi.vfs.newvfs.NewVirtualFile
import com.intellij.util.indexing.FileBasedIndex
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.vfilefinder.KotlinClassFileIndex
import org.jetbrains.kotlin.idea.vfilefinder.KotlinJavaScriptMetaFileIndex
import org.jetbrains.kotlin.idea.vfilefinder.KotlinModuleMappingIndex
import org.jetbrains.kotlin.idea.vfilefinder.*
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
@@ -64,6 +62,8 @@ class KotlinUpdatePluginComponent : ApplicationComponent {
fileBasedIndex.requestRebuild(KotlinJavaScriptAbiVersionIndex.name)
fileBasedIndex.requestRebuild(KotlinClassFileIndex.KEY)
fileBasedIndex.requestRebuild(KotlinJavaScriptMetaFileIndex.KEY)
fileBasedIndex.requestRebuild(KotlinMetadataFileIndex.KEY)
fileBasedIndex.requestRebuild(KotlinMetadataFilePackageIndex.KEY)
fileBasedIndex.requestRebuild(KotlinModuleMappingIndex.KEY)
PropertiesComponent.getInstance()?.setValue(INSTALLED_KOTLIN_VERSION, KotlinPluginUtil.getPluginVersion())