Ejemplo n.º 1
0
  /**
   * Given a list of field names and a node referring to a type, finds each name in the list that
   * does not match a field within the type.
   */
  public static List<Integer> createListOfNonExistentFields(
      List<String> list, JavacNode type, boolean excludeStandard, boolean excludeTransient) {
    boolean[] matched = new boolean[list.size()];

    for (JavacNode child : type.down()) {
      if (list.isEmpty()) break;
      if (child.getKind() != Kind.FIELD) continue;
      JCVariableDecl field = (JCVariableDecl) child.get();
      if (excludeStandard) {
        if ((field.mods.flags & Flags.STATIC) != 0) continue;
        if (field.name.toString().startsWith("$")) continue;
      }
      if (excludeTransient && (field.mods.flags & Flags.TRANSIENT) != 0) continue;

      int idx = list.indexOf(child.getName());
      if (idx > -1) matched[idx] = true;
    }

    ListBuffer<Integer> problematic = ListBuffer.lb();
    for (int i = 0; i < list.size(); i++) {
      if (!matched[i]) problematic.append(i);
    }

    return problematic.toList();
  }
 private ListBuffer<JCAnnotation> getAnnotations() {
   ListBuffer<JCAnnotation> result = ListBuffer.lb();
   if (!noAnnotations) {
     if (!ignoreAnnotations) {
       result.appendList(this.annotations);
     }
     if (isOverride) {
       result.appendList(gen.makeAtOverride());
     }
     if (ignoreAnnotations) {
       result.appendList(gen.makeAtIgnore());
     } else {
       if (resultTypeAnnos != null) {
         result.appendList(resultTypeAnnos);
       }
       if (!typeParamAnnotations.isEmpty()) {
         result.appendList(gen.makeAtTypeParameters(typeParamAnnotations.toList()));
       }
     }
   } else {
     // only those two are preserved
     if (isOverride) {
       result.appendList(gen.makeAtOverride());
     }
     if (ignoreAnnotations) {
       result.appendList(gen.makeAtIgnore());
     }
   }
   return result;
 }
 /** Returns a list of the expressions in the given list */
 public static List<JCExpression> toExpressionList(Iterable<ExpressionAndType> exprAndTypes) {
   ListBuffer<JCExpression> lb = ListBuffer.<JCExpression>lb();
   for (ExpressionAndType arg : exprAndTypes) {
     lb.append(arg.expression);
   }
   return lb.toList();
 }
Ejemplo n.º 4
0
 private static List<JCAnnotation> filterList(List<JCAnnotation> annotations, JCTree jcTree) {
   ListBuffer<JCAnnotation> newAnnotations = ListBuffer.lb();
   for (JCAnnotation ann : annotations) {
     if (jcTree != ann) newAnnotations.append(ann);
   }
   return newAnnotations.toList();
 }
  public JCTree.JCMethodDecl build() {
    if (built) {
      throw new IllegalStateException();
    }
    built = true;

    ListBuffer<JCVariableDecl> params = ListBuffer.lb();
    for (ParameterDefinitionBuilder pdb : this.params) {
      if (noAnnotations || ignoreAnnotations) {
        pdb.noAnnotations();
      }
      params.append(pdb.build());
    }

    return gen.make()
        .MethodDef(
            gen.make().Modifiers(modifiers, getAnnotations().toList()),
            makeName(name),
            resultTypeExpr,
            typeParams.toList(),
            params.toList(),
            List.<JCExpression>nil(),
            makeBody(body),
            null);
  }
Ejemplo n.º 6
0
 /**
  * * Get a localized string representation for all the symbols in the input list.
  *
  * @param ts symbols to be displayed
  * @param locale the locale in which the string is to be rendered
  * @return localized string representation
  */
 public String visitSymbols(List<Symbol> ts, Locale locale) {
   ListBuffer<String> sbuf = ListBuffer.lb();
   for (Symbol t : ts) {
     sbuf.append(visit(t, locale));
   }
   return sbuf.toList().toString();
 }
Ejemplo n.º 7
0
 /**
  * Get a localized string representation for all the types in the input list.
  *
  * @param ts types to be displayed
  * @param locale the locale in which the string is to be rendered
  * @return localized string representation
  */
 public String visitTypes(List<Type> ts, Locale locale) {
   ListBuffer<String> sbuf = ListBuffer.lb();
   for (Type t : ts) {
     sbuf.append(visit(t, locale));
   }
   return sbuf.toList().toString();
 }
Ejemplo n.º 8
0
 private static List<JCTree> addAllButOne(List<JCTree> defs, int idx) {
   ListBuffer<JCTree> out = ListBuffer.lb();
   int i = 0;
   for (JCTree def : defs) {
     if (i++ != idx) out.append(def);
   }
   return out.toList();
 }
Ejemplo n.º 9
0
 static List<JCAnnotation> copyAnnotations(List<? extends JCExpression> in) {
   ListBuffer<JCAnnotation> out = ListBuffer.lb();
   for (JCExpression expr : in) {
     if (!(expr instanceof JCAnnotation)) continue;
     out.append((JCAnnotation) expr.clone());
   }
   return out.toList();
 }
Ejemplo n.º 10
0
  public static class Comments {
    public com.sun.tools.javac.util.ListBuffer<Comment> comments =
        com.sun.tools.javac.util.ListBuffer.lb();

    void add(Comment comment) {
      comments.append(comment);
    }
  }
Ejemplo n.º 11
0
 public <T extends JCTree> List<T> build(
     final java.util.List<? extends lombok.ast.Node<?>> nodes, final Class<T> extectedType) {
   if (nodes == null) return null;
   ListBuffer<T> list = ListBuffer.lb();
   for (lombok.ast.Node<?> node : nodes) {
     list.append(build(node, extectedType));
   }
   return list.toList();
 }
Ejemplo n.º 12
0
 @Override
 public JCTree visitAnnotation(final lombok.ast.Annotation node, final Void p) {
   final ListBuffer<JCExpression> args = ListBuffer.lb();
   for (Entry<String, lombok.ast.Expression<?>> entry : node.getValues().entrySet()) {
     args.append(build(Assign(Name(entry.getKey()), entry.getValue()), JCExpression.class));
   }
   final JCAnnotation annotation =
       setGeneratedBy(M(node).Annotation(build(node.getType()), args.toList()), source);
   return annotation;
 }
Ejemplo n.º 13
0
  private static JCExpression cloneType0(TreeMaker maker, JCTree in) {
    if (in == null) return null;

    if (in instanceof JCPrimitiveTypeTree) return (JCExpression) in;

    if (in instanceof JCIdent) {
      return maker.Ident(((JCIdent) in).name);
    }

    if (in instanceof JCFieldAccess) {
      JCFieldAccess fa = (JCFieldAccess) in;
      return maker.Select(cloneType0(maker, fa.selected), fa.name);
    }

    if (in instanceof JCArrayTypeTree) {
      JCArrayTypeTree att = (JCArrayTypeTree) in;
      return maker.TypeArray(cloneType0(maker, att.elemtype));
    }

    if (in instanceof JCTypeApply) {
      JCTypeApply ta = (JCTypeApply) in;
      ListBuffer<JCExpression> lb = ListBuffer.lb();
      for (JCExpression typeArg : ta.arguments) {
        lb.append(cloneType0(maker, typeArg));
      }
      return maker.TypeApply(cloneType0(maker, ta.clazz), lb.toList());
    }

    if (in instanceof JCWildcard) {
      JCWildcard w = (JCWildcard) in;
      JCExpression newInner = cloneType0(maker, w.inner);
      TypeBoundKind newKind;
      switch (w.getKind()) {
        case SUPER_WILDCARD:
          newKind = maker.TypeBoundKind(BoundKind.SUPER);
          break;
        case EXTENDS_WILDCARD:
          newKind = maker.TypeBoundKind(BoundKind.EXTENDS);
          break;
        default:
        case UNBOUNDED_WILDCARD:
          newKind = maker.TypeBoundKind(BoundKind.UNBOUND);
          break;
      }
      return maker.Wildcard(newKind, newInner);
    }

    // This is somewhat unsafe, but it's better than outright throwing an exception here. Returning
    // null will just cause an exception down the pipeline.
    return (JCExpression) in;
  }
Ejemplo n.º 14
0
 /**
  * Searches the given field node for annotations and returns each one that matches the provided
  * regular expression pattern.
  *
  * <p>Only the simple name is checked - the package and any containing class are ignored.
  */
 public static List<JCAnnotation> findAnnotations(JavacNode fieldNode, Pattern namePattern) {
   ListBuffer<JCAnnotation> result = ListBuffer.lb();
   for (JavacNode child : fieldNode.down()) {
     if (child.getKind() == Kind.ANNOTATION) {
       JCAnnotation annotation = (JCAnnotation) child.get();
       String name = annotation.annotationType.toString();
       int idx = name.lastIndexOf(".");
       String suspect = idx == -1 ? name : name.substring(idx + 1);
       if (namePattern.matcher(suspect).matches()) {
         result.append(annotation);
       }
     }
   }
   return result.toList();
 }
Ejemplo n.º 15
0
  public static void deleteImportFromCompilationUnit(JavacNode node, String name) {
    if (inNetbeansEditor(node)) return;
    if (!node.shouldDeleteLombokAnnotations()) return;
    ListBuffer<JCTree> newDefs = ListBuffer.lb();

    JCCompilationUnit unit = (JCCompilationUnit) node.top().get();

    for (JCTree def : unit.defs) {
      boolean delete = false;
      if (def instanceof JCImport) {
        JCImport imp0rt = (JCImport) def;
        delete = (!imp0rt.staticImport && imp0rt.qualid.toString().equals(name));
      }
      if (!delete) newDefs.append(def);
    }
    unit.defs = newDefs.toList();
  }
Ejemplo n.º 16
0
 @Override
 public JCTree visitNewArray(final lombok.ast.NewArray node, final Void p) {
   final ListBuffer<JCExpression> dims = ListBuffer.lb();
   dims.appendList(build(node.getDimensionExpressions(), JCExpression.class));
   final JCExpression elemtype = build(node.getType());
   final List<JCExpression> initializerExpressions =
       build(node.getInitializerExpressions(), JCExpression.class);
   JCNewArray newClass =
       setGeneratedBy(
           M(node)
               .NewArray(
                   elemtype,
                   dims.toList(),
                   initializerExpressions.isEmpty() ? null : initializerExpressions),
           source);
   return newClass;
 }
 /**
  * Generates the class and returns the generated tree.
  *
  * @return the generated class tree, to be added to the appropriate {@link
  *     JCTree.JCCompilationUnit}.
  */
 public List<JCTree> build() {
   ListBuffer<JCTree> defs = ListBuffer.lb();
   appendDefinitionsTo(defs);
   if (javaClassName != null) {
     ClassDefinitionBuilder classBuilder =
         ClassDefinitionBuilder.klass(owner, javaClassName, null)
             .modifiers(Flags.FINAL | (modifiers & (Flags.PUBLIC | Flags.PRIVATE)))
             .constructorModifiers(Flags.PRIVATE)
             .annotations(owner.makeAtAttribute())
             .annotations(annotations.toList())
             .defs(defs.toList());
     if (valueConstructor && hasField) generateValueConstructor(classBuilder.addConstructor());
     return classBuilder.build();
   } else {
     return defs.toList();
   }
 }
Ejemplo n.º 18
0
 public static JCExpression cloneSelfType(JavacNode field) {
   JavacNode typeNode = field;
   TreeMaker maker = field.getTreeMaker();
   while (typeNode != null && typeNode.getKind() != Kind.TYPE) typeNode = typeNode.up();
   if (typeNode != null && typeNode.get() instanceof JCClassDecl) {
     JCClassDecl type = (JCClassDecl) typeNode.get();
     ListBuffer<JCExpression> typeArgs = ListBuffer.lb();
     if (!type.typarams.isEmpty()) {
       for (JCTypeParameter tp : type.typarams) {
         typeArgs.append(maker.Ident(tp.name));
       }
       return maker.TypeApply(maker.Ident(type.name), typeArgs.toList());
     } else {
       return maker.Ident(type.name);
     }
   } else {
     return null;
   }
 }
Ejemplo n.º 19
0
 @Override
 public JCTree visitTry(final lombok.ast.Try node, final Void p) {
   final ListBuffer<JCCatch> catchers = ListBuffer.lb();
   final Iterator<lombok.ast.Argument> iter = node.getCatchArguments().iterator();
   for (lombok.ast.Block catchBlock : node.getCatchBlocks()) {
     lombok.ast.Argument catchArgument = iter.next();
     catchers.append(
         M(node)
             .Catch(build(catchArgument, JCVariableDecl.class), build(catchBlock, JCBlock.class)));
   }
   final JCTry tryStatement =
       setGeneratedBy(
           M(node)
               .Try(
                   build(node.getTryBlock(), JCBlock.class),
                   catchers.toList(),
                   build(node.getFinallyBlock(), JCBlock.class)),
           source);
   return tryStatement;
 }
Ejemplo n.º 20
0
 @Override
 public JCTree visitClassDecl(final lombok.ast.ClassDecl node, final Void p) {
   final JCModifiers mods =
       setGeneratedBy(
           M(node)
               .Modifiers(
                   flagsFor(node.getModifiers()),
                   build(node.getAnnotations(), JCAnnotation.class)),
           source);
   if (node.isInterface()) mods.flags |= Flags.INTERFACE;
   final ListBuffer<JCTree> defs = ListBuffer.lb();
   defs.appendList(build(node.getFields()));
   defs.appendList(build(node.getMethods()));
   defs.appendList(build(node.getMemberTypes()));
   final List<JCTypeParameter> typarams = build(node.getTypeParameters());
   final JCExpression extending = build(node.getSuperclass());
   final List<JCExpression> implementing = build(node.getSuperInterfaces());
   final JCClassDecl classDecl =
       setGeneratedBy(
           createClassDef(
               node, mods, name(node.getName()), typarams, extending, implementing, defs.toList()),
           source);
   return classDecl;
 }
/**
 * Builder for Java Methods. With special pre-definied builders for normal methods, constructors,
 * getters and setters.
 *
 * @author Tako Schotanus
 */
public class MethodDefinitionBuilder {
  private final AbstractTransformer gen;

  private final String name;

  private long modifiers;

  private boolean isOverride;
  private boolean isAbstract;

  private JCExpression resultTypeExpr;
  private List<JCAnnotation> resultTypeAnnos;

  private final ListBuffer<JCAnnotation> annotations = ListBuffer.lb();

  private final ListBuffer<JCTypeParameter> typeParams = ListBuffer.lb();
  private final ListBuffer<JCExpression> typeParamAnnotations = ListBuffer.lb();

  private final ListBuffer<ParameterDefinitionBuilder> params = ListBuffer.lb();

  private ListBuffer<JCStatement> body = ListBuffer.lb();

  private boolean ignoreAnnotations;

  private boolean noAnnotations = false;

  private boolean built = false;

  public static MethodDefinitionBuilder method(
      AbstractTransformer gen, boolean isMember, String name) {
    return new MethodDefinitionBuilder(
        gen, false, isMember ? Naming.getErasedMethodName(name) : Naming.getMethodName(name));
  }

  public static MethodDefinitionBuilder method2(AbstractTransformer gen, String name) {
    return new MethodDefinitionBuilder(gen, false, name);
  }

  public static MethodDefinitionBuilder callable(AbstractTransformer gen) {
    return systemMethod(gen, "$call");
  }

  public static MethodDefinitionBuilder systemMethod(AbstractTransformer gen, String name) {
    MethodDefinitionBuilder builder = new MethodDefinitionBuilder(gen, true, name);
    return builder;
  }

  public static MethodDefinitionBuilder constructor(AbstractTransformer gen) {
    return new MethodDefinitionBuilder(gen, false, null);
  }

  public static MethodDefinitionBuilder main(AbstractTransformer gen) {
    MethodDefinitionBuilder mdb =
        new MethodDefinitionBuilder(gen, false, "main").modifiers(PUBLIC | STATIC);
    ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.instance(mdb.gen, "args");
    pdb.type(
        gen.make().TypeArray(gen.make().Type(gen.syms().stringType)), List.<JCAnnotation>nil());
    return mdb.parameter(pdb);
  }

  private MethodDefinitionBuilder(AbstractTransformer gen, boolean ignoreAnnotations, String name) {
    this.gen = gen;
    this.name = name;
    this.ignoreAnnotations = ignoreAnnotations;
    resultTypeExpr = makeVoidType();
  }

  private ListBuffer<JCAnnotation> getAnnotations() {
    ListBuffer<JCAnnotation> result = ListBuffer.lb();
    if (!noAnnotations) {
      if (!ignoreAnnotations) {
        result.appendList(this.annotations);
      }
      if (isOverride) {
        result.appendList(gen.makeAtOverride());
      }
      if (ignoreAnnotations) {
        result.appendList(gen.makeAtIgnore());
      } else {
        if (resultTypeAnnos != null) {
          result.appendList(resultTypeAnnos);
        }
        if (!typeParamAnnotations.isEmpty()) {
          result.appendList(gen.makeAtTypeParameters(typeParamAnnotations.toList()));
        }
      }
    } else {
      // only those two are preserved
      if (isOverride) {
        result.appendList(gen.makeAtOverride());
      }
      if (ignoreAnnotations) {
        result.appendList(gen.makeAtIgnore());
      }
    }
    return result;
  }

  public JCTree.JCMethodDecl build() {
    if (built) {
      throw new IllegalStateException();
    }
    built = true;

    ListBuffer<JCVariableDecl> params = ListBuffer.lb();
    for (ParameterDefinitionBuilder pdb : this.params) {
      if (noAnnotations || ignoreAnnotations) {
        pdb.noAnnotations();
      }
      params.append(pdb.build());
    }

    return gen.make()
        .MethodDef(
            gen.make().Modifiers(modifiers, getAnnotations().toList()),
            makeName(name),
            resultTypeExpr,
            typeParams.toList(),
            params.toList(),
            List.<JCExpression>nil(),
            makeBody(body),
            null);
  }

  private Name makeName(String name) {
    if (name != null) {
      return gen.names().fromString(name);
    } else {
      return gen.names().init;
    }
  }

  private JCBlock makeBody(ListBuffer<JCStatement> body2) {
    return (!isAbstract && (body != null) && ((modifiers & ABSTRACT) == 0))
        ? gen.make().Block(0, body.toList())
        : null;
  }

  JCExpression makeVoidType() {
    return gen.make().TypeIdent(VOID);
  }

  JCExpression makeResultType(TypedDeclaration typedDeclaration, ProducedType type, int flags) {
    if (typedDeclaration == null
        || (!(typedDeclaration instanceof FunctionalParameter) && gen.isVoid(type))) {
      if ((typedDeclaration instanceof Method)
          && ((Method) typedDeclaration).isDeclaredVoid()
          && !Strategy.useBoxedVoid((Method) typedDeclaration)) {
        return makeVoidType();
      } else {
        return gen.makeJavaType(
            typedDeclaration, gen.typeFact().getVoidDeclaration().getType(), flags);
      }
    } else {
      return gen.makeJavaType(typedDeclaration, type, flags);
    }
  }

  /*
   * Builder methods - they transform the inner state before doing the final construction
   */

  public MethodDefinitionBuilder modifiers(long... modifiers) {
    long mods = 0;
    for (long mod : modifiers) {
      mods |= mod;
    }
    this.modifiers = mods;
    return this;
  }

  /** The class will be generated with the {@code @Ignore} annotation only */
  public MethodDefinitionBuilder ignoreAnnotations() {
    ignoreAnnotations = true;
    return this;
  }

  public MethodDefinitionBuilder noAnnotations() {
    return noAnnotations(true);
  }

  public MethodDefinitionBuilder noAnnotations(boolean noAnnotations) {
    this.noAnnotations = noAnnotations;
    return this;
  }

  public MethodDefinitionBuilder annotations(List<JCTree.JCAnnotation> annotations) {
    this.annotations.appendList(annotations);
    return this;
  }

  public MethodDefinitionBuilder typeParameter(TypeParameter param) {
    return typeParameter(gen.makeTypeParameter(param), gen.makeAtTypeParameter(param));
  }

  private MethodDefinitionBuilder typeParameter(JCTypeParameter tp, JCAnnotation tpAnno) {
    typeParams.append(tp);
    typeParamAnnotations.append(tpAnno);
    return this;
  }

  public MethodDefinitionBuilder parameters(List<ParameterDefinitionBuilder> pdbs) {
    params.appendList(pdbs);
    return this;
  }

  public MethodDefinitionBuilder parameter(ParameterDefinitionBuilder pdb) {
    params.append(pdb);
    return this;
  }

  public MethodDefinitionBuilder parameter(
      long modifiers,
      String name,
      TypedDeclaration decl,
      TypedDeclaration nonWideningDecl,
      ProducedType nonWideningType,
      int flags) {
    return parameter(modifiers, name, name, decl, nonWideningDecl, nonWideningType, flags);
  }

  private MethodDefinitionBuilder parameter(
      long modifiers,
      String name,
      String aliasedName,
      TypedDeclaration decl,
      TypedDeclaration nonWideningDecl,
      ProducedType nonWideningType,
      int flags) {
    ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.instance(gen, name);
    pdb.modifiers(modifiers);
    pdb.aliasName(aliasedName);
    pdb.sequenced(decl instanceof Parameter && ((Parameter) decl).isSequenced());
    pdb.defaulted(decl instanceof Parameter && ((Parameter) decl).isDefaulted());
    pdb.type(paramType(nonWideningDecl, nonWideningType, flags), gen.makeJavaTypeAnnotations(decl));
    return parameter(pdb);
  }

  private JCExpression paramType(
      TypedDeclaration nonWideningDecl, ProducedType nonWideningType, int flags) {
    if (gen.typeFact().isUnion(nonWideningType) || gen.typeFact().isIntersection(nonWideningType)) {
      final TypeDeclaration refinedTypeDecl =
          ((TypedDeclaration) CodegenUtil.getTopmostRefinedDeclaration(nonWideningDecl))
              .getType()
              .getDeclaration();
      if (refinedTypeDecl instanceof TypeParameter
          && !refinedTypeDecl.getSatisfiedTypes().isEmpty()) {
        nonWideningType = refinedTypeDecl.getSatisfiedTypes().get(0);
      }
    }
    JCExpression type = gen.makeJavaType(nonWideningDecl, nonWideningType, flags);
    return type;
  }

  public MethodDefinitionBuilder parameter(
      Parameter paramDecl, ProducedType paramType, int mods, int flags) {
    String name = paramDecl.getName();
    return parameter(mods, name, paramDecl, paramDecl, paramType, flags);
  }

  public MethodDefinitionBuilder parameter(Parameter param, int flags) {
    String paramName = param.getName();
    String aliasedName = paramName;
    MethodOrValue mov = CodegenUtil.findMethodOrValueForParam(param);
    int mods = 0;
    if (!(mov instanceof Value) || !mov.isVariable() || mov.isCaptured()) {
      mods |= FINAL;
    }
    if (mov instanceof Method || mov instanceof Value && mov.isVariable() && mov.isCaptured()) {
      aliasedName = Naming.getAliasedParameterName(param);
    }
    TypedDeclaration nonWideningDecl;
    ProducedType nonWideningType;
    if (mov instanceof Value) {
      ProducedTypedReference typedRef = gen.getTypedReference(mov);
      ProducedTypedReference nonWideningTypedRef = gen.nonWideningTypeDecl(typedRef);
      nonWideningType = gen.nonWideningType(typedRef, nonWideningTypedRef);
      nonWideningDecl = nonWideningTypedRef.getDeclaration();
    } else {
      nonWideningType = param.getType();
      nonWideningDecl = param;
    }
    return parameter(mods, paramName, aliasedName, param, nonWideningDecl, nonWideningType, flags);
  }

  public MethodDefinitionBuilder isOverride(boolean isOverride) {
    this.isOverride = isOverride;
    return this;
  }

  public MethodDefinitionBuilder isAbstract(boolean isAbstract) {
    this.isAbstract = isAbstract;
    return this;
  }

  public MethodDefinitionBuilder body(JCStatement statement) {
    if (statement != null) {
      this.body.append(statement);
    }
    return this;
  }

  public MethodDefinitionBuilder body(List<JCStatement> body) {
    if (body != null) {
      this.body.appendList(body);
    }
    return this;
  }

  MethodDefinitionBuilder noBody() {
    this.body = null;
    return this;
  }

  public MethodDefinitionBuilder block(JCBlock block) {
    if (block != null) {
      body.clear();
      return body(block.getStatements());
    } else {
      return noBody();
    }
  }

  public MethodDefinitionBuilder resultType(Method method, int flags) {
    if (Decl.isMpl(method)) {
      // Create a String with the TypeInfo
      StringBuilder sb = new StringBuilder();
      // It's a bunch of nested callables (# of param lists - 1)
      for (int i = 1; i < method.getParameterLists().size(); i++) {
        sb.append("ceylon.language::Callable<");
      }
      // Then the return type as defined originally
      sb.append(method.getType().getProducedTypeQualifiedName());
      // And then the parameter types of each nested callable
      for (int i = method.getParameterLists().size() - 1; i > 0; i--) {
        ParameterList plist = method.getParameterLists().get(i);
        for (Parameter p : plist.getParameters()) {
          sb.append(',');
          sb.append(p.getType().getProducedTypeQualifiedName());
        }
        sb.append('>');
      }
      return resultType(
          gen.makeAtType(sb.toString(), false),
          gen.makeJavaType(gen.functionalReturnType(method), flags));
    } else {
      ProducedTypedReference typedRef = gen.getTypedReference(method);
      ProducedTypedReference nonWideningTypedRef = gen.nonWideningTypeDecl(typedRef);
      ProducedType nonWideningType = gen.nonWideningType(typedRef, nonWideningTypedRef);
      return resultType(
          makeResultType(nonWideningTypedRef.getDeclaration(), nonWideningType, flags), method);
    }
  }

  public MethodDefinitionBuilder resultTypeNonWidening(
      ProducedTypedReference typedRef, ProducedType returnType, int flags) {
    ProducedTypedReference nonWideningTypedRef = gen.nonWideningTypeDecl(typedRef);
    returnType = gen.nonWideningType(typedRef, nonWideningTypedRef);
    return resultType(
        makeResultType(nonWideningTypedRef.getDeclaration(), returnType, flags),
        typedRef.getDeclaration());
  }

  public MethodDefinitionBuilder resultType(
      TypedDeclaration resultType, ProducedType type, int flags) {
    return resultType(makeResultType(resultType, type, flags), resultType);
  }

  public MethodDefinitionBuilder resultType(JCExpression resultType, TypedDeclaration typeDecl) {
    return resultType(gen.makeJavaTypeAnnotations(typeDecl), resultType);
  }

  public MethodDefinitionBuilder resultType(
      List<JCAnnotation> resultTypeAnnos, JCExpression resultType) {
    this.resultTypeAnnos = resultTypeAnnos;
    this.resultTypeExpr = resultType;
    return this;
  }

  public MethodDefinitionBuilder modelAnnotations(java.util.List<Annotation> annotations) {
    annotations(gen.makeAtAnnotations(annotations));
    return this;
  }

  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append(getAnnotations()).append(' ');
    sb.append(Flags.toString(this.modifiers)).append(' ');
    sb.append(resultTypeExpr).append(' ');
    sb.append(name).append('(');
    int i = 0;
    for (ParameterDefinitionBuilder param : params) {
      sb.append(param);
      if (i < params.count - 1) {
        sb.append(',');
      }
    }
    sb.append(')');
    return sb.toString();
  }
}
Ejemplo n.º 22
0
  static List<JCAnnotation> unboxAndRemoveAnnotationParameter(
      JCAnnotation ast, String parameterName, String errorName, JavacNode errorNode) {
    ListBuffer<JCExpression> params = ListBuffer.lb();
    ListBuffer<JCAnnotation> result = ListBuffer.lb();

    errorNode.removeDeferredErrors();

    outer:
    for (JCExpression param : ast.args) {
      String nameOfParam = "value";
      JCExpression valueOfParam = null;
      if (param instanceof JCAssign) {
        JCAssign assign = (JCAssign) param;
        if (assign.lhs instanceof JCIdent) {
          JCIdent ident = (JCIdent) assign.lhs;
          nameOfParam = ident.name.toString();
        }
        valueOfParam = assign.rhs;
      }

      if (!parameterName.equals(nameOfParam)) {
        params.append(param);
        continue outer;
      }

      if (valueOfParam instanceof JCAnnotation) {
        String dummyAnnotationName = ((JCAnnotation) valueOfParam).annotationType.toString();
        dummyAnnotationName = dummyAnnotationName.replace("_", "");
        if (dummyAnnotationName.length() > 0) {
          errorNode.addError(
              "The correct format is "
                  + errorName
                  + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
          continue outer;
        }
        for (JCExpression expr : ((JCAnnotation) valueOfParam).args) {
          if (expr instanceof JCAssign && ((JCAssign) expr).lhs instanceof JCIdent) {
            JCIdent id = (JCIdent) ((JCAssign) expr).lhs;
            if ("value".equals(id.name.toString())) {
              expr = ((JCAssign) expr).rhs;
            } else {
              errorNode.addError(
                  "The correct format is "
                      + errorName
                      + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
              continue outer;
            }
          }

          if (expr instanceof JCAnnotation) {
            result.append((JCAnnotation) expr);
          } else if (expr instanceof JCNewArray) {
            for (JCExpression expr2 : ((JCNewArray) expr).elems) {
              if (expr2 instanceof JCAnnotation) {
                result.append((JCAnnotation) expr2);
              } else {
                errorNode.addError(
                    "The correct format is "
                        + errorName
                        + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
                continue outer;
              }
            }
          } else {
            errorNode.addError(
                "The correct format is "
                    + errorName
                    + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
            continue outer;
          }
        }
      } else {
        if (valueOfParam instanceof JCNewArray && ((JCNewArray) valueOfParam).elems.isEmpty()) {
          // Then we just remove it and move on (it's onMethod={} for example).
        } else {
          errorNode.addError(
              "The correct format is "
                  + errorName
                  + "@_({@SomeAnnotation, @SomeOtherAnnotation}))");
        }
      }
    }
    ast.args = params.toList();
    return result.toList();
  }
/**
 * Builds a class for global variables. See {@link GlobalTransformer} for an overview.
 *
 * <p>The generated class can be customized by calling methods of this class.
 */
public class AttributeDefinitionBuilder {
  private boolean hasField = true;
  private final String fieldName;

  private final JCTree.JCExpression attrType;
  private final JCTree.JCExpression attrTypeRaw;
  private final String attrName;
  private String javaClassName;

  private long modifiers;

  private final ListBuffer<JCTree.JCAnnotation> annotations = ListBuffer.lb();

  private boolean readable = true;
  private final MethodDefinitionBuilder getterBuilder;

  private JCTree.JCExpression variableInit;

  private boolean writable = true;
  private final MethodDefinitionBuilder setterBuilder;

  private AbstractTransformer owner;

  private boolean toplevel = false;

  private boolean noAnnotations = false;

  // do we need a constructor that takes the initial value?
  private boolean valueConstructor;

  private AttributeDefinitionBuilder(
      AbstractTransformer owner,
      TypedDeclaration attrType,
      String javaClassName,
      String attrName,
      String fieldName,
      boolean toplevel) {
    int typeFlags = 0;
    ProducedTypedReference typedRef = owner.getTypedReference(attrType);
    ProducedTypedReference nonWideningTypedRef = owner.nonWideningTypeDecl(typedRef);
    ProducedType nonWideningType = owner.nonWideningType(typedRef, nonWideningTypedRef);
    if (!CodegenUtil.isUnBoxed(nonWideningTypedRef.getDeclaration())) {
      typeFlags |= AbstractTransformer.JT_NO_PRIMITIVES;
    }

    this.attrType = owner.makeJavaType(nonWideningType, typeFlags);
    this.attrTypeRaw = owner.makeJavaType(nonWideningType, AbstractTransformer.JT_RAW);
    this.owner = owner;
    this.javaClassName = javaClassName;
    this.attrName = attrName;
    this.fieldName = fieldName;
    this.toplevel = toplevel;

    // Make sure we use the declaration for building the getter/setter names, as we might be trying
    // to
    // override a JavaBean property with an "isFoo" getter, or non-Ceylon casing, and we have to
    // respect that.
    getterBuilder =
        MethodDefinitionBuilder.method2(owner, Naming.getGetterName(attrType))
            .block(generateDefaultGetterBlock())
            .isOverride(attrType.isActual())
            .annotations(owner.makeAtAnnotations(attrType.getAnnotations()))
            .resultType(this.attrType, attrType);
    setterBuilder =
        MethodDefinitionBuilder.method2(owner, Naming.getSetterName(attrType))
            .block(generateDefaultSetterBlock())
            // only actual if the superclass is also variable
            .isOverride(
                attrType.isActual()
                    && ((TypedDeclaration) attrType.getRefinedDeclaration()).isVariable())
            .parameter(
                Flags.FINAL,
                attrName,
                attrType,
                nonWideningTypedRef.getDeclaration(),
                nonWideningType,
                0);
  }

  public static AttributeDefinitionBuilder wrapped(
      AbstractTransformer owner,
      String javaClassName,
      String attrName,
      TypedDeclaration attrType,
      boolean toplevel) {
    return new AttributeDefinitionBuilder(
        owner, attrType, javaClassName, attrName, "value", toplevel);
  }

  public static AttributeDefinitionBuilder getter(
      AbstractTransformer owner, String attrAndFieldName, TypedDeclaration attrType) {
    return new AttributeDefinitionBuilder(
            owner, attrType, null, attrAndFieldName, attrAndFieldName, false)
        .skipField()
        .immutable();
  }

  public static AttributeDefinitionBuilder setter(
      AbstractTransformer owner, String attrAndFieldName, TypedDeclaration attrType) {
    return new AttributeDefinitionBuilder(
            owner, attrType, null, attrAndFieldName, attrAndFieldName, false)
        .skipField()
        .skipGetter();
  }

  /**
   * Generates the class and returns the generated tree.
   *
   * @return the generated class tree, to be added to the appropriate {@link
   *     JCTree.JCCompilationUnit}.
   */
  public List<JCTree> build() {
    ListBuffer<JCTree> defs = ListBuffer.lb();
    appendDefinitionsTo(defs);
    if (javaClassName != null) {
      ClassDefinitionBuilder classBuilder =
          ClassDefinitionBuilder.klass(owner, javaClassName, null)
              .modifiers(Flags.FINAL | (modifiers & (Flags.PUBLIC | Flags.PRIVATE)))
              .constructorModifiers(Flags.PRIVATE)
              .annotations(owner.makeAtAttribute())
              .annotations(annotations.toList())
              .defs(defs.toList());
      if (valueConstructor && hasField) generateValueConstructor(classBuilder.addConstructor());
      return classBuilder.build();
    } else {
      return defs.toList();
    }
  }

  /**
   * Appends to <tt>defs</tt> the definitions that would go into the class generated by {@link
   * #build()}
   *
   * @param defs a {@link ListBuffer} to which the definitions will be appended.
   */
  public void appendDefinitionsTo(ListBuffer<JCTree> defs) {
    if (hasField) {
      defs.append(generateField());
      if (variableInit != null) defs.append(generateFieldInit());
    }

    if (readable) {
      getterBuilder.modifiers(getGetSetModifiers());
      getterBuilder.noAnnotations(noAnnotations);
      defs.append(getterBuilder.build());
    }

    if (writable) {
      setterBuilder.modifiers(getGetSetModifiers());
      setterBuilder.noAnnotations(noAnnotations);
      defs.append(setterBuilder.build());
    }
  }

  private void generateValueConstructor(MethodDefinitionBuilder methodDefinitionBuilder) {
    ParameterDefinitionBuilder paramBuilder =
        ParameterDefinitionBuilder.instance(owner, fieldName).type(attrType, null);
    JCTree.JCAssign init =
        owner
            .make()
            .Assign(
                owner.makeQualIdent(owner.makeUnquotedIdent("this"), fieldName),
                owner.makeUnquotedIdent(fieldName));
    methodDefinitionBuilder.parameter(paramBuilder).body(owner.make().Exec(init));
  }

  private long getGetSetModifiers() {
    return modifiers & (Flags.PUBLIC | Flags.PRIVATE | Flags.ABSTRACT | Flags.FINAL | Flags.STATIC);
  }

  private JCTree generateField() {
    long flags = Flags.PRIVATE | (modifiers & Flags.STATIC);
    // only make it final if we have an init, otherwise we still have to initialise it
    if (!writable && (variableInit != null || valueConstructor)) {
      flags |= Flags.FINAL;
    }

    return owner
        .make()
        .VarDef(
            owner.make().Modifiers(flags),
            owner.names().fromString(Naming.quoteIfJavaKeyword(fieldName)),
            (toplevel) ? owner.make().TypeArray(attrType) : attrType,
            null);
  }

  private JCTree generateFieldInit() {
    long flags = (modifiers & Flags.STATIC);

    JCTree.JCExpression varInit = variableInit;
    if (toplevel) {
      varInit =
          owner
              .make()
              .NewArray(
                  attrTypeRaw,
                  List.<JCTree.JCExpression>nil(),
                  List.<JCTree.JCExpression>of(varInit));
    }
    JCTree.JCAssign init = owner.make().Assign(owner.makeUnquotedIdent(fieldName), varInit);
    return owner.make().Block(flags, List.<JCTree.JCStatement>of(owner.make().Exec(init)));
  }

  private JCTree.JCBlock generateDefaultGetterBlock() {
    JCTree.JCExpression returnExpr = owner.makeUnquotedIdent(fieldName);
    if (toplevel) {
      returnExpr = owner.make().Indexed(returnExpr, owner.make().Literal(0));
    }
    JCTree.JCBlock block =
        owner.make().Block(0L, List.<JCTree.JCStatement>of(owner.make().Return(returnExpr)));
    if (toplevel) {
      JCTree.JCThrow throwStmt =
          owner
              .make()
              .Throw(
                  owner.makeNewClass(
                      owner.makeIdent(owner.syms().ceylonRecursiveInitializationExceptionType),
                      null));
      JCTree.JCBlock catchBlock = owner.make().Block(0, List.<JCTree.JCStatement>of(throwStmt));
      JCVariableDecl excepType =
          owner.makeVar("ex", owner.make().Type(owner.syms().nullPointerExceptionType), null);
      JCTree.JCCatch catcher = owner.make().Catch(excepType, catchBlock);
      JCTree.JCTry tryExpr = owner.make().Try(block, List.<JCTree.JCCatch>of(catcher), null);
      block = owner.make().Block(0L, List.<JCTree.JCStatement>of(tryExpr));
    }
    return block;
  }

  public JCTree.JCBlock generateDefaultSetterBlock() {
    JCTree.JCExpression fld;
    if (fieldName.equals(attrName)) {
      fld = owner.makeSelect("this", fieldName);
    } else {
      fld = owner.makeUnquotedIdent(fieldName);
    }
    if (toplevel) {
      fld = owner.make().Indexed(fld, owner.make().Literal(0));
    }
    return owner
        .make()
        .Block(
            0L,
            List.<JCTree.JCStatement>of(
                owner.make().Exec(owner.make().Assign(fld, owner.makeUnquotedIdent(attrName)))));
  }

  public AttributeDefinitionBuilder modifiers(long... modifiers) {
    long mods = 0;
    for (long mod : modifiers) {
      mods |= mod;
    }
    this.modifiers = mods;
    return this;
  }

  public AttributeDefinitionBuilder is(long flag, boolean value) {
    if (value) {
      this.modifiers |= flag;
    } else {
      this.modifiers &= ~flag;
    }
    return this;
  }

  public AttributeDefinitionBuilder noAnnotations() {
    this.noAnnotations = true;
    return this;
  }

  public AttributeDefinitionBuilder annotations(List<JCTree.JCAnnotation> annotations) {
    this.annotations.appendList(annotations);
    return this;
  }

  public AttributeDefinitionBuilder isFormal(boolean isFormal) {
    getterBuilder.isAbstract(isFormal);
    setterBuilder.isAbstract(isFormal);
    return this;
  }

  /**
   * Causes no field to be generated.
   *
   * @return this instance for method chaining
   */
  public AttributeDefinitionBuilder skipField() {
    this.hasField = false;
    return this;
  }

  /**
   * Sets the code block to use for the generated getter. If no getter is generated the code block
   * will be silently ignored.
   *
   * @param getterBlock a code block
   * @return this instance for method chaining
   */
  public AttributeDefinitionBuilder getterBlock(JCTree.JCBlock getterBlock) {
    skipField();
    getterBuilder.block(getterBlock);
    return this;
  }

  /**
   * Causes no getter to be generated.
   *
   * @return this instance for method chaining
   */
  public AttributeDefinitionBuilder skipGetter() {
    this.readable = false;
    return this;
  }

  /**
   * Sets the code block to use for the generated setter. If no setter is generated the code block
   * will be silently ignored.
   *
   * @param setterBlock a code block
   * @return this instance for method chaining
   */
  public AttributeDefinitionBuilder setterBlock(JCTree.JCBlock setterBlock) {
    setterBuilder.block(setterBlock);
    return this;
  }

  /**
   * Causes the generated attribute to be immutable. The <tt>value</tt> field is declared
   * <tt>final</tt> and no setter is generated.
   *
   * @return this instance for method chaining
   */
  public AttributeDefinitionBuilder immutable() {
    this.writable = false;
    return this;
  }

  /**
   * The <tt>value</tt> field will be declared with the initial value given by the parameter
   *
   * @param initialValue the initial value of the global.
   * @return this instance for method chaining
   */
  public AttributeDefinitionBuilder initialValue(JCTree.JCExpression initialValue) {
    this.variableInit = initialValue;
    return this;
  }

  /**
   * Marks the getter/setter methods as not actual. In general <tt>actual</tt> is derived from the
   * model while creating this builder so it will be correct. You can only disable this computation.
   * Enabling <tt>actual</tt> would otherwise depend on the question of whether the getter is or not
   * actual which may be different for the setter if the refined decl is not variable so we'd need
   * two parameters.
   */
  public AttributeDefinitionBuilder notActual() {
    getterBuilder.isOverride(false);
    setterBuilder.isOverride(false);
    return this;
  }

  /** Produces a constructor that receives the initial value for this attribute. */
  public AttributeDefinitionBuilder valueConstructor() {
    valueConstructor = true;
    return this;
  }
}