From adbf09816684ab3ff9fc6483f1056762fa143014 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Mon, 11 Jan 2016 18:10:53 +0300 Subject: [PATCH] Store information is file was compiled with Kotlin in attributes (KT-10312) - Add boolean attribute for all binary files in the project - Stop using JarUserDataManager for full file indexing - Store full header of files compiled with Kotlin in file UserData --- .../idea/caches/FileAttributeService.kt | 11 +- .../idea/caches/IDEKotlinBinaryClassCache.kt | 100 ++++++++++++++++++ .../kotlin/idea/caches/JarUserDataManager.kt | 6 +- .../classFile/ClassFileDecompilerUtil.kt | 38 ++++--- .../DeserializerForClassfileDecompiler.kt | 9 +- .../classFile/KotlinClassFileDecompiler.kt | 12 +-- .../classFile/KotlinClsStubBuilder.kt | 12 +-- .../decompiler/stubBuilder/clsStubBuilding.kt | 5 +- .../kotlin/idea/vfilefinder/fileIndexes.kt | 6 +- .../kotlin/idea/PluginStartupComponent.java | 3 +- .../idea/caches/FileAttributeServiceImpl.kt | 40 ++++++- .../AbstractInternalCompiledClassesTest.kt | 4 +- 12 files changed, 190 insertions(+), 56 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/IDEKotlinBinaryClassCache.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/FileAttributeService.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/FileAttributeService.kt index 29b76489c04..81ccddf453f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/FileAttributeService.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/FileAttributeService.kt @@ -18,13 +18,18 @@ package org.jetbrains.kotlin.idea.caches import com.intellij.openapi.vfs.VirtualFile -data class CachedAttributeData>(val value: T?, val timeStamp: Long) +data class CachedAttributeData(val value: T, val timeStamp: Long) interface FileAttributeService { fun register(id: String, version: Int) {} - fun > writeAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData = + fun > writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData = CachedAttributeData(value, timeStamp = file.timeStamp) - fun > readAttribute(id: String, file: VirtualFile, klass: Class): CachedAttributeData? = null + fun > readEnumAttribute(id: String, file: VirtualFile, klass: Class): CachedAttributeData? = null + + fun writeBooleanAttribute(id: String, file: VirtualFile, value: Boolean): CachedAttributeData = + CachedAttributeData(value, timeStamp = file.timeStamp) + + fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData? = null } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/IDEKotlinBinaryClassCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/IDEKotlinBinaryClassCache.kt new file mode 100644 index 00000000000..c90cd2c1bf2 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/IDEKotlinBinaryClassCache.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.caches + +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader +import org.jetbrains.kotlin.name.ClassId + +object IDEKotlinBinaryClassCache { + data class KotlinBinaryHeaderData(val classHeader: KotlinClassHeader, val classId: ClassId) + data class KotlinBinaryData(val isKotlinBinary: Boolean, val timestamp: Long, val headerData: KotlinBinaryHeaderData?) + + fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? { + val cached = getKotlinBinaryFromCache(file) + if (cached != null && !cached.isKotlinBinary) { + return null + } + + val kotlinBinaryClass = KotlinBinaryClassCache.getKotlinBinaryClass(file, fileContent) + + val isKotlinBinaryClass = kotlinBinaryClass != null + attributeService.writeBooleanAttribute(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE, file, isKotlinBinaryClass) + + if (isKotlinBinaryClass) { + val headerInfo = createHeaderInfo(kotlinBinaryClass) + file.putUserData(KOTLIN_BINARY_DATA_KEY, KotlinBinaryData(isKotlinBinaryClass, file.timeStamp, headerInfo)) + } + + return kotlinBinaryClass + } + + fun getKotlinBinaryClassHeaderData(file: VirtualFile, fileContent: ByteArray? = null): KotlinBinaryHeaderData? { + val cached = getKotlinBinaryFromCache(file) + if (cached != null) { + if (!cached.isKotlinBinary) { + return null + } + if (cached.headerData != null) { + return cached.headerData + } + } + + val kotlinBinaryClass = getKotlinBinaryClass(file, fileContent) + return createHeaderInfo(kotlinBinaryClass) + } + + private val attributeService = ServiceManager.getService(FileAttributeService::class.java) + + private fun createHeaderInfo(kotlinBinaryClass: KotlinJvmBinaryClass?): KotlinBinaryHeaderData? { + val header = kotlinBinaryClass?.classHeader + val classId = kotlinBinaryClass?.classId + + return if (header != null && classId != null) KotlinBinaryHeaderData(header, classId) else null + } + + private val KOTLIN_IS_COMPILED_FILE_ATTRIBUTE: String = "kotlin-is-binary-compiled".apply { + ServiceManager.getService(FileAttributeService::class.java).register(this, 1) + } + + private val KOTLIN_BINARY_DATA_KEY = Key.create(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE) + + private fun getKotlinBinaryFromCache(file: VirtualFile): KotlinBinaryData? { + val userData = file.getUserData(KOTLIN_BINARY_DATA_KEY) + if (userData != null && userData.timestamp == file.timeStamp) { + return userData + } + + val isKotlinBinaryAttribute = attributeService.readBooleanAttribute(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE, file) + + if (isKotlinBinaryAttribute != null) { + val isKotlinBinary = isKotlinBinaryAttribute.value + val kotlinBinaryData = KotlinBinaryData(isKotlinBinary, file.timeStamp, null) + if (isKotlinBinary) { + file.putUserData(KOTLIN_BINARY_DATA_KEY, kotlinBinaryData) + } + + return kotlinBinaryData + } + + return null + } +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/JarUserDataManager.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/JarUserDataManager.kt index 5aa5a2c532d..e50bfdc35dd 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/JarUserDataManager.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/JarUserDataManager.kt @@ -52,8 +52,8 @@ object JarUserDataManager { } if (stored == null && fileAttributeService != null) { - val savedData = fileAttributeService.readAttribute(counter.key.toString(), localJarFile, State::class.java) - if (savedData != null && savedData.value != null) { + val savedData = fileAttributeService.readEnumAttribute(counter.key.toString(), localJarFile, State::class.java) + if (savedData != null) { val hasFileWithProperty = savedData.value == State.HAS_FILE storeUserData(counter, localJarFile, hasFileWithProperty, savedData.timeStamp) @@ -91,7 +91,7 @@ object JarUserDataManager { val state = if (hasFileWithProperty) State.HAS_FILE else State.NO_FILE - val savedData = fileAttributeService?.writeAttribute(counter.key.toString(), localJarFile, state) + val savedData = fileAttributeService?.writeEnumAttribute(counter.key.toString(), localJarFile, state) storeUserData(counter, localJarFile, hasFileWithProperty, (savedData?.timeStamp ?: localJarFile.timeStamp)) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt index 998f1d94d7c..fc5ff120c0b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt @@ -17,15 +17,25 @@ package org.jetbrains.kotlin.idea.decompiler.classFile import com.intellij.ide.highlighter.JavaClassFileType +import com.intellij.openapi.components.ServiceManager +import com.intellij.openapi.util.Key import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.ClassFileViewProvider -import org.jetbrains.kotlin.idea.caches.JarUserDataManager -import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache +import org.jetbrains.kotlin.idea.caches.FileAttributeService +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name +data class IsKotlinBinary(val isKotlinBinary: Boolean, val timestamp: Long) + +val KOTLIN_COMPILED_FILE_ATTRIBUTE: String = "kotlin-compiled-file".apply { + ServiceManager.getService(FileAttributeService::class.java).register(this, 1) +} + +val KEY = Key.create(KOTLIN_COMPILED_FILE_ATTRIBUTE) + /** * Checks if this file is a compiled Kotlin class file (not necessarily ABI-compatible with the current plugin) */ @@ -34,12 +44,7 @@ fun isKotlinJvmCompiledFile(file: VirtualFile): Boolean { return false } - if (HasCompiledKotlinInJar.isInNoKotlinJar(file)) { - return false - } - - val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.classHeader - return header != null + return IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file) != null } /** @@ -48,7 +53,7 @@ fun isKotlinJvmCompiledFile(file: VirtualFile): Boolean { fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean { if (!isKotlinJvmCompiledFile(file)) return false - val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.classHeader + val header = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)?.classHeader return header != null && header.isCompatibleAbiVersion } @@ -64,24 +69,17 @@ fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean { if (ClassFileViewProvider.isInnerClass(file)) { return true } - val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.classHeader ?: return false + val header = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)?.classHeader ?: return false return header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS || header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART || header.isLocalClass || header.syntheticClassKind == "PACKAGE_PART" } -object HasCompiledKotlinInJar : JarUserDataManager.JarBooleanPropertyCounter(HasCompiledKotlinInJar::class.simpleName!!) { - override fun hasProperty(file: VirtualFile) = isKotlinJvmCompiledFile(file) - - fun isInNoKotlinJar(file: VirtualFile): Boolean = - JarUserDataManager.hasFileWithProperty(HasCompiledKotlinInJar, file) == false -} - -fun findMultifileClassParts(file: VirtualFile, multifileClass: KotlinJvmBinaryClass): List { - val packageFqName = multifileClass.classId.packageFqName +fun findMultifileClassParts(file: VirtualFile, classId: ClassId, kotlinClassHeader: KotlinClassHeader): List { + val packageFqName = classId.packageFqName val partsFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName) - val partNames = multifileClass.classHeader.filePartClassNames ?: return emptyList() + val partNames = kotlinClassHeader.filePartClassNames ?: return emptyList() return partNames.mapNotNull { partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/')))) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt index 1e7cbfa7233..eb13c238687 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.decompiler.classFile import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.idea.decompiler.textBuilder.DeserializerForDecompilerBase import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassResolver @@ -37,9 +38,9 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil fun DeserializerForClassfileDecompiler(classFile: VirtualFile): DeserializerForClassfileDecompiler { - val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) - assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } - val packageFqName = kotlinClass!!.classId.packageFqName + val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile) + assert(kotlinClassHeaderInfo != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } + val packageFqName = kotlinClassHeaderInfo!!.classId.packageFqName return DeserializerForClassfileDecompiler(classFile.parent!!, packageFqName) } @@ -103,7 +104,7 @@ class DirectoryBasedClassFinder( val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class") val virtualFile = packageDirectory.findChild(targetName) if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) { - return KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile) + return IDEKotlinBinaryClassCache.getKotlinBinaryClass(virtualFile) } return null } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt index db4fa6c146f..b8463b6d739 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt @@ -21,6 +21,7 @@ import com.intellij.openapi.roots.FileIndexFacade import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager import com.intellij.psi.compiled.ClassFileDecompilers +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText @@ -28,7 +29,6 @@ import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind @@ -79,10 +79,10 @@ fun buildDecompiledTextForClassFile( classFile: VirtualFile, resolver: ResolverForDecompiler = DeserializerForClassfileDecompiler(classFile) ): DecompiledText { - val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(classFile) - assert(kotlinClass != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } - val classId = kotlinClass!!.classId - val classHeader = kotlinClass.classHeader + val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(classFile) + assert(kotlinClassHeaderInfo != null) { "Decompiled data factory shouldn't be called on an unsupported file: " + classFile } + val classId = kotlinClassHeaderInfo!!.classId + val classHeader = kotlinClassHeaderInfo.classHeader val packageFqName = classId.packageFqName return when { @@ -98,7 +98,7 @@ fun buildDecompiledTextForClassFile( classHeader.isCompatibleClassKind() -> buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), decompilerRendererForClassFiles) classHeader.isCompatibleMultifileClassKind() -> { - val partClasses = findMultifileClassParts(classFile, kotlinClass) + val partClasses = findMultifileClassParts(classFile, classId, classHeader) val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) } buildDecompiledText(packageFqName, partMembers, decompilerRendererForClassFiles) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt index 168665d3d14..50c8c2ba65d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt @@ -24,10 +24,10 @@ import com.intellij.psi.stubs.PsiFileStub import com.intellij.util.indexing.FileContent import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.idea.decompiler.stubBuilder.* import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter import org.jetbrains.kotlin.load.kotlin.AbstractBinaryClassAnnotationAndConstantLoader -import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind @@ -58,9 +58,9 @@ open class KotlinClsStubBuilder : ClsStubBuilder() { } fun doBuildFileStub(file: VirtualFile): PsiFileStub? { - val kotlinBinaryClass = KotlinBinaryClassCache.getKotlinBinaryClass(file)!! - val header = kotlinBinaryClass.classHeader - val classId = kotlinBinaryClass.classId + val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file)!! + val header = kotlinClassHeaderInfo.classHeader + val classId = kotlinClassHeaderInfo.classId val packageFqName = classId.packageFqName if (!header.isCompatibleAbiVersion) { return createIncompatibleAbiVersionFileStub() @@ -68,8 +68,8 @@ open class KotlinClsStubBuilder : ClsStubBuilder() { val components = createStubBuilderComponents(file, packageFqName) if (header.isCompatibleMultifileClassKind()) { - val partFiles = findMultifileClassParts(file, kotlinBinaryClass) - return createMultifileClassStub(kotlinBinaryClass, partFiles, classId.asSingleFqName(), components) + val partFiles = findMultifileClassParts(file, classId, header) + return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components) } val annotationData = header.annotationData diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt index 9a83d75e2ef..0bed4997dc7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass +import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -74,13 +75,13 @@ fun createFileFacadeStub( } fun createMultifileClassStub( - multifileClass: KotlinJvmBinaryClass, + kotlinClassHeader: KotlinClassHeader, partFiles: List, facadeFqName: FqName, components: ClsStubBuilderComponents ): KotlinFileStubImpl { val packageFqName = facadeFqName.parent() - val partNames = multifileClass.classHeader.filePartClassNames?.asList()?.map { it.substringAfterLast('/') } + val partNames = kotlinClassHeader.filePartClassNames?.asList()?.map { it.substringAfterLast('/') } val fileStub = KotlinFileStubForIde.forMultifileClassStub(facadeFqName, partNames, packageFqName.isRoot) setupFileStub(fileStub, packageFqName) for (partFile in partFiles) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt index 33ed9a9f931..d83ec870a38 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt @@ -20,9 +20,9 @@ import com.intellij.ide.highlighter.JavaClassFileType import com.intellij.openapi.diagnostic.Logger import com.intellij.util.indexing.* import com.intellij.util.io.KeyDescriptor +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.idea.decompiler.js.JsMetaFileUtils import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType -import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.name.FqName import java.io.DataInput import java.io.DataOutput @@ -78,8 +78,8 @@ object KotlinClassFileIndex : KotlinFileIndexBase(KotlinCl private val VERSION = 2 private val INDEXER = indexer() { fileContent -> - val kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(fileContent.file, fileContent.content) - if (kotlinClass != null && kotlinClass.classHeader.isCompatibleAbiVersion) kotlinClass.classId.asSingleFqName() else null + val kotlinClassHeaderInfo = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(fileContent.file, fileContent.content) + if (kotlinClassHeaderInfo != null && kotlinClassHeaderInfo.classHeader.isCompatibleAbiVersion) kotlinClassHeaderInfo.classId.asSingleFqName() else null } } diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java index 6b5f29e925f..a32cd45029b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java @@ -26,9 +26,9 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.updateSettings.impl.UpdateChecker; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache; import org.jetbrains.kotlin.idea.caches.JarUserDataManager; import org.jetbrains.kotlin.idea.debugger.filter.DebuggerFiltersUtilKt; -import org.jetbrains.kotlin.idea.decompiler.classFile.HasCompiledKotlinInJar; import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil; import org.jetbrains.kotlin.utils.PathUtil; @@ -53,7 +53,6 @@ public class PluginStartupComponent implements ApplicationComponent { registerPathVariable(); JarUserDataManager.INSTANCE.register(KotlinJavaScriptLibraryDetectionUtil.HasKotlinJSMetadataInJar.INSTANCE); - JarUserDataManager.INSTANCE.register(HasCompiledKotlinInJar.INSTANCE); DebuggerFiltersUtilKt.addKotlinStdlibDebugFilterIfNeeded(); diff --git a/idea/src/org/jetbrains/kotlin/idea/caches/FileAttributeServiceImpl.kt b/idea/src/org/jetbrains/kotlin/idea/caches/FileAttributeServiceImpl.kt index ca01468dd0f..22be215252a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/caches/FileAttributeServiceImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/caches/FileAttributeServiceImpl.kt @@ -20,6 +20,8 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.newvfs.FileAttribute import com.intellij.util.containers.ContainerUtil import com.intellij.util.io.DataInputOutputUtil +import java.io.DataInput +import java.io.DataOutput class FileAttributeServiceImpl : FileAttributeService { val attributes: MutableMap = ContainerUtil.newConcurrentMap() @@ -28,29 +30,54 @@ class FileAttributeServiceImpl : FileAttributeService { attributes[id] = FileAttribute(id, version, true) } - override fun > writeAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData { + override fun > writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData { + return write(file, id, value) { output, v -> + DataInputOutputUtil.writeINT(output, v.ordinal) + } + } + + override fun > readEnumAttribute(id: String, file: VirtualFile, klass: Class): CachedAttributeData? { + return read(file, id) { input -> + deserializeEnumValue(DataInputOutputUtil.readINT(input), klass) + } + } + + + override fun writeBooleanAttribute(id: String, file: VirtualFile, value: Boolean): CachedAttributeData { + return write(file, id, value) { output, v -> + DataInputOutputUtil.writeINT(output, if (v) 1 else 0) + } + } + + override fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData? { + return read(file, id) { input -> + DataInputOutputUtil.readINT(input) > 0 + } + } + + private inline fun write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData { val attribute = attributes[id] ?: throw IllegalArgumentException("Attribute with $id wasn't registered") val data = CachedAttributeData(value, timeStamp = file.timeStamp) attribute.writeAttribute(file).use { DataInputOutputUtil.writeTIME(it, data.timeStamp) - DataInputOutputUtil.writeINT(it, data.value?.ordinal ?: -1) + writeValueFun(it, value) } return data } - override fun > readAttribute(id: String, file: VirtualFile, klass: Class): CachedAttributeData? { + private inline fun read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData? { val attribute = attributes[id] ?: throw IllegalArgumentException("Attribute with $id wasn't registered") val stream = attribute.readAttribute(file) ?: return null return stream.use { val timeStamp = DataInputOutputUtil.readTIME(it) - val intValue = DataInputOutputUtil.readINT(it) + val value = readValueFun(it) if (file.timeStamp == timeStamp) { - CachedAttributeData(deserializeEnumValue(intValue, klass), timeStamp) + CachedAttributeData(value, timeStamp) } else { null @@ -60,7 +87,10 @@ class FileAttributeServiceImpl : FileAttributeService { private fun > deserializeEnumValue(i: Int, klass: Class): T { val method = klass.getMethod("values") + + @Suppress("UNCHECKED_CAST") val values = method.invoke(null) as Array + return values[i] } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/AbstractInternalCompiledClassesTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/AbstractInternalCompiledClassesTest.kt index f6f89785fb2..9119403245e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/AbstractInternalCompiledClassesTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/AbstractInternalCompiledClassesTest.kt @@ -18,15 +18,15 @@ package org.jetbrains.kotlin.idea.decompiler import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiManager +import org.jetbrains.kotlin.idea.caches.IDEKotlinBinaryClassCache import org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToDecompiledLibraryTest import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase -import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.junit.Assert abstract class AbstractInternalCompiledClassesTest : KotlinLightCodeInsightFixtureTestCase() { private fun isFileWithHeader(predicate: (KotlinClassHeader) -> Boolean) : VirtualFile.() -> Boolean = { - val header = KotlinBinaryClassCache.getKotlinBinaryClass(this)?.classHeader + val header = IDEKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(this)?.classHeader header != null && predicate(header) }