Esempio n. 1
0
  /**
   * When generating a setter, the setter either returns void (beanspec) or Self (fluent). This
   * method scans for the {@code Accessors} annotation to figure that out.
   */
  public static boolean shouldReturnThis(JavacNode field) {
    if ((((JCVariableDecl) field.get()).mods.flags & Flags.STATIC) != 0) return false;

    AnnotationValues<Accessors> accessors = JavacHandlerUtil.getAccessorsForField(field);

    boolean forced = (accessors.getActualExpression("chain") != null);
    Accessors instance = accessors.getInstance();
    return instance.chain() || (instance.fluent() && !forced);
  }
Esempio n. 2
0
  public JCMethodDecl createCanEqual(JavacNode typeNode, JCTree source) {
    /* public boolean canEqual(final java.lang.Object other) {
     *     return other instanceof Outer.Inner.MyType;
     * }
     */
    JavacTreeMaker maker = typeNode.getTreeMaker();

    JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.<JCAnnotation>nil());
    JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN);
    Name canEqualName = typeNode.toName("canEqual");
    JCExpression objectType = genJavaLangTypeRef(typeNode, "Object");
    Name otherName = typeNode.toName("other");
    long flags = JavacHandlerUtil.addFinalIfNeeded(Flags.PARAMETER, typeNode.getContext());
    List<JCVariableDecl> params =
        List.of(maker.VarDef(maker.Modifiers(flags), otherName, objectType, null));

    JCBlock body =
        maker.Block(
            0,
            List.<JCStatement>of(
                maker.Return(
                    maker.TypeTest(maker.Ident(otherName), createTypeReference(typeNode)))));

    return recursiveSetGeneratedBy(
        maker.MethodDef(
            mods,
            canEqualName,
            returnType,
            List.<JCTypeParameter>nil(),
            params,
            List.<JCExpression>nil(),
            body,
            null),
        source,
        typeNode.getContext());
  }
Esempio n. 3
0
  public JCMethodDecl createEquals(
      JavacNode typeNode,
      List<JavacNode> fields,
      boolean callSuper,
      FieldAccess fieldAccess,
      boolean needsCanEqual,
      JCTree source) {
    JavacTreeMaker maker = typeNode.getTreeMaker();
    JCClassDecl type = (JCClassDecl) typeNode.get();

    Name oName = typeNode.toName("o");
    Name otherName = typeNode.toName("other");
    Name thisName = typeNode.toName("this");

    JCAnnotation overrideAnnotation =
        maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
    JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation));
    JCExpression objectType = genJavaLangTypeRef(typeNode, "Object");
    JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN);

    long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());

    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
    final List<JCVariableDecl> params =
        List.of(
            maker.VarDef(maker.Modifiers(finalFlag | Flags.PARAMETER), oName, objectType, null));

    /* if (o == this) return true; */ {
      statements.append(
          maker.If(
              maker.Binary(CTC_EQUAL, maker.Ident(oName), maker.Ident(thisName)),
              returnBool(maker, true),
              null));
    }

    /* if (!(o instanceof Outer.Inner.MyType) return false; */ {
      JCUnary notInstanceOf =
          maker.Unary(CTC_NOT, maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode)));
      statements.append(maker.If(notInstanceOf, returnBool(maker, false), null));
    }

    /* MyType<?> other = (MyType<?>) o; */ {
      if (!fields.isEmpty() || needsCanEqual) {
        final JCExpression selfType1, selfType2;
        ListBuffer<JCExpression> wildcards1 = new ListBuffer<JCExpression>();
        ListBuffer<JCExpression> wildcards2 = new ListBuffer<JCExpression>();
        for (int i = 0; i < type.typarams.length(); i++) {
          wildcards1.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
          wildcards2.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
        }

        if (type.typarams.isEmpty()) {
          selfType1 = maker.Ident(type.name);
          selfType2 = maker.Ident(type.name);
        } else {
          selfType1 = maker.TypeApply(maker.Ident(type.name), wildcards1.toList());
          selfType2 = maker.TypeApply(maker.Ident(type.name), wildcards2.toList());
        }

        statements.append(
            maker.VarDef(
                maker.Modifiers(finalFlag),
                otherName,
                selfType1,
                maker.TypeCast(selfType2, maker.Ident(oName))));
      }
    }

    /* if (!other.canEqual((java.lang.Object) this)) return false; */ {
      if (needsCanEqual) {
        List<JCExpression> exprNil = List.nil();
        JCExpression thisRef = maker.Ident(thisName);
        JCExpression castThisRef = maker.TypeCast(genJavaLangTypeRef(typeNode, "Object"), thisRef);
        JCExpression equalityCheck =
            maker.Apply(
                exprNil,
                maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")),
                List.of(castThisRef));
        statements.append(
            maker.If(maker.Unary(CTC_NOT, equalityCheck), returnBool(maker, false), null));
      }
    }

    /* if (!super.equals(o)) return false; */
    if (callSuper) {
      JCMethodInvocation callToSuper =
          maker.Apply(
              List.<JCExpression>nil(),
              maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")),
              List.<JCExpression>of(maker.Ident(oName)));
      JCUnary superNotEqual = maker.Unary(CTC_NOT, callToSuper);
      statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
    }

    Name thisDollar = typeNode.toName("this$");
    Name otherDollar = typeNode.toName("other$");
    for (JavacNode fieldNode : fields) {
      JCExpression fType = getFieldType(fieldNode, fieldAccess);
      JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
      JCExpression otherFieldAccessor =
          createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName));
      if (fType instanceof JCPrimitiveTypeTree) {
        switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
          case FLOAT:
            /* if (Float.compare(this.fieldName, other.fieldName) != 0) return false; */
            statements.append(
                generateCompareFloatOrDouble(
                    thisFieldAccessor, otherFieldAccessor, maker, typeNode, false));
            break;
          case DOUBLE:
            /* if (Double.compare(this.fieldName, other.fieldName) != 0) return false; */
            statements.append(
                generateCompareFloatOrDouble(
                    thisFieldAccessor, otherFieldAccessor, maker, typeNode, true));
            break;
          default:
            /* if (this.fieldName != other.fieldName) return false; */
            statements.append(
                maker.If(
                    maker.Binary(CTC_NOT_EQUAL, thisFieldAccessor, otherFieldAccessor),
                    returnBool(maker, false),
                    null));
            break;
        }
      } else if (fType instanceof JCArrayTypeTree) {
        /* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */
        boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
        boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
        boolean useDeepEquals = multiDim || !primitiveArray;

        JCExpression eqMethod =
            chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals");
        List<JCExpression> args = List.of(thisFieldAccessor, otherFieldAccessor);
        statements.append(
            maker.If(
                maker.Unary(CTC_NOT, maker.Apply(List.<JCExpression>nil(), eqMethod, args)),
                returnBool(maker, false),
                null));
      } else /* objects */ {
        /* final java.lang.Object this$fieldName = this.fieldName; */
        /* final java.lang.Object other$fieldName = other.fieldName; */
        /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;; */
        Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
        Name thisDollarFieldName = thisDollar.append(fieldName);
        Name otherDollarFieldName = otherDollar.append(fieldName);

        statements.append(
            maker.VarDef(
                maker.Modifiers(finalFlag),
                thisDollarFieldName,
                genJavaLangTypeRef(typeNode, "Object"),
                thisFieldAccessor));
        statements.append(
            maker.VarDef(
                maker.Modifiers(finalFlag),
                otherDollarFieldName,
                genJavaLangTypeRef(typeNode, "Object"),
                otherFieldAccessor));

        JCExpression thisEqualsNull =
            maker.Binary(CTC_EQUAL, maker.Ident(thisDollarFieldName), maker.Literal(CTC_BOT, null));
        JCExpression otherNotEqualsNull =
            maker.Binary(
                CTC_NOT_EQUAL, maker.Ident(otherDollarFieldName), maker.Literal(CTC_BOT, null));
        JCExpression thisEqualsThat =
            maker.Apply(
                List.<JCExpression>nil(),
                maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")),
                List.<JCExpression>of(maker.Ident(otherDollarFieldName)));
        JCExpression fieldsAreNotEqual =
            maker.Conditional(
                thisEqualsNull, otherNotEqualsNull, maker.Unary(CTC_NOT, thisEqualsThat));
        statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null));
      }
    }

    /* return true; */ {
      statements.append(returnBool(maker, true));
    }

    JCBlock body = maker.Block(0, statements.toList());
    return recursiveSetGeneratedBy(
        maker.MethodDef(
            mods,
            typeNode.toName("equals"),
            returnType,
            List.<JCTypeParameter>nil(),
            params,
            List.<JCExpression>nil(),
            body,
            null),
        source,
        typeNode.getContext());
  }
Esempio n. 4
0
  public JCMethodDecl createHashCode(
      JavacNode typeNode,
      List<JavacNode> fields,
      boolean callSuper,
      FieldAccess fieldAccess,
      JCTree source) {
    JavacTreeMaker maker = typeNode.getTreeMaker();

    JCAnnotation overrideAnnotation =
        maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
    JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation));
    JCExpression returnType = maker.TypeIdent(CTC_INT);
    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();

    Name primeName = typeNode.toName(PRIME_NAME);
    Name resultName = typeNode.toName(RESULT_NAME);
    long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());

    /* final int PRIME = X; */ {
      if (!fields.isEmpty() || callSuper) {
        statements.append(
            maker.VarDef(
                maker.Modifiers(finalFlag),
                primeName,
                maker.TypeIdent(CTC_INT),
                maker.Literal(HandlerUtil.primeForHashcode())));
      }
    }

    /* int result = 1; */ {
      statements.append(
          maker.VarDef(maker.Modifiers(0), resultName, maker.TypeIdent(CTC_INT), maker.Literal(1)));
    }

    if (callSuper) {
      JCMethodInvocation callToSuper =
          maker.Apply(
              List.<JCExpression>nil(),
              maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")),
              List.<JCExpression>nil());
      statements.append(createResultCalculation(typeNode, callToSuper));
    }

    Name dollar = typeNode.toName("$");
    for (JavacNode fieldNode : fields) {
      JCExpression fType = getFieldType(fieldNode, fieldAccess);
      JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
      if (fType instanceof JCPrimitiveTypeTree) {
        switch (((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
          case BOOLEAN:
            /* this.fieldName ? X : Y */
            statements.append(
                createResultCalculation(
                    typeNode,
                    maker.Conditional(
                        fieldAccessor,
                        maker.Literal(HandlerUtil.primeForTrue()),
                        maker.Literal(HandlerUtil.primeForFalse()))));
            break;
          case LONG:
            {
              Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
              statements.append(
                  maker.VarDef(
                      maker.Modifiers(finalFlag),
                      dollarFieldName,
                      maker.TypeIdent(CTC_LONG),
                      fieldAccessor));
              statements.append(
                  createResultCalculation(
                      typeNode,
                      longToIntForHashCode(
                          maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
            }
            break;
          case FLOAT:
            /* Float.floatToIntBits(this.fieldName) */
            statements.append(
                createResultCalculation(
                    typeNode,
                    maker.Apply(
                        List.<JCExpression>nil(),
                        genJavaLangTypeRef(typeNode, "Float", "floatToIntBits"),
                        List.of(fieldAccessor))));
            break;
          case DOUBLE:
            {
              /* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */
              Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
              JCExpression init =
                  maker.Apply(
                      List.<JCExpression>nil(),
                      genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"),
                      List.of(fieldAccessor));
              statements.append(
                  maker.VarDef(
                      maker.Modifiers(finalFlag),
                      dollarFieldName,
                      maker.TypeIdent(CTC_LONG),
                      init));
              statements.append(
                  createResultCalculation(
                      typeNode,
                      longToIntForHashCode(
                          maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
            }
            break;
          default:
          case BYTE:
          case SHORT:
          case INT:
          case CHAR:
            /* just the field */
            statements.append(createResultCalculation(typeNode, fieldAccessor));
            break;
        }
      } else if (fType instanceof JCArrayTypeTree) {
        /* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */
        boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
        boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
        boolean useDeepHC = multiDim || !primitiveArray;

        JCExpression hcMethod =
            chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode");
        statements.append(
            createResultCalculation(
                typeNode, maker.Apply(List.<JCExpression>nil(), hcMethod, List.of(fieldAccessor))));
      } else /* objects */ {
        /* final java.lang.Object $fieldName = this.fieldName; */
        /* $fieldName == null ? 0 : $fieldName.hashCode() */

        Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
        statements.append(
            maker.VarDef(
                maker.Modifiers(finalFlag),
                dollarFieldName,
                genJavaLangTypeRef(typeNode, "Object"),
                fieldAccessor));

        JCExpression hcCall =
            maker.Apply(
                List.<JCExpression>nil(),
                maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")),
                List.<JCExpression>nil());
        JCExpression thisEqualsNull =
            maker.Binary(CTC_EQUAL, maker.Ident(dollarFieldName), maker.Literal(CTC_BOT, null));
        statements.append(
            createResultCalculation(
                typeNode, maker.Conditional(thisEqualsNull, maker.Literal(0), hcCall)));
      }
    }

    /* return result; */ {
      statements.append(maker.Return(maker.Ident(resultName)));
    }

    JCBlock body = maker.Block(0, statements.toList());
    return recursiveSetGeneratedBy(
        maker.MethodDef(
            mods,
            typeNode.toName("hashCode"),
            returnType,
            List.<JCTypeParameter>nil(),
            List.<JCVariableDecl>nil(),
            List.<JCExpression>nil(),
            body,
            null),
        source,
        typeNode.getContext());
  }