Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dart] Use Object.hash and Object.hashAll if supported #926

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NlsContexts;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.jetbrains.lang.dart.DartBundle;
Expand All @@ -14,6 +15,7 @@
import com.jetbrains.lang.dart.psi.DartClass;
import com.jetbrains.lang.dart.psi.DartComponent;
import com.jetbrains.lang.dart.psi.DartComponentName;
import com.jetbrains.lang.dart.sdk.DartSdk;
import org.dartlang.analysis.server.protocol.TypeHierarchyItem;
import org.jetbrains.annotations.NotNull;

Expand All @@ -23,6 +25,7 @@
public class CreateEqualsAndHashcodeFix extends BaseCreateMethodsFix<DartComponent> {

private boolean mySuperclassOverridesEqualEqualAndHashCode;
private boolean supportsObjectHashMethods = false;

public CreateEqualsAndHashcodeFix(@NotNull final DartClass dartClass) {
super(dartClass);
Expand All @@ -32,6 +35,9 @@ public CreateEqualsAndHashcodeFix(@NotNull final DartClass dartClass) {
public void beforeInvoke(@NotNull Project project, Editor editor, PsiElement file) {
super.beforeInvoke(project, editor, file);
mySuperclassOverridesEqualEqualAndHashCode = doesSuperclassOverrideEqualEqualAndHashCode(myDartClass);

final DartSdk sdk = DartSdk.getDartSdk(project);
supportsObjectHashMethods = sdk != null && StringUtil.compareVersionNumbers(sdk.getVersion(), "2.14") >= 0;
}

@Override
Expand Down Expand Up @@ -94,20 +100,54 @@ protected Template buildFunctionsText(TemplateManager templateManager, @NotNull

template.addTextSegment("@override\n");
template.addTextSegment("int get hashCode => ");
boolean firstItem = true;
if (mySuperclassOverridesEqualEqualAndHashCode) {
template.addTextSegment("super.hashCode");
firstItem = false;

final int totalItems = elementsToProcess.size() + (mySuperclassOverridesEqualEqualAndHashCode ? 1 : 0);
if (totalItems <= 0) {
template.addTextSegment("0");
}
for (DartComponent component : elementsToProcess) {
if (!firstItem) {
template.addTextSegment(" ^ ");
else if (supportsObjectHashMethods && totalItems > 1) {
final boolean useHashAll = totalItems > 20;
if (useHashAll) {
template.addTextSegment("Object.hashAll(");
template.addTextSegment("[");
}
else {
template.addTextSegment("Object.hash(");
}

boolean shouldPrependComma = false;
if (mySuperclassOverridesEqualEqualAndHashCode) {
template.addTextSegment("super.hashCode");
shouldPrependComma = true;
}

for (final DartComponent component : elementsToProcess) {
if (shouldPrependComma) {
template.addTextSegment(",");
}
template.addTextSegment(String.valueOf(component.getName()));
shouldPrependComma = true;
}
template.addTextSegment(component.getName() + ".hashCode");
firstItem = false;

if (useHashAll) {
template.addTextSegment("]");
}

template.addTextSegment(")");
}
if (!mySuperclassOverridesEqualEqualAndHashCode && elementsToProcess.isEmpty()) {
template.addTextSegment("0");
else {
boolean firstItem = true;
if (mySuperclassOverridesEqualEqualAndHashCode) {
template.addTextSegment("super.hashCode");
firstItem = false;
}
for (DartComponent component : elementsToProcess) {
if (!firstItem) {
template.addTextSegment(" ^ ");
}
template.addTextSegment(component.getName() + ".hashCode");
firstItem = false;
}
}
template.addTextSegment(";\n");
template.addTextSegment(" "); // trailing space is removed when auto-reformatting, but it helps to enter line break if needed
Expand Down
2 changes: 1 addition & 1 deletion Dart/testData/generate/EqualsAndHashCode1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ class EqualsAndHashCode1 {
str == other.str && v == other.v && i == other.i;

@override
int get hashCode => str.hashCode ^ v.hashCode ^ i.hashCode;
int get hashCode => Object.hash(str, v, i);
<caret>
}
23 changes: 23 additions & 0 deletions Dart/testData/generate/EqualsAndHashCode20.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
class Test {
int? a;
int? b;
int? c;
int? d;
int? e;
int? f;
int? g;
int? h;
int? i;
int? j;
int? k;
int? l;
int? m;
int? n;
int? o;
int? p;
int? q;
int? r;
int? s;
int? t;<caret>
}
53 changes: 53 additions & 0 deletions Dart/testData/generate/EqualsAndHashCode20.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
class Test {
int? a;
int? b;
int? c;
int? d;
int? e;
int? f;
int? g;
int? h;
int? i;
int? j;
int? k;
int? l;
int? m;
int? n;
int? o;
int? p;
int? q;
int? r;
int? s;
int? t;

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Test &&
runtimeType == other.runtimeType &&
a == other.a &&
b == other.b &&
c == other.c &&
d == other.d &&
e == other.e &&
f == other.f &&
g == other.g &&
h == other.h &&
i == other.i &&
j == other.j &&
k == other.k &&
l == other.l &&
m == other.m &&
n == other.n &&
o == other.o &&
p == other.p &&
q == other.q &&
r == other.r &&
s == other.s &&
t == other.t;

@override
int get hashCode =>
Object.hash(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t);<caret>
}
24 changes: 24 additions & 0 deletions Dart/testData/generate/EqualsAndHashCode21.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
class Test {
int? a;
int? b;
int? c;
int? d;
int? e;
int? f;
int? g;
int? h;
int? i;
int? j;
int? k;
int? l;
int? m;
int? n;
int? o;
int? p;
int? q;
int? r;
int? s;
int? t;
int? u;<caret>
}
55 changes: 55 additions & 0 deletions Dart/testData/generate/EqualsAndHashCode21.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
class Test {
int? a;
int? b;
int? c;
int? d;
int? e;
int? f;
int? g;
int? h;
int? i;
int? j;
int? k;
int? l;
int? m;
int? n;
int? o;
int? p;
int? q;
int? r;
int? s;
int? t;
int? u;

@override
bool operator ==(Object other) =>
identical(this, other) ||
other is Test &&
runtimeType == other.runtimeType &&
a == other.a &&
b == other.b &&
c == other.c &&
d == other.d &&
e == other.e &&
f == other.f &&
g == other.g &&
h == other.h &&
i == other.i &&
j == other.j &&
k == other.k &&
l == other.l &&
m == other.m &&
n == other.n &&
o == other.o &&
p == other.p &&
q == other.q &&
r == other.r &&
s == other.s &&
t == other.t &&
u == other.u;

@override
int get hashCode => Object.hashAll(
[a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u]);<caret>
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ public void testEqualsAndHashCode2() {
doEqualsAndHashcodeTest();
}

public void testEqualsAndHashCode20() {
doEqualsAndHashcodeTest();
}

public void testEqualsAndHashCode21() {
doEqualsAndHashcodeTest();
}

public void testImplement1() {
doImplementTest();
}
Expand Down