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
@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.builtins.BuiltInsSerializerExtension 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 org.jetbrains.kotlin.serialization.jvm.JvmPackageTable
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.DataOutputStream import java.io.DataOutputStream
@@ -132,10 +132,10 @@ open class MetadataSerializer(private val dependOnOldBuiltIns: Boolean) {
private fun getPackageFilePath(packageFqName: FqName, fileName: String): String = private fun getPackageFilePath(packageFqName: FqName, fileName: String): String =
packageFqName.asString().replace('.', '/') + "/" + 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 = 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( protected inner class PackageSerializer(
private val classes: Collection<DeclarationDescriptor>, private val classes: Collection<DeclarationDescriptor>,
@@ -39,13 +39,13 @@ class JvmCliVirtualFileFinder(
override fun findMetadata(classId: ClassId): InputStream? { override fun findMetadata(classId: ClassId): InputStream? {
assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" } 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 { override fun hasMetadataPackage(fqName: FqName): Boolean {
var found = false var found = false
index.traverseDirectoriesInPackage(fqName, continueSearch = { dir, _ -> 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 !found
}) })
return found return found
@@ -132,6 +132,7 @@ class MetadataPackageFragment(
} }
companion object { companion object {
val METADATA_FILE_EXTENSION = ".kotlin_metadata" val DOT_METADATA_FILE_EXTENSION = ".kotlin_metadata"
val METADATA_FILE_EXTENSION = "kotlin_metadata"
} }
} }
+1
View File
@@ -34,5 +34,6 @@
<orderEntry type="module" module-name="idea-core" /> <orderEntry type="module" module-name="idea-core" />
<orderEntry type="module" module-name="idea-jps-common" /> <orderEntry type="module" module-name="idea-jps-common" />
<orderEntry type="module" module-name="cli-common" /> <orderEntry type="module" module-name="cli-common" />
<orderEntry type="module" module-name="descriptors" />
</component> </component>
</module> </module>
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendere
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@@ -91,12 +92,14 @@ fun buildDecompiledTextForBuiltIns(builtInFile: VirtualFile): DecompiledText {
sealed class BuiltInDefinitionFile { sealed class BuiltInDefinitionFile {
class Incompatible(val version: BuiltInsBinaryVersion) : 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 nameResolver = NameResolverImpl(proto.strings, proto.qualifiedNames)
val packageFqName = nameResolver.getPackageFqName(proto.`package`.getExtension(BuiltInsProtoBuf.packageFqName)) val packageFqName = nameResolver.getPackageFqName(proto.`package`.getExtension(BuiltInsProtoBuf.packageFqName))
val classesToDecompile = 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)) shouldDecompileBuiltInClass(nameResolver.getClassId(classProto.fqName))
} }
else proto.class_List else proto.class_List
@@ -114,7 +117,11 @@ sealed class BuiltInDefinitionFile {
@TestOnly set @TestOnly set
fun read(file: VirtualFile): BuiltInDefinitionFile? { 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) val version = BuiltInsBinaryVersion.readFrom(stream)
if (!version.isCompatible()) { if (!version.isCompatible()) {
@@ -122,7 +129,7 @@ sealed class BuiltInDefinitionFile {
} }
val proto = BuiltInsProtoBuf.BuiltIns.parseFrom(stream, BuiltInSerializerProtocol.extensionRegistry) 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() && if (result.classesToDecompile.isEmpty() &&
result.proto.`package`.functionCount == 0 && result.proto.`package`.functionCount == 0 &&
result.proto.`package`.propertyCount == 0) { result.proto.`package`.propertyCount == 0) {
@@ -56,11 +56,14 @@ class JsIDEVirtualFileFinder(private val scope: GlobalSearchScope) : JsVirtualFi
} }
class JvmIDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileKotlinClassFinder(), JvmVirtualFileFinder { class JvmIDEVirtualFileFinder(private val scope: GlobalSearchScope) : VirtualFileKotlinClassFinder(), JvmVirtualFileFinder {
// TODO override fun findMetadata(classId: ClassId): InputStream? {
override fun findMetadata(classId: ClassId): InputStream? = null return findVirtualFileWithHeader(classId, KotlinMetadataFileIndex.KEY, scope, LOG)?.inputStream
}
// TODO override fun hasMetadataPackage(fqName: FqName): Boolean {
override fun hasMetadataPackage(fqName: FqName): Boolean = false return !FileBasedIndex.getInstance().processValues(KotlinMetadataFilePackageIndex.KEY,
fqName, null, { _, _ -> false }, scope)
}
// TODO: load built-ins metadata from scope // TODO: load built-ins metadata from scope
override fun findBuiltInsData(packageFqName: FqName): InputStream? = null override fun findBuiltInsData(packageFqName: FqName): InputStream? = null
@@ -22,9 +22,14 @@ import com.intellij.util.indexing.*
import com.intellij.util.io.IOUtil import com.intellij.util.io.IOUtil
import com.intellij.util.io.KeyDescriptor import com.intellij.util.io.KeyDescriptor
import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache 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.JsMetaFileUtils
import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType 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.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import java.io.DataInput import java.io.DataInput
import java.io.DataOutput import java.io.DataOutput
import java.util.* import java.util.*
@@ -101,3 +106,32 @@ object KotlinJavaScriptMetaFileIndex : KotlinFileIndexBase<KotlinJavaScriptMetaF
override fun dependsOnFileContent(): Boolean = false 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)
@@ -43,11 +43,13 @@ object KotlinModuleMappingIndex : FileBasedIndexExtension<String, PackageParts>(
override fun read(input: DataInput): PackageParts? = override fun read(input: DataInput): PackageParts? =
PackageParts(IOUtil.readUTF(input)).apply { PackageParts(IOUtil.readUTF(input)).apply {
parts.addAll(IOUtil.readStringList(input)) parts.addAll(IOUtil.readStringList(input))
metadataParts.addAll(IOUtil.readStringList(input))
} }
override fun save(out: DataOutput, value: PackageParts?) { override fun save(out: DataOutput, value: PackageParts?) {
IOUtil.writeUTF(out, value!!.packageFqName) IOUtil.writeUTF(out, value!!.packageFqName)
IOUtil.writeStringList(out, value.parts) 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 } 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> { override fun getIndexer(): DataIndexer<String, PackageParts, FileContent> {
return DataIndexer<String, PackageParts, FileContent> { inputData -> return DataIndexer<String, PackageParts, FileContent> { inputData ->
+2
View File
@@ -662,6 +662,8 @@
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinJavaScriptAbiVersionIndex"/> <fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinJavaScriptAbiVersionIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinClassFileIndex"/> <fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinClassFileIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinJavaScriptMetaFileIndex"/> <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"/> <fileBasedIndex implementation="org.jetbrains.kotlin.idea.vfilefinder.KotlinModuleMappingIndex"/>
<idIndexer filetype="Kotlin" implementationClass="org.jetbrains.kotlin.idea.search.KotlinIdIndexer"/> <idIndexer filetype="Kotlin" implementationClass="org.jetbrains.kotlin.idea.search.KotlinIdIndexer"/>
@@ -19,9 +19,11 @@ package org.jetbrains.kotlin.idea
import com.intellij.openapi.fileTypes.FileTypeConsumer import com.intellij.openapi.fileTypes.FileTypeConsumer
import com.intellij.openapi.fileTypes.FileTypeFactory import com.intellij.openapi.fileTypes.FileTypeFactory
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
class KotlinBuiltInFileTypeFactory : FileTypeFactory() { class KotlinBuiltInFileTypeFactory : FileTypeFactory() {
override fun createFileTypes(consumer: FileTypeConsumer) { override fun createFileTypes(consumer: FileTypeConsumer) {
consumer.consume(KotlinBuiltInFileType, KotlinBuiltInFileType.defaultExtension) consumer.consume(KotlinBuiltInFileType, KotlinBuiltInFileType.defaultExtension)
consumer.consume(KotlinBuiltInFileType, MetadataPackageFragment.METADATA_FILE_EXTENSION)
} }
} }
@@ -26,9 +26,7 @@ import com.intellij.openapi.vfs.VirtualFileVisitor
import com.intellij.openapi.vfs.newvfs.NewVirtualFile import com.intellij.openapi.vfs.newvfs.NewVirtualFile
import com.intellij.util.indexing.FileBasedIndex import com.intellij.util.indexing.FileBasedIndex
import org.jetbrains.kotlin.idea.KotlinPluginUtil import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.vfilefinder.KotlinClassFileIndex import org.jetbrains.kotlin.idea.vfilefinder.*
import org.jetbrains.kotlin.idea.vfilefinder.KotlinJavaScriptMetaFileIndex
import org.jetbrains.kotlin.idea.vfilefinder.KotlinModuleMappingIndex
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
import java.io.File import java.io.File
@@ -64,6 +62,8 @@ class KotlinUpdatePluginComponent : ApplicationComponent {
fileBasedIndex.requestRebuild(KotlinJavaScriptAbiVersionIndex.name) fileBasedIndex.requestRebuild(KotlinJavaScriptAbiVersionIndex.name)
fileBasedIndex.requestRebuild(KotlinClassFileIndex.KEY) fileBasedIndex.requestRebuild(KotlinClassFileIndex.KEY)
fileBasedIndex.requestRebuild(KotlinJavaScriptMetaFileIndex.KEY) fileBasedIndex.requestRebuild(KotlinJavaScriptMetaFileIndex.KEY)
fileBasedIndex.requestRebuild(KotlinMetadataFileIndex.KEY)
fileBasedIndex.requestRebuild(KotlinMetadataFilePackageIndex.KEY)
fileBasedIndex.requestRebuild(KotlinModuleMappingIndex.KEY) fileBasedIndex.requestRebuild(KotlinModuleMappingIndex.KEY)
PropertiesComponent.getInstance()?.setValue(INSTALLED_KOTLIN_VERSION, KotlinPluginUtil.getPluginVersion()) PropertiesComponent.getInstance()?.setValue(INSTALLED_KOTLIN_VERSION, KotlinPluginUtil.getPluginVersion())