Refactor: repackage decompiler code and explicitly extract class file and js metafile parts

This commit is contained in:
Pavel V. Talanov
2015-12-02 18:31:12 +03:00
parent 70c200d265
commit 136e8d9d02
39 changed files with 441 additions and 404 deletions
@@ -16,10 +16,8 @@
package org.jetbrains.kotlin.idea.decompiler
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.FileIndexFacade
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
@@ -30,7 +28,7 @@ import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.utils.concurrent.block.LockedClearableLazyValue
abstract class KotlinClassFileViewProviderBase(
abstract class KotlinDecompiledFileViewProviderBase(
manager: PsiManager,
file: VirtualFile,
physical: Boolean) : SingleRootFileViewProvider(manager, file, physical, KotlinLanguage.INSTANCE) {
@@ -55,37 +53,4 @@ abstract class KotlinClassFileViewProviderBase(
}
override fun getContents() = content.get()
}
public class KotlinClassFileViewProvider(
manager: PsiManager,
file: VirtualFile,
physical: Boolean,
val isInternal: Boolean) : KotlinClassFileViewProviderBase(manager, file, physical) {
override fun createFile(project: Project, file: VirtualFile, fileType: FileType): PsiFile? {
val fileIndex = ServiceManager.getService(project, javaClass<FileIndexFacade>())
if (!fileIndex.isInLibraryClasses(file) && fileIndex.isInSource(file)) {
return null
}
if (isInternal) return null
return KtClsFile(this)
}
override fun createCopy(copy: VirtualFile) = KotlinClassFileViewProvider(getManager(), copy, false, isInternal)
}
public class KotlinJavascriptMetaFileViewProvider (
manager: PsiManager,
val file: VirtualFile,
physical: Boolean,
val isInternal: Boolean) : KotlinClassFileViewProviderBase(manager, file, physical) {
//TODO: check index that file is library file, as in ClassFileViewProvider
override fun createFile(project: Project, file: VirtualFile, fileType: FileType) =
if (!isInternal) KotlinJavascriptMetaFile(this) else null
override fun createCopy(copy: VirtualFile) = KotlinJavascriptMetaFileViewProvider(getManager(), copy, false, isInternal)
}
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2015 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.decompiler
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledTextFromJsMetadata
import org.jetbrains.kotlin.utils.concurrent.block.LockedClearableLazyValue
public class KotlinJavascriptMetaFile(provider: KotlinClassFileViewProviderBase) : KtClsFileBase(provider) {
protected override val decompiledText: LockedClearableLazyValue<DecompiledText> = LockedClearableLazyValue(Any()) {
buildDecompiledTextFromJsMetadata(getVirtualFile())
}
}
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2015 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.decompiler
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
import org.jetbrains.kotlin.utils.concurrent.block.LockedClearableLazyValue
public class KtClsFile(provider: KotlinClassFileViewProviderBase) : KtClsFileBase(provider) {
protected override val decompiledText: LockedClearableLazyValue<DecompiledText> = LockedClearableLazyValue(Any()) {
buildDecompiledText(getVirtualFile())
}
}
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.utils.concurrent.block.LockedClearableLazyValue
public abstract class KtClsFileBase(val provider: KotlinClassFileViewProviderBase) : KtFile(provider, true) {
public abstract class KtDecompiledFileBase(val provider: KotlinDecompiledFileViewProviderBase) : KtFile(provider, true) {
protected abstract val decompiledText: LockedClearableLazyValue<DecompiledText>
public fun getDeclarationForDescriptor(descriptor: DeclarationDescriptor): KtDeclaration? {
@@ -14,13 +14,12 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler
package org.jetbrains.kotlin.idea.decompiler.classFile
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ClassFileViewProvider
import org.jetbrains.kotlin.idea.caches.JarUserDataManager
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -43,8 +42,6 @@ public fun isKotlinJvmCompiledFile(file: VirtualFile): Boolean {
return header != null
}
public fun isKotlinJsMetaFile(file: VirtualFile): Boolean = file.getFileType() == KotlinJavaScriptMetaFileType
/**
* Checks if this file is a compiled Kotlin class file ABI-compatible with the current plugin
*/
@@ -74,9 +71,6 @@ public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean {
header.isLocalClass || header.syntheticClassKind == "PACKAGE_PART"
}
public fun isKotlinJavaScriptInternalCompiledFile(file: VirtualFile): Boolean =
isKotlinJsMetaFile(file) && file.getNameWithoutExtension().contains('.')
public object HasCompiledKotlinInJar : JarUserDataManager.JarBooleanPropertyCounter(HasCompiledKotlinInJar::class.simpleName!!) {
override fun hasProperty(file: VirtualFile) = isKotlinJvmCompiledFile(file)
@@ -91,4 +85,4 @@ public fun findMultifileClassParts(file: VirtualFile, multifileClass: KotlinJvmB
return partNames.mapNotNull {
partsFinder.findKotlinClass(ClassId(packageFqName, Name.identifier(it.substringAfterLast('/'))))
}
}
}
@@ -14,25 +14,29 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler.textBuilder
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.decompiler.textBuilder.DeserializerForDecompilerBase
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassResolver
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.load.kotlin.BinaryClassAnnotationAndConstantLoaderImpl
import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeCapabilitiesDeserializer
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.serialization.ClassDataWithSource
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.ClassDescriptorFactory
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
public fun DeserializerForDecompiler(classFile: VirtualFile): DeserializerForClassfileDecompiler {
public 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
@@ -84,3 +88,51 @@ public class DeserializerForClassfileDecompiler(
private val LOG = Logger.getInstance(DeserializerForClassfileDecompiler::class.java)
}
}
class DirectoryBasedClassFinder(
val packageDirectory: VirtualFile,
val directoryPackageFqName: FqName
) : KotlinClassFinder {
override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.classId)
override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
if (classId.getPackageFqName() != directoryPackageFqName) {
return null
}
val targetName = classId.getRelativeClassName().pathSegments().joinToString("$", postfix = ".class")
val virtualFile = packageDirectory.findChild(targetName)
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) {
return KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile)
}
return null
}
}
class DirectoryBasedDataFinder(
val classFinder: DirectoryBasedClassFinder,
val log: Logger
) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassDataWithSource? {
val binaryClass = classFinder.findKotlinClass(classId) ?: return null
val classHeader = binaryClass.classHeader
val data = classHeader.annotationData
if (data == null) {
log.error("Annotation data missing for ${binaryClass.classId}")
return null
}
val strings = classHeader.strings
if (strings == null) {
log.error("String table not found in class ${binaryClass.classId}")
return null
}
return ClassDataWithSource(JvmProtoBufUtil.readClassDataFrom(data, strings))
}
}
private val JavaClass.classId: ClassId
get() {
val outer = getOuterClass()
return if (outer == null) ClassId.topLevel(getFqName()!!) else outer.classId.createNestedClassId(getName())
}
@@ -14,12 +14,11 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler
package org.jetbrains.kotlin.idea.decompiler.classFile
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import com.intellij.psi.compiled.ClassFileDecompilers
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.KotlinClsStubBuilder
public class KotlinClassFileDecompiler : ClassFileDecompilers.Full() {
private val stubBuilder = KotlinClsStubBuilder()
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2015 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.decompiler.classFile
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.FileIndexFacade
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProviderBase
public class KotlinClassFileViewProvider(
manager: PsiManager,
file: VirtualFile,
physical: Boolean,
val isInternal: Boolean) : KotlinDecompiledFileViewProviderBase(manager, file, physical) {
override fun createFile(project: Project, file: VirtualFile, fileType: FileType): PsiFile? {
val fileIndex = ServiceManager.getService(project, javaClass<FileIndexFacade>())
if (!fileIndex.isInLibraryClasses(file) && fileIndex.isInSource(file)) {
return null
}
if (isInternal) return null
return KtClsFile(this)
}
override fun createCopy(copy: VirtualFile) = KotlinClassFileViewProvider(getManager(), copy, false, isInternal)
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
package org.jetbrains.kotlin.idea.decompiler.classFile
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
@@ -22,19 +22,27 @@ import com.intellij.psi.compiled.ClsStubBuilder
import com.intellij.psi.impl.compiled.ClassFileStubBuilder
import com.intellij.psi.stubs.PsiFileStub
import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.idea.decompiler.findMultifileClassParts
import org.jetbrains.kotlin.idea.decompiler.isKotlinInternalCompiledFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedDataFinder
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
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
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.ErrorReporter
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
import org.jetbrains.kotlin.storage.LockBasedStorageManager
public open class KotlinClsStubBuilder : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + 1
@@ -93,7 +101,7 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName): ClsStubBuilderComponents {
val classFinder = DirectoryBasedClassFinder(file.getParent()!!, packageFqName)
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
val annotationLoader = AnnotationLoaderForStubBuilder(classFinder, LoggingErrorReporter(LOG))
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, LoggingErrorReporter(LOG))
return ClsStubBuilderComponents(classDataFinder, annotationLoader)
}
@@ -101,3 +109,39 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
val LOG = Logger.getInstance(KotlinClsStubBuilder::class.java)
}
}
class AnnotationLoaderForClassFileStubBuilder(
kotlinClassFinder: KotlinClassFinder,
errorReporter: ErrorReporter
) : AbstractBinaryClassAnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget>(
LockBasedStorageManager.NO_LOCKS, kotlinClassFinder, errorReporter) {
override fun loadClassAnnotations(
classProto: ProtoBuf.Class,
nameResolver: NameResolver
): List<ClassId> {
val binaryAnnotationDescriptors = super.loadClassAnnotations(classProto, nameResolver)
val serializedAnnotations = classProto.getExtension(JvmProtoBuf.classAnnotation).orEmpty()
val serializedAnnotationDescriptors = serializedAnnotations.map { nameResolver.getClassId(it.id) }
return binaryAnnotationDescriptors + serializedAnnotationDescriptors
}
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): ClassId =
nameResolver.getClassId(proto.getId())
override fun loadConstant(desc: String, initializer: Any) = null
override fun loadAnnotation(
annotationClassId: ClassId, source: SourceElement, result: MutableList<ClassId>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
result.add(annotationClassId)
return null
}
override fun loadPropertyAnnotations(propertyAnnotations: List<ClassId>, fieldAnnotations: List<ClassId>): List<ClassIdWithTarget> {
return propertyAnnotations.map { ClassIdWithTarget(it, null) } +
fieldAnnotations.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.FIELD) }
}
override fun transformAnnotations(annotations: List<ClassId>) = annotations.map { ClassIdWithTarget(it, null) }
}
@@ -0,0 +1,93 @@
/*
* Copyright 2010-2015 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.decompiler.classFile
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProviderBase
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFileBase
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
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
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.ExcludedTypeAnnotations
import org.jetbrains.kotlin.types.flexibility
import org.jetbrains.kotlin.types.isFlexible
import org.jetbrains.kotlin.utils.concurrent.block.LockedClearableLazyValue
import java.util.*
public class KtClsFile(provider: KotlinDecompiledFileViewProviderBase) : KtDecompiledFileBase(provider) {
protected override val decompiledText: LockedClearableLazyValue<DecompiledText> = LockedClearableLazyValue(Any()) {
buildDecompiledTextForClassFile(virtualFile)
}
}
private val descriptorRendererForClassFileDecompiler = DescriptorRenderer.withOptions {
withDefinedIn = false
classWithPrimaryConstructor = true
typeNormalizer = { type -> if (type.isFlexible()) type.flexibility().lowerBound else type }
secondaryConstructorsAsPrimary = false
modifiers = DescriptorRendererModifier.ALL
excludedTypeAnnotationClasses = ExcludedTypeAnnotations.annotationsForNullabilityAndMutability
}
private val FILE_ABI_VERSION_MARKER: String = "FILE_ABI"
private val CURRENT_ABI_VERSION_MARKER: String = "CURRENT_ABI"
public val INCOMPATIBLE_ABI_VERSION_GENERAL_COMMENT: String = "// This class file was compiled with different version of Kotlin compiler and can't be decompiled."
public val INCOMPATIBLE_ABI_VERSION_COMMENT: String =
"$INCOMPATIBLE_ABI_VERSION_GENERAL_COMMENT\n" +
"//\n" +
"// Current compiler ABI version is $CURRENT_ABI_VERSION_MARKER\n" +
"// File ABI version is $FILE_ABI_VERSION_MARKER"
public 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!!.getClassId()
val classHeader = kotlinClass.getClassHeader()
val packageFqName = classId.getPackageFqName()
return when {
!classHeader.isCompatibleAbiVersion -> {
DecompiledText(
INCOMPATIBLE_ABI_VERSION_COMMENT
.replace(CURRENT_ABI_VERSION_MARKER, JvmAbi.VERSION.toString())
.replace(FILE_ABI_VERSION_MARKER, classHeader.version.toString()),
mapOf())
}
classHeader.isCompatibleFileFacadeKind() ->
buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())), descriptorRendererForClassFileDecompiler)
classHeader.isCompatibleClassKind() ->
buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), descriptorRendererForClassFileDecompiler)
classHeader.isCompatibleMultifileClassKind() -> {
val partClasses = findMultifileClassParts(classFile, kotlinClass)
val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) }
buildDecompiledText(packageFqName, partMembers, descriptorRendererForClassFileDecompiler)
}
else ->
throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}")
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler
package org.jetbrains.kotlin.idea.decompiler.js
import com.google.protobuf.MessageLite
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.ClassIdWithTarget
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler.navigation
package org.jetbrains.kotlin.idea.decompiler.js
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
@@ -24,6 +24,10 @@ import org.jetbrains.kotlin.serialization.js.isDefaultPackageMetafile
import org.jetbrains.kotlin.serialization.js.isPackageClassFqName
public object JsMetaFileUtils {
public fun isKotlinJsMetaFile(file: VirtualFile): Boolean = file.getFileType() == KotlinJavaScriptMetaFileType
public fun isKotlinJavaScriptInternalCompiledFile(file: VirtualFile): Boolean =
isKotlinJsMetaFile(file) && file.getNameWithoutExtension().contains('.')
public fun getPackageFqName(file: VirtualFile): FqName = getPackageFqName(getRelativeToRootPath(file))
@@ -62,7 +66,7 @@ public object JsMetaFileUtils {
private fun getModuleName(relPath: String): String = relPath.substringBefore(VfsUtilCore.VFS_SEPARATOR_CHAR)
private fun isPackageHeader(relPath: String): Boolean {
val classFqName = JsMetaFileUtils.getClassFqName(relPath)
val classFqName = getClassFqName(relPath)
return classFqName.isPackageClassFqName()
}
@@ -14,22 +14,22 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler.textBuilder
package org.jetbrains.kotlin.idea.decompiler.js
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DeserializerForDecompilerBase
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassResolver
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.serialization.ClassDataWithSource
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptAnnotationAndConstantLoader
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializedResourcePaths
import org.jetbrains.kotlin.serialization.js.toPackageData
import org.jetbrains.kotlin.serialization.js.*
import java.io.ByteArrayInputStream
public class KotlinJavaScriptDeserializerForDecompiler(
@@ -82,3 +82,29 @@ public class KotlinJavaScriptDeserializerForDecompiler(
private val LOG = Logger.getInstance(KotlinJavaScriptDeserializerForDecompiler::class.java)
}
}
class DirectoryBasedKotlinJavaScriptMetaFileFinder(
val packageDirectory: VirtualFile,
val directoryPackageFqName: FqName,
val nameResolver: NameResolver
) {
fun findKotlinJavascriptMetaFile(classId: ClassId): VirtualFile? {
if (classId.getPackageFqName() != directoryPackageFqName) return null
val targetName = classId.getRelativeClassName().pathSegments().joinToString(".", postfix = "." + KotlinJavascriptSerializationUtil.CLASS_METADATA_FILE_EXTENSION)
return packageDirectory.findChild(targetName)
}
}
class DirectoryBasedKotlinJavaScriptDataFinder(
val classFinder: DirectoryBasedKotlinJavaScriptMetaFileFinder,
val log: Logger
) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassDataWithSource? {
val file = classFinder.findKotlinJavascriptMetaFile(classId) ?: return null
val content = file.contentsToByteArray(false)
val classData = content.toClassData(classFinder.nameResolver)
return ClassDataWithSource(classData)
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler;
package org.jetbrains.kotlin.idea.decompiler.js;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.FileViewProvider;
@@ -22,7 +22,6 @@ import com.intellij.psi.PsiManager;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.compiled.ClsStubBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.KotlinJavaScriptStubBuilder;
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil;
public class KotlinJavaScriptMetaFileDecompiler extends ClassFileDecompilers.Full {
@@ -42,7 +41,6 @@ public class KotlinJavaScriptMetaFileDecompiler extends ClassFileDecompilers.Ful
@NotNull
@Override
public FileViewProvider createFileViewProvider(@NotNull VirtualFile file, @NotNull PsiManager manager, boolean physical) {
return new KotlinJavascriptMetaFileViewProvider(manager, file, physical, DecompiledUtilsKt.isKotlinJavaScriptInternalCompiledFile(
file));
return new KotlinJavascriptMetaFileViewProvider(manager, file, physical, JsMetaFileUtils.INSTANCE.isKotlinJavaScriptInternalCompiledFile(file));
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler
package org.jetbrains.kotlin.idea.decompiler.js
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.vfs.VirtualFile
@@ -35,4 +35,4 @@ public object KotlinJavaScriptMetaFileType : FileType {
override fun isReadOnly() = true
override fun getCharset(file: VirtualFile, content: ByteArray) = null
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
package org.jetbrains.kotlin.idea.decompiler.js
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
@@ -22,11 +22,9 @@ import com.intellij.psi.compiled.ClsStubBuilder
import com.intellij.psi.impl.compiled.ClassFileStubBuilder
import com.intellij.psi.stubs.PsiFileStub
import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.idea.decompiler.AnnotationLoaderForKotlinJavaScriptStubBuilder
import org.jetbrains.kotlin.idea.decompiler.isKotlinJavaScriptInternalCompiledFile
import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedKotlinJavaScriptDataFinder
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedKotlinJavaScriptMetaFileFinder
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.ClsStubBuilderComponents
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createPackageFacadeStub
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createTopLevelClassStub
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
@@ -37,13 +35,13 @@ import org.jetbrains.kotlin.serialization.js.toClassData
import org.jetbrains.kotlin.serialization.js.toPackageData
import java.io.ByteArrayInputStream
public open class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
public class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + 1
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
val file = content.file
if (isKotlinJavaScriptInternalCompiledFile(file)) return null
if (JsMetaFileUtils.isKotlinJavaScriptInternalCompiledFile(file)) return null
return doBuildFileStub(file)
}
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2015 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.decompiler.js
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFileBase
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
import org.jetbrains.kotlin.load.kotlin.OldPackageFacadeClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.ExcludedTypeAnnotations
import org.jetbrains.kotlin.utils.concurrent.block.LockedClearableLazyValue
import java.util.*
public class KotlinJavascriptMetaFile(provider: KotlinJavascriptMetaFileViewProvider) : KtDecompiledFileBase(provider) {
protected override val decompiledText: LockedClearableLazyValue<DecompiledText> = LockedClearableLazyValue(Any()) {
buildDecompiledTextFromJsMetadata(getVirtualFile())
}
}
private val descriptorRendererForKotlinJavascriptDecompiler = DescriptorRenderer.withOptions {
withDefinedIn = false
classWithPrimaryConstructor = true
secondaryConstructorsAsPrimary = false
modifiers = DescriptorRendererModifier.ALL
excludedTypeAnnotationClasses = ExcludedTypeAnnotations.annotationsForNullabilityAndMutability
}
public fun buildDecompiledTextFromJsMetadata(
classFile: VirtualFile,
resolver: ResolverForDecompiler = KotlinJavaScriptDeserializerForDecompiler(classFile)
): DecompiledText {
val packageFqName = JsMetaFileUtils.getPackageFqName(classFile)
val isPackageHeader = JsMetaFileUtils.isPackageHeader(classFile)
if (isPackageHeader) {
return buildDecompiledText(packageFqName,
resolveDeclarationsInPackage(packageFqName, resolver),
descriptorRendererForKotlinJavascriptDecompiler)
}
else {
val classId = JsMetaFileUtils.getClassId(classFile)
return buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), descriptorRendererForKotlinJavascriptDecompiler)
}
}
private fun resolveDeclarationsInPackage(packageFqName: FqName, resolver: ResolverForDecompiler) =
ArrayList(resolver.resolveDeclarationsInFacade(OldPackageFacadeClassUtils.getPackageClassFqName(packageFqName)))
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2015 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.decompiler.js
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProviderBase
public class KotlinJavascriptMetaFileViewProvider (
manager: PsiManager,
val file: VirtualFile,
physical: Boolean,
val isInternal: Boolean) : KotlinDecompiledFileViewProviderBase(manager, file, physical) {
//TODO: check index that file is library file, as in ClassFileViewProvider
override fun createFile(project: Project, file: VirtualFile, fileType: FileType) =
if (!isInternal) KotlinJavascriptMetaFile(this) else null
override fun createCopy(copy: VirtualFile) = KotlinJavascriptMetaFileViewProvider(getManager(), copy, false, isInternal)
}
@@ -25,7 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil;
import org.jetbrains.kotlin.idea.decompiler.KtClsFileBase;
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFileBase;
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope;
import org.jetbrains.kotlin.idea.stubindex.StaticFacadeIndexUtil;
import org.jetbrains.kotlin.idea.vfilefinder.JsVirtualFileFinderFactory;
@@ -62,11 +62,11 @@ public final class DecompiledNavigationUtils {
if (virtualFile == null) return null;
PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
if (!(psiFile instanceof KtClsFileBase)) {
if (!(psiFile instanceof KtDecompiledFileBase)) {
return null;
}
return ((KtClsFileBase) psiFile).getDeclarationForDescriptor(referencedDescriptor);
return ((KtDecompiledFileBase) psiFile).getDeclarationForDescriptor(referencedDescriptor);
}
private static boolean isLocal(DeclarationDescriptor descriptor) {
@@ -16,18 +16,15 @@
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.load.kotlin.AbstractBinaryClassAnnotationAndConstantLoader
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantLoader
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
data class ClassIdWithTarget(val classId: ClassId, val target: AnnotationUseSiteTarget?)
@@ -96,39 +93,3 @@ internal fun ClsStubBuilderContext.child(nameResolver: NameResolver, typeTable:
typeTable
)
}
class AnnotationLoaderForStubBuilder(
kotlinClassFinder: KotlinClassFinder,
errorReporter: ErrorReporter
) : AbstractBinaryClassAnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget>(
LockBasedStorageManager.NO_LOCKS, kotlinClassFinder, errorReporter) {
override fun loadClassAnnotations(
classProto: ProtoBuf.Class,
nameResolver: NameResolver
): List<ClassId> {
val binaryAnnotationDescriptors = super.loadClassAnnotations(classProto, nameResolver)
val serializedAnnotations = classProto.getExtension(JvmProtoBuf.classAnnotation).orEmpty()
val serializedAnnotationDescriptors = serializedAnnotations.map { nameResolver.getClassId(it.id) }
return binaryAnnotationDescriptors + serializedAnnotationDescriptors
}
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): ClassId =
nameResolver.getClassId(proto.getId())
override fun loadConstant(desc: String, initializer: Any) = null
override fun loadAnnotation(
annotationClassId: ClassId, source: SourceElement, result: MutableList<ClassId>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
result.add(annotationClassId)
return null
}
override fun loadPropertyAnnotations(propertyAnnotations: List<ClassId>, fieldAnnotations: List<ClassId>): List<ClassIdWithTarget> {
return propertyAnnotations.map { ClassIdWithTarget(it, null) } +
fieldAnnotations.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.FIELD) }
}
override fun transformAnnotations(annotations: List<ClassId>) = annotations.map { ClassIdWithTarget(it, null) }
}
@@ -17,112 +17,21 @@
package org.jetbrains.kotlin.idea.decompiler.textBuilder
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.decompiler.findMultifileClassParts
import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.OldPackageFacadeClassUtils
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.ExcludedTypeAnnotations
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
import org.jetbrains.kotlin.types.error.MissingDependencyErrorClass
import org.jetbrains.kotlin.types.flexibility
import org.jetbrains.kotlin.types.isFlexible
import java.util.*
private val FILE_ABI_VERSION_MARKER: String = "FILE_ABI"
private val CURRENT_ABI_VERSION_MARKER: String = "CURRENT_ABI"
public val INCOMPATIBLE_ABI_VERSION_GENERAL_COMMENT: String = "// This class file was compiled with different version of Kotlin compiler and can't be decompiled."
public val INCOMPATIBLE_ABI_VERSION_COMMENT: String =
"$INCOMPATIBLE_ABI_VERSION_GENERAL_COMMENT\n" +
"//\n" +
"// Current compiler ABI version is $CURRENT_ABI_VERSION_MARKER\n" +
"// File ABI version is $FILE_ABI_VERSION_MARKER"
public fun buildDecompiledText(
classFile: VirtualFile,
resolver: ResolverForDecompiler = DeserializerForDecompiler(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!!.getClassId()
val classHeader = kotlinClass.getClassHeader()
val packageFqName = classId.getPackageFqName()
return when {
!classHeader.isCompatibleAbiVersion -> {
DecompiledText(
INCOMPATIBLE_ABI_VERSION_COMMENT
.replace(CURRENT_ABI_VERSION_MARKER, JvmAbi.VERSION.toString())
.replace(FILE_ABI_VERSION_MARKER, classHeader.version.toString()),
mapOf())
}
classHeader.isCompatibleFileFacadeKind() ->
buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())))
classHeader.isCompatibleClassKind() ->
buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)))
classHeader.isCompatibleMultifileClassKind() -> {
val partClasses = findMultifileClassParts(classFile, kotlinClass)
val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) }
buildDecompiledText(packageFqName, partMembers)
}
else ->
throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}")
}
}
public fun buildDecompiledTextFromJsMetadata(
classFile: VirtualFile,
resolver: ResolverForDecompiler = KotlinJavaScriptDeserializerForDecompiler(classFile)
): DecompiledText {
val packageFqName = JsMetaFileUtils.getPackageFqName(classFile)
val isPackageHeader = JsMetaFileUtils.isPackageHeader(classFile)
if (isPackageHeader) {
return buildDecompiledText(packageFqName,
resolveDeclarationsInPackage(packageFqName, resolver),
descriptorRendererForKotlinJavascriptDecompiler)
}
else {
val classId = JsMetaFileUtils.getClassId(classFile)
return buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), descriptorRendererForKotlinJavascriptDecompiler)
}
}
private fun resolveDeclarationsInPackage(packageFqName: FqName, resolver: ResolverForDecompiler) =
ArrayList(resolver.resolveDeclarationsInFacade(OldPackageFacadeClassUtils.getPackageClassFqName(packageFqName)))
private val DECOMPILED_CODE_COMMENT = "/* compiled code */"
private val DECOMPILED_COMMENT_FOR_PARAMETER = "/* = compiled code */"
private val FLEXIBLE_TYPE_COMMENT = "/* platform type */"
private val descriptorRendererForDecompiler = DescriptorRenderer.withOptions {
withDefinedIn = false
classWithPrimaryConstructor = true
typeNormalizer = { type -> if (type.isFlexible()) type.flexibility().lowerBound else type }
secondaryConstructorsAsPrimary = false
modifiers = DescriptorRendererModifier.ALL
excludedTypeAnnotationClasses = ExcludedTypeAnnotations.annotationsForNullabilityAndMutability
}
private val descriptorRendererForKotlinJavascriptDecompiler = DescriptorRenderer.withOptions {
withDefinedIn = false
classWithPrimaryConstructor = true
secondaryConstructorsAsPrimary = false
modifiers = DescriptorRendererModifier.ALL
excludedTypeAnnotationClasses = ExcludedTypeAnnotations.annotationsForNullabilityAndMutability
}
private val descriptorRendererForKeys = DescriptorRenderer.COMPACT_WITH_MODIFIERS.withOptions {
modifiers = DescriptorRendererModifier.ALL
}
@@ -136,7 +45,7 @@ public data class DecompiledText(public val text: String, public val renderedDes
public fun buildDecompiledText(
packageFqName: FqName,
descriptors: List<DeclarationDescriptor>,
descriptorRenderer: DescriptorRenderer = descriptorRendererForDecompiler
descriptorRenderer: DescriptorRenderer
): DecompiledText {
val builder = StringBuilder()
val renderedDescriptorsToRange = HashMap<String, TextRange>()
@@ -17,6 +17,8 @@
package org.jetbrains.kotlin.idea.decompiler.textBuilder
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleParameters
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
@@ -32,6 +34,7 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantLoader
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.LocalClassResolver
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
@@ -79,4 +82,8 @@ public abstract class DeserializerForDecompilerBase(
moduleDescriptor, targetPlatform.builtIns.builtInsModule, moduleContainingMissingDependencies
)
}
}
}
class ResolveEverythingToKotlinAnyLocalClassResolver(private val builtIns: KotlinBuiltIns) : LocalClassResolver {
override fun resolveLocalClass(classId: ClassId): ClassDescriptor = builtIns.any
}
@@ -1,113 +0,0 @@
/*
* Copyright 2010-2015 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.decompiler.textBuilder
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.decompiler.isKotlinWithCompatibleAbiVersion
import org.jetbrains.kotlin.load.java.structure.JavaClass
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.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.ClassDataWithSource
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.LocalClassResolver
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.serialization.js.toClassData
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
class DirectoryBasedClassFinder(
val packageDirectory: VirtualFile,
val directoryPackageFqName: FqName
) : KotlinClassFinder {
override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.classId)
override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
if (classId.getPackageFqName() != directoryPackageFqName) {
return null
}
val targetName = classId.getRelativeClassName().pathSegments().joinToString("$", postfix = ".class")
val virtualFile = packageDirectory.findChild(targetName)
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) {
return KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile)
}
return null
}
}
class DirectoryBasedKotlinJavaScriptMetaFileFinder(
val packageDirectory: VirtualFile,
val directoryPackageFqName: FqName,
val nameResolver: NameResolver
) {
fun findKotlinJavascriptMetaFile(classId: ClassId): VirtualFile? {
if (classId.getPackageFqName() != directoryPackageFqName) return null
val targetName = classId.getRelativeClassName().pathSegments().joinToString(".", postfix = "." + KotlinJavascriptSerializationUtil.CLASS_METADATA_FILE_EXTENSION)
return packageDirectory.findChild(targetName)
}
}
class DirectoryBasedDataFinder(
val classFinder: DirectoryBasedClassFinder,
val log: Logger
) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassDataWithSource? {
val binaryClass = classFinder.findKotlinClass(classId) ?: return null
val classHeader = binaryClass.classHeader
val data = classHeader.annotationData
if (data == null) {
log.error("Annotation data missing for ${binaryClass.classId}")
return null
}
val strings = classHeader.strings
if (strings == null) {
log.error("String table not found in class ${binaryClass.classId}")
return null
}
return ClassDataWithSource(JvmProtoBufUtil.readClassDataFrom(data, strings))
}
}
class DirectoryBasedKotlinJavaScriptDataFinder(
val classFinder: DirectoryBasedKotlinJavaScriptMetaFileFinder,
val log: Logger
) : ClassDataFinder {
override fun findClassData(classId: ClassId): ClassDataWithSource? {
val file = classFinder.findKotlinJavascriptMetaFile(classId) ?: return null
val content = file.contentsToByteArray(false)
val classData = content.toClassData(classFinder.nameResolver)
return ClassDataWithSource(classData)
}
}
class ResolveEverythingToKotlinAnyLocalClassResolver(private val builtIns: KotlinBuiltIns) : LocalClassResolver {
override fun resolveLocalClass(classId: ClassId): ClassDescriptor = builtIns.any
}
private val JavaClass.classId: ClassId
get() {
val outer = getOuterClass()
return if (outer == null) ClassId.topLevel(getFqName()!!) else outer.classId.createNestedClassId(getName())
}
@@ -22,7 +22,7 @@ import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.idea.decompiler.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
//TODO: workaround for bug in JavaClsStructureViewBuilderProvider, remove when IDEA api is updated
public class KtClsStructureViewBuilderProvider : StructureViewBuilderProvider {
@@ -20,8 +20,8 @@ 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.decompiler.KotlinJavaScriptMetaFileType
import org.jetbrains.kotlin.idea.decompiler.navigation.JsMetaFileUtils
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
@@ -32,8 +32,8 @@ import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.decompiler.KotlinClassFileViewProvider
import org.jetbrains.kotlin.idea.decompiler.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.classFile.KotlinClassFileViewProvider
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
import org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver
import org.jetbrains.kotlin.psi.KtFile
import java.util.*
+2 -2
View File
@@ -558,8 +558,8 @@
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.KotlinMultifileClassPartIndex"/>
<stubIndex implementation="org.jetbrains.kotlin.idea.stubindex.KotlinScriptFqnIndex"/>
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.KotlinClassFileDecompiler"/>
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.KotlinJavaScriptMetaFileDecompiler"/>
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.classFile.KotlinClassFileDecompiler"/>
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileDecompiler"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinAbiVersionIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinJavaScriptAbiVersionIndex"/>
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.idea
import com.intellij.openapi.fileTypes.FileTypeConsumer
import com.intellij.openapi.fileTypes.FileTypeFactory
import org.jetbrains.kotlin.idea.decompiler.KotlinJavaScriptMetaFileType
import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType
public class KotlinJavaScriptMetaFileTypeFactory : FileTypeFactory() {
override fun createFileTypes(consumer: FileTypeConsumer) {
@@ -28,7 +28,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.caches.JarUserDataManager;
import org.jetbrains.kotlin.idea.debugger.filter.DebuggerFiltersUtilKt;
import org.jetbrains.kotlin.idea.decompiler.HasCompiledKotlinInJar;
import org.jetbrains.kotlin.idea.decompiler.classFile.HasCompiledKotlinInJar;
import org.jetbrains.kotlin.idea.framework.KotlinJavaScriptLibraryDetectionUtil;
import org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver;
import org.jetbrains.kotlin.utils.PathUtil;
@@ -54,7 +54,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
import org.jetbrains.kotlin.idea.decompiler.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage
import org.jetbrains.kotlin.idea.util.DebuggerUtils
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
@@ -34,9 +34,9 @@ import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile;
import org.jetbrains.kotlin.idea.test.JdkAndMockLibraryProjectDescriptor;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.idea.decompiler.KtClsFile;
import org.jetbrains.kotlin.psi.KtDeclaration;
import org.jetbrains.kotlin.psi.KtFile;
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.util.indexing.FileContentImpl
import org.jetbrains.kotlin.idea.decompiler.classFile.KotlinClsStubBuilder
import org.jetbrains.kotlin.idea.stubs.AbstractStubBuilderTest
import org.jetbrains.kotlin.psi.stubs.elements.KtFileStubBuilder
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -17,7 +17,8 @@
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
import org.jetbrains.kotlin.idea.decompiler.classFile.KotlinClsStubBuilder
import org.jetbrains.kotlin.idea.decompiler.classFile.buildDecompiledTextForClassFile
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
@@ -30,7 +31,7 @@ public class ClsStubConsistencyTest : StubConsistencyBaseTest() {
override fun createStubBuilder() = KotlinClsStubBuilder()
override fun getDecompiledText(packageFile: VirtualFile): String = buildDecompiledText(packageFile).text
override fun getDecompiledText(packageFile: VirtualFile): String = buildDecompiledTextForClassFile(packageFile).text
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
}
@@ -17,7 +17,8 @@
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledTextFromJsMetadata
import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptStubBuilder
import org.jetbrains.kotlin.idea.decompiler.js.buildDecompiledTextFromJsMetadata
import org.jetbrains.kotlin.idea.test.KotlinStdJSProjectDescriptor
import org.jetbrains.kotlin.idea.vfilefinder.JsVirtualFileFinder
import org.jetbrains.kotlin.load.kotlin.OldPackageFacadeClassUtils
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.idea.decompiler.textBuilder
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.decompiler.KotlinJavascriptMetaFile
import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavascriptMetaFile
import org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToDecompiledLibraryTest
import org.jetbrains.kotlin.idea.test.ModuleKind
import org.jetbrains.kotlin.idea.test.configureAs
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.idea.decompiler.textBuilder
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.decompiler.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToDecompiledLibraryTest
import kotlin.test.assertTrue
@@ -22,6 +22,8 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.idea.caches.resolve.IDEPackagePartProvider
import org.jetbrains.kotlin.idea.decompiler.classFile.DeserializerForClassfileDecompiler
import org.jetbrains.kotlin.idea.decompiler.classFile.buildDecompiledTextForClassFile
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.load.kotlin.JvmVirtualFileFinder
@@ -44,7 +46,7 @@ public class DecompiledTextConsistencyTest : TextConsistencyBaseTest() {
JvmVirtualFileFinder.SERVICE.getInstance(project)
override fun getDecompiledText(packageFile: VirtualFile, resolver: ResolverForDecompiler?): String =
(resolver?.let { buildDecompiledText(packageFile, it) } ?: buildDecompiledText(packageFile)).text
(resolver?.let { buildDecompiledTextForClassFile(packageFile, it) } ?: buildDecompiledTextForClassFile(packageFile)).text
override fun getModuleDescriptor(): ModuleDescriptor =
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(
@@ -20,7 +20,8 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.decompiler.AbstractInternalCompiledClassesTest
import org.jetbrains.kotlin.idea.decompiler.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.classFile.INCOMPATIBLE_ABI_VERSION_GENERAL_COMMENT
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToDecompiledLibraryTest
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.findClassFileByName
import org.jetbrains.kotlin.idea.test.KotlinJdkAndLibraryProjectDescriptor
@@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.idea.decompiler.js.buildDecompiledTextFromJsMetadata
import org.jetbrains.kotlin.idea.test.KotlinStdJSProjectDescriptor
import org.jetbrains.kotlin.idea.vfilefinder.JsVirtualFileFinder
import org.jetbrains.kotlin.js.resolve.JsPlatform