Refactoring: extract logic about methods from Any for scopes out

This commit is contained in:
Mikhail Zarechenskiy
2018-07-29 21:30:30 +02:00
parent 6e3497771d
commit fdf538007c
4 changed files with 110 additions and 53 deletions
@@ -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,
@@ -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<SimpleFunctionDescriptor>,
fromSupertypes: List<SimpleFunctionDescriptor>
): 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<SimpleFunctionDescriptor>,
fromSupertypes: List<SimpleFunctionDescriptor>
): Boolean {
return name == HASH_CODE_METHOD_NAME && shouldAddFunctionFromAny(
declaredFunctions,
fromSupertypes
) {
it.valueParameters.isEmpty()
}
}
fun shouldAddToString(
name: Name,
declaredFunctions: Collection<SimpleFunctionDescriptor>,
fromSupertypes: List<SimpleFunctionDescriptor>
): 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 <SimpleFunctionDescriptor>,
fromSupertypes: List<SimpleFunctionDescriptor>,
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 }
}
}
@@ -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))
}
}
}
@@ -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)
}