< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java

Print this page

  33 import com.sun.tools.javac.code.Symbol.RecordComponent;
  34 import com.sun.tools.javac.comp.AttrContext;
  35 import com.sun.tools.javac.comp.Env;
  36 import com.sun.tools.javac.tree.JCTree.*;
  37 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
  38 import com.sun.tools.javac.util.*;
  39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  40 
  41 import static com.sun.tools.javac.code.Flags.*;
  42 import static com.sun.tools.javac.code.Kinds.Kind.*;
  43 import com.sun.tools.javac.code.Symbol.VarSymbol;
  44 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  45 import static com.sun.tools.javac.code.TypeTag.BOT;
  46 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  47 import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK;
  48 import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED;
  49 
  50 import javax.lang.model.element.ElementKind;
  51 import javax.tools.JavaFileObject;
  52 

  53 import java.util.function.Predicate;
  54 import java.util.function.ToIntFunction;
  55 
  56 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  57 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.RIGHT;
  58 
  59 /** Utility class containing inspector methods for trees.
  60  *
  61  *  <p><b>This is NOT part of any supported API.
  62  *  If you write code that depends on this, you do so at your own risk.
  63  *  This code and its internal interfaces are subject to change or
  64  *  deletion without notice.</b>
  65  */
  66 public class TreeInfo {
  67 
  68     public static List<JCExpression> args(JCTree t) {
  69         switch (t.getTag()) {
  70             case APPLY:
  71                 return ((JCMethodInvocation)t).args;
  72             case NEWCLASS:

  96         // the record flag is only set to the canonical constructor
  97         return isCanonicalConstructor(tree) && (((JCMethodDecl)tree).sym.flags_field & COMPACT_RECORD_CONSTRUCTOR) != 0;
  98     }
  99 
 100     public static boolean isReceiverParam(JCTree tree) {
 101         if (tree.hasTag(VARDEF)) {
 102             return ((JCVariableDecl)tree).nameexpr != null;
 103         } else {
 104             return false;
 105         }
 106     }
 107 
 108     /** Is there a constructor declaration in the given list of trees?
 109      */
 110     public static boolean hasConstructors(List<JCTree> trees) {
 111         for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
 112             if (isConstructor(l.head)) return true;
 113         return false;
 114     }
 115 
 116     /** Is there a constructor invocation in the given list of trees?
 117      */
 118     public static Name getConstructorInvocationName(List<? extends JCTree> trees, Names names) {
 119         for (JCTree tree : trees) {
 120             if (tree.hasTag(EXEC)) {
 121                 JCExpressionStatement stat = (JCExpressionStatement)tree;
 122                 if (stat.expr.hasTag(APPLY)) {
 123                     JCMethodInvocation apply = (JCMethodInvocation)stat.expr;
 124                     Name methName = TreeInfo.name(apply.meth);
 125                     if (methName == names._this ||
 126                         methName == names._super) {
 127                         return methName;
 128                     }
 129                 }
 130             }
 131         }
 132         return names.empty;
 133     }
 134 
 135     public static boolean isMultiCatch(JCCatch catchClause) {
 136         return catchClause.param.vartype.hasTag(TYPEUNION);
 137     }
 138 
 139     /** Is statement an initializer for a synthetic field?
 140      */
 141     public static boolean isSyntheticInit(JCTree stat) {
 142         if (stat.hasTag(EXEC)) {
 143             JCExpressionStatement exec = (JCExpressionStatement)stat;
 144             if (exec.expr.hasTag(ASSIGN)) {
 145                 JCAssign assign = (JCAssign)exec.expr;
 146                 if (assign.lhs.hasTag(SELECT)) {
 147                     JCFieldAccess select = (JCFieldAccess)assign.lhs;
 148                     if (select.sym != null &&
 149                         (select.sym.flags() & SYNTHETIC) != 0) {
 150                         Name selected = name(select.selected);
 151                         if (selected != null && selected == selected.table.names._this)
 152                             return true;
 153                     }
 154                 }
 155             }
 156         }
 157         return false;
 158     }
 159 
 160     /** If the expression is a method call, return the method name, null
 161      *  otherwise. */
 162     public static Name calledMethodName(JCTree tree) {
 163         if (tree.hasTag(EXEC)) {
 164             JCExpressionStatement exec = (JCExpressionStatement)tree;
 165             if (exec.expr.hasTag(APPLY)) {
 166                 Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
 167                 return mname;
 168             }
 169         }
 170         return null;
 171     }
 172 
 173     /** Is this a call to this or super?
 174      */
 175     public static boolean isSelfCall(JCTree tree) {
 176         Name name = calledMethodName(tree);
 177         if (name != null) {
 178             Names names = name.table.names;
 179             return name==names._this || name==names._super;
 180         } else {
 181             return false;
 182         }
 183     }
 184 
 185     /** Is this tree a 'this' identifier?
 186      */
 187     public static boolean isThisQualifier(JCTree tree) {
 188         switch (tree.getTag()) {
 189             case PARENS:
 190                 return isThisQualifier(skipParens(tree));
 191             case IDENT: {
 192                 JCIdent id = (JCIdent)tree;
 193                 return id.name == id.name.table.names._this;
 194             }
 195             default:
 196                 return false;
 197         }
 198     }
 199 
 200     /** Is this tree an identifier, possibly qualified by 'this'?
 201      */
 202     public static boolean isIdentOrThisDotIdent(JCTree tree) {
 203         switch (tree.getTag()) {
 204             case PARENS:

 221             return name==names._super;
 222         } else {
 223             return false;
 224         }
 225     }
 226 
 227     public static List<JCVariableDecl> recordFields(JCClassDecl tree) {
 228         return tree.defs.stream()
 229                 .filter(t -> t.hasTag(VARDEF))
 230                 .map(t -> (JCVariableDecl)t)
 231                 .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD)
 232                 .collect(List.collector());
 233     }
 234 
 235     public static List<Type> recordFieldTypes(JCClassDecl tree) {
 236         return recordFields(tree).stream()
 237                 .map(vd -> vd.type)
 238                 .collect(List.collector());
 239     }
 240 
 241     /** Is this a constructor whose first (non-synthetic) statement is not
 242      *  of the form this(...)?













 243      */
 244     public static boolean isInitialConstructor(JCTree tree) {
 245         JCMethodInvocation app = firstConstructorCall(tree);
 246         if (app == null) return false;
 247         Name meth = name(app.meth);
 248         return meth == null || meth != meth.table.names._this;
 249     }
 250 
 251     /** Return the first call in a constructor definition. */
 252     public static JCMethodInvocation firstConstructorCall(JCTree tree) {
 253         if (!tree.hasTag(METHODDEF)) return null;
 254         JCMethodDecl md = (JCMethodDecl) tree;
 255         Names names = md.name.table.names;
 256         if (md.name != names.init) return null;
 257         if (md.body == null) return null;
 258         List<JCStatement> stats = md.body.stats;
 259         // Synthetic initializations can appear before the super call.
 260         while (stats.nonEmpty() && isSyntheticInit(stats.head))
 261             stats = stats.tail;
 262         if (stats.isEmpty()) return null;
 263         if (!stats.head.hasTag(EXEC)) return null;
 264         JCExpressionStatement exec = (JCExpressionStatement) stats.head;
 265         if (!exec.expr.hasTag(APPLY)) return null;
 266         return (JCMethodInvocation)exec.expr;



























































 267     }
 268 
 269     /** Return true if a tree represents a diamond new expr. */
 270     public static boolean isDiamond(JCTree tree) {
 271         switch(tree.getTag()) {
 272             case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
 273             case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
 274             case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType);
 275             default: return false;
 276         }
 277     }
 278 
 279     public static boolean isEnumInit(JCTree tree) {
 280         switch (tree.getTag()) {
 281             case VARDEF:
 282                 return (((JCVariableDecl)tree).mods.flags & ENUM) != 0;
 283             default:
 284                 return false;
 285         }
 286     }

  33 import com.sun.tools.javac.code.Symbol.RecordComponent;
  34 import com.sun.tools.javac.comp.AttrContext;
  35 import com.sun.tools.javac.comp.Env;
  36 import com.sun.tools.javac.tree.JCTree.*;
  37 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
  38 import com.sun.tools.javac.util.*;
  39 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  40 
  41 import static com.sun.tools.javac.code.Flags.*;
  42 import static com.sun.tools.javac.code.Kinds.Kind.*;
  43 import com.sun.tools.javac.code.Symbol.VarSymbol;
  44 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  45 import static com.sun.tools.javac.code.TypeTag.BOT;
  46 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  47 import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK;
  48 import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED;
  49 
  50 import javax.lang.model.element.ElementKind;
  51 import javax.tools.JavaFileObject;
  52 
  53 import java.util.function.Function;
  54 import java.util.function.Predicate;
  55 import java.util.function.ToIntFunction;
  56 
  57 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  58 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.RIGHT;
  59 
  60 /** Utility class containing inspector methods for trees.
  61  *
  62  *  <p><b>This is NOT part of any supported API.
  63  *  If you write code that depends on this, you do so at your own risk.
  64  *  This code and its internal interfaces are subject to change or
  65  *  deletion without notice.</b>
  66  */
  67 public class TreeInfo {
  68 
  69     public static List<JCExpression> args(JCTree t) {
  70         switch (t.getTag()) {
  71             case APPLY:
  72                 return ((JCMethodInvocation)t).args;
  73             case NEWCLASS:

  97         // the record flag is only set to the canonical constructor
  98         return isCanonicalConstructor(tree) && (((JCMethodDecl)tree).sym.flags_field & COMPACT_RECORD_CONSTRUCTOR) != 0;
  99     }
 100 
 101     public static boolean isReceiverParam(JCTree tree) {
 102         if (tree.hasTag(VARDEF)) {
 103             return ((JCVariableDecl)tree).nameexpr != null;
 104         } else {
 105             return false;
 106         }
 107     }
 108 
 109     /** Is there a constructor declaration in the given list of trees?
 110      */
 111     public static boolean hasConstructors(List<JCTree> trees) {
 112         for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
 113             if (isConstructor(l.head)) return true;
 114         return false;
 115     }
 116 



















 117     public static boolean isMultiCatch(JCCatch catchClause) {
 118         return catchClause.param.vartype.hasTag(TYPEUNION);
 119     }
 120 
 121     /** Is statement an initializer for a synthetic field?
 122      */
 123     public static boolean isSyntheticInit(JCTree stat) {
 124         if (stat.hasTag(EXEC)) {
 125             JCExpressionStatement exec = (JCExpressionStatement)stat;
 126             if (exec.expr.hasTag(ASSIGN)) {
 127                 JCAssign assign = (JCAssign)exec.expr;
 128                 if (assign.lhs.hasTag(SELECT)) {
 129                     JCFieldAccess select = (JCFieldAccess)assign.lhs;
 130                     if (select.sym != null &&
 131                         (select.sym.flags() & SYNTHETIC) != 0) {
 132                         Name selected = name(select.selected);
 133                         if (selected != null && selected == selected.table.names._this)
 134                             return true;
 135                     }
 136                 }
 137             }
 138         }
 139         return false;
 140     }
 141 
 142     /** If the expression is a method call, return the method name, null
 143      *  otherwise. */
 144     public static Name calledMethodName(JCTree tree) {
 145         if (tree.hasTag(EXEC)) {
 146             JCExpressionStatement exec = (JCExpressionStatement)tree;
 147             if (exec.expr.hasTag(APPLY)) {
 148                 Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
 149                 return mname;
 150             }
 151         }
 152         return null;
 153     }
 154 












 155     /** Is this tree a 'this' identifier?
 156      */
 157     public static boolean isThisQualifier(JCTree tree) {
 158         switch (tree.getTag()) {
 159             case PARENS:
 160                 return isThisQualifier(skipParens(tree));
 161             case IDENT: {
 162                 JCIdent id = (JCIdent)tree;
 163                 return id.name == id.name.table.names._this;
 164             }
 165             default:
 166                 return false;
 167         }
 168     }
 169 
 170     /** Is this tree an identifier, possibly qualified by 'this'?
 171      */
 172     public static boolean isIdentOrThisDotIdent(JCTree tree) {
 173         switch (tree.getTag()) {
 174             case PARENS:

 191             return name==names._super;
 192         } else {
 193             return false;
 194         }
 195     }
 196 
 197     public static List<JCVariableDecl> recordFields(JCClassDecl tree) {
 198         return tree.defs.stream()
 199                 .filter(t -> t.hasTag(VARDEF))
 200                 .map(t -> (JCVariableDecl)t)
 201                 .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD)
 202                 .collect(List.collector());
 203     }
 204 
 205     public static List<Type> recordFieldTypes(JCClassDecl tree) {
 206         return recordFields(tree).stream()
 207                 .map(vd -> vd.type)
 208                 .collect(List.collector());
 209     }
 210 
 211     /** Is the given method a constructor containing a super() or this() call?
 212       */
 213     public static boolean hasAnyConstructorCall(JCMethodDecl tree) {
 214         return hasConstructorCall(tree, null);
 215     }
 216 
 217     /** Is the given method a constructor containing a super() and/or this() call?
 218       * The "target" is either names._this, names._super, or null for either/both.
 219       */
 220     public static boolean hasConstructorCall(JCMethodDecl tree, Name target) {
 221         JCMethodInvocation app = findConstructorCall(tree);
 222         return app != null && (target == null || target == name(app.meth));
 223     }
 224 
 225     /** Find the first super() or init() call in the given constructor.
 226      */
 227     public static JCMethodInvocation findConstructorCall(JCMethodDecl md) {
 228         if (!TreeInfo.isConstructor(md) || md.body == null)
 229             return null;
 230         return new ConstructorCallFinder(md.name.table.names).find(md).head;

 231     }
 232 
 233     /** Finds all calls to this() and/or super() in a given constructor.
 234      *  We can't assume they will be "top level" statements, because
 235      *  some synthetic calls to super() are added inside { } blocks.
 236      *  So we must recurse through the method's entire syntax tree.
 237      */
 238     private static class ConstructorCallFinder extends TreeScanner {
 239 
 240         final ListBuffer<JCMethodInvocation> calls = new ListBuffer<>();
 241         final Names names;
 242 
 243         ConstructorCallFinder(Names names) {
 244             this.names = names;
 245         }
 246 
 247         List<JCMethodInvocation> find(JCMethodDecl meth) {
 248             scan(meth);
 249             return calls.toList();
 250         }
 251 
 252         @Override
 253         public void visitApply(JCMethodInvocation invoke) {
 254             Name name = TreeInfo.name(invoke.meth);
 255             if ((name == names._this || name == names._super))
 256                 calls.append(invoke);
 257             super.visitApply(invoke);
 258         }
 259 
 260         @Override
 261         public void visitClassDef(JCClassDecl tree) {
 262             // don't descend any further
 263         }
 264 
 265         @Override
 266         public void visitLambda(JCLambda tree) {
 267             // don't descend any further
 268         }
 269     }
 270 
 271     /** Finds super() invocations and translates them using the given mapping.
 272      */
 273     public static void mapSuperCalls(JCBlock block, Function<? super JCExpressionStatement, ? extends JCStatement> mapper) {
 274         block.stats = block.stats.map(new TreeInfo.SuperCallTranslator(mapper)::translate);
 275     }
 276 
 277     /** Finds all super() invocations and translates them somehow.
 278      */
 279     private static class SuperCallTranslator extends TreeTranslator {
 280 
 281         final Function<? super JCExpressionStatement, ? extends JCStatement> translator;
 282 
 283         /** Constructor.
 284          *
 285          * @param translator translates super() invocations, returning replacement statement or null for no change
 286          */
 287         SuperCallTranslator(Function<? super JCExpressionStatement, ? extends JCStatement> translator) {
 288             this.translator = translator;
 289         }
 290 
 291         // Because it returns void, anywhere super() can legally appear must be a location where a JCStatement
 292         // could also appear, so it's OK that we are replacing a JCExpressionStatement with a JCStatement here.
 293         @Override
 294         public void visitExec(JCExpressionStatement stat) {
 295             if (!TreeInfo.isSuperCall(stat) || (result = this.translator.apply(stat)) == null)
 296                 super.visitExec(stat);
 297         }
 298 
 299         @Override
 300         public void visitClassDef(JCClassDecl tree) {
 301             // don't descend any further
 302         }
 303 
 304         @Override
 305         public void visitLambda(JCLambda tree) {
 306             // don't descend any further
 307         }
 308     }
 309 
 310     /** Return true if a tree represents a diamond new expr. */
 311     public static boolean isDiamond(JCTree tree) {
 312         switch(tree.getTag()) {
 313             case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
 314             case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
 315             case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType);
 316             default: return false;
 317         }
 318     }
 319 
 320     public static boolean isEnumInit(JCTree tree) {
 321         switch (tree.getTag()) {
 322             case VARDEF:
 323                 return (((JCVariableDecl)tree).mods.flags & ENUM) != 0;
 324             default:
 325                 return false;
 326         }
 327     }
< prev index next >