public boolean generateMethods(
      EclipseNode typeNode,
      EclipseNode errorNode,
      List<String> excludes,
      List<String> includes,
      Boolean callSuper,
      boolean whineIfExists,
      FieldAccess fieldAccess) {
    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 false;
    }

    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 true;
    }

    if (!isDirectDescendantOfObject && !callSuper && implicitCallSuper) {
      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.");
    }

    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 (!EclipseHandlerUtil.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 needsCanEqual = false;
    switch (methodExists("equals", typeNode)) {
      case NOT_EXISTS:
        boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0;
        needsCanEqual = !isDirectDescendantOfObject || !isFinal;

        MethodDeclaration equals =
            createEquals(
                typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual);
        injectMethod(typeNode, equals);
        break;
      case EXISTS_BY_LOMBOK:
        break;
      default:
      case EXISTS_BY_USER:
        if (whineIfExists) {
          errorNode.addWarning(
              "Not generating equals(Object other): A method with that name already exists");
        }
        break;
    }

    if (needsCanEqual) {
      switch (methodExists("canEqual", typeNode)) {
        case NOT_EXISTS:
          MethodDeclaration equals = createCanEqual(typeNode, errorNode.get());
          injectMethod(typeNode, equals);
          break;
        case EXISTS_BY_LOMBOK:
        case EXISTS_BY_USER:
        default:
          break;
      }
    }

    switch (methodExists("hashCode", typeNode)) {
      case NOT_EXISTS:
        MethodDeclaration hashCode =
            createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess);
        injectMethod(typeNode, hashCode);
        break;
      case EXISTS_BY_LOMBOK:
        break;
      default:
      case EXISTS_BY_USER:
        if (whineIfExists) {
          errorNode.addWarning("Not generating hashCode(): A method with that name already exists");
        }
        break;
    }

    return true;
  }
Exemple #2
0
  public boolean generateToString(
      EclipseNode typeNode,
      EclipseNode errorNode,
      List<String> excludes,
      List<String> includes,
      boolean includeFieldNames,
      Boolean callSuper,
      boolean whineIfExists,
      FieldAccess fieldAccess) {
    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)) != 0;

    if (typeDecl == null || notAClass) {
      errorNode.addError("@ToString is only supported on a class or enum.");
      return false;
    }

    if (callSuper == null) {
      try {
        callSuper =
            ((Boolean) ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue();
      } catch (Exception ignore) {
      }
    }

    List<EclipseNode> nodesForToString = 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))) nodesForToString.add(child);
      }
    } else {
      for (EclipseNode child : typeNode.down()) {
        if (child.getKind() != Kind.FIELD) continue;
        FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
        if (!EclipseHandlerUtil.filterField(fieldDecl)) continue;

        // Skip excluded fields.
        if (excludes != null && excludes.contains(new String(fieldDecl.name))) continue;

        nodesForToString.add(child);
      }
    }

    switch (methodExists("toString", typeNode)) {
      case NOT_EXISTS:
        MethodDeclaration toString =
            createToString(
                typeNode,
                nodesForToString,
                includeFieldNames,
                callSuper,
                errorNode.get(),
                fieldAccess);
        injectMethod(typeNode, toString);
        return true;
      case EXISTS_BY_LOMBOK:
        return true;
      default:
      case EXISTS_BY_USER:
        if (whineIfExists) {
          errorNode.addWarning("Not generating toString(): A method with that name already exists");
        }
        return true;
    }
  }