mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] KTIJ-31612 Generate equals() with primitive fields come first
Merge-request: IJ-MR-146523 Merged-by: Maksim Zuev <Maksim.Zuev@jetbrains.com> GitOrigin-RevId: ed92f3474ee18e280297f1e6c935975496a36b8c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4855ba7c77
commit
96b8929d41
+29
-2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.api.symbols.KaNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbolModality
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaSymbolOrigin
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaValueParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.symbol
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.isNonNullableBooleanType
|
||||
@@ -164,8 +165,9 @@ object GenerateEqualsAndHashCodeUtils {
|
||||
contextMap[SUPER_HAS_EQUALS] = equalsFunction != null && (equalsFunction.containingSymbol as? KaClassSymbol)?.classId != StandardClassIds.Any
|
||||
contextMap[CHECK_PARAMETER_WITH_INSTANCEOF] = CodeInsightSettings.getInstance().USE_INSTANCEOF_ON_EQUALS_PARAMETER
|
||||
|
||||
val sortedVariables = info.variablesForEquals.sortedWithPrimitiveFirst()
|
||||
val methodText = VelocityGeneratorHelper
|
||||
.velocityGenerateCode(klass, info.variablesForEquals, contextMap,
|
||||
.velocityGenerateCode(klass, sortedVariables, contextMap,
|
||||
KotlinEqualsHashCodeTemplatesManager.getInstance().defaultEqualsTemplate.template, false) ?: return null
|
||||
|
||||
|
||||
@@ -185,8 +187,10 @@ object GenerateEqualsAndHashCodeUtils {
|
||||
val hashCodeFunction = findHashCodeMethodForClass(klass.symbol as KaClassSymbol)
|
||||
contextMap[SUPER_HAS_HASHCODE] = hashCodeFunction != null && (hashCodeFunction.containingSymbol as? KaClassSymbol)?.classId != StandardClassIds.Any
|
||||
|
||||
// Sort variables in `hashCode()` to preserve the same order as in `equals()`
|
||||
val sortedVariables = info.variablesForHashCode.sortedWithPrimitiveFirst()
|
||||
val methodText = VelocityGeneratorHelper
|
||||
.velocityGenerateCode(klass, info.variablesForHashCode,
|
||||
.velocityGenerateCode(klass, sortedVariables,
|
||||
contextMap, KotlinEqualsHashCodeTemplatesManager.getInstance().defaultHashcodeTemplate.template, false) ?: return null
|
||||
|
||||
|
||||
@@ -266,4 +270,27 @@ object GenerateEqualsAndHashCodeUtils {
|
||||
) == Messages.YES
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
private fun List<KtNamedDeclaration>.sortedWithPrimitiveFirst(): List<KtNamedDeclaration> = sortedWith(object : Comparator<KtNamedDeclaration> {
|
||||
override fun compare(o1: KtNamedDeclaration, o2: KtNamedDeclaration): Int {
|
||||
val isBacking1 = o1.propertyHasBackingField()
|
||||
val isBacking2 = o2.propertyHasBackingField()
|
||||
val fieldCompare = -isBacking1.compareTo(isBacking2)
|
||||
if (fieldCompare != 0) return fieldCompare
|
||||
return -o1.returnType.isPrimitive.compareTo(o2.returnType.isPrimitive)
|
||||
}
|
||||
})
|
||||
|
||||
context(KaSession)
|
||||
private fun KtNamedDeclaration.propertyHasBackingField(): Boolean {
|
||||
val symbol = symbol
|
||||
return when (symbol) {
|
||||
is KaPropertySymbol -> symbol.hasBackingField
|
||||
is KaValueParameterSymbol -> {
|
||||
symbol.generatedPrimaryConstructorProperty?.hasBackingField == true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -217,7 +217,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
|
||||
|
||||
append('\n')
|
||||
|
||||
variablesForEquals.forEach {
|
||||
variablesForEquals.sortedWithPrimitivesFirst().forEach {
|
||||
val isNullable = TypeUtils.isNullableType(it.type)
|
||||
val isArray = KotlinBuiltIns.isArrayOrPrimitiveArray(it.type)
|
||||
val canUseArrayContentFunctions = targetClass.canUseArrayContentFunctions()
|
||||
@@ -292,7 +292,8 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
|
||||
val hashCodeFun = generateFunctionSkeleton(superHashCode, targetClass)
|
||||
val builtins = superHashCode.builtIns
|
||||
|
||||
val propertyIterator = variablesForHashCode.iterator()
|
||||
// Sort variables in `hashCode()` to preserve the same order as in `equals()`
|
||||
val propertyIterator = variablesForEquals.sortedWithPrimitivesFirst().iterator()
|
||||
val initialValue = when {
|
||||
!builtins.isMemberOfAny(superHashCode) -> "super.hashCode()"
|
||||
propertyIterator.hasNext() -> propertyIterator.next().genVariableHashCode(false)
|
||||
@@ -326,3 +327,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
|
||||
return insertMembersAfterAndReformat(editor, targetClass, prototypes, anchor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<VariableDescriptor>.sortedWithPrimitivesFirst(): List<VariableDescriptor> = sortedBy {
|
||||
!KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(it.type)
|
||||
}
|
||||
|
||||
+3
-3
@@ -11,17 +11,17 @@ class A(val n: IntArray, val s: Array<String>) {
|
||||
|
||||
other as A
|
||||
|
||||
if (f != other.f) 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 = n.contentHashCode()
|
||||
var result = f.hashCode()
|
||||
result = 31 * result + n.contentHashCode()
|
||||
result = 31 * result + s.contentHashCode()
|
||||
result = 31 * result + f.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -1,11 +1,12 @@
|
||||
class Test {
|
||||
val age by lazy { 15 + 10 }
|
||||
val color: String
|
||||
get() = "Purple"
|
||||
var serial: String = ""
|
||||
set(value) {
|
||||
field = value.toUpperCase()
|
||||
}
|
||||
var name: String = ""
|
||||
val age by lazy { 15 + 10 }
|
||||
val color: String
|
||||
get() = "Purple"
|
||||
var id = 42
|
||||
<caret>
|
||||
}
|
||||
+11
-9
@@ -1,32 +1,34 @@
|
||||
class Test {
|
||||
val age by lazy { 15 + 10 }
|
||||
val color: String
|
||||
get() = "Purple"
|
||||
var serial: String = ""
|
||||
set(value) {
|
||||
field = value.toUpperCase()
|
||||
}
|
||||
var name: String = ""
|
||||
val age by lazy { 15 + 10 }
|
||||
val color: String
|
||||
get() = "Purple"
|
||||
|
||||
var id = 42
|
||||
<caret>override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Test
|
||||
|
||||
if (age != other.age) return false
|
||||
if (id != other.id) return false
|
||||
if (color != other.color) return false
|
||||
if (serial != other.serial) return false
|
||||
if (name != other.name) return false
|
||||
if (age != other.age) return false
|
||||
if (color != other.color) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = serial.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + age
|
||||
var result = age
|
||||
result = 31 * result + id
|
||||
result = 31 * result + color.hashCode()
|
||||
result = 31 * result + serial.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
class Test {
|
||||
val age by lazy { 15 + 10 }
|
||||
val color: String
|
||||
get() = "Purple"
|
||||
var serial: String = ""
|
||||
set(value) {
|
||||
field = value.toUpperCase()
|
||||
}
|
||||
var name: String = ""
|
||||
var id = 42
|
||||
<caret>override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Test
|
||||
|
||||
if (id != other.id) return false
|
||||
if (serial != other.serial) return false
|
||||
if (name != other.name) return false
|
||||
if (age != other.age) return false
|
||||
if (color != other.color) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id
|
||||
result = 31 * result + serial.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + age
|
||||
result = 31 * result + color.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -5,17 +5,17 @@ class Example(val `in`: String, val `cl ass`: String, val `valid`: Boolean) {
|
||||
|
||||
other as Example
|
||||
|
||||
if (`valid` != other.`valid`) return false
|
||||
if (`in` != other.`in`) return false
|
||||
if (`cl ass` != other.`cl ass`) return false
|
||||
if (`valid` != other.`valid`) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = `in`.hashCode()
|
||||
var result = `valid`.hashCode()
|
||||
result = 31 * result + `in`.hashCode()
|
||||
result = 31 * result + `cl ass`.hashCode()
|
||||
result = 31 * result + `valid`.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -12,16 +12,16 @@ class A(val n: Int, val s: String) {
|
||||
other as A
|
||||
|
||||
if (n != other.n) return false
|
||||
if (s != other.s) return false
|
||||
if (f != other.f) return false
|
||||
if (s != other.s) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = n
|
||||
result = 31 * result + s.hashCode()
|
||||
result = 31 * result + f.hashCode()
|
||||
result = 31 * result + s.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -13,16 +13,16 @@ class A(val n: Int, val s: String) {
|
||||
other as A
|
||||
|
||||
if (n != other.n) return false
|
||||
if (s != other.s) return false
|
||||
if (f != other.f) return false
|
||||
if (s != other.s) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = n
|
||||
result = 31 * result + s.hashCode()
|
||||
result = 31 * result + f.hashCode()
|
||||
result = 31 * result + s.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -13,16 +13,16 @@ class A(val n: Int, val s: String) {
|
||||
other as A
|
||||
|
||||
if (n != other.n) return false
|
||||
if (s != other.s) return false
|
||||
if (f != other.f) return false
|
||||
if (s != other.s) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = n
|
||||
result = 31 * result + s.hashCode()
|
||||
result = 31 * result + f.hashCode()
|
||||
result = 31 * result + s.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -12,16 +12,16 @@ class A(val n: Int?, val s: String) {
|
||||
other as A
|
||||
|
||||
if (n != other.n) return false
|
||||
if (s != other.s) return false
|
||||
if (f != other.f) return false
|
||||
if (s != other.s) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = n ?: 0
|
||||
result = 31 * result + s.hashCode()
|
||||
result = 31 * result + (f?.hashCode() ?: 0)
|
||||
result = 31 * result + s.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -18,8 +18,8 @@ class A(val n: Int, val s: String) : X() {
|
||||
other as A
|
||||
|
||||
if (n != other.n) return false
|
||||
if (s != other.s) return false
|
||||
if (f != other.f) return false
|
||||
if (s != other.s) return false
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -27,8 +27,8 @@ class A(val n: Int, val s: String) : X() {
|
||||
override fun hashCode(): Int {
|
||||
var result = super.hashCode()
|
||||
result = 31 * result + n
|
||||
result = 31 * result + s.hashCode()
|
||||
result = 31 * result + f.hashCode()
|
||||
result = 31 * result + s.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -11,6 +11,7 @@ class A(val n: IntArray?, val s: Array<String>?) {
|
||||
|
||||
other as A
|
||||
|
||||
if (f != other.f) return false
|
||||
if (n != null) {
|
||||
if (other.n == null) return false
|
||||
if (!n.contentEquals(other.n)) return false
|
||||
@@ -19,15 +20,14 @@ class A(val n: IntArray?, val s: Array<String>?) {
|
||||
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?.contentHashCode() ?: 0
|
||||
var result = f.hashCode()
|
||||
result = 31 * result + (n?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (s?.contentHashCode() ?: 0)
|
||||
result = 31 * result + f.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -11,17 +11,17 @@ class A(val n: IntArray?, val s: Array<String>?) {
|
||||
|
||||
other as A
|
||||
|
||||
if (f != other.f) 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 = n?.contentHashCode() ?: 0
|
||||
var result = f.hashCode()
|
||||
result = 31 * result + (n?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (s?.contentHashCode() ?: 0)
|
||||
result = 31 * result + f.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -15,20 +15,20 @@ data class A(
|
||||
|
||||
other as A
|
||||
|
||||
if (d != other.d) return false
|
||||
if (!a.contentEquals(other.a)) return false
|
||||
if (!b.contentEquals(other.b)) return false
|
||||
if (c != other.c) return false
|
||||
if (d != other.d) return false
|
||||
if (e != other.e) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = a.contentHashCode()
|
||||
var result = d
|
||||
result = 31 * result + a.contentHashCode()
|
||||
result = 31 * result + b.contentHashCode()
|
||||
result = 31 * result + c.hashCode()
|
||||
result = 31 * result + d
|
||||
result = 31 * result + e.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user