/** * 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(); }
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); }
/** * * 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(); }
/** * 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(); }
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(); }
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(); }
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); } }
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(); }
@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; }
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; }
/** * 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(); }
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(); }
@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(); } }
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; } }
@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; }
@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(); } }
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; } }