From fdf538007c79fdc9d2d32b6d41255e7581d734bd Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Sun, 29 Jul 2018 21:30:30 +0200 Subject: [PATCH] Refactoring: extract logic about methods from `Any` for scopes out --- .../resolve/DataClassDescriptorResolver.kt | 34 ------ .../kotlin/resolve/FunctionsFromAny.kt | 101 ++++++++++++++++++ .../lazy/descriptors/LazyClassMemberScope.kt | 22 ++-- .../lightClasses/IDELightClassContexts.kt | 6 +- 4 files changed, 110 insertions(+), 53 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionsFromAny.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DataClassDescriptorResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DataClassDescriptorResolver.kt index 4f533267ff4..bf029f01628 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DataClassDescriptorResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DataClassDescriptorResolver.kt @@ -26,10 +26,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.util.OperatorNameConventions object DataClassDescriptorResolver { - val EQUALS_METHOD_NAME = OperatorNameConventions.EQUALS - val HASH_CODE_METHOD_NAME = Name.identifier("hashCode") - val TO_STRING_METHOD_NAME = Name.identifier("toString") - val COPY_METHOD_NAME = Name.identifier("copy") private val COMPONENT_FUNCTION_NAME_PREFIX = "component" @@ -52,36 +48,6 @@ object DataClassDescriptorResolver { return true } - fun createEqualsFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor = - doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME) - - fun createHashCodeFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor = - doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME) - - fun createToStringFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor = - doCreateFunctionFromAny(classDescriptor, TO_STRING_METHOD_NAME) - - private fun doCreateFunctionFromAny(classDescriptor: ClassDescriptor, name: Name): SimpleFunctionDescriptor { - val functionDescriptor = SimpleFunctionDescriptorImpl.create( - classDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, classDescriptor.source - ) - - val functionFromAny = classDescriptor.builtIns.any.getMemberScope(emptyList()) - .getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single() - - functionDescriptor.initialize( - null, - classDescriptor.thisAsReceiverParameter, - functionFromAny.typeParameters, - functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) }, - functionFromAny.returnType, - Modality.OPEN, - Visibilities.PUBLIC - ) - - return functionDescriptor - } - fun createComponentFunctionDescriptor( parameterIndex: Int, property: PropertyDescriptor, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionsFromAny.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionsFromAny.kt new file mode 100644 index 00000000000..2fa7acc245b --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/FunctionsFromAny.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.util.OperatorNameConventions + +object FunctionsFromAny { + val EQUALS_METHOD_NAME = OperatorNameConventions.EQUALS + val HASH_CODE_METHOD_NAME = Name.identifier("hashCode") + val TO_STRING_METHOD_NAME = Name.identifier("toString") + + fun shouldAddEquals( + name: Name, + declaredFunctions: Collection, + fromSupertypes: List + ): Boolean { + return name == EQUALS_METHOD_NAME && shouldAddFunctionFromAny( + declaredFunctions, + fromSupertypes + ) { function -> + val parameters = function.valueParameters + parameters.size == 1 && KotlinBuiltIns.isNullableAny(parameters.first().type) + } + } + + fun shouldAddHashCode( + name: Name, + declaredFunctions: Collection, + fromSupertypes: List + ): Boolean { + return name == HASH_CODE_METHOD_NAME && shouldAddFunctionFromAny( + declaredFunctions, + fromSupertypes + ) { + it.valueParameters.isEmpty() + } + } + + fun shouldAddToString( + name: Name, + declaredFunctions: Collection, + fromSupertypes: List + ): Boolean { + return name == TO_STRING_METHOD_NAME && shouldAddFunctionFromAny( + declaredFunctions, + fromSupertypes + ) { + it.valueParameters.isEmpty() + } + } + + fun createEqualsFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor = + doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME) + + fun createHashCodeFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor = + doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME) + + fun createToStringFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor = + doCreateFunctionFromAny(classDescriptor, TO_STRING_METHOD_NAME) + + private fun doCreateFunctionFromAny(classDescriptor: ClassDescriptor, name: Name): SimpleFunctionDescriptor { + val functionDescriptor = SimpleFunctionDescriptorImpl.create( + classDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, classDescriptor.source + ) + + val functionFromAny = classDescriptor.builtIns.any.getMemberScope(emptyList()) + .getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single() + + functionDescriptor.initialize( + null, + classDescriptor.thisAsReceiverParameter, + functionFromAny.typeParameters, + functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) }, + functionFromAny.returnType, + Modality.OPEN, + Visibilities.PUBLIC + ) + + return functionDescriptor + } + + private fun shouldAddFunctionFromAny( + declaredFunctions: Collection , + fromSupertypes: List, + checkParameters: (FunctionDescriptor) -> Boolean + ): Boolean { + // Add 'equals', 'hashCode', 'toString' iff there is no such declared member AND there is no such final member in supertypes + return declaredFunctions.none(checkParameters) && + fromSupertypes.none { checkParameters(it) && it.modality == Modality.FINAL } + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt index 10f9dcf6807..c044cd1e45c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.resolve.lazy.descriptors -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION @@ -256,25 +255,16 @@ open class LazyClassMemberScope( } if (c.languageVersionSettings.supportsFeature(LanguageFeature.DataClassInheritance)) { - fun shouldAddFunctionFromAny(checkParameters: (FunctionDescriptor) -> Boolean): Boolean { - // Add 'equals', 'hashCode', 'toString' iff there is no such declared member AND there is no such final member in supertypes - return result.none(checkParameters) && - fromSupertypes.none { checkParameters(it) && it.modality == Modality.FINAL } + if (FunctionsFromAny.shouldAddEquals(name, result, fromSupertypes)) { + result.add(FunctionsFromAny.createEqualsFunctionDescriptor(thisDescriptor)) } - if (name == DataClassDescriptorResolver.EQUALS_METHOD_NAME && shouldAddFunctionFromAny { function -> - val parameters = function.valueParameters - parameters.size == 1 && KotlinBuiltIns.isNullableAny(parameters.first().type) - }) { - result.add(DataClassDescriptorResolver.createEqualsFunctionDescriptor(thisDescriptor)) + if (FunctionsFromAny.shouldAddHashCode(name, result, fromSupertypes)) { + result.add(FunctionsFromAny.createHashCodeFunctionDescriptor(thisDescriptor)) } - if (name == DataClassDescriptorResolver.HASH_CODE_METHOD_NAME && shouldAddFunctionFromAny { it.valueParameters.isEmpty() }) { - result.add(DataClassDescriptorResolver.createHashCodeFunctionDescriptor(thisDescriptor)) - } - - if (name == DataClassDescriptorResolver.TO_STRING_METHOD_NAME && shouldAddFunctionFromAny { it.valueParameters.isEmpty() }) { - result.add(DataClassDescriptorResolver.createToStringFunctionDescriptor(thisDescriptor)) + if (FunctionsFromAny.shouldAddToString(name, result, fromSupertypes)) { + result.add(FunctionsFromAny.createToStringFunctionDescriptor(thisDescriptor)) } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt index 0908c4a90c1..1b7658b7965 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/lightClasses/IDELightClassContexts.kt @@ -191,11 +191,11 @@ internal object IDELightClassContexts { } private fun isGeneratedForDataClass(name: Name): Boolean { - return name == DataClassDescriptorResolver.EQUALS_METHOD_NAME || + return name == FunctionsFromAny.EQUALS_METHOD_NAME || // known failure is related to equals override, checking for other methods 'just in case' name == DataClassDescriptorResolver.COPY_METHOD_NAME || - name == DataClassDescriptorResolver.HASH_CODE_METHOD_NAME || - name == DataClassDescriptorResolver.TO_STRING_METHOD_NAME || + name == FunctionsFromAny.HASH_CODE_METHOD_NAME || + name == FunctionsFromAny.TO_STRING_METHOD_NAME || DataClassDescriptorResolver.isComponentLike(name) }