From 86c1dbe7b537b1c2edce2cf830e31d30d58239e4 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 31 Aug 2016 18:56:59 +0300 Subject: [PATCH] Fix decompilation of types based on local classifiers If deserializing a type with arguments based on a local class for decompiler, then just return Any type (without arguments). Previously Any constructor was used with serialized arguments, that lead to exception Note that in case of deserialization for compiler nothing changes about local-classes-based types (LocalClassifierResolverImpl is just inlined) #KT-13408 Fixed --- .../DeserializationComponentsForJava.kt | 5 +-- .../load/kotlin/reflect/RuntimeModuleData.kt | 3 +- .../builtInsPackageFragmentProvider.kt | 5 +-- .../LocalClassifierResolverImpl.kt | 41 ------------------- ...lver.kt => LocalClassifierTypeSettings.kt} | 14 ++++--- .../deserialization/TypeDeserializer.kt | 23 +++++++++-- .../serialization/deserialization/context.kt | 2 +- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 2 +- .../DeserializerForDecompilerBase.kt | 13 +++--- .../LocalClassAsTypeWithArgument.expected.kt | 8 ++++ .../LocalClassAsTypeWithArgument.kt | 8 ++++ .../directives.txt | 2 + ...mpiledTextFromJsMetadataTestGenerated.java | 6 +++ .../CommonDecompiledTextTestGenerated.java | 6 +++ ...kotlinJavascriptPackageFragmentProvider.kt | 5 +-- 15 files changed, 73 insertions(+), 70 deletions(-) delete mode 100644 core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolverImpl.kt rename core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/{LocalClassifierResolver.kt => LocalClassifierTypeSettings.kt} (66%) create mode 100644 idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument.expected.kt create mode 100644 idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/LocalClassAsTypeWithArgument.kt create mode 100644 idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt diff --git a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt index 2d68d28221d..c20e3c71929 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt +++ b/core/descriptor.loader.java/src/org/jetbrains/kotlin/load/kotlin/DeserializationComponentsForJava.kt @@ -37,15 +37,14 @@ class DeserializationComponentsForJava( val components: DeserializationComponents init { - val localClassResolver = LocalClassifierResolverImpl() val settings = JvmBuiltInsSettings(moduleDescriptor, storageManager, { moduleDescriptor }) components = DeserializationComponents( - storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, localClassResolver, + storageManager, moduleDescriptor, classDataFinder, annotationAndConstantLoader, packageFragmentProvider, + LocalClassifierTypeSettings.Default, errorReporter, lookupTracker, JavaFlexibleTypeDeserializer, ClassDescriptorFactory.EMPTY, notFoundClasses, additionalClassPartsProvider = settings, platformDependentDeclarationFilter = settings ) - localClassResolver.setDeserializationComponents(components) } } diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt index 446d7620868..32c5c0ed5e7 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/load/kotlin/reflect/RuntimeModuleData.kt @@ -36,13 +36,12 @@ import org.jetbrains.kotlin.platform.JavaToKotlinClassMap import org.jetbrains.kotlin.platform.JvmBuiltIns import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents -import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierResolver +import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierTypeSettings import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses import org.jetbrains.kotlin.storage.LockBasedStorageManager class RuntimeModuleData private constructor(val deserialization: DeserializationComponents, val packageFacadeProvider: RuntimePackagePartProvider) { val module: ModuleDescriptor get() = deserialization.moduleDescriptor - val localClassifierResolver: LocalClassifierResolver get() = deserialization.localClassifierResolver companion object { fun create(classLoader: ClassLoader): RuntimeModuleData { diff --git a/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt b/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt index 7abf79e39bf..18417b0d2c4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/builtins/builtInsPackageFragmentProvider.kt @@ -40,7 +40,6 @@ fun createBuiltInPackageFragmentProvider( val provider = PackageFragmentProviderImpl(packageFragments) val notFoundClasses = NotFoundClasses(storageManager, module) - val localClassResolver = LocalClassifierResolverImpl() val components = DeserializationComponents( storageManager, @@ -48,7 +47,7 @@ fun createBuiltInPackageFragmentProvider( DeserializedClassDataFinder(provider), AnnotationAndConstantLoaderImpl(module, notFoundClasses, BuiltInSerializerProtocol), provider, - localClassResolver, + LocalClassifierTypeSettings.Default, ErrorReporter.DO_NOTHING, LookupTracker.DO_NOTHING, FlexibleTypeDeserializer.ThrowException, @@ -58,8 +57,6 @@ fun createBuiltInPackageFragmentProvider( platformDependentDeclarationFilter = platformDependentDeclarationFilter ) - localClassResolver.setDeserializationComponents(components) - for (packageFragment in packageFragments) { packageFragment.components = components } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolverImpl.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolverImpl.kt deleted file mode 100644 index 8bdf7a461d8..00000000000 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolverImpl.kt +++ /dev/null @@ -1,41 +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.serialization.deserialization - -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor -import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor -import org.jetbrains.kotlin.name.ClassId -import javax.inject.Inject -import kotlin.properties.Delegates - -class LocalClassifierResolverImpl : LocalClassifierResolver { - var components: DeserializationComponents by Delegates.notNull() - - // component dependency cycle - @Inject fun setDeserializationComponents(components: DeserializationComponents) { - this.components = components - } - - override fun resolveLocalClass(classId: ClassId): ClassDescriptor? { - return components.deserializeClass(classId) - } - - override fun resolveLocalTypeAlias(typeAliasId: ClassId): ClassifierDescriptor? { - return components.deserializeTypeAlias(typeAliasId) - } -} diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolver.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierTypeSettings.kt similarity index 66% rename from core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolver.kt rename to core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierTypeSettings.kt index 6da40302479..435fe5dac3c 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierResolver.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/LocalClassifierTypeSettings.kt @@ -16,11 +16,13 @@ package org.jetbrains.kotlin.serialization.deserialization -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ClassifierDescriptor -import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.types.SimpleType -interface LocalClassifierResolver { - fun resolveLocalClass(classId: ClassId): ClassDescriptor? - fun resolveLocalTypeAlias(typeAliasId: ClassId): ClassifierDescriptor? +interface LocalClassifierTypeSettings { + val replacementTypeForLocalClassifiers: SimpleType? + + object Default : LocalClassifierTypeSettings { + override val replacementTypeForLocalClassifiers: SimpleType? + get() = null + } } diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt index dca11344e9d..c5a3db8d0af 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/TypeDeserializer.kt @@ -16,7 +16,9 @@ package org.jetbrains.kotlin.serialization.deserialization -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.serialization.ProtoBuf @@ -68,6 +70,14 @@ class TypeDeserializer( } fun simpleType(proto: ProtoBuf.Type, additionalAnnotations: Annotations = Annotations.EMPTY): SimpleType { + val localClassifierType = when { + proto.hasClassName() -> computeLocalClassifierReplacementType(proto.className) + proto.hasTypeAliasName() -> computeLocalClassifierReplacementType(proto.typeAliasName) + else -> null + } + + if (localClassifierType != null) return localClassifierType + val constructor = typeConstructor(proto) if (ErrorUtils.isError(constructor.declarationDescriptor)) { return ErrorUtils.createErrorTypeWithCustomConstructor(constructor.toString(), constructor) @@ -122,15 +132,22 @@ class TypeDeserializer( val id = c.nameResolver.getClassId(fqNameIndex) if (id.isLocal) { // Local classes can't be found in scopes - return c.components.localClassifierResolver.resolveLocalClass(id) + return c.components.deserializeClass(id) } return c.components.moduleDescriptor.findClassAcrossModuleDependencies(id) } + private fun computeLocalClassifierReplacementType(className: Int): SimpleType? { + if (c.nameResolver.getClassId(className).isLocal) { + return c.components.localClassifierTypeSettings.replacementTypeForLocalClassifiers + } + return null + } + private fun computeTypeAliasDescriptor(fqNameIndex: Int): ClassifierDescriptor? { val id = c.nameResolver.getClassId(fqNameIndex) return if (id.isLocal) { - c.components.localClassifierResolver.resolveLocalTypeAlias(id) + c.components.deserializeTypeAlias(id) } else { c.components.moduleDescriptor.findTypeAliasAcrossModuleDependencies(id) diff --git a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/context.kt b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/context.kt index 6d3f0bed03e..a65ad3b8f0f 100644 --- a/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/context.kt +++ b/core/deserialization/src/org/jetbrains/kotlin/serialization/deserialization/context.kt @@ -31,7 +31,7 @@ class DeserializationComponents( val classDataFinder: ClassDataFinder, val annotationAndConstantLoader: AnnotationAndConstantLoader, AnnotationWithTarget>, val packageFragmentProvider: PackageFragmentProvider, - val localClassifierResolver: LocalClassifierResolver, + val localClassifierTypeSettings: LocalClassifierTypeSettings, val errorReporter: ErrorReporter, val lookupTracker: LookupTracker, val flexibleTypeDeserializer: FlexibleTypeDeserializer, diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 52c7d193094..8a469a9506e 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -39,7 +39,7 @@ internal class KClassImpl(override val jClass: Class) : val classId = classId val descriptor = - if (classId.isLocal) moduleData.localClassifierResolver.resolveLocalClass(classId) + if (classId.isLocal) moduleData.deserialization.deserializeClass(classId) else moduleData.module.findClassAcrossModuleDependencies(classId) descriptor ?: reportUnresolvedClass() 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 1fed32e2b47..18ead62280f 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 @@ -18,7 +18,9 @@ package org.jetbrains.kotlin.idea.decompiler.textBuilder import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.builtins.KotlinBuiltIns -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.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor import org.jetbrains.kotlin.name.ClassId @@ -26,9 +28,10 @@ import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents -import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierResolver +import org.jetbrains.kotlin.serialization.deserialization.LocalClassifierTypeSettings import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.StorageManager +import org.jetbrains.kotlin.types.SimpleType abstract class DeserializerForDecompilerBase( val packageDirectory: VirtualFile, @@ -66,7 +69,7 @@ abstract class DeserializerForDecompilerBase( } } -class ResolveEverythingToKotlinAnyLocalClassifierResolver(private val builtIns: KotlinBuiltIns) : LocalClassifierResolver { - override fun resolveLocalClass(classId: ClassId): ClassDescriptor = builtIns.any - override fun resolveLocalTypeAlias(typeAliasId: ClassId): ClassifierDescriptor = builtIns.any +class ResolveEverythingToKotlinAnyLocalClassifierResolver(private val builtIns: KotlinBuiltIns) : LocalClassifierTypeSettings { + override val replacementTypeForLocalClassifiers: SimpleType? + get() = builtIns.anyType } diff --git a/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument.expected.kt b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument.expected.kt new file mode 100644 index 00000000000..4d3cd96cece --- /dev/null +++ b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument.expected.kt @@ -0,0 +1,8 @@ +// IntelliJ API Decompiler stub source generated from a class file +// Implementation of methods is not available + +package test + +public final class LocalClassAsTypeWithArgument public constructor() { + private final val z: kotlin.Any /* compiled code */ +} diff --git a/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/LocalClassAsTypeWithArgument.kt b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/LocalClassAsTypeWithArgument.kt new file mode 100644 index 00000000000..acf3ad1f023 --- /dev/null +++ b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/LocalClassAsTypeWithArgument.kt @@ -0,0 +1,8 @@ +package test + +class LocalClassAsTypeWithArgument { + // anonymous type captures type parameter E of containing class + private val z = object : Iterable { + override fun iterator() = null!! + } +} diff --git a/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt new file mode 100644 index 00000000000..9a460ecb7a0 --- /dev/null +++ b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt @@ -0,0 +1,2 @@ +// See KT-13691 +// TARGET_BACKEND: JVM diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java index 2b9a0c548b8..4da2e1057cd 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java @@ -49,6 +49,12 @@ public class CommonDecompiledTextFromJsMetadataTestGenerated extends AbstractCom doTest(fileName); } + @TestMetadata("LocalClassAsTypeWithArgument") + public void ignoredLocalClassAsTypeWithArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/"); + doTest(fileName); + } + @TestMetadata("NestedClasses") public void ignoredNestedClasses() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/NestedClasses/"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java index f16b5780c15..ac1f966fe6d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java @@ -107,6 +107,12 @@ public class CommonDecompiledTextTestGenerated extends AbstractCommonDecompiledT doTest(fileName); } + @TestMetadata("LocalClassAsTypeWithArgument") + public void testLocalClassAsTypeWithArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/"); + doTest(fileName); + } + @TestMetadata("Modifiers") public void testModifiers() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/Modifiers/"); diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt index 6b08995213a..f84d902859f 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/kotlinJavascriptPackageFragmentProvider.kt @@ -37,7 +37,6 @@ fun createKotlinJavascriptPackageFragmentProvider( val provider = PackageFragmentProviderImpl(packageFragments) val notFoundClasses = NotFoundClasses(storageManager, module) - val localClassResolver = LocalClassifierResolverImpl() val components = DeserializationComponents( storageManager, @@ -45,7 +44,7 @@ fun createKotlinJavascriptPackageFragmentProvider( DeserializedClassDataFinder(provider), AnnotationAndConstantLoaderImpl(module, notFoundClasses, JsSerializerProtocol), provider, - localClassResolver, + LocalClassifierTypeSettings.Default, ErrorReporter.DO_NOTHING, LookupTracker.DO_NOTHING, DynamicTypeDeserializer, @@ -53,8 +52,6 @@ fun createKotlinJavascriptPackageFragmentProvider( notFoundClasses ) - localClassResolver.setDeserializationComponents(components) - for (packageFragment in packageFragments) { packageFragment.components = components }