Decompile builtins (kotlin_class and kotlin_package files)

The main purpose of this is to be able to index builtin declarations and enable go to symbol/class functionality in ide
Also it makes sense to show builtin classes (Any, Int ...) as classes when browsing kotlin-runtime.jar

Refactor decompiler code to eliminate existing and potential duplication
Share the code between js (kjsm) decompilation and builtin decompilation heavily
This commit is contained in:
Pavel V. Talanov
2015-12-03 18:10:45 +03:00
parent 6164566cad
commit c40d6af1e5
21 changed files with 533 additions and 137 deletions
@@ -30,9 +30,9 @@ public object BuiltInsSerializedResourcePaths : SerializedResourcePaths() {
BuiltInsProtoBuf.registerAllExtensions(extensionRegistry) BuiltInsProtoBuf.registerAllExtensions(extensionRegistry)
} }
private val CLASS_METADATA_FILE_EXTENSION = "kotlin_class" val CLASS_METADATA_FILE_EXTENSION = "kotlin_class"
private val PACKAGE_FILE_EXTENSION = "kotlin_package" val PACKAGE_FILE_EXTENSION = "kotlin_package"
private val STRING_TABLE_FILE_EXTENSION = "kotlin_string_table" val STRING_TABLE_FILE_EXTENSION = "kotlin_string_table"
public override fun getClassMetadataPath(classId: ClassId): String { public override fun getClassMetadataPath(classId: ClassId): String {
return packageFqNameToPath(classId.getPackageFqName()) + "/" + classId.getRelativeClassName().asString() + return packageFqNameToPath(classId.getPackageFqName()) + "/" + classId.getRelativeClassName().asString() +
@@ -0,0 +1,118 @@
/*
* 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.builtIns
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.FileViewProvider
import com.intellij.psi.PsiManager
import com.intellij.psi.compiled.ClassFileDecompilers
import org.jetbrains.kotlin.builtins.BuiltInsSerializedResourcePaths
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
import org.jetbrains.kotlin.idea.decompiler.common.toClassProto
import org.jetbrains.kotlin.idea.decompiler.common.toPackageProto
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.builtins.BuiltInsProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
class KotlinBuiltInDecompiler : ClassFileDecompilers.Full() {
private val stubBuilder = KotlinBuiltInStubBuilder()
override fun accepts(file: VirtualFile): Boolean {
return file.fileType == KotlinBuiltInClassFileType || file.fileType == KotlinBuiltInPackageFileType
}
override fun getStubBuilder() = stubBuilder
override fun createFileViewProvider(file: VirtualFile, manager: PsiManager, physical: Boolean): FileViewProvider {
return KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
if (isInternalBuiltInFile(provider.virtualFile)) {
null
}
else {
KtDecompiledFile(provider) { file ->
buildDecompiledTextForBuiltIns(file)
}
}
}
}
companion object {
val LOG = Logger.getInstance(KotlinBuiltInDecompiler::class.java)
}
}
private val decompilerRendererForBuiltIns = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
public fun buildDecompiledTextForBuiltIns(
builtInFile: VirtualFile
): DecompiledText {
val directory = builtInFile.parent!!
val nameResolver = readStringTable(directory, KotlinBuiltInDecompiler.LOG)!!
val content = builtInFile.contentsToByteArray()
return when (builtInFile.fileType) {
KotlinBuiltInPackageFileType -> {
val packageFqName = content.toPackageProto(BuiltInsSerializedResourcePaths.extensionRegistry).packageFqName(nameResolver)
val resolver = KotlinBuiltInDeserializerForDecompiler(directory, packageFqName, nameResolver)
buildDecompiledText(packageFqName, resolver.resolveDeclarationsInFacade(packageFqName), decompilerRendererForBuiltIns)
}
KotlinBuiltInClassFileType -> {
val classProto = content.toClassProto(BuiltInsSerializedResourcePaths.extensionRegistry)
val classId = nameResolver.getClassId(classProto.fqName)
val packageFqName = classId.packageFqName
val resolver = KotlinBuiltInDeserializerForDecompiler(directory, packageFqName, nameResolver)
buildDecompiledText(
packageFqName,
listOfNotNull(resolver.resolveTopLevelClass(classId)),
decompilerRendererForBuiltIns
)
}
else -> error("Unexpected filetype ${builtInFile.fileType}")
}
}
fun ProtoBuf.Package.packageFqName(nameResolver: NameResolverImpl): FqName {
return nameResolver.getPackageFqName(getExtension(BuiltInsProtoBuf.packageFqName))
}
fun isInternalBuiltInFile(virtualFile: VirtualFile): Boolean {
when (virtualFile.fileType) {
KotlinBuiltInPackageFileType -> {
// do not accept kotlin_package files without packageFqName extension to avoid failing on older runtimes
// this check may be costly but there are few kotlin_package files
val packageProto = virtualFile.contentsToByteArray().toPackageProto(BuiltInsSerializedResourcePaths.extensionRegistry)
return !packageProto.hasExtension(BuiltInsProtoBuf.packageFqName)
}
KotlinBuiltInClassFileType -> {
val correspondsToInnerClass = virtualFile.nameWithoutExtension.contains('.')
if (correspondsToInnerClass) {
return true
}
val classFileName = virtualFile.nameWithoutExtension + "." + JavaClassFileType.INSTANCE.defaultExtension
val classFileForTheSameClassIsPresent = virtualFile.parent!!.findChild(classFileName) != null
return classFileForTheSameClassIsPresent
}
else -> error("Unexpected filetype ${virtualFile.fileType}")
}
}
@@ -0,0 +1,57 @@
/*
* 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.builtIns
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.builtins.BuiltInsSerializedResourcePaths
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.decompiler.common.DirectoryBasedClassDataFinder
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.name.FqName
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.serialization.deserialization.*
public class KotlinBuiltInDeserializerForDecompiler(
packageDirectory: VirtualFile,
packageFqName: FqName,
private val nameResolver: NameResolver
) : DeserializerForDecompilerBase(packageDirectory, packageFqName) {
override val targetPlatform: TargetPlatform get() = TargetPlatform.Default
private val classDataFinder = DirectoryBasedClassDataFinder(
packageDirectory, directoryPackageFqName, nameResolver, BuiltInsSerializedResourcePaths
)
override val deserializationComponents = DeserializationComponents(
storageManager, moduleDescriptor, classDataFinder, AnnotationAndConstantLoaderImpl(moduleDescriptor, BuiltInSerializerProtocol),
packageFragmentProvider, ResolveEverythingToKotlinAnyLocalClassResolver(targetPlatform.builtIns), LoggingErrorReporter(LOG),
LookupTracker.DO_NOTHING, FlexibleTypeCapabilitiesDeserializer.ThrowException, ClassDescriptorFactory.EMPTY
)
override fun resolveDeclarationsInFacade(facadeFqName: FqName): List<DeclarationDescriptor> {
return getDescriptorsFromPackageFile(facadeFqName, BuiltInsSerializedResourcePaths, LOG, nameResolver)
}
companion object {
private val LOG = Logger.getInstance(KotlinBuiltInDeserializerForDecompiler::class.java)
}
}
@@ -0,0 +1,106 @@
/*
* 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.builtIns
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
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.annotations.TestOnly
import org.jetbrains.kotlin.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.builtins.BuiltInsSerializedResourcePaths
import org.jetbrains.kotlin.idea.decompiler.common.AnnotationLoaderForStubBuilderImpl
import org.jetbrains.kotlin.idea.decompiler.common.DirectoryBasedClassDataFinder
import org.jetbrains.kotlin.idea.decompiler.common.toClassProto
import org.jetbrains.kotlin.idea.decompiler.common.toPackageProto
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.stubs.impl.KotlinFileStubImpl
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import java.io.ByteArrayInputStream
public class KotlinBuiltInStubBuilder : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + 1
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
if (isInternalBuiltInFile(content.file)) return null
return doBuildFileStub(content)
}
@TestOnly
fun doBuildFileStub(content: FileContent): KotlinFileStubImpl? {
val file = content.file
val directory = file.parent!!
val nameResolver = readStringTable(directory, LOG) ?: return null
val contentAsBytes = content.content
return when (file.fileType) {
KotlinBuiltInPackageFileType -> {
val packageProto = contentAsBytes.toPackageProto(BuiltInsSerializedResourcePaths.extensionRegistry)
val packageFqName = packageProto.packageFqName(nameResolver)
val components = createStubBuilderComponents(file, packageFqName, nameResolver)
val context = components.createContext(
nameResolver, packageFqName, TypeTable(packageProto.typeTable)
)
createPackageFacadeStub(packageProto, packageFqName, context)
}
KotlinBuiltInClassFileType -> {
val classProto = contentAsBytes.toClassProto(BuiltInsSerializedResourcePaths.extensionRegistry)
val classId = nameResolver.getClassId(classProto.fqName)
val packageFqName = classId.packageFqName
val components = createStubBuilderComponents(file, packageFqName, nameResolver)
val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable))
createTopLevelClassStub(classId, classProto, context)
}
else -> error("Unexpected filetype ${file.fileType}")
}
}
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName, nameResolver: NameResolver): ClsStubBuilderComponents {
val finder = DirectoryBasedClassDataFinder(file.parent!!, packageFqName, nameResolver, BuiltInsSerializedResourcePaths)
val annotationLoader = AnnotationLoaderForStubBuilderImpl(BuiltInSerializerProtocol)
return ClsStubBuilderComponents(finder, annotationLoader)
}
companion object {
val LOG = Logger.getInstance(KotlinBuiltInStubBuilder::class.java)
}
}
fun readStringTable(directory: VirtualFile, log: Logger): NameResolverImpl? {
val stringsFileName = "${directory.name}.${BuiltInsSerializedResourcePaths.STRING_TABLE_FILE_EXTENSION}"
val stringTableFile = directory.findFileByRelativePath(stringsFileName) ?: return run {
log.error("$stringsFileName not found in $directory")
null
}
val nameResolver = try {
NameResolverImpl.read(ByteArrayInputStream(stringTableFile.contentsToByteArray(false)))
}
catch (e: Exception) {
log.error("Error reading data from $stringTableFile ", e)
null
}
return nameResolver
}
@@ -0,0 +1,54 @@
/*
* 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.builtIns
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.BuiltInsSerializedResourcePaths
import org.jetbrains.kotlin.idea.KotlinIcons
public object KotlinBuiltInClassFileType : FileType {
override fun getName() = "kotlin_class"
override fun getDescription() = "Kotlin builtin class"
override fun getDefaultExtension() = BuiltInsSerializedResourcePaths.CLASS_METADATA_FILE_EXTENSION
override fun getIcon() = KotlinIcons.CLASS
override fun isBinary() = true
override fun isReadOnly() = true
override fun getCharset(file: VirtualFile, content: ByteArray) = null
}
public object KotlinBuiltInPackageFileType : FileType {
override fun getName() = "kotlin_package"
override fun getDescription() = "Kotlin builtin package"
override fun getDefaultExtension() = BuiltInsSerializedResourcePaths.PACKAGE_FILE_EXTENSION
override fun getIcon() = KotlinIcons.FILE
override fun isBinary() = true
override fun isReadOnly() = true
override fun getCharset(file: VirtualFile, content: ByteArray) = null
}
@@ -64,7 +64,7 @@ public class DeserializerForClassfileDecompiler(
LookupTracker.DO_NOTHING, JavaFlexibleTypeCapabilitiesDeserializer, ClassDescriptorFactory.EMPTY LookupTracker.DO_NOTHING, JavaFlexibleTypeCapabilitiesDeserializer, ClassDescriptorFactory.EMPTY
) )
override fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection<DeclarationDescriptor> { override fun resolveDeclarationsInFacade(facadeFqName: FqName): List<DeclarationDescriptor> {
val packageFqName = facadeFqName.parent() val packageFqName = facadeFqName.parent()
assert(packageFqName == directoryPackageFqName) { assert(packageFqName == directoryPackageFqName) {
"Was called for $facadeFqName; only members of $directoryPackageFqName package are expected." "Was called for $facadeFqName; only members of $directoryPackageFqName package are expected."
@@ -81,7 +81,7 @@ public class DeserializerForClassfileDecompiler(
val membersScope = DeserializedPackageMemberScope( val membersScope = DeserializedPackageMemberScope(
createDummyPackageFragment(packageFqName), packageProto, nameResolver, deserializationComponents createDummyPackageFragment(packageFqName), packageProto, nameResolver, deserializationComponents
) { emptyList() } ) { emptyList() }
return membersScope.getContributedDescriptors() return membersScope.getContributedDescriptors().toList()
} }
companion object { companion object {
@@ -26,14 +26,13 @@ import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText 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.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleMultifileClassKind
import org.jetbrains.kotlin.renderer.DescriptorRenderer 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.flexibility
import org.jetbrains.kotlin.types.isFlexible import org.jetbrains.kotlin.types.isFlexible
import java.util.* import java.util.*
@@ -50,14 +49,10 @@ public class KotlinClassFileDecompiler : ClassFileDecompilers.Full() {
return KotlinDecompiledFileViewProvider(manager, file, physical) { provider -> return KotlinDecompiledFileViewProvider(manager, file, physical) { provider ->
val virtualFile = provider.virtualFile val virtualFile = provider.virtualFile
val fileIndex = ServiceManager.getService(project, FileIndexFacade::class.java) val fileIndex = ServiceManager.getService(project, FileIndexFacade::class.java)
if (!fileIndex.isInLibraryClasses(virtualFile) && fileIndex.isInSource(virtualFile)) { when {
null !fileIndex.isInLibraryClasses(virtualFile) && fileIndex.isInSource(virtualFile) -> null
} isKotlinInternalCompiledFile(virtualFile) -> null
else if (isKotlinInternalCompiledFile(virtualFile)) { else -> KtClsFile(provider)
null
}
else {
KtClsFile(provider)
} }
} }
} }
@@ -65,13 +60,9 @@ public class KotlinClassFileDecompiler : ClassFileDecompilers.Full() {
class KtClsFile(provider: KotlinDecompiledFileViewProvider) : KtDecompiledFile(provider, { file -> buildDecompiledTextForClassFile(file) }) class KtClsFile(provider: KotlinDecompiledFileViewProvider) : KtDecompiledFile(provider, { file -> buildDecompiledTextForClassFile(file) })
private val descriptorRendererForClassFileDecompiler = DescriptorRenderer.withOptions { private val decompilerRendererForClassFiles = DescriptorRenderer.withOptions {
withDefinedIn = false defaultDecompilerRendererOptions()
classWithPrimaryConstructor = true
typeNormalizer = { type -> if (type.isFlexible()) type.flexibility().lowerBound else type } 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 FILE_ABI_VERSION_MARKER: String = "FILE_ABI"
@@ -103,13 +94,13 @@ public fun buildDecompiledTextForClassFile(
mapOf()) mapOf())
} }
classHeader.isCompatibleFileFacadeKind() -> classHeader.isCompatibleFileFacadeKind() ->
buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())), descriptorRendererForClassFileDecompiler) buildDecompiledText(packageFqName, ArrayList(resolver.resolveDeclarationsInFacade(classId.asSingleFqName())), decompilerRendererForClassFiles)
classHeader.isCompatibleClassKind() -> classHeader.isCompatibleClassKind() ->
buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), descriptorRendererForClassFileDecompiler) buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), decompilerRendererForClassFiles)
classHeader.isCompatibleMultifileClassKind() -> { classHeader.isCompatibleMultifileClassKind() -> {
val partClasses = findMultifileClassParts(classFile, kotlinClass) val partClasses = findMultifileClassParts(classFile, kotlinClass)
val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) } val partMembers = partClasses.flatMap { partClass -> resolver.resolveDeclarationsInFacade(partClass.classId.asSingleFqName()) }
buildDecompiledText(packageFqName, partMembers, descriptorRendererForClassFileDecompiler) buildDecompiledText(packageFqName, partMembers, decompilerRendererForClassFiles)
} }
else -> else ->
throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}") throw UnsupportedOperationException("Unknown header kind: ${classHeader.kind} ${classHeader.isCompatibleAbiVersion}")
@@ -14,25 +14,27 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.idea.decompiler.js package org.jetbrains.kotlin.idea.decompiler.common
import com.google.protobuf.MessageLite import com.google.protobuf.MessageLite
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.ClassIdWithTarget import org.jetbrains.kotlin.idea.decompiler.stubBuilder.ClassIdWithTarget
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantLoader import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantLoader
import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.js.JsProtoBuf
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
public class AnnotationLoaderForKotlinJavaScriptStubBuilder() : AnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget> { public class AnnotationLoaderForStubBuilderImpl(
private val protocol: SerializerExtensionProtocol
) : AnnotationAndConstantLoader<ClassId, Unit, ClassIdWithTarget> {
override fun loadClassAnnotations( override fun loadClassAnnotations(
classProto: ProtoBuf.Class, nameResolver: NameResolver classProto: ProtoBuf.Class, nameResolver: NameResolver
): List<ClassId> = ): List<ClassId> =
classProto.getExtension(JsProtoBuf.classAnnotation).orEmpty().map { nameResolver.getClassId(it.id) } classProto.getExtension(protocol.classAnnotation).orEmpty().map { nameResolver.getClassId(it.id) }
override fun loadCallableAnnotations( override fun loadCallableAnnotations(
container: ProtoContainer, container: ProtoContainer,
@@ -40,9 +42,9 @@ public class AnnotationLoaderForKotlinJavaScriptStubBuilder() : AnnotationAndCon
kind: AnnotatedCallableKind kind: AnnotatedCallableKind
): List<ClassIdWithTarget> { ): List<ClassIdWithTarget> {
val annotations = when (proto) { val annotations = when (proto) {
is ProtoBuf.Constructor -> proto.getExtension(JsProtoBuf.constructorAnnotation) is ProtoBuf.Constructor -> proto.getExtension(protocol.constructorAnnotation)
is ProtoBuf.Function -> proto.getExtension(JsProtoBuf.functionAnnotation) is ProtoBuf.Function -> proto.getExtension(protocol.functionAnnotation)
is ProtoBuf.Property -> proto.getExtension(JsProtoBuf.propertyAnnotation) is ProtoBuf.Property -> proto.getExtension(protocol.propertyAnnotation)
else -> error("Unknown message: $proto") else -> error("Unknown message: $proto")
}.orEmpty() }.orEmpty()
return annotations.map { return annotations.map {
@@ -57,7 +59,7 @@ public class AnnotationLoaderForKotlinJavaScriptStubBuilder() : AnnotationAndCon
parameterIndex: Int, parameterIndex: Int,
proto: ProtoBuf.ValueParameter proto: ProtoBuf.ValueParameter
): List<ClassId> = ): List<ClassId> =
proto.getExtension(JsProtoBuf.parameterAnnotation).orEmpty().map { proto.getExtension(protocol.parameterAnnotation).orEmpty().map {
container.nameResolver.getClassId(it.id) container.nameResolver.getClassId(it.id)
} }
@@ -71,10 +73,10 @@ public class AnnotationLoaderForKotlinJavaScriptStubBuilder() : AnnotationAndCon
proto: ProtoBuf.Type, proto: ProtoBuf.Type,
nameResolver: NameResolver nameResolver: NameResolver
): List<ClassId> = ): List<ClassId> =
proto.getExtension(JsProtoBuf.typeAnnotation).orEmpty().map { nameResolver.getClassId(it.id) } proto.getExtension(protocol.typeAnnotation).orEmpty().map { nameResolver.getClassId(it.id) }
override fun loadTypeParameterAnnotations(proto: ProtoBuf.TypeParameter, nameResolver: NameResolver): List<ClassId> = override fun loadTypeParameterAnnotations(proto: ProtoBuf.TypeParameter, nameResolver: NameResolver): List<ClassId> =
proto.getExtension(JsProtoBuf.typeParameterAnnotation).orEmpty().map { nameResolver.getClassId(it.id) } proto.getExtension(protocol.typeParameterAnnotation).orEmpty().map { nameResolver.getClassId(it.id) }
override fun loadPropertyConstant( override fun loadPropertyConstant(
container: ProtoContainer, container: ProtoContainer,
@@ -14,18 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
package org.jetbrains.kotlin.serialization.js package org.jetbrains.kotlin.idea.decompiler.common
import com.google.protobuf.ExtensionRegistryLite
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
public fun ByteArray.toPackageProto(): ProtoBuf.Package { fun ByteArray.toPackageProto(extensionRegistry: ExtensionRegistryLite): ProtoBuf.Package {
val registry = KotlinJavascriptSerializedResourcePaths.extensionRegistry return ProtoBuf.Package.parseFrom(ByteArrayInputStream(this), extensionRegistry)!!
return ProtoBuf.Package.parseFrom(ByteArrayInputStream(this), registry)!!
}
public fun ByteArray.toClassProto(): ProtoBuf.Class {
val registry = KotlinJavascriptSerializedResourcePaths.extensionRegistry
return ProtoBuf.Class.parseFrom(ByteArrayInputStream(this), registry)
} }
fun ByteArray.toClassProto(extensionRegistry: ExtensionRegistryLite): ProtoBuf.Class {
return ProtoBuf.Class.parseFrom(ByteArrayInputStream(this), extensionRegistry)
}
@@ -0,0 +1,49 @@
/*
* 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.common
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.ClassData
import org.jetbrains.kotlin.serialization.ClassDataWithSource
import org.jetbrains.kotlin.serialization.SerializedResourcePaths
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
class DirectoryBasedClassDataFinder(
private val packageDirectory: VirtualFile,
private val directoryPackageFqName: FqName,
private val nameResolver: NameResolver,
private val paths: SerializedResourcePaths
) : ClassDataFinder {
fun findFileForClass(classId: ClassId): VirtualFile? {
if (classId.packageFqName != directoryPackageFqName) return null
val pathRelativeToDir = paths.getClassMetadataPath(classId).substringAfterLast("/")
return packageDirectory.findChild(pathRelativeToDir)
}
override fun findClassData(classId: ClassId): ClassDataWithSource? {
val virtualFile = findFileForClass(classId) ?: return null
val content = virtualFile.contentsToByteArray(false)
val classProto = content.toClassProto(paths.extensionRegistry)
return ClassDataWithSource(ClassData(nameResolver, classProto))
}
}
@@ -19,19 +19,17 @@ package org.jetbrains.kotlin.idea.decompiler.js
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.decompiler.common.DirectoryBasedClassDataFinder
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DeserializerForDecompilerBase import org.jetbrains.kotlin.idea.decompiler.textBuilder.DeserializerForDecompilerBase
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassResolver import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolveEverythingToKotlinAnyLocalClassResolver
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.resolve.JsPlatform import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.serialization.ClassData
import org.jetbrains.kotlin.serialization.ClassDataWithSource
import org.jetbrains.kotlin.serialization.deserialization.* import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.serialization.js.* import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializedResourcePaths
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
public class KotlinJavaScriptDeserializerForDecompiler( public class KotlinJavaScriptDeserializerForDecompiler(
@@ -48,62 +46,22 @@ public class KotlinJavaScriptDeserializerForDecompiler(
override val targetPlatform: TargetPlatform get() = JsPlatform override val targetPlatform: TargetPlatform get() = JsPlatform
private val metaFileFinder = DirectoryBasedKotlinJavaScriptMetaFileFinder(packageDirectory, directoryPackageFqName, nameResolver) private val finder = DirectoryBasedClassDataFinder(packageDirectory, directoryPackageFqName, nameResolver, KotlinJavascriptSerializedResourcePaths)
private val classDataFinder = DirectoryBasedKotlinJavaScriptDataFinder(metaFileFinder, LOG)
private val annotationAndConstantLoader = AnnotationAndConstantLoaderImpl(moduleDescriptor, JsSerializerProtocol) private val annotationAndConstantLoader = AnnotationAndConstantLoaderImpl(moduleDescriptor, JsSerializerProtocol)
override val deserializationComponents = DeserializationComponents( override val deserializationComponents = DeserializationComponents(
storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, storageManager, moduleDescriptor, finder, annotationAndConstantLoader, packageFragmentProvider,
ResolveEverythingToKotlinAnyLocalClassResolver(targetPlatform.builtIns), LoggingErrorReporter(LOG), ResolveEverythingToKotlinAnyLocalClassResolver(targetPlatform.builtIns), LoggingErrorReporter(LOG),
LookupTracker.DO_NOTHING, FlexibleTypeCapabilitiesDeserializer.Dynamic, ClassDescriptorFactory.EMPTY LookupTracker.DO_NOTHING, FlexibleTypeCapabilitiesDeserializer.Dynamic, ClassDescriptorFactory.EMPTY
) )
override fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection<DeclarationDescriptor> { override fun resolveDeclarationsInFacade(facadeFqName: FqName): List<DeclarationDescriptor> {
val packageFqName = facadeFqName.parent() val packageFqName = facadeFqName.parent()
assert(packageFqName == directoryPackageFqName) { return getDescriptorsFromPackageFile(packageFqName, KotlinJavascriptSerializedResourcePaths, LOG, nameResolver)
"Was called for $facadeFqName; only members of $directoryPackageFqName package are expected."
}
val file = metaFileFinder.findKotlinJavascriptMetaFile(ClassId.topLevel(facadeFqName))
if (file == null) {
LOG.error("Could not read data for $facadeFqName")
return emptyList()
}
val content = file.contentsToByteArray(false)
val membersScope = DeserializedPackageMemberScope(
createDummyPackageFragment(packageFqName), content.toPackageProto(), nameResolver, deserializationComponents
) { emptyList() }
return membersScope.getContributedDescriptors()
} }
companion object { companion object {
private val LOG = Logger.getInstance(KotlinJavaScriptDeserializerForDecompiler::class.java) 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)
return ClassDataWithSource(ClassData(classFinder.nameResolver, content.toClassProto()))
}
}
@@ -26,11 +26,10 @@ import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler import org.jetbrains.kotlin.idea.decompiler.textBuilder.ResolverForDecompiler
import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText import org.jetbrains.kotlin.idea.decompiler.textBuilder.buildDecompiledText
import org.jetbrains.kotlin.idea.decompiler.textBuilder.defaultDecompilerRendererOptions
import org.jetbrains.kotlin.load.kotlin.OldPackageFacadeClassUtils import org.jetbrains.kotlin.load.kotlin.OldPackageFacadeClassUtils
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.ExcludedTypeAnnotations
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import java.util.* import java.util.*
@@ -57,13 +56,7 @@ class KotlinJavaScriptMetaFileDecompiler : ClassFileDecompilers.Full() {
} }
} }
private val descriptorRendererForKotlinJavascriptDecompiler = DescriptorRenderer.withOptions { private val decompilerRendererForJS = DescriptorRenderer.withOptions { defaultDecompilerRendererOptions() }
withDefinedIn = false
classWithPrimaryConstructor = true
secondaryConstructorsAsPrimary = false
modifiers = DescriptorRendererModifier.ALL
excludedTypeAnnotationClasses = ExcludedTypeAnnotations.annotationsForNullabilityAndMutability
}
public fun buildDecompiledTextFromJsMetadata( public fun buildDecompiledTextFromJsMetadata(
classFile: VirtualFile, classFile: VirtualFile,
@@ -75,11 +68,11 @@ public fun buildDecompiledTextFromJsMetadata(
if (isPackageHeader) { if (isPackageHeader) {
return buildDecompiledText(packageFqName, return buildDecompiledText(packageFqName,
resolveDeclarationsInPackage(packageFqName, resolver), resolveDeclarationsInPackage(packageFqName, resolver),
descriptorRendererForKotlinJavascriptDecompiler) decompilerRendererForJS)
} }
else { else {
val classId = JsMetaFileUtils.getClassId(classFile) val classId = JsMetaFileUtils.getClassId(classFile)
return buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), descriptorRendererForKotlinJavascriptDecompiler) return buildDecompiledText(packageFqName, listOfNotNull(resolver.resolveTopLevelClass(classId)), decompilerRendererForJS)
} }
} }
@@ -16,12 +16,15 @@
package org.jetbrains.kotlin.idea.decompiler.js package org.jetbrains.kotlin.idea.decompiler.js
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.compiled.ClsStubBuilder import com.intellij.psi.compiled.ClsStubBuilder
import com.intellij.psi.impl.compiled.ClassFileStubBuilder import com.intellij.psi.impl.compiled.ClassFileStubBuilder
import com.intellij.psi.stubs.PsiFileStub import com.intellij.psi.stubs.PsiFileStub
import com.intellij.util.indexing.FileContent import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.idea.decompiler.common.AnnotationLoaderForStubBuilderImpl
import org.jetbrains.kotlin.idea.decompiler.common.DirectoryBasedClassDataFinder
import org.jetbrains.kotlin.idea.decompiler.common.toClassProto
import org.jetbrains.kotlin.idea.decompiler.common.toPackageProto
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.ClsStubBuilderComponents import org.jetbrains.kotlin.idea.decompiler.stubBuilder.ClsStubBuilderComponents
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createPackageFacadeStub import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createPackageFacadeStub
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createTopLevelClassStub import org.jetbrains.kotlin.idea.decompiler.stubBuilder.createTopLevelClassStub
@@ -30,9 +33,8 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.deserialization.NameResolver import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl import org.jetbrains.kotlin.serialization.deserialization.NameResolverImpl
import org.jetbrains.kotlin.serialization.deserialization.TypeTable import org.jetbrains.kotlin.serialization.deserialization.TypeTable
import org.jetbrains.kotlin.serialization.js.JsSerializerProtocol
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializedResourcePaths import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializedResourcePaths
import org.jetbrains.kotlin.serialization.js.toClassProto
import org.jetbrains.kotlin.serialization.js.toPackageProto
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
public class KotlinJavaScriptStubBuilder : ClsStubBuilder() { public class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
@@ -61,14 +63,14 @@ public class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
val components = createStubBuilderComponents(file, packageFqName, nameResolver) val components = createStubBuilderComponents(file, packageFqName, nameResolver)
if (isPackageHeader) { if (isPackageHeader) {
val packageProto = content.toPackageProto() val packageProto = content.toPackageProto(KotlinJavascriptSerializedResourcePaths.extensionRegistry)
val context = components.createContext( val context = components.createContext(
nameResolver, packageFqName, TypeTable(packageProto.typeTable) nameResolver, packageFqName, TypeTable(packageProto.typeTable)
) )
return createPackageFacadeStub(packageProto, packageFqName, context) return createPackageFacadeStub(packageProto, packageFqName, context)
} }
else { else {
val classProto = content.toClassProto() val classProto = content.toClassProto(KotlinJavascriptSerializedResourcePaths.extensionRegistry)
val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable)) val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable))
val classId = JsMetaFileUtils.getClassId(file) val classId = JsMetaFileUtils.getClassId(file)
return createTopLevelClassStub(classId, classProto, context) return createTopLevelClassStub(classId, classProto, context)
@@ -76,13 +78,10 @@ public class KotlinJavaScriptStubBuilder : ClsStubBuilder() {
} }
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName, nameResolver: NameResolver): ClsStubBuilderComponents { private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName, nameResolver: NameResolver): ClsStubBuilderComponents {
val metaFileFinder = DirectoryBasedKotlinJavaScriptMetaFileFinder(file.parent!!, packageFqName, nameResolver) val classDataFinder = DirectoryBasedClassDataFinder(
val classDataFinder = DirectoryBasedKotlinJavaScriptDataFinder(metaFileFinder, LOG) file.parent!!, packageFqName, nameResolver, KotlinJavascriptSerializedResourcePaths
val annotationLoader = AnnotationLoaderForKotlinJavaScriptStubBuilder() )
val annotationLoader = AnnotationLoaderForStubBuilderImpl(JsSerializerProtocol)
return ClsStubBuilderComponents(classDataFinder, annotationLoader) return ClsStubBuilderComponents(classDataFinder, annotationLoader)
} }
companion object {
val LOG = Logger.getInstance(KotlinJavaScriptStubBuilder::class.java)
}
} }
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.DescriptorRendererOptions
import org.jetbrains.kotlin.renderer.ExcludedTypeAnnotations
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
@@ -42,6 +44,14 @@ public fun descriptorToKey(descriptor: DeclarationDescriptor): String {
public data class DecompiledText(public val text: String, public val renderedDescriptorsToRange: Map<String, TextRange>) public data class DecompiledText(public val text: String, public val renderedDescriptorsToRange: Map<String, TextRange>)
fun DescriptorRendererOptions.defaultDecompilerRendererOptions() {
withDefinedIn = false
classWithPrimaryConstructor = true
secondaryConstructorsAsPrimary = false
modifiers = DescriptorRendererModifier.ALL
excludedTypeAnnotationClasses = ExcludedTypeAnnotations.annotationsForNullabilityAndMutability
}
public fun buildDecompiledText( public fun buildDecompiledText(
packageFqName: FqName, packageFqName: FqName,
descriptors: List<DeclarationDescriptor>, descriptors: List<DeclarationDescriptor>,
@@ -16,25 +16,22 @@
package org.jetbrains.kotlin.idea.decompiler.textBuilder package org.jetbrains.kotlin.idea.decompiler.textBuilder
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ModuleParameters
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.idea.decompiler.common.toPackageProto
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.serialization.SerializedResourcePaths
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.DeserializationComponents
import org.jetbrains.kotlin.serialization.deserialization.LocalClassResolver import org.jetbrains.kotlin.serialization.deserialization.LocalClassResolver
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager import org.jetbrains.kotlin.storage.StorageManager
@@ -63,7 +60,31 @@ public abstract class DeserializerForDecompilerBase(
override fun resolveTopLevelClass(classId: ClassId) = deserializationComponents.deserializeClass(classId) override fun resolveTopLevelClass(classId: ClassId) = deserializationComponents.deserializeClass(classId)
protected fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor = protected fun createDummyPackageFragment(fqName: FqName): MutablePackageFragmentDescriptor =
MutablePackageFragmentDescriptor(moduleDescriptor, fqName) MutablePackageFragmentDescriptor(moduleDescriptor, fqName)
protected fun getDescriptorsFromPackageFile(
packageFqName: FqName,
paths: SerializedResourcePaths,
log: Logger,
nameResolver: NameResolver
): List<DeclarationDescriptor> {
assert(packageFqName == directoryPackageFqName) {
"Was called for $packageFqName; only members of $directoryPackageFqName package are expected."
}
val packageFilePath = paths.getPackageFilePath(directoryPackageFqName).substringAfterLast("/")
val file = packageDirectory.findChild(packageFilePath)
if (file == null) {
log.error("Could not read data for package $packageFqName; $packageFilePath absent in $packageDirectory")
return emptyList()
}
val content = file.contentsToByteArray(false)
val packageProto = content.toPackageProto(paths.extensionRegistry)
val membersScope = DeserializedPackageMemberScope(
createDummyPackageFragment(packageFqName), packageProto, nameResolver, deserializationComponents
) { emptyList() }
return membersScope.getContributedDescriptors().toList()
}
private fun createDummyModule(name: String) = ModuleDescriptorImpl(Name.special("<$name>"), storageManager, ModuleParameters.Empty, targetPlatform.builtIns) private fun createDummyModule(name: String) = ModuleDescriptorImpl(Name.special("<$name>"), storageManager, ModuleParameters.Empty, targetPlatform.builtIns)
@@ -24,5 +24,5 @@ import org.jetbrains.kotlin.name.ClassId
public interface ResolverForDecompiler { public interface ResolverForDecompiler {
public fun resolveTopLevelClass(classId: ClassId): ClassDescriptor? public fun resolveTopLevelClass(classId: ClassId): ClassDescriptor?
public fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection<DeclarationDescriptor> public fun resolveDeclarationsInFacade(facadeFqName: FqName): List<DeclarationDescriptor>
} }
@@ -16,14 +16,18 @@
package org.jetbrains.kotlin.idea.util package org.jetbrains.kotlin.idea.util
import com.intellij.openapi.roots.ProjectFileIndex import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.util.application.runReadAction
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectFileIndex
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiDirectory
import com.intellij.ide.highlighter.JavaClassFileType import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.caches.resolve.JsProjectDetector import org.jetbrains.kotlin.idea.caches.resolve.JsProjectDetector
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInClassFileType
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInPackageFileType
import org.jetbrains.kotlin.idea.util.application.runReadAction
private val classFileLike = setOf(JavaClassFileType.INSTANCE, KotlinBuiltInClassFileType, KotlinBuiltInPackageFileType)
public object ProjectRootsUtil { public object ProjectRootsUtil {
@JvmStatic @JvmStatic
@@ -42,7 +46,7 @@ public object ProjectRootsUtil {
|| (includeLibraryClasses && fileIndex.isLibraryClassFile(file)) || (includeLibraryClasses && fileIndex.isLibraryClassFile(file))
} }
// NOTE: the following is a workaround for cases when class files are under library source roots and source files are under class roots // NOTE: the following is a workaround for cases when class files are under library source roots and source files are under class roots
val isClassFile = file.getFileType() == JavaClassFileType.INSTANCE val isClassFile = file.fileType in classFileLike
return (includeLibraryClasses && isClassFile && fileIndex.isInLibraryClasses(file)) return (includeLibraryClasses && isClassFile && fileIndex.isInLibraryClasses(file))
|| (includeLibrarySource && !isClassFile && fileIndex.isInLibrarySource(file)) || (includeLibrarySource && !isClassFile && fileIndex.isInLibrarySource(file))
} }
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker import org.jetbrains.kotlin.idea.caches.resolve.LibraryModificationTracker
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
import org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver import org.jetbrains.kotlin.idea.references.BuiltInsReferenceResolver
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import java.util.* import java.util.*
@@ -106,7 +106,7 @@ public fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: RunnableWit
builtInsSources.forEach { unInvalidateFile(it) } builtInsSources.forEach { unInvalidateFile(it) }
stdLibViewProviders.forEach { stdLibViewProviders.forEach {
it.allFiles.forEach { unInvalidateFile(it as KtClsFile) } it.allFiles.forEach { unInvalidateFile(it as KtDecompiledFile) }
vFileToViewProviderMap.set(it.virtualFile, it) vFileToViewProviderMap.set(it.virtualFile, it)
} }
} }
+11 -3
View File
@@ -275,7 +275,7 @@
<projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache" <projectService serviceInterface="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"
serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"/> serviceImplementation="org.jetbrains.kotlin.idea.caches.resolve.ClsJavaStubByVirtualFileCache"/>
<projectService serviceInterface="org.jetbrains.kotlin.console.KotlinConsoleKeeper" <projectService serviceInterface="org.jetbrains.kotlin.console.KotlinConsoleKeeper"
serviceImplementation="org.jetbrains.kotlin.console.KotlinConsoleKeeper"/> serviceImplementation="org.jetbrains.kotlin.console.KotlinConsoleKeeper"/>
@@ -293,6 +293,7 @@
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinFileTypeFactory"/> <fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinFileTypeFactory"/>
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinJavaScriptMetaFileTypeFactory"/> <fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinJavaScriptMetaFileTypeFactory"/>
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinBuiltInFileTypeFactory"/>
<fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinModuleFileFactory"/> <fileTypeFactory implementation="org.jetbrains.kotlin.idea.KotlinModuleFileFactory"/>
<compileServer.plugin classpath="jps/kotlin-jps-plugin.jar;kotlin-runtime.jar;kotlin-reflect.jar;kotlin-plugin.jar;kotlin-android-extensions-plugin.jar;kotlin-android-extensions-compiler-plugin.jar"/> <compileServer.plugin classpath="jps/kotlin-jps-plugin.jar;kotlin-runtime.jar;kotlin-reflect.jar;kotlin-plugin.jar;kotlin-android-extensions-plugin.jar;kotlin-android-extensions-compiler-plugin.jar"/>
@@ -560,6 +561,7 @@
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.classFile.KotlinClassFileDecompiler"/> <psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.classFile.KotlinClassFileDecompiler"/>
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileDecompiler"/> <psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileDecompiler"/>
<psi.classFileDecompiler implementation="org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInDecompiler"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinAbiVersionIndex"/> <fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinAbiVersionIndex"/>
<fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinJavaScriptAbiVersionIndex"/> <fileBasedIndex implementation="org.jetbrains.kotlin.idea.versions.KotlinJavaScriptAbiVersionIndex"/>
@@ -1300,11 +1302,17 @@
<referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/> <referenceImporter implementation="org.jetbrains.kotlin.idea.quickfix.KotlinReferenceImporter"/>
<fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/> <fileType.fileViewProviderFactory filetype="KJSM" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
<filetype.stubBuilder filetype="KJSM" implementationClass="com.intellij.psi.impl.compiled.ClassFileStubBuilder"/> <filetype.stubBuilder filetype="KJSM" implementationClass="com.intellij.psi.impl.compiled.ClassFileStubBuilder"/>
<filetype.decompiler filetype="KJSM" implementationClass="com.intellij.psi.impl.compiled.ClassFileDecompiler"/> <filetype.decompiler filetype="KJSM" implementationClass="com.intellij.psi.impl.compiled.ClassFileDecompiler"/>
<fileType.fileViewProviderFactory filetype="kotlin_class" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
<filetype.stubBuilder filetype="kotlin_class" implementationClass="com.intellij.psi.impl.compiled.ClassFileStubBuilder"/>
<filetype.decompiler filetype="kotlin_class" implementationClass="com.intellij.psi.impl.compiled.ClassFileDecompiler"/>
<fileType.fileViewProviderFactory filetype="kotlin_package" implementationClass="com.intellij.psi.ClassFileViewProviderFactory"/>
<filetype.stubBuilder filetype="kotlin_package" implementationClass="com.intellij.psi.impl.compiled.ClassFileStubBuilder"/>
<filetype.decompiler filetype="kotlin_package" implementationClass="com.intellij.psi.impl.compiled.ClassFileDecompiler"/>
<pathMacroExpandableProtocol protocol="kotlin-js-meta"/> <pathMacroExpandableProtocol protocol="kotlin-js-meta"/>
</extensions> </extensions>
@@ -0,0 +1,28 @@
/*
* 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
import com.intellij.openapi.fileTypes.FileTypeConsumer
import com.intellij.openapi.fileTypes.FileTypeFactory
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInClassFileType
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInPackageFileType
class KotlinBuiltInFileTypeFactory : FileTypeFactory() {
override fun createFileTypes(consumer: FileTypeConsumer) {
consumer.consume(KotlinBuiltInClassFileType, KotlinBuiltInClassFileType.defaultExtension)
consumer.consume(KotlinBuiltInPackageFileType, KotlinBuiltInPackageFileType.defaultExtension)
}
}
@@ -77,7 +77,7 @@ public abstract class TextConsistencyBaseTest : KotlinLightCodeInsightFixtureTes
override fun resolveTopLevelClass(classId: ClassId): ClassDescriptor? = override fun resolveTopLevelClass(classId: ClassId): ClassDescriptor? =
module.resolveTopLevelClass(classId.asSingleFqName(), NoLookupLocation.FROM_TEST) module.resolveTopLevelClass(classId.asSingleFqName(), NoLookupLocation.FROM_TEST)
override fun resolveDeclarationsInFacade(facadeFqName: FqName): Collection<DeclarationDescriptor> = override fun resolveDeclarationsInFacade(facadeFqName: FqName): List<DeclarationDescriptor> =
module.getPackage(facadeFqName.parent()).memberScope.getContributedDescriptors().filter { module.getPackage(facadeFqName.parent()).memberScope.getContributedDescriptors().filter {
it is CallableMemberDescriptor && it is CallableMemberDescriptor &&
it.module != module.builtIns.builtInsModule && it.module != module.builtIns.builtInsModule &&