From 136e8d9d0206feb6a8e909a65deebb2eba2f24b0 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Wed, 2 Dec 2015 18:31:12 +0300 Subject: [PATCH] Refactor: repackage decompiler code and explicitly extract class file and js metafile parts --- ...> KotlinDecompiledFileViewProviderBase.kt} | 37 +----- .../decompiler/KotlinJavascriptMetaFile.kt | 27 ----- .../kotlin/idea/decompiler/KtClsFile.kt | 27 ----- ...ClsFileBase.kt => KtDecompiledFileBase.kt} | 2 +- .../ClassFileDecompilerUtil.kt} | 10 +- .../DeserializerForClassfileDecompiler.kt | 62 +++++++++- .../KotlinClassFileDecompiler.kt | 3 +- .../classFile/KotlinClassFileViewProvider.kt | 46 +++++++ .../KotlinClsStubBuilder.kt | 56 ++++++++- .../idea/decompiler/classFile/KtClsFile.kt | 93 ++++++++++++++ ...ionLoaderForKotlinJavaScriptStubBuilder.kt | 2 +- .../{navigation => js}/JsMetaFileUtils.kt | 8 +- ...tlinJavaScriptDeserializerForDecompiler.kt | 36 +++++- .../KotlinJavaScriptMetaFileDecompiler.java | 6 +- .../{ => js}/KotlinJavaScriptMetaFileType.kt | 4 +- .../KotlinJavaScriptStubBuilder.kt | 14 +-- .../decompiler/js/KotlinJavascriptMetaFile.kt | 65 ++++++++++ .../KotlinJavascriptMetaFileViewProvider.kt | 36 ++++++ .../navigation/DecompiledNavigationUtils.java | 6 +- .../stubBuilder/ClsStubBuilderContext.kt | 47 +------- .../textBuilder/DecompiledTextFactory.kt | 93 +------------- .../DeserializerForDecompilerBase.kt | 9 +- .../textBuilder/DirectoryBasedClassFinder.kt | 113 ------------------ .../KtClsStructureViewBuilderProvider.kt | 2 +- .../kotlin/idea/vfilefinder/fileIndexes.kt | 4 +- .../jetbrains/kotlin/idea/test/testUtils.kt | 4 +- idea/src/META-INF/plugin.xml | 4 +- .../KotlinJavaScriptMetaFileTypeFactory.kt | 2 +- .../kotlin/idea/PluginStartupComponent.java | 2 +- .../idea/debugger/KotlinPositionManager.kt | 2 +- .../NavigateToDecompiledLibraryTest.java | 2 +- .../stubBuilder/AbstractClsStubBuilderTest.kt | 1 + .../stubBuilder/ClsStubConsistencyTest.kt | 5 +- .../KotlinJavaScriptStubConsistencyTest.kt | 3 +- ...bstractDecompiledTextFromJsMetadataTest.kt | 2 +- .../textBuilder/AbstractDecompiledTextTest.kt | 2 +- .../DecompiledTextConsistencyTest.kt | 4 +- .../DecompiledTextForWrongAbiVersionTest.kt | 3 +- ...JavaScriptDecompiledTextConsistencyTest.kt | 1 + 39 files changed, 441 insertions(+), 404 deletions(-) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{kotlinFileViewProviders.kt => KotlinDecompiledFileViewProviderBase.kt} (58%) delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavascriptMetaFile.kt delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFile.kt rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{KtClsFileBase.kt => KtDecompiledFileBase.kt} (95%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{DecompiledUtils.kt => classFile/ClassFileDecompilerUtil.kt} (89%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{textBuilder => classFile}/DeserializerForClassfileDecompiler.kt (63%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{ => classFile}/KotlinClassFileDecompiler.kt (90%) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileViewProvider.kt rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{stubBuilder => classFile}/KotlinClsStubBuilder.kt (62%) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KtClsFile.kt rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{ => js}/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt (98%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{navigation => js}/JsMetaFileUtils.kt (88%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{textBuilder => js}/KotlinJavaScriptDeserializerForDecompiler.kt (72%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{ => js}/KotlinJavaScriptMetaFileDecompiler.java (87%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{ => js}/KotlinJavaScriptMetaFileType.kt (96%) rename idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/{stubBuilder => js}/KotlinJavaScriptStubBuilder.kt (85%) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFile.kt create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFileViewProvider.kt delete mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DirectoryBasedClassFinder.kt diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/kotlinFileViewProviders.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinDecompiledFileViewProviderBase.kt similarity index 58% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/kotlinFileViewProviders.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinDecompiledFileViewProviderBase.kt index 2a11c520118..3b55177a35f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/kotlinFileViewProviders.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinDecompiledFileViewProviderBase.kt @@ -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()) - 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) } \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavascriptMetaFile.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavascriptMetaFile.kt deleted file mode 100644 index 27edb383799..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavascriptMetaFile.kt +++ /dev/null @@ -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 = LockedClearableLazyValue(Any()) { - buildDecompiledTextFromJsMetadata(getVirtualFile()) - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFile.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFile.kt deleted file mode 100644 index 0a7a3d9b59e..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFile.kt +++ /dev/null @@ -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 = LockedClearableLazyValue(Any()) { - buildDecompiledText(getVirtualFile()) - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFileBase.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtDecompiledFileBase.kt similarity index 95% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFileBase.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtDecompiledFileBase.kt index 04191131da2..3620cf739f3 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtClsFileBase.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KtDecompiledFileBase.kt @@ -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 public fun getDeclarationForDescriptor(descriptor: DeclarationDescriptor): KtDeclaration? { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/DecompiledUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt similarity index 89% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/DecompiledUtils.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt index 4d686ba9c1f..bf23bd95131 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/DecompiledUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/ClassFileDecompilerUtil.kt @@ -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('/')))) } -} +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForClassfileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt similarity index 63% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForClassfileDecompiler.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt index 2d80f6f7075..440110b41f0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForClassfileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/DeserializerForClassfileDecompiler.kt @@ -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()) + } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinClassFileDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt similarity index 90% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinClassFileDecompiler.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt index a3c1b2b5b03..55ed1494817 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinClassFileDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileDecompiler.kt @@ -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() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileViewProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileViewProvider.kt new file mode 100644 index 00000000000..1b80dedaffa --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClassFileViewProvider.kt @@ -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()) + 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) +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt similarity index 62% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt index 03e550ea088..e0f2ca01592 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KotlinClsStubBuilder.kt @@ -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( + LockBasedStorageManager.NO_LOCKS, kotlinClassFinder, errorReporter) { + + override fun loadClassAnnotations( + classProto: ProtoBuf.Class, + nameResolver: NameResolver + ): List { + 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 + ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + result.add(annotationClassId) + return null + } + + override fun loadPropertyAnnotations(propertyAnnotations: List, fieldAnnotations: List): List { + return propertyAnnotations.map { ClassIdWithTarget(it, null) } + + fieldAnnotations.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.FIELD) } + } + + override fun transformAnnotations(annotations: List) = annotations.map { ClassIdWithTarget(it, null) } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KtClsFile.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KtClsFile.kt new file mode 100644 index 00000000000..1a77bf86d0e --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/classFile/KtClsFile.kt @@ -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 = 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}") + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt similarity index 98% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt index 66288ba8f6b..1e3f04c1069 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/AnnotationLoaderForKotlinJavaScriptStubBuilder.kt @@ -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 diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/JsMetaFileUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/JsMetaFileUtils.kt similarity index 88% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/JsMetaFileUtils.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/JsMetaFileUtils.kt index 3335beed7c4..b744eca58de 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/JsMetaFileUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/JsMetaFileUtils.kt @@ -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() } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptDeserializerForDecompiler.kt similarity index 72% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptDeserializerForDecompiler.kt index 2d55be008eb..0a960653172 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDeserializerForDecompiler.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptDeserializerForDecompiler.kt @@ -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) + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavaScriptMetaFileDecompiler.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.java similarity index 87% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavaScriptMetaFileDecompiler.java rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.java index 1fbd81b93cd..c1ba5e77497 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavaScriptMetaFileDecompiler.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileDecompiler.java @@ -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)); } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavaScriptMetaFileType.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileType.kt similarity index 96% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavaScriptMetaFileType.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileType.kt index 7b975c27772..a24e0206bb5 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/KotlinJavaScriptMetaFileType.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptMetaFileType.kt @@ -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 -} \ No newline at end of file +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt similarity index 85% rename from idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt rename to idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt index 7db2b680049..3797eb3382a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavaScriptStubBuilder.kt @@ -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) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFile.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFile.kt new file mode 100644 index 00000000000..dece86b90f3 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFile.kt @@ -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 = 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))) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFileViewProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFileViewProvider.kt new file mode 100644 index 00000000000..7da4f2f1d8f --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/js/KotlinJavascriptMetaFileViewProvider.kt @@ -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) +} \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/DecompiledNavigationUtils.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/DecompiledNavigationUtils.java index dba41456e5e..46173caa636 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/DecompiledNavigationUtils.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/DecompiledNavigationUtils.java @@ -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) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderContext.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderContext.kt index 072bbe78e40..ad3872f9e7b 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderContext.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubBuilderContext.kt @@ -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( - LockBasedStorageManager.NO_LOCKS, kotlinClassFinder, errorReporter) { - - override fun loadClassAnnotations( - classProto: ProtoBuf.Class, - nameResolver: NameResolver - ): List { - 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 - ): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { - result.add(annotationClassId) - return null - } - - override fun loadPropertyAnnotations(propertyAnnotations: List, fieldAnnotations: List): List { - return propertyAnnotations.map { ClassIdWithTarget(it, null) } + - fieldAnnotations.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.FIELD) } - } - - override fun transformAnnotations(annotations: List) = annotations.map { ClassIdWithTarget(it, null) } -} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt index 8516aed51a1..6e3e427ca0d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt @@ -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, - descriptorRenderer: DescriptorRenderer = descriptorRendererForDecompiler + descriptorRenderer: DescriptorRenderer ): DecompiledText { val builder = StringBuilder() val renderedDescriptorsToRange = HashMap() diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt index 457e8ad1b2e..14395cf9114 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DeserializerForDecompilerBase.kt @@ -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 ) } -} \ No newline at end of file +} + +class ResolveEverythingToKotlinAnyLocalClassResolver(private val builtIns: KotlinBuiltIns) : LocalClassResolver { + override fun resolveLocalClass(classId: ClassId): ClassDescriptor = builtIns.any +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DirectoryBasedClassFinder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DirectoryBasedClassFinder.kt deleted file mode 100644 index a27c76914b7..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DirectoryBasedClassFinder.kt +++ /dev/null @@ -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()) - } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/structureView/KtClsStructureViewBuilderProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/structureView/KtClsStructureViewBuilderProvider.kt index 302bec0d054..4c180e10b22 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/structureView/KtClsStructureViewBuilderProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/structureView/KtClsStructureViewBuilderProvider.kt @@ -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 { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt index 506027a41bd..1fa3a4b4b20 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/vfilefinder/fileIndexes.kt @@ -20,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 diff --git a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt index d3651bb3f3d..dc76aebf515 100644 --- a/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt +++ b/idea/idea-test-framework/src/org/jetbrains/kotlin/idea/test/testUtils.kt @@ -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.* diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 4faae67eaab..28fb856adbb 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -558,8 +558,8 @@ - - + + diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinJavaScriptMetaFileTypeFactory.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinJavaScriptMetaFileTypeFactory.kt index c8a2cacbac8..bd8dbeefb8a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/KotlinJavaScriptMetaFileTypeFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/KotlinJavaScriptMetaFileTypeFactory.kt @@ -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) { diff --git a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java index 2f425dc59cd..cc6047192e5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java +++ b/idea/src/org/jetbrains/kotlin/idea/PluginStartupComponent.java @@ -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; diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt index eef172bf589..c7ae0a309b8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTest.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTest.java index 4bc7f2ee104..3882c1dd9cc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/navigation/NavigateToDecompiledLibraryTest.java @@ -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; diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt index dea1715cac8..0c36c2c4672 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/AbstractClsStubBuilderTest.kt @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubConsistencyTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubConsistencyTest.kt index 3deb9a72430..b4457fb40b4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubConsistencyTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClsStubConsistencyTest.kt @@ -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 } diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubConsistencyTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubConsistencyTest.kt index d6cd3a4af0d..f115cf886be 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubConsistencyTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/KotlinJavaScriptStubConsistencyTest.kt @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextFromJsMetadataTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextFromJsMetadataTest.kt index 73892258cc6..0904721a363 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextFromJsMetadataTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextFromJsMetadataTest.kt @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextTest.kt index 4d90aab9397..215fc7e4746 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/AbstractDecompiledTextTest.kt @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextConsistencyTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextConsistencyTest.kt index 4c732d52703..1073160bdcc 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextConsistencyTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextConsistencyTest.kt @@ -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( diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextForWrongAbiVersionTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextForWrongAbiVersionTest.kt index 1a88e04f307..c32efd09740 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextForWrongAbiVersionTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextForWrongAbiVersionTest.kt @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDecompiledTextConsistencyTest.kt b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDecompiledTextConsistencyTest.kt index 7b006fb9cde..12089b124fa 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDecompiledTextConsistencyTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/KotlinJavaScriptDecompiledTextConsistencyTest.kt @@ -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