mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 00:16:47 +00:00
Merge remote-tracking branch 'origin/master'
# Conflicts: # src/core/lombok/javac/handlers/HandleEqualsAndHashCode.java
This commit is contained in:
10 files changed
+576
-17
No files matched your search
@@ -2,6 +2,7 @@ Lombok contributors in alphabetical order:
|
||||
|
||||
Adam Juraszek <juriad@gmail.com>
|
||||
Aleksandr Zhelezniak <lekan1992@gmail.com>
|
||||
Andre Brait <andrebrait@gmail.com>
|
||||
Bulgakov Alexander <buls@yandex.ru>
|
||||
Caleb Brinkman <floralvikings@gmail.com>
|
||||
Christian Nüssgens <christian@nuessgens.com>
|
||||
|
||||
@@ -71,6 +71,14 @@ public @interface EqualsAndHashCode {
|
||||
* @return If {@code true}, always use direct field access instead of calling the getter method.
|
||||
*/
|
||||
boolean doNotUseGetters() default false;
|
||||
|
||||
/**
|
||||
* Determines how the result of the {@code hashCode} method will be cached.
|
||||
* <strong>default: {@link CacheStrategy#NEVER}</strong>
|
||||
*
|
||||
* @return The {@code hashCode} cache strategy to be used.
|
||||
*/
|
||||
CacheStrategy cacheStrategy() default CacheStrategy.NEVER;
|
||||
|
||||
/**
|
||||
* Any annotations listed here are put on the generated parameter of {@code equals} and {@code canEqual}.
|
||||
@@ -132,4 +140,19 @@ public @interface EqualsAndHashCode {
|
||||
*/
|
||||
int rank() default 0;
|
||||
}
|
||||
|
||||
public enum CacheStrategy {
|
||||
/**
|
||||
* Never cache. Perform the calculation every time the method is called.
|
||||
*/
|
||||
NEVER,
|
||||
/**
|
||||
* Cache the result of the first invocation of {@code hashCode} and use it for subsequent invocations.
|
||||
* This can improve performance if all fields used for calculating the {@code hashCode} are immutable
|
||||
* and thus every invocation of {@code hashCode} will always return the same value.
|
||||
* <strong>Do not use this if there's <em>any</em> chance that different invocations of {@code hashCode}
|
||||
* might return different values.</strong>
|
||||
*/
|
||||
LAZY
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import java.util.Set;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.EqualsAndHashCode.CacheStrategy;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.core.handlers.InclusionExclusionUtils;
|
||||
@@ -59,6 +60,8 @@ import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.EqualExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
|
||||
@@ -94,6 +97,9 @@ import org.mangosdk.spi.ProviderFor;
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndHashCode> {
|
||||
|
||||
private static final String HASH_CODE_CACHE_NAME = "$hashCodeCache";
|
||||
|
||||
private final char[] HASH_CODE_CACHE_NAME_ARR = HASH_CODE_CACHE_NAME.toCharArray();
|
||||
private final char[] PRIME = "PRIME".toCharArray();
|
||||
private final char[] RESULT = "result".toCharArray();
|
||||
|
||||
@@ -116,7 +122,9 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
|
||||
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
|
||||
|
||||
generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, fieldAccess, onParam);
|
||||
boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY;
|
||||
|
||||
generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam);
|
||||
}
|
||||
|
||||
public void generateEqualsAndHashCodeForType(EclipseNode typeNode, EclipseNode errorNode) {
|
||||
@@ -130,11 +138,11 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
|
||||
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
|
||||
|
||||
generateMethods(typeNode, errorNode, members, null, false, access, new ArrayList<Annotation>());
|
||||
generateMethods(typeNode, errorNode, members, null, false, false, access, new ArrayList<Annotation>());
|
||||
}
|
||||
|
||||
public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<Included<EclipseNode, EqualsAndHashCode.Include>> members,
|
||||
Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) {
|
||||
Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<Annotation> onParam) {
|
||||
|
||||
TypeDeclaration typeDecl = null;
|
||||
|
||||
@@ -222,12 +230,33 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
injectMethod(typeNode, canEqualMethod);
|
||||
}
|
||||
|
||||
MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, errorNode.get(), fieldAccess);
|
||||
if (cacheHashCode){
|
||||
if (fieldExists(HASH_CODE_CACHE_NAME, typeNode) != MemberExistsResult.NOT_EXISTS) {
|
||||
String msg = String.format("Not caching the result of hashCode: A field named %s already exists.", HASH_CODE_CACHE_NAME);
|
||||
errorNode.addWarning(msg);
|
||||
cacheHashCode = false;
|
||||
} else {
|
||||
createHashCodeCacheField(typeNode, errorNode.get());
|
||||
}
|
||||
}
|
||||
|
||||
MethodDeclaration hashCodeMethod = createHashCode(typeNode, members, callSuper, cacheHashCode, errorNode.get(), fieldAccess);
|
||||
hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
|
||||
injectMethod(typeNode, hashCodeMethod);
|
||||
}
|
||||
|
||||
private void createHashCodeCacheField(EclipseNode typeNode, ASTNode source) {
|
||||
FieldDeclaration hashCodeCacheDecl = new FieldDeclaration(HASH_CODE_CACHE_NAME_ARR, 0, 0);
|
||||
hashCodeCacheDecl.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccTransient;
|
||||
hashCodeCacheDecl.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
hashCodeCacheDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
|
||||
hashCodeCacheDecl.declarationSourceEnd = -1;
|
||||
injectFieldAndMarkGenerated(typeNode, hashCodeCacheDecl);
|
||||
setGeneratedBy(hashCodeCacheDecl, source);
|
||||
setGeneratedBy(hashCodeCacheDecl.type, source);
|
||||
}
|
||||
|
||||
public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, ASTNode source, FieldAccess fieldAccess) {
|
||||
public MethodDeclaration createHashCode(EclipseNode type, Collection<Included<EclipseNode, EqualsAndHashCode.Include>> members, boolean callSuper, boolean cacheHashCode, ASTNode source, FieldAccess fieldAccess) {
|
||||
int pS = source.sourceStart, pE = source.sourceEnd;
|
||||
long p = (long) pS << 32 | pE;
|
||||
|
||||
@@ -238,7 +267,10 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
method.returnType = TypeReference.baseTypeReference(TypeIds.T_int, 0);
|
||||
setGeneratedBy(method.returnType, source);
|
||||
Annotation overrideAnnotation = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source);
|
||||
if (getCheckerFrameworkVersion(type).generateSideEffectFree()) {
|
||||
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(type);
|
||||
if (cacheHashCode && checkerFramework.generatePure()) {
|
||||
method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__PURE) };
|
||||
} else if (checkerFramework.generateSideEffectFree()) {
|
||||
method.annotations = new Annotation[] { overrideAnnotation, generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) };
|
||||
} else {
|
||||
method.annotations = new Annotation[] { overrideAnnotation };
|
||||
@@ -262,6 +294,22 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
}
|
||||
}
|
||||
|
||||
/* if (this.$hashCodeCache != 0) return this.$hashCodeCache; */ {
|
||||
if (cacheHashCode) {
|
||||
FieldReference hashCodeCacheRef = new FieldReference(HASH_CODE_CACHE_NAME_ARR, p);
|
||||
hashCodeCacheRef.receiver = new ThisReference(pS, pE);
|
||||
setGeneratedBy(hashCodeCacheRef, source);
|
||||
setGeneratedBy(hashCodeCacheRef.receiver, source);
|
||||
EqualExpression cacheNotZero = new EqualExpression(hashCodeCacheRef, makeIntLiteral("0".toCharArray(), source), OperatorIds.NOT_EQUAL);
|
||||
setGeneratedBy(cacheNotZero, source);
|
||||
ReturnStatement returnCache = new ReturnStatement(hashCodeCacheRef, pS, pE);
|
||||
setGeneratedBy(returnCache, source);
|
||||
IfStatement ifStatement = new IfStatement(cacheNotZero, returnCache, pS, pE);
|
||||
setGeneratedBy(ifStatement, source);
|
||||
statements.add(ifStatement);
|
||||
}
|
||||
}
|
||||
|
||||
/* final int PRIME = X; */ {
|
||||
/* Without members, PRIME isn't used, as that would trigger a 'local variable not used' warning. */
|
||||
if (!isEmpty) {
|
||||
@@ -296,7 +344,7 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
resultDecl.initialization = init;
|
||||
resultDecl.type = TypeReference.baseTypeReference(TypeIds.T_int, 0);
|
||||
resultDecl.type.sourceStart = pS; resultDecl.type.sourceEnd = pE;
|
||||
if (isEmpty) resultDecl.modifiers |= Modifier.FINAL;
|
||||
if (isEmpty && !cacheHashCode) resultDecl.modifiers |= Modifier.FINAL;
|
||||
setGeneratedBy(resultDecl.type, source);
|
||||
statements.add(resultDecl);
|
||||
}
|
||||
@@ -391,6 +439,49 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if (result == 0) result = Integer.MIN_VALUE;
|
||||
* this.$hashCodeCache = result;
|
||||
*
|
||||
*/ {
|
||||
if (cacheHashCode) {
|
||||
SingleNameReference resultRef = new SingleNameReference(RESULT, p);
|
||||
setGeneratedBy(resultRef, source);
|
||||
|
||||
EqualExpression resultIsZero = new EqualExpression(resultRef, makeIntLiteral("0".toCharArray(), source), OperatorIds.EQUAL_EQUAL);
|
||||
setGeneratedBy(resultIsZero, source);
|
||||
|
||||
resultRef = new SingleNameReference(RESULT, p);
|
||||
setGeneratedBy(resultRef, source);
|
||||
|
||||
FieldReference integerMinValue = new FieldReference("MIN_VALUE".toCharArray(), p);
|
||||
integerMinValue.receiver = generateQualifiedNameRef(source, TypeConstants.JAVA_LANG_INTEGER);
|
||||
setGeneratedBy(integerMinValue, source);
|
||||
|
||||
Assignment newResult = new Assignment(resultRef, integerMinValue, pE);
|
||||
newResult.sourceStart = pS; newResult.statementEnd = newResult.sourceEnd = pE;
|
||||
setGeneratedBy(newResult, source);
|
||||
|
||||
IfStatement ifStatement = new IfStatement(resultIsZero, newResult, pS, pE);
|
||||
setGeneratedBy(ifStatement, source);
|
||||
statements.add(ifStatement);
|
||||
|
||||
|
||||
FieldReference hashCodeCacheRef = new FieldReference(HASH_CODE_CACHE_NAME_ARR, p);
|
||||
hashCodeCacheRef.receiver = new ThisReference(pS, pE);
|
||||
setGeneratedBy(hashCodeCacheRef, source);
|
||||
setGeneratedBy(hashCodeCacheRef.receiver, source);
|
||||
|
||||
resultRef = new SingleNameReference(RESULT, p);
|
||||
setGeneratedBy(resultRef, source);
|
||||
|
||||
Assignment cacheResult = new Assignment(hashCodeCacheRef, resultRef, pE);
|
||||
cacheResult.sourceStart = pS; cacheResult.statementEnd = cacheResult.sourceEnd = pE;
|
||||
setGeneratedBy(cacheResult, source);
|
||||
statements.add(cacheResult);
|
||||
}
|
||||
}
|
||||
|
||||
/* return result; */ {
|
||||
SingleNameReference resultRef = new SingleNameReference(RESULT, p);
|
||||
setGeneratedBy(resultRef, source);
|
||||
|
||||
@@ -42,6 +42,8 @@ import com.sun.tools.javac.tree.JCTree.JCBlock;
|
||||
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCModifiers;
|
||||
@@ -56,6 +58,7 @@ import com.sun.tools.javac.util.Name;
|
||||
|
||||
import lombok.ConfigurationKeys;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.EqualsAndHashCode.CacheStrategy;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.configuration.CallSuperType;
|
||||
@@ -76,11 +79,13 @@ import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult;
|
||||
public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHashCode> {
|
||||
private static final String RESULT_NAME = "result";
|
||||
private static final String PRIME_NAME = "PRIME";
|
||||
private static final String HASH_CODE_CACHE_NAME = "$hashCodeCache";
|
||||
|
||||
@Override public void handle(AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode");
|
||||
|
||||
deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class);
|
||||
deleteImportFromCompilationUnit(annotationNode, CacheStrategy.class.getName());
|
||||
EqualsAndHashCode ann = annotation.getInstance();
|
||||
java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode);
|
||||
JavacNode typeNode = annotationNode.up();
|
||||
@@ -92,8 +97,10 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
|
||||
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
|
||||
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
|
||||
|
||||
generateMethods(typeNode, annotationNode, members, callSuper, true, fieldAccess, onParam);
|
||||
|
||||
boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY;
|
||||
|
||||
generateMethods(typeNode, annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam);
|
||||
}
|
||||
|
||||
public void generateEqualsAndHashCodeForType(JavacNode typeNode, JavacNode source) {
|
||||
@@ -107,11 +114,11 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(typeNode, null, null);
|
||||
|
||||
generateMethods(typeNode, source, members, null, false, access, List.<JCAnnotation>nil());
|
||||
generateMethods(typeNode, source, members, null, false, false, access, List.<JCAnnotation>nil());
|
||||
}
|
||||
|
||||
public void generateMethods(JavacNode typeNode, JavacNode source, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members,
|
||||
Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
|
||||
Boolean callSuper, boolean whineIfExists, boolean cacheHashCode, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
|
||||
|
||||
boolean notAClass = true;
|
||||
if (typeNode.get() instanceof JCClassDecl) {
|
||||
@@ -196,17 +203,39 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
injectMethod(typeNode, canEqualMethod);
|
||||
}
|
||||
|
||||
JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, fieldAccess, source.get());
|
||||
if (cacheHashCode){
|
||||
if (fieldExists(HASH_CODE_CACHE_NAME, typeNode) != MemberExistsResult.NOT_EXISTS) {
|
||||
String msg = String.format("Not caching the result of hashCode: A field named %s already exists.", HASH_CODE_CACHE_NAME);
|
||||
source.addWarning(msg);
|
||||
cacheHashCode = false;
|
||||
} else {
|
||||
createHashCodeCacheField(typeNode, source.get());
|
||||
}
|
||||
}
|
||||
|
||||
JCMethodDecl hashCodeMethod = createHashCode(typeNode, members, callSuper, cacheHashCode, fieldAccess, source.get());
|
||||
injectMethod(typeNode, hashCodeMethod);
|
||||
}
|
||||
|
||||
private void createHashCodeCacheField(JavacNode typeNode, JCTree source) {
|
||||
JavacTreeMaker maker = typeNode.getTreeMaker();
|
||||
JCModifiers mods = maker.Modifiers(Flags.PRIVATE | Flags.TRANSIENT);
|
||||
JCVariableDecl hashCodeCacheField = maker.VarDef(mods, typeNode.toName(HASH_CODE_CACHE_NAME), maker.TypeIdent(CTC_INT), null);
|
||||
injectFieldAndMarkGenerated(typeNode, hashCodeCacheField);
|
||||
recursiveSetGeneratedBy(hashCodeCacheField, source, typeNode.getContext());
|
||||
}
|
||||
|
||||
public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, FieldAccess fieldAccess, JCTree source) {
|
||||
public JCMethodDecl createHashCode(JavacNode typeNode, java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members, boolean callSuper, boolean cacheHashCode, FieldAccess fieldAccess, JCTree source) {
|
||||
JavacTreeMaker maker = typeNode.getTreeMaker();
|
||||
|
||||
JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
|
||||
List<JCAnnotation> annsOnMethod = List.of(overrideAnnotation);
|
||||
CheckerFrameworkVersion checkerFramework = getCheckerFrameworkVersion(typeNode);
|
||||
if (checkerFramework.generateSideEffectFree()) annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));
|
||||
if (cacheHashCode && checkerFramework.generatePure()) {
|
||||
annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()));
|
||||
} else if (checkerFramework.generateSideEffectFree()) {
|
||||
annsOnMethod = annsOnMethod.prepend(maker.Annotation(genTypeRef(typeNode, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE), List.<JCExpression>nil()));
|
||||
}
|
||||
JCModifiers mods = maker.Modifiers(Flags.PUBLIC, annsOnMethod);
|
||||
JCExpression returnType = maker.TypeIdent(CTC_INT);
|
||||
ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
|
||||
@@ -217,6 +246,15 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
|
||||
boolean isEmpty = members.isEmpty();
|
||||
|
||||
/* if (this.$hashCodeCache != 0) return this.$hashCodeCache; */ {
|
||||
if (cacheHashCode) {
|
||||
JCIdent receiver = maker.Ident(typeNode.toName("this"));
|
||||
JCFieldAccess cacheHashCodeFieldAccess = maker.Select(receiver, typeNode.toName(HASH_CODE_CACHE_NAME));
|
||||
JCExpression cacheNotZero = maker.Binary(CTC_NOT_EQUAL, cacheHashCodeFieldAccess, maker.Literal(CTC_INT, 0));
|
||||
statements.append(maker.If(cacheNotZero, maker.Return(cacheHashCodeFieldAccess), null));
|
||||
}
|
||||
}
|
||||
|
||||
/* final int PRIME = X; */ {
|
||||
if (!isEmpty) {
|
||||
statements.append(maker.VarDef(maker.Modifiers(finalFlag), primeName, maker.TypeIdent(CTC_INT), maker.Literal(HandlerUtil.primeForHashcode())));
|
||||
@@ -234,7 +272,7 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
/* ... 1; */
|
||||
init = maker.Literal(1);
|
||||
}
|
||||
statements.append(maker.VarDef(maker.Modifiers(isEmpty ? finalFlag : 0L), resultName, maker.TypeIdent(CTC_INT), init));
|
||||
statements.append(maker.VarDef(maker.Modifiers(isEmpty && !cacheHashCode ? finalFlag : 0L), resultName, maker.TypeIdent(CTC_INT), init));
|
||||
}
|
||||
|
||||
for (Included<JavacNode, EqualsAndHashCode.Include> member : members) {
|
||||
@@ -306,6 +344,20 @@ public class HandleEqualsAndHashCode extends JavacAnnotationHandler<EqualsAndHas
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if (result == 0) result = Integer.MIN_VALUE;
|
||||
* this.$hashCodeCache = result;
|
||||
*
|
||||
*/ {
|
||||
if (cacheHashCode) {
|
||||
statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(resultName), maker.Literal(CTC_INT, 0)),
|
||||
maker.Exec(maker.Assign(maker.Ident(resultName), genJavaLangTypeRef(typeNode, "Integer", "MIN_VALUE"))), null));
|
||||
|
||||
JCFieldAccess cacheHashCodeFieldAccess = maker.Select(maker.Ident(typeNode.toName("this")), typeNode.toName(HASH_CODE_CACHE_NAME));
|
||||
statements.append(maker.Exec(maker.Assign(cacheHashCodeFieldAccess, maker.Ident(resultName))));
|
||||
}
|
||||
}
|
||||
|
||||
/* return result; */ {
|
||||
statements.append(maker.Return(maker.Ident(resultName)));
|
||||
}
|
||||
|
||||
@@ -701,8 +701,12 @@ public class Delombok {
|
||||
|
||||
if (!disablePreview && Javac.getJavaCompilerVersion() >= 11) argsList.add("--enable-preview");
|
||||
|
||||
String[] argv = argsList.toArray(new String[0]);
|
||||
args.init("javac", argv);
|
||||
if (Javac.getJavaCompilerVersion() < 15) {
|
||||
String[] argv = argsList.toArray(new String[0]);
|
||||
args.init("javac", argv);
|
||||
} else {
|
||||
args.init("javac", argsList);
|
||||
}
|
||||
options.put("diags.legacy", "TRUE");
|
||||
options.put("allowStringFolding", "FALSE");
|
||||
} else {
|
||||
|
||||
@@ -10,4 +10,7 @@ public class Arguments {
|
||||
public void init(String ownName, String... argv) {}
|
||||
public Map<Option, String> getDeferredFileManagerOptions() { return null; }
|
||||
public boolean validate() { return false; }
|
||||
|
||||
// JDK15
|
||||
public void init(String ownName, Iterable<String> args) {}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,167 @@
|
||||
class EqualsAndHashCode {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private transient int $hashCodeCache;
|
||||
int x;
|
||||
boolean[] y;
|
||||
Object[] z;
|
||||
String a;
|
||||
String b;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public boolean equals(final java.lang.Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof EqualsAndHashCode)) return false;
|
||||
final EqualsAndHashCode other = (EqualsAndHashCode) o;
|
||||
if (!other.canEqual((java.lang.Object) this)) return false;
|
||||
if (this.x != other.x) return false;
|
||||
if (!java.util.Arrays.equals(this.y, other.y)) return false;
|
||||
if (!java.util.Arrays.deepEquals(this.z, other.z)) return false;
|
||||
final java.lang.Object this$a = this.a;
|
||||
final java.lang.Object other$a = other.a;
|
||||
if (this$a == null ? other$a != null : !this$a.equals(other$a)) return false;
|
||||
final java.lang.Object this$b = this.b;
|
||||
final java.lang.Object other$b = other.b;
|
||||
if (this$b == null ? other$b != null : !this$b.equals(other$b)) return false;
|
||||
return true;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected boolean canEqual(final java.lang.Object other) {
|
||||
return other instanceof EqualsAndHashCode;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public int hashCode() {
|
||||
if (this.$hashCodeCache != 0) return this.$hashCodeCache;
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + this.x;
|
||||
result = result * PRIME + java.util.Arrays.hashCode(this.y);
|
||||
result = result * PRIME + java.util.Arrays.deepHashCode(this.z);
|
||||
final java.lang.Object $a = this.a;
|
||||
result = result * PRIME + ($a == null ? 43 : $a.hashCode());
|
||||
final java.lang.Object $b = this.b;
|
||||
result = result * PRIME + ($b == null ? 43 : $b.hashCode());
|
||||
if (result == 0) result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
final class EqualsAndHashCode2 {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private transient int $hashCodeCache;
|
||||
int x;
|
||||
long y;
|
||||
float f;
|
||||
double d;
|
||||
boolean b;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public boolean equals(final java.lang.Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof EqualsAndHashCode2)) return false;
|
||||
final EqualsAndHashCode2 other = (EqualsAndHashCode2) o;
|
||||
if (this.x != other.x) return false;
|
||||
if (this.y != other.y) return false;
|
||||
if (java.lang.Float.compare(this.f, other.f) != 0) return false;
|
||||
if (java.lang.Double.compare(this.d, other.d) != 0) return false;
|
||||
if (this.b != other.b) return false;
|
||||
return true;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public int hashCode() {
|
||||
if (this.$hashCodeCache != 0) return this.$hashCodeCache;
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = result * PRIME + this.x;
|
||||
final long $y = this.y;
|
||||
result = result * PRIME + (int) ($y >>> 32 ^ $y);
|
||||
result = result * PRIME + java.lang.Float.floatToIntBits(this.f);
|
||||
final long $d = java.lang.Double.doubleToLongBits(this.d);
|
||||
result = result * PRIME + (int) ($d >>> 32 ^ $d);
|
||||
result = result * PRIME + (this.b ? 79 : 97);
|
||||
if (result == 0) result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
final class EqualsAndHashCode3 extends EqualsAndHashCode {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private transient int $hashCodeCache;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public boolean equals(final java.lang.Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof EqualsAndHashCode3)) return false;
|
||||
final EqualsAndHashCode3 other = (EqualsAndHashCode3) o;
|
||||
if (!other.canEqual((java.lang.Object) this)) return false;
|
||||
return true;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected boolean canEqual(final java.lang.Object other) {
|
||||
return other instanceof EqualsAndHashCode3;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public int hashCode() {
|
||||
if (this.$hashCodeCache != 0) return this.$hashCodeCache;
|
||||
int result = 1;
|
||||
if (result == 0) result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
class EqualsAndHashCode4 extends EqualsAndHashCode {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private transient int $hashCodeCache;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public boolean equals(final java.lang.Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof EqualsAndHashCode4)) return false;
|
||||
final EqualsAndHashCode4 other = (EqualsAndHashCode4) o;
|
||||
if (!other.canEqual((java.lang.Object) this)) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
return true;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected boolean canEqual(final java.lang.Object other) {
|
||||
return other instanceof EqualsAndHashCode4;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public int hashCode() {
|
||||
if (this.$hashCodeCache != 0) return this.$hashCodeCache;
|
||||
int result = super.hashCode();
|
||||
if (result == 0) result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
final class EqualsAndHashCode5 extends EqualsAndHashCode {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private transient int $hashCodeCache;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public boolean equals(final java.lang.Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof EqualsAndHashCode5)) return false;
|
||||
final EqualsAndHashCode5 other = (EqualsAndHashCode5) o;
|
||||
if (!other.canEqual((java.lang.Object) this)) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
return true;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected boolean canEqual(final java.lang.Object other) {
|
||||
return other instanceof EqualsAndHashCode5;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public int hashCode() {
|
||||
if (this.$hashCodeCache != 0) return this.$hashCodeCache;
|
||||
int result = super.hashCode();
|
||||
if (result == 0) result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
@lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode {
|
||||
private transient @java.lang.SuppressWarnings("all") int $hashCodeCache;
|
||||
int x;
|
||||
boolean[] y;
|
||||
Object[] z;
|
||||
String a;
|
||||
String b;
|
||||
EqualsAndHashCode() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
|
||||
if ((o == this))
|
||||
return true;
|
||||
if ((! (o instanceof EqualsAndHashCode)))
|
||||
return false;
|
||||
final EqualsAndHashCode other = (EqualsAndHashCode) o;
|
||||
if ((! other.canEqual((java.lang.Object) this)))
|
||||
return false;
|
||||
if ((this.x != other.x))
|
||||
return false;
|
||||
if ((! java.util.Arrays.equals(this.y, other.y)))
|
||||
return false;
|
||||
if ((! java.util.Arrays.deepEquals(this.z, other.z)))
|
||||
return false;
|
||||
final java.lang.Object this$a = this.a;
|
||||
final java.lang.Object other$a = other.a;
|
||||
if (((this$a == null) ? (other$a != null) : (! this$a.equals(other$a))))
|
||||
return false;
|
||||
final java.lang.Object this$b = this.b;
|
||||
final java.lang.Object other$b = other.b;
|
||||
if (((this$b == null) ? (other$b != null) : (! this$b.equals(other$b))))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) {
|
||||
return (other instanceof EqualsAndHashCode);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
|
||||
if ((this.$hashCodeCache != 0))
|
||||
return this.$hashCodeCache;
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = ((result * PRIME) + this.x);
|
||||
result = ((result * PRIME) + java.util.Arrays.hashCode(this.y));
|
||||
result = ((result * PRIME) + java.util.Arrays.deepHashCode(this.z));
|
||||
final java.lang.Object $a = this.a;
|
||||
result = ((result * PRIME) + (($a == null) ? 43 : $a.hashCode()));
|
||||
final java.lang.Object $b = this.b;
|
||||
result = ((result * PRIME) + (($b == null) ? 43 : $b.hashCode()));
|
||||
if ((result == 0))
|
||||
result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
final @lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode2 {
|
||||
private transient @java.lang.SuppressWarnings("all") int $hashCodeCache;
|
||||
int x;
|
||||
long y;
|
||||
float f;
|
||||
double d;
|
||||
boolean b;
|
||||
EqualsAndHashCode2() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
|
||||
if ((o == this))
|
||||
return true;
|
||||
if ((! (o instanceof EqualsAndHashCode2)))
|
||||
return false;
|
||||
final EqualsAndHashCode2 other = (EqualsAndHashCode2) o;
|
||||
if ((this.x != other.x))
|
||||
return false;
|
||||
if ((this.y != other.y))
|
||||
return false;
|
||||
if ((java.lang.Float.compare(this.f, other.f) != 0))
|
||||
return false;
|
||||
if ((java.lang.Double.compare(this.d, other.d) != 0))
|
||||
return false;
|
||||
if ((this.b != other.b))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
|
||||
if ((this.$hashCodeCache != 0))
|
||||
return this.$hashCodeCache;
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
result = ((result * PRIME) + this.x);
|
||||
final long $y = this.y;
|
||||
result = ((result * PRIME) + (int) ($y ^ ($y >>> 32)));
|
||||
result = ((result * PRIME) + java.lang.Float.floatToIntBits(this.f));
|
||||
final long $d = java.lang.Double.doubleToLongBits(this.d);
|
||||
result = ((result * PRIME) + (int) ($d ^ ($d >>> 32)));
|
||||
result = ((result * PRIME) + (this.b ? 79 : 97));
|
||||
if ((result == 0))
|
||||
result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
final @lombok.EqualsAndHashCode(callSuper = false,cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode3 extends EqualsAndHashCode {
|
||||
private transient @java.lang.SuppressWarnings("all") int $hashCodeCache;
|
||||
EqualsAndHashCode3() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
|
||||
if ((o == this))
|
||||
return true;
|
||||
if ((! (o instanceof EqualsAndHashCode3)))
|
||||
return false;
|
||||
final EqualsAndHashCode3 other = (EqualsAndHashCode3) o;
|
||||
if ((! other.canEqual((java.lang.Object) this)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) {
|
||||
return (other instanceof EqualsAndHashCode3);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
|
||||
if ((this.$hashCodeCache != 0))
|
||||
return this.$hashCodeCache;
|
||||
int result = 1;
|
||||
if ((result == 0))
|
||||
result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@lombok.EqualsAndHashCode(callSuper = true,cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode4 extends EqualsAndHashCode {
|
||||
private transient @java.lang.SuppressWarnings("all") int $hashCodeCache;
|
||||
EqualsAndHashCode4() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
|
||||
if ((o == this))
|
||||
return true;
|
||||
if ((! (o instanceof EqualsAndHashCode4)))
|
||||
return false;
|
||||
final EqualsAndHashCode4 other = (EqualsAndHashCode4) o;
|
||||
if ((! other.canEqual((java.lang.Object) this)))
|
||||
return false;
|
||||
if ((! super.equals(o)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) {
|
||||
return (other instanceof EqualsAndHashCode4);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
|
||||
if ((this.$hashCodeCache != 0))
|
||||
return this.$hashCodeCache;
|
||||
int result = super.hashCode();
|
||||
if ((result == 0))
|
||||
result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
final @lombok.EqualsAndHashCode(callSuper = true,cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY) class EqualsAndHashCode5 extends EqualsAndHashCode {
|
||||
private transient @java.lang.SuppressWarnings("all") int $hashCodeCache;
|
||||
EqualsAndHashCode5() {
|
||||
super();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") boolean equals(final java.lang.Object o) {
|
||||
if ((o == this))
|
||||
return true;
|
||||
if ((! (o instanceof EqualsAndHashCode5)))
|
||||
return false;
|
||||
final EqualsAndHashCode5 other = (EqualsAndHashCode5) o;
|
||||
if ((! other.canEqual((java.lang.Object) this)))
|
||||
return false;
|
||||
if ((! super.equals(o)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
protected @java.lang.SuppressWarnings("all") boolean canEqual(final java.lang.Object other) {
|
||||
return (other instanceof EqualsAndHashCode5);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") int hashCode() {
|
||||
if ((this.$hashCodeCache != 0))
|
||||
return this.$hashCodeCache;
|
||||
int result = super.hashCode();
|
||||
if ((result == 0))
|
||||
result = java.lang.Integer.MIN_VALUE;
|
||||
this.$hashCodeCache = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
@lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY)
|
||||
class EqualsAndHashCode {
|
||||
int x;
|
||||
boolean[] y;
|
||||
Object[] z;
|
||||
String a;
|
||||
String b;
|
||||
}
|
||||
|
||||
@lombok.EqualsAndHashCode(cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY)
|
||||
final class EqualsAndHashCode2 {
|
||||
int x;
|
||||
long y;
|
||||
float f;
|
||||
double d;
|
||||
boolean b;
|
||||
}
|
||||
|
||||
@lombok.EqualsAndHashCode(callSuper=false, cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY)
|
||||
final class EqualsAndHashCode3 extends EqualsAndHashCode {
|
||||
}
|
||||
|
||||
@lombok.EqualsAndHashCode(callSuper=true, cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY)
|
||||
class EqualsAndHashCode4 extends EqualsAndHashCode {
|
||||
}
|
||||
|
||||
@lombok.EqualsAndHashCode(callSuper=true, cacheStrategy = lombok.EqualsAndHashCode.CacheStrategy.LAZY)
|
||||
final class EqualsAndHashCode5 extends EqualsAndHashCode {
|
||||
}
|
||||
Reference in new issue
Block a user