Search in sources :

Example 1 with MemberExistsResult

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);
}
Also used : MemberExistsResult(lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) EqualsAndHashCode(lombok.EqualsAndHashCode) ListBuffer(com.sun.tools.javac.util.ListBuffer) JCTree(com.sun.tools.javac.tree.JCTree) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JavacNode(lombok.javac.JavacNode) CallSuperType(lombok.core.configuration.CallSuperType)

Aggregations

JCTree (com.sun.tools.javac.tree.JCTree)1 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)1 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)1 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)1 ListBuffer (com.sun.tools.javac.util.ListBuffer)1 EqualsAndHashCode (lombok.EqualsAndHashCode)1 CallSuperType (lombok.core.configuration.CallSuperType)1 JavacNode (lombok.javac.JavacNode)1 MemberExistsResult (lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult)1