static JCExpression createFieldAccessor( TreeMaker maker, JavacNode field, FieldAccess fieldAccess, JCExpression receiver) { boolean lookForGetter = lookForGetter(field, fieldAccess); GetterMethod getter = lookForGetter ? findGetter(field) : null; JCVariableDecl fieldDecl = (JCVariableDecl) field.get(); if (getter == null) { if (receiver == null) { if ((fieldDecl.mods.flags & Flags.STATIC) == 0) { receiver = maker.Ident(field.toName("this")); } else { JavacNode containerNode = field.up(); if (containerNode != null && containerNode.get() instanceof JCClassDecl) { JCClassDecl container = (JCClassDecl) field.up().get(); receiver = maker.Ident(container.name); } } } return receiver == null ? maker.Ident(fieldDecl.name) : maker.Select(receiver, fieldDecl.name); } if (receiver == null) receiver = maker.Ident(field.toName("this")); JCMethodInvocation call = maker.Apply( List.<JCExpression>nil(), maker.Select(receiver, getter.name), List.<JCExpression>nil()); return call; }
@Override public boolean handle( AnnotationValues<Synchronized> annotation, JCAnnotation ast, Node annotationNode) { Node methodNode = annotationNode.up(); if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof JCMethodDecl)) { annotationNode.addError("@Synchronized is legal only on methods."); return true; } JCMethodDecl method = (JCMethodDecl) methodNode.get(); if ((method.mods.flags & Flags.ABSTRACT) != 0) { annotationNode.addError("@Synchronized is legal only on concrete methods."); return true; } boolean isStatic = (method.mods.flags & Flags.STATIC) != 0; String lockName = annotation.getInstance().value(); boolean autoMake = false; if (lockName.length() == 0) { autoMake = true; lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME; } TreeMaker maker = methodNode.getTreeMaker(); if (fieldExists(lockName, methodNode) == MemberExistsResult.NOT_EXISTS) { if (!autoMake) { annotationNode.addError("The field " + new String(lockName) + " does not exist."); return true; } JCExpression objectType = chainDots(maker, methodNode, "java", "lang", "Object"); // We use 'new Object[0];' because quite unlike 'new Object();', empty arrays *ARE* // serializable! JCNewArray newObjectArray = maker.NewArray( chainDots(maker, methodNode, "java", "lang", "Object"), List.<JCExpression>of(maker.Literal(TypeTags.INT, 0)), null); JCVariableDecl fieldDecl = maker.VarDef( maker.Modifiers(Flags.FINAL | (isStatic ? Flags.STATIC : 0)), methodNode.toName(lockName), objectType, newObjectArray); injectField(methodNode.up(), fieldDecl); } if (method.body == null) return false; JCExpression lockNode = maker.Ident(methodNode.toName(lockName)); method.body = maker.Block(0, List.<JCStatement>of(maker.Synchronized(lockNode, method.body))); methodNode.rebuild(); return true; }
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; } }
/** * In javac, dotted access of any kind, from {@code java.lang.String} to {@code var.methodName} is * represented by a fold-left of {@code Select} nodes with the leftmost string represented by a * {@code Ident} node. This method generates such an expression. * * <p>The position of the generated node(s) will be equal to the {@code pos} parameter. * * <p>For example, maker.Select(maker.Select(maker.Ident(NAME[java]), NAME[lang]), NAME[String]). * * @see com.sun.tools.javac.tree.JCTree.JCIdent * @see com.sun.tools.javac.tree.JCTree.JCFieldAccess */ public static JCExpression chainDots(JavacNode node, int pos, String... elems) { assert elems != null; assert elems.length > 0; TreeMaker maker = node.getTreeMaker(); if (pos != -1) maker = maker.at(pos); JCExpression e = maker.Ident(node.toName(elems[0])); for (int i = 1; i < elems.length; i++) { e = maker.Select(e, node.toName(elems[i])); } return e; }
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; }
/** * Process a single compound annotation, returning its Attribute. Used from MemberEnter for * attaching the attributes to the annotated symbol. */ Attribute.Compound enterAnnotation(JCAnnotation a, Type expected, Env<AttrContext> env) { // The annotation might have had its type attributed (but not checked) // by attr.attribAnnotationTypes during MemberEnter, in which case we do not // need to do it again. Type at = (a.annotationType.type != null ? a.annotationType.type : attr.attribType(a.annotationType, env)); a.type = chk.checkType(a.annotationType.pos(), at, expected); if (a.type.isErroneous()) return new Attribute.Compound(a.type, List.<Pair<MethodSymbol, Attribute>>nil()); if ((a.type.tsym.flags() & Flags.ANNOTATION) == 0) { log.error(a.annotationType.pos(), "not.annotation.type", a.type.toString()); return new Attribute.Compound(a.type, List.<Pair<MethodSymbol, Attribute>>nil()); } List<JCExpression> args = a.args; if (args.length() == 1 && args.head.getTag() != JCTree.ASSIGN) { // special case: elided "value=" assumed args.head = make.at(args.head.pos).Assign(make.Ident(names.value), args.head); } ListBuffer<Pair<MethodSymbol, Attribute>> buf = new ListBuffer<Pair<MethodSymbol, Attribute>>(); for (List<JCExpression> tl = args; tl.nonEmpty(); tl = tl.tail) { JCExpression t = tl.head; if (t.getTag() != JCTree.ASSIGN) { log.error(t.pos(), "annotation.value.must.be.name.value"); continue; } JCAssign assign = (JCAssign) t; if (assign.lhs.getTag() != JCTree.IDENT) { log.error(t.pos(), "annotation.value.must.be.name.value"); continue; } JCIdent left = (JCIdent) assign.lhs; Symbol method = rs.resolveQualifiedMethod(left.pos(), env, a.type, left.name, List.<Type>nil(), null); left.sym = method; left.type = method.type; if (method.owner != a.type.tsym) log.error(left.pos(), "no.annotation.member", left.name, a.type); Type result = method.type.getReturnType(); Attribute value = enterAttributeValue(result, assign.rhs, env); if (!method.type.isErroneous()) buf.append(new Pair<MethodSymbol, Attribute>((MethodSymbol) method, value)); t.type = result; } return new Attribute.Compound(a.type, buf.toList()); }
/** * Generates a new statement that checks if the given variable is null, and if so, throws a {@code * NullPointerException} with the variable name as message. */ public static JCStatement generateNullCheck(TreeMaker treeMaker, JavacNode variable) { JCVariableDecl varDecl = (JCVariableDecl) variable.get(); if (isPrimitive(varDecl.vartype)) return null; Name fieldName = varDecl.name; JCExpression npe = chainDots(variable, "java", "lang", "NullPointerException"); JCTree exception = treeMaker.NewClass( null, List.<JCExpression>nil(), npe, List.<JCExpression>of(treeMaker.Literal(fieldName.toString())), null); JCStatement throwStatement = treeMaker.Throw(exception); return treeMaker.If( treeMaker.Binary(CTC_EQUAL, treeMaker.Ident(fieldName), treeMaker.Literal(CTC_BOT, null)), throwStatement, null); }
private JCStatement buildTryCatchBlock( JavacNode node, List<JCStatement> contents, String exception) { TreeMaker maker = node.getTreeMaker(); JCBlock tryBlock = maker.Block(0, contents); JCExpression varType = chainDots(maker, node, exception.split("\\.")); JCVariableDecl catchParam = maker.VarDef(maker.Modifiers(Flags.FINAL), node.toName("$ex"), varType, null); JCExpression lombokLombokSneakyThrowNameRef = chainDots(maker, node, "lombok", "Lombok", "sneakyThrow"); JCBlock catchBody = maker.Block( 0, List.<JCStatement>of( maker.Throw( maker.Apply( List.<JCExpression>nil(), lombokLombokSneakyThrowNameRef, List.<JCExpression>of(maker.Ident(node.toName("$ex"))))))); return maker.Try(tryBlock, List.of(maker.Catch(catchParam, catchBody)), null); }