diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt index e5a9208678f..27cd16d239e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/generate/KotlinGenerateEqualsAndHashcodeAction.kt @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project import com.intellij.psi.PsiNameIdentifierOwner import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -159,6 +160,42 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase= ApiVersion.KOTLIN_1_1 + + private fun generateArraysEqualsCall( + variable: VariableDescriptor, + canUseContentFunctions: Boolean, + arg1: String, + arg2: String + ): String { + return if (canUseContentFunctions) { + val methodName = if (isNestedArray(variable)) "contentDeepEquals" else "contentEquals" + "$arg1.$methodName($arg2)" + } else { + val methodName = if (isNestedArray(variable)) "deepEquals" else "equals" + "java.util.Arrays.$methodName($arg1, $arg2)" + } + } + + private fun generateArrayHashCodeCall( + variable: VariableDescriptor, + canUseContentFunctions: Boolean, + argument: String + ): String { + return if (canUseContentFunctions) { + val methodName = if (isNestedArray(variable)) "contentDeepHashCode" else "contentHashCode" + val dot = if (TypeUtils.isNullableType(variable.type)) "?." else "." + "$argument$dot$methodName()" + } else { + val methodName = if (isNestedArray(variable)) "deepHashCode" else "hashCode" + "java.util.Arrays.$methodName($argument)" + } + } + private fun generateEquals(project: Project, info: Info, targetClass: KtClassOrObject): KtNamedFunction? { with(info) { if (!needEquals) return null @@ -197,17 +234,26 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase { - val isNestedArray = KotlinBuiltIns.isArrayOrPrimitiveArray(classDescriptor.builtIns.getArrayElementType(it.type)) - val methodName = if (isNestedArray) "deepEquals" else "equals" - "!java.util.Arrays.$methodName($propName, $paramName.$propName)" - } - else -> + isArray -> { + "!${generateArraysEqualsCall(it, canUseArrayContentFunctions, propName, "$paramName.$propName")}" + } else -> { "$propName != $paramName.$propName" + } + } + val equalsCheck = "if ($notEquals) return false\n" + if (isArray && isNullable && canUseArrayContentFunctions) { + append("if ($propName != null) {\n") + append("if ($paramName.$propName == null) return false\n") + append(equalsCheck) + append("} else if ($paramName.$propName != null) return false\n") + } else { + append(equalsCheck) } - append("if ($notEquals) return false\n") } append('\n') @@ -234,9 +280,11 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase ref KotlinBuiltIns.isArrayOrPrimitiveArray(type) -> { - val isNestedArray = KotlinBuiltIns.isArrayOrPrimitiveArray(builtIns.getArrayElementType(type)) - val methodName = if (isNestedArray) "deepHashCode" else "hashCode" - if (isNullable) "$ref?.let { java.util.Arrays.$methodName(it) }" else "java.util.Arrays.$methodName($ref)" + val canUseArrayContentFunctions = targetClass.canUseArrayContentFunctions() + val shouldWrapInLet = isNullable && !canUseArrayContentFunctions + val hashCodeArg = if (shouldWrapInLet) "it" else ref + val hashCodeCall = generateArrayHashCodeCall(this, canUseArrayContentFunctions, hashCodeArg) + if (shouldWrapInLet) "$ref?.let { $hashCodeCall }" else hashCodeCall } else -> if (isNullable) "$ref?.hashCode()" else "$ref.hashCode()" diff --git a/idea/testData/codeInsight/generate/equalsWithHashCode/arrays.kt.after b/idea/testData/codeInsight/generate/equalsWithHashCode/arrays.kt.after index e02b7825ab4..f4cf115647e 100644 --- a/idea/testData/codeInsight/generate/equalsWithHashCode/arrays.kt.after +++ b/idea/testData/codeInsight/generate/equalsWithHashCode/arrays.kt.after @@ -1,5 +1,3 @@ -import java.util.Arrays - class A(val n: IntArray, val s: Array) { val f: Float = 1.0f @@ -13,16 +11,16 @@ class A(val n: IntArray, val s: Array) { other as A - if (!Arrays.equals(n, other.n)) return false - if (!Arrays.equals(s, other.s)) return false + if (!n.contentEquals(other.n)) return false + if (!s.contentEquals(other.s)) return false if (f != other.f) return false return true } override fun hashCode(): Int { - var result = Arrays.hashCode(n) - result = 31 * result + Arrays.hashCode(s) + var result = n.contentHashCode() + result = 31 * result + s.contentHashCode() result = 31 * result + f.hashCode() return result } diff --git a/idea/testData/codeInsight/generate/equalsWithHashCode/dataClassHasArrayProperty.kt.after b/idea/testData/codeInsight/generate/equalsWithHashCode/dataClassHasArrayProperty.kt.after index 29e36f36ff9..3f29f4ecb32 100644 --- a/idea/testData/codeInsight/generate/equalsWithHashCode/dataClassHasArrayProperty.kt.after +++ b/idea/testData/codeInsight/generate/equalsWithHashCode/dataClassHasArrayProperty.kt.after @@ -1,5 +1,3 @@ -import java.util.Arrays - data class A(val a: IntArray) { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -7,12 +5,12 @@ data class A(val a: IntArray) { other as A - if (!Arrays.equals(a, other.a)) return false + if (!a.contentEquals(other.a)) return false return true } override fun hashCode(): Int { - return Arrays.hashCode(a) + return a.contentHashCode() } } \ No newline at end of file diff --git a/idea/testData/codeInsight/generate/equalsWithHashCode/nestedArray.kt.after b/idea/testData/codeInsight/generate/equalsWithHashCode/nestedArray.kt.after index f94a9542429..706e5adfcb9 100644 --- a/idea/testData/codeInsight/generate/equalsWithHashCode/nestedArray.kt.after +++ b/idea/testData/codeInsight/generate/equalsWithHashCode/nestedArray.kt.after @@ -1,5 +1,3 @@ -import java.util.Arrays - class EqKotlin(val a: Array>) { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -7,12 +5,12 @@ class EqKotlin(val a: Array>) { other as EqKotlin - if (!Arrays.deepEquals(a, other.a)) return false + if (!a.contentDeepEquals(other.a)) return false return true } override fun hashCode(): Int { - return Arrays.deepHashCode(a) + return a.contentDeepHashCode() } } \ No newline at end of file diff --git a/idea/testData/codeInsight/generate/equalsWithHashCode/nullableArrays.kt.after b/idea/testData/codeInsight/generate/equalsWithHashCode/nullableArrays.kt.after index 3840c5aa1ab..751332e33d2 100644 --- a/idea/testData/codeInsight/generate/equalsWithHashCode/nullableArrays.kt.after +++ b/idea/testData/codeInsight/generate/equalsWithHashCode/nullableArrays.kt.after @@ -1,5 +1,3 @@ -import java.util.Arrays - class A(val n: IntArray?, val s: Array?) { val f: Float = 1.0f @@ -13,16 +11,22 @@ class A(val n: IntArray?, val s: Array?) { other as A - if (!Arrays.equals(n, other.n)) return false - if (!Arrays.equals(s, other.s)) return false + if (n != null) { + if (other.n == null) return false + if (!n.contentEquals(other.n)) return false + } else if (other.n != null) return false + if (s != null) { + if (other.s == null) return false + if (!s.contentEquals(other.s)) return false + } else if (other.s != null) return false if (f != other.f) return false return true } override fun hashCode(): Int { - var result = n?.let { Arrays.hashCode(it) } ?: 0 - result = 31 * result + (s?.let { Arrays.hashCode(it) } ?: 0) + var result = n?.contentHashCode() ?: 0 + result = 31 * result + (s?.contentHashCode() ?: 0) result = 31 * result + f.hashCode() return result }