示例#1
0
 private CodeBlock getInstanceCodeBlockWithPotentialCast(
     Element injectionSiteElement, Element bindingElement) {
   if (injectionSiteElement.equals(bindingElement)) {
     return CodeBlocks.format("instance");
   }
   TypeName injectionSiteName = TypeName.get(injectionSiteElement.asType());
   if (injectionSiteName instanceof ParameterizedTypeName) {
     injectionSiteName = ((ParameterizedTypeName) injectionSiteName).rawType;
   }
   return CodeBlocks.format("(($T) instance)", injectionSiteName);
 }
  private int processConstructor(ExecutableElement constrElt) {
    if (constrElt.getModifiers().contains(Modifier.PUBLIC)) {
      Element ownerElt = constrElt.getEnclosingElement();
      if (ownerElt.equals(modelElt)) {
        List<? extends VariableElement> parameters = constrElt.getParameters();
        int size = parameters.size();
        if (size == 1) {
          TypeInfo ti = typeFactory.create(parameters.get(0).asType());
          if (ti instanceof ClassTypeInfo) {
            ClassTypeInfo cl = (ClassTypeInfo) ti;
            if (cl.getKind() == ClassKind.JSON_OBJECT) {
              return 2;
            }
          }
        }
      }
    }

    return 0;
  }
  // TODO: handle != comparisons too!
  private boolean suppressInsideComparison(final BinaryTree node) {
    // Only handle == binary trees
    if (node.getKind() != Tree.Kind.EQUAL_TO) return false;

    Tree left = node.getLeftOperand();
    Tree right = node.getRightOperand();

    // Only valid if we're comparing identifiers.
    if (!(left.getKind() == Tree.Kind.IDENTIFIER && right.getKind() == Tree.Kind.IDENTIFIER))
      return false;

    // If we're not directly in an if statement in a method (ignoring
    // parens and blocks), terminate.
    // TODO: only if it's the first statement in the block
    if (!Heuristics.matchParents(getCurrentPath(), Tree.Kind.IF, Tree.Kind.METHOD)) return false;

    ExecutableElement enclosing = TreeUtils.elementFromDeclaration(visitorState.getMethodTree());
    assert enclosing != null;

    final Element lhs = TreeUtils.elementFromUse((IdentifierTree) left);
    final Element rhs = TreeUtils.elementFromUse((IdentifierTree) right);

    // Matcher to check for if statement that returns zero
    Heuristics.Matcher matcher =
        new Heuristics.Matcher() {

          @Override
          public Boolean visitIf(IfTree tree, Void p) {
            return visit(tree.getThenStatement(), p);
          }

          @Override
          public Boolean visitBlock(BlockTree tree, Void p) {
            if (tree.getStatements().size() > 0) return visit(tree.getStatements().get(0), p);
            return false;
          }

          @Override
          public Boolean visitReturn(ReturnTree tree, Void p) {
            ExpressionTree expr = tree.getExpression();
            return (expr != null
                && expr.getKind() == Tree.Kind.INT_LITERAL
                && ((LiteralTree) expr).getValue().equals(0));
          }
        };

    // Determine whether or not the "then" statement of the if has a single
    // "return 0" statement (for the Comparator.compare heuristic).
    if (overrides(enclosing, Comparator.class, "compare")) {
      final boolean returnsZero =
          Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcher))
              .match(getCurrentPath());

      if (!returnsZero) return false;

      assert enclosing.getParameters().size() == 2;
      Element p1 = enclosing.getParameters().get(0);
      Element p2 = enclosing.getParameters().get(1);
      return (p1.equals(lhs) && p2.equals(rhs)) || (p2.equals(lhs) && p1.equals(rhs));

    } else if (overrides(enclosing, Object.class, "equals")) {
      assert enclosing.getParameters().size() == 1;
      Element param = enclosing.getParameters().get(0);
      Element thisElt = getThis(trees.getScope(getCurrentPath()));
      assert thisElt != null;
      return (thisElt.equals(lhs) && param.equals(rhs))
          || (param.equals(lhs) && thisElt.equals(rhs));

    } else if (overrides(enclosing, Comparable.class, "compareTo")) {

      final boolean returnsZero =
          Heuristics.Matchers.withIn(Heuristics.Matchers.ofKind(Tree.Kind.IF, matcher))
              .match(getCurrentPath());

      if (!returnsZero) {
        return false;
      }

      assert enclosing.getParameters().size() == 1;
      Element param = enclosing.getParameters().get(0);
      Element thisElt = getThis(trees.getScope(getCurrentPath()));
      assert thisElt != null;
      return (thisElt.equals(lhs) && param.equals(rhs))
          || (param.equals(lhs) && thisElt.equals(rhs));
    }
    return false;
  }
  private void processMethod(
      String name,
      ExecutableElement getterElt,
      ExecutableElement setterElt,
      ExecutableElement adderElt) {

    PropertyKind propKind = null;
    TypeInfo propType = null;
    TypeMirror propTypeMirror = null;

    //
    if (setterElt != null) {
      VariableElement paramElt = setterElt.getParameters().get(0);
      propTypeMirror = paramElt.asType();
      propType = typeFactory.create(propTypeMirror);
      propKind = PropertyKind.forType(propType.getKind());
      switch (propKind) {
        case LIST:
        case SET:
          propType = ((ParameterizedTypeInfo) propType).getArgs().get(0);
          propTypeMirror = ((DeclaredType) propTypeMirror).getTypeArguments().get(0);
          break;
        case MAP:
          propType = ((ParameterizedTypeInfo) propType).getArgs().get(1);
          propTypeMirror = ((DeclaredType) propTypeMirror).getTypeArguments().get(1);
          break;
      }
    }

    //
    if (getterElt != null) {
      TypeMirror getterTypeMirror = getterElt.getReturnType();
      TypeInfo getterType = typeFactory.create(getterTypeMirror);
      PropertyKind getterKind = PropertyKind.forType(getterType.getKind());
      switch (getterKind) {
        case LIST:
        case SET:
          getterType = ((ParameterizedTypeInfo) getterType).getArgs().get(0);
          getterTypeMirror = ((DeclaredType) getterTypeMirror).getTypeArguments().get(0);
          break;
        case MAP:
          getterType = ((ParameterizedTypeInfo) getterType).getArgs().get(1);
          getterTypeMirror = ((DeclaredType) getterTypeMirror).getTypeArguments().get(1);
          break;
      }
      if (propType != null) {
        if (propKind != getterKind) {
          throw new GenException(
              getterElt, name + " getter " + getterKind + " does not match the setter " + propKind);
        }
        if (!getterType.equals(propType)) {
          throw new GenException(
              getterElt,
              name + " getter type " + getterType + " does not match the setter type " + propType);
        }
      } else {
        propTypeMirror = getterTypeMirror;
        propType = getterType;
        propKind = getterKind;
      }
    }

    //
    if (adderElt != null) {
      switch (adderElt.getParameters().size()) {
        case 1:
          {
            VariableElement paramElt = adderElt.getParameters().get(0);
            TypeMirror adderTypeMirror = paramElt.asType();
            TypeInfo adderType = typeFactory.create(adderTypeMirror);
            if (propTypeMirror != null) {
              if (propKind != PropertyKind.LIST && propKind != PropertyKind.SET) {
                throw new GenException(
                    adderElt, name + "adder does not correspond to non list/set");
              }
              if (!adderType.equals(propType)) {
                throw new GenException(
                    adderElt,
                    name
                        + " adder type "
                        + adderType
                        + "  does not match the property type "
                        + propType);
              }
            } else {
              propTypeMirror = adderTypeMirror;
              propType = adderType;
              propKind = PropertyKind.LIST;
            }
            break;
          }
        case 2:
          {
            VariableElement paramElt = adderElt.getParameters().get(1);
            TypeMirror adderTypeMirror = paramElt.asType();
            TypeInfo adderType = typeFactory.create(adderTypeMirror);
            if (propTypeMirror != null) {
              if (propKind != PropertyKind.MAP) {
                throw new GenException(adderElt, name + "adder does not correspond to non map");
              }
              if (!adderType.equals(propType)) {
                throw new GenException(
                    adderElt,
                    name
                        + " adder type "
                        + adderType
                        + "  does not match the property type "
                        + propType);
              }
            } else {
              propTypeMirror = adderTypeMirror;
              propType = adderType;
              propKind = PropertyKind.MAP;
            }
            break;
          }
      }
    }

    //
    boolean jsonifiable;
    switch (propType.getKind()) {
      case OBJECT:
        if (propKind == PropertyKind.VALUE) {
          return;
        }
      case PRIMITIVE:
      case BOXED_PRIMITIVE:
      case STRING:
      case API:
      case JSON_OBJECT:
      case JSON_ARRAY:
      case ENUM:
        jsonifiable = true;
        break;
      case DATA_OBJECT:
        Element propTypeElt = typeUtils.asElement(propTypeMirror);
        jsonifiable =
            propTypeElt.getAnnotation(DataObject.class) == null
                || Helper.isJsonifiable(elementUtils, typeUtils, (TypeElement) propTypeElt);
        break;
      default:
        return;
    }

    boolean declared = false;
    Doc doc = null;
    for (ExecutableElement methodElt : Arrays.asList(setterElt, adderElt, getterElt)) {
      if (methodElt != null) {

        // A stream that list all overriden methods from super types
        // the boolean control whether or not we want to filter only annotated
        // data objects
        Function<Boolean, Stream<ExecutableElement>> overridenMeths =
            (annotated) -> {
              Set<DeclaredType> ancestorTypes = Helper.resolveAncestorTypes(modelElt, true, true);
              return ancestorTypes
                  .stream()
                  .map(DeclaredType::asElement)
                  .filter(elt -> !annotated || elt.getAnnotation(DataObject.class) != null)
                  .flatMap(Helper.cast(TypeElement.class))
                  .flatMap(elt -> elementUtils.getAllMembers(elt).stream())
                  .flatMap(Helper.instanceOf(ExecutableElement.class))
                  .filter(
                      executableElt ->
                          executableElt.getKind() == ElementKind.METHOD
                              && elementUtils.overrides(methodElt, executableElt, modelElt));
            };

        //
        if (doc == null) {
          doc = docFactory.createDoc(methodElt);
          if (doc == null) {
            Optional<Doc> first =
                overridenMeths
                    .apply(false)
                    .map(docFactory::createDoc)
                    .filter(d -> d != null)
                    .findFirst();
            doc = first.orElse(null);
          }
        }

        //
        if (!declared) {
          Element ownerElt = methodElt.getEnclosingElement();
          if (ownerElt.equals(modelElt)) {
            Object[] arr =
                overridenMeths
                    .apply(true)
                    .limit(1)
                    .filter(elt -> !elt.getModifiers().contains(Modifier.ABSTRACT))
                    .toArray();
            // Handle the case where this methods overrides from another data object
            declared = arr.length == 0;
          } else {
            declared = ownerElt.getAnnotation(DataObject.class) == null;
          }
        }
      }
    }

    PropertyInfo property =
        new PropertyInfo(
            declared,
            name,
            doc,
            propType,
            setterElt != null ? setterElt.getSimpleName().toString() : null,
            adderElt != null ? adderElt.getSimpleName().toString() : null,
            getterElt != null ? getterElt.getSimpleName().toString() : null,
            propKind,
            jsonifiable);
    propertyMap.put(property.name, property);
  }