use of lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method generateMethods.
public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) {
assert excludes == null || includes == null;
TypeDeclaration typeDecl = null;
if (typeNode.get() instanceof TypeDeclaration)
typeDecl = (TypeDeclaration) typeNode.get();
int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
if (typeDecl == null || notAClass) {
errorNode.addError("@EqualsAndHashCode is only supported on a class.");
return;
}
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.");
}
}
boolean isDirectDescendantOfObject = true;
if (typeDecl.superclass != null) {
String p = typeDecl.superclass.toString();
isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object");
}
if (isDirectDescendantOfObject && callSuper) {
errorNode.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:
errorNode.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;
}
}
List<EclipseNode> nodesForEquality = new ArrayList<EclipseNode>();
if (includes != null) {
for (EclipseNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD)
continue;
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
if (includes.contains(new String(fieldDecl.name)))
nodesForEquality.add(child);
}
} else {
for (EclipseNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD)
continue;
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
if (!filterField(fieldDecl))
continue;
// Skip transient fields.
if ((fieldDecl.modifiers & ClassFileConstants.AccTransient) != 0)
continue;
// Skip excluded fields.
if (excludes != null && excludes.contains(new String(fieldDecl.name)))
continue;
nodesForEquality.add(child);
}
}
boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 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).";
errorNode.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");
errorNode.addWarning(msg);
}
return;
case NOT_EXISTS:
default:
}
MethodDeclaration equalsMethod = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam);
equalsMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration) typeNode.get()).scope);
injectMethod(typeNode, equalsMethod);
if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) {
MethodDeclaration canEqualMethod = createCanEqual(typeNode, errorNode.get(), onParam);
canEqualMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration) typeNode.get()).scope);
injectMethod(typeNode, canEqualMethod);
}
MethodDeclaration hashCodeMethod = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess);
hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration) typeNode.get()).scope);
injectMethod(typeNode, hashCodeMethod);
}
Aggregations