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:
committed by
Nikolay Krasko
parent
5431c6937f
commit
adbf098166
@@ -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))
|
||||
}
|
||||
|
||||
+18
-20
@@ -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('/'))))
|
||||
}
|
||||
|
||||
+5
-4
@@ -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
|
||||
}
|
||||
|
||||
+6
-6
@@ -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)
|
||||
}
|
||||
|
||||
+6
-6
@@ -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
|
||||
|
||||
+3
-2
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user