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
This commit is contained in:
Nikolay Krasko
2016-01-11 18:10:53 +03:00
committed by Nikolay Krasko
parent 5431c6937f
commit adbf098166
12 changed files with 190 additions and 56 deletions
@@ -18,13 +18,18 @@ package org.jetbrains.kotlin.idea.caches
import com.intellij.openapi.vfs.VirtualFile
data class CachedAttributeData<T: Enum<T>>(val value: T?, val timeStamp: Long)
data class CachedAttributeData<T>(val value: T, val timeStamp: Long)
interface FileAttributeService {
fun register(id: String, version: Int) {}
fun <T: Enum<T>> writeAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> =
fun <T: Enum<T>> writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> =
CachedAttributeData(value, timeStamp = file.timeStamp)
fun <T: Enum<T>> readAttribute(id: String, file: VirtualFile, klass: Class<T>): CachedAttributeData<T>? = null
fun <T: Enum<T>> readEnumAttribute(id: String, file: VirtualFile, klass: Class<T>): CachedAttributeData<T>? = null
fun writeBooleanAttribute(id: String, file: VirtualFile, value: Boolean): CachedAttributeData<Boolean> =
CachedAttributeData(value, timeStamp = file.timeStamp)
fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData<Boolean>? = null
}
@@ -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<KotlinBinaryData>(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
}
}
@@ -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))
}
@@ -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<IsKotlinBinary>(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<KotlinJvmBinaryClass> {
val packageFqName = multifileClass.classId.packageFqName
fun findMultifileClassParts(file: VirtualFile, classId: ClassId, kotlinClassHeader: KotlinClassHeader): List<KotlinJvmBinaryClass> {
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('/'))))
}
@@ -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
}
@@ -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)
}
@@ -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<KtFile>? {
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
@@ -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<KotlinJvmBinaryClass>,
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) {
@@ -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<KotlinClassFileIndex>(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
}
}
@@ -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();
@@ -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<String, FileAttribute> = ContainerUtil.newConcurrentMap()
@@ -28,29 +30,54 @@ class FileAttributeServiceImpl : FileAttributeService {
attributes[id] = FileAttribute(id, version, true)
}
override fun <T: Enum<T>> writeAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> {
override fun <T: Enum<T>> writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> {
return write(file, id, value) { output, v ->
DataInputOutputUtil.writeINT(output, v.ordinal)
}
}
override fun <T: Enum<T>> readEnumAttribute(id: String, file: VirtualFile, klass: Class<T>): CachedAttributeData<T>? {
return read(file, id) { input ->
deserializeEnumValue(DataInputOutputUtil.readINT(input), klass)
}
}
override fun writeBooleanAttribute(id: String, file: VirtualFile, value: Boolean): CachedAttributeData<Boolean> {
return write(file, id, value) { output, v ->
DataInputOutputUtil.writeINT(output, if (v) 1 else 0)
}
}
override fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData<Boolean>? {
return read(file, id) { input ->
DataInputOutputUtil.readINT(input) > 0
}
}
private inline fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T> {
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 <T: Enum<T>> readAttribute(id: String, file: VirtualFile, klass: Class<T>): CachedAttributeData<T>? {
private inline fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>? {
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 <T: Enum<T>> deserializeEnumValue(i: Int, klass: Class<T>): T {
val method = klass.getMethod("values")
@Suppress("UNCHECKED_CAST")
val values = method.invoke(null) as Array<T>
return values[i]
}
}
@@ -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)
}