use of lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method generateMethods.
public void generateMethods(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
boolean notAClass = true;
if (typeNode.get() instanceof JCClassDecl) {
long flags = ((JCClassDecl) typeNode.get()).mods.flags;
notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
}
if (notAClass) {
source.addError("@EqualsAndHashCode is only supported on a class.");
return;
}
boolean isDirectDescendantOfObject = true;
boolean implicitCallSuper = callSuper == null;
if (callSuper == null) {
try {
callSuper = ((Boolean) EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue();
} catch (Exception ignore) {
throw new InternalError("Lombok bug - this cannot happen - can't find callSuper field in EqualsAndHashCode annotation.");
}
}
JCTree extending = Javac.getExtendsClause((JCClassDecl) typeNode.get());
if (extending != null) {
String p = extending.toString();
isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object");
}
if (isDirectDescendantOfObject && callSuper) {
source.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless.");
return;
}
if (implicitCallSuper && !isDirectDescendantOfObject) {
CallSuperType cst = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_CALL_SUPER);
if (cst == null)
cst = CallSuperType.WARN;
switch(cst) {
default:
case WARN:
source.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.");
callSuper = false;
break;
case SKIP:
callSuper = false;
break;
case CALL:
callSuper = true;
break;
}
}
ListBuffer<JavacNode> nodesForEquality = new ListBuffer<JavacNode>();
if (includes != null) {
for (JavacNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD)
continue;
JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
if (includes.contains(fieldDecl.name.toString()))
nodesForEquality.append(child);
}
} else {
for (JavacNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD)
continue;
JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
//Skip static fields.
if ((fieldDecl.mods.flags & Flags.STATIC) != 0)
continue;
//Skip transient fields.
if ((fieldDecl.mods.flags & Flags.TRANSIENT) != 0)
continue;
//Skip excluded fields.
if (excludes != null && excludes.contains(fieldDecl.name.toString()))
continue;
//Skip fields that start with $
if (fieldDecl.name.toString().startsWith("$"))
continue;
nodesForEquality.append(child);
}
}
boolean isFinal = (((JCClassDecl) typeNode.get()).mods.flags & Flags.FINAL) != 0;
boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject;
MemberExistsResult equalsExists = methodExists("equals", typeNode, 1);
MemberExistsResult hashCodeExists = methodExists("hashCode", typeNode, 0);
MemberExistsResult canEqualExists = methodExists("canEqual", typeNode, 1);
switch(Collections.max(Arrays.asList(equalsExists, hashCodeExists))) {
case EXISTS_BY_LOMBOK:
return;
case EXISTS_BY_USER:
if (whineIfExists) {
String msg = "Not generating equals and hashCode: A method with one of those names already exists. (Either both or none of these methods will be generated).";
source.addWarning(msg);
} else if (equalsExists == MemberExistsResult.NOT_EXISTS || hashCodeExists == MemberExistsResult.NOT_EXISTS) {
// This means equals OR hashCode exists and not both.
// Even though we should suppress the message about not generating these, this is such a weird and surprising situation we should ALWAYS generate a warning.
// The user code couldn't possibly (barring really weird subclassing shenanigans) be in a shippable state anyway; the implementations of these 2 methods are
// all inter-related and should be written by the same entity.
String msg = String.format("Not generating %s: One of equals or hashCode exists. " + "You should either write both of these or none of these (in the latter case, lombok generates them).", equalsExists == MemberExistsResult.NOT_EXISTS ? "equals" : "hashCode");
source.addWarning(msg);
}
return;
case NOT_EXISTS:
default:
}
JCMethodDecl equalsMethod = createEquals(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, needsCanEqual, source.get(), onParam);
injectMethod(typeNode, equalsMethod);
if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) {
JCMethodDecl canEqualMethod = createCanEqual(typeNode, source.get(), onParam);
injectMethod(typeNode, canEqualMethod);
}
JCMethodDecl hashCodeMethod = createHashCode(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, source.get());
injectMethod(typeNode, hashCodeMethod);
}
Aggregations