1 /*
   2  * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.tree;
  27 
  28 
  29 
  30 import com.sun.source.tree.Tree;
  31 import com.sun.source.util.TreePath;
  32 import com.sun.tools.javac.code.*;
  33 import com.sun.tools.javac.comp.AttrContext;
  34 import com.sun.tools.javac.comp.Env;
  35 import com.sun.tools.javac.tree.JCTree.*;
  36 import com.sun.tools.javac.tree.JCTree.JCPolyExpression.*;
  37 import com.sun.tools.javac.util.*;
  38 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  39 
  40 import static com.sun.tools.javac.code.Flags.*;
  41 import static com.sun.tools.javac.code.Kinds.Kind.*;
  42 import static com.sun.tools.javac.code.TypeTag.BOT;
  43 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  44 import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK;
  45 import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED;
  46 
  47 import javax.tools.JavaFileObject;
  48 
  49 import java.util.function.ToIntFunction;
  50 
  51 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  52 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.RIGHT;
  53 
  54 /** Utility class containing inspector methods for trees.
  55  *
  56  *  <p><b>This is NOT part of any supported API.
  57  *  If you write code that depends on this, you do so at your own risk.
  58  *  This code and its internal interfaces are subject to change or
  59  *  deletion without notice.</b>
  60  */
  61 public class TreeInfo {
  62 
  63     public static List<JCExpression> args(JCTree t) {
  64         switch (t.getTag()) {
  65             case APPLY:
  66                 return ((JCMethodInvocation)t).args;
  67             case NEWCLASS:
  68                 return ((JCNewClass)t).args;
  69             default:
  70                 return null;
  71         }
  72     }
  73 
  74     /** Is tree a constructor declaration?
  75      */
  76     public static boolean isConstructor(JCTree tree) {
  77         if (tree.hasTag(METHODDEF)) {
  78             Name name = ((JCMethodDecl) tree).name;
  79             return name == name.table.names.init;
  80         } else {
  81             return false;
  82         }
  83     }
  84 
  85     public static boolean isReceiverParam(JCTree tree) {
  86         if (tree.hasTag(VARDEF)) {
  87             return ((JCVariableDecl)tree).nameexpr != null;
  88         } else {
  89             return false;
  90         }
  91     }
  92 
  93     /** Is there a constructor declaration in the given list of trees?
  94      */
  95     public static boolean hasConstructors(List<JCTree> trees) {
  96         for (List<JCTree> l = trees; l.nonEmpty(); l = l.tail)
  97             if (isConstructor(l.head)) return true;
  98         return false;
  99     }
 100 
 101     /** Is there a constructor invocation in the given list of trees?
 102      */
 103     public static Name getConstructorInvocationName(List<? extends JCTree> trees, Names names, boolean isRecord) {
 104         for (JCTree tree : trees) {
 105             if (tree.hasTag(EXEC)) {
 106                 JCExpressionStatement stat = (JCExpressionStatement)tree;
 107                 if (stat.expr.hasTag(APPLY)) {
 108                     JCMethodInvocation apply = (JCMethodInvocation)stat.expr;
 109                     Name methName = TreeInfo.name(apply.meth);
 110                     if (methName == names._this ||
 111                         methName == names._super) {
 112                         return methName;
 113                     }
 114                 }
 115             }
 116         }
 117         return names.empty;
 118     }
 119 
 120     public static boolean isMultiCatch(JCCatch catchClause) {
 121         return catchClause.param.vartype.hasTag(TYPEUNION);
 122     }
 123 
 124     /** Is statement an initializer for a synthetic field?
 125      */
 126     public static boolean isSyntheticInit(JCTree stat) {
 127         if (stat.hasTag(EXEC)) {
 128             JCExpressionStatement exec = (JCExpressionStatement)stat;
 129             if (exec.expr.hasTag(ASSIGN)) {
 130                 JCAssign assign = (JCAssign)exec.expr;
 131                 if (assign.lhs.hasTag(SELECT)) {
 132                     JCFieldAccess select = (JCFieldAccess)assign.lhs;
 133                     if (select.sym != null &&
 134                         (select.sym.flags() & SYNTHETIC) != 0) {
 135                         Name selected = name(select.selected);
 136                         if (selected != null && selected == selected.table.names._this)
 137                             return true;
 138                     }
 139                 }
 140             }
 141         }
 142         return false;
 143     }
 144 
 145     /** If the expression is a method call, return the method name, null
 146      *  otherwise. */
 147     public static Name calledMethodName(JCTree tree) {
 148         if (tree.hasTag(EXEC)) {
 149             JCExpressionStatement exec = (JCExpressionStatement)tree;
 150             if (exec.expr.hasTag(APPLY)) {
 151                 Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth);
 152                 return mname;
 153             }
 154         }
 155         return null;
 156     }
 157 
 158     /** Is this a call to this or super?
 159      */
 160     public static boolean isSelfCall(JCTree tree) {
 161         Name name = calledMethodName(tree);
 162         if (name != null) {
 163             Names names = name.table.names;
 164             return name==names._this || name==names._super;
 165         } else {
 166             return false;
 167         }
 168     }
 169 
 170     /** Is this tree a 'this' identifier?
 171      */
 172     public static boolean isThisQualifier(JCTree tree) {
 173         switch (tree.getTag()) {
 174             case PARENS:
 175                 return isThisQualifier(skipParens(tree));
 176             case IDENT: {
 177                 JCIdent id = (JCIdent)tree;
 178                 return id.name == id.name.table.names._this;
 179             }
 180             default:
 181                 return false;
 182         }
 183     }
 184 
 185     /** Is this tree an identifier, possibly qualified by 'this'?
 186      */
 187     public static boolean isIdentOrThisDotIdent(JCTree tree) {
 188         switch (tree.getTag()) {
 189             case PARENS:
 190                 return isIdentOrThisDotIdent(skipParens(tree));
 191             case IDENT:
 192                 return true;
 193             case SELECT:
 194                 return isThisQualifier(((JCFieldAccess)tree).selected);
 195             default:
 196                 return false;
 197         }
 198     }
 199 
 200     /** Is this a call to super?
 201      */
 202     public static boolean isSuperCall(JCTree tree) {
 203         Name name = calledMethodName(tree);
 204         if (name != null) {
 205             Names names = name.table.names;
 206             return name==names._super;
 207         } else {
 208             return false;
 209         }
 210     }
 211 
 212     public static List<JCVariableDecl> recordFields(JCClassDecl tree) {
 213         return tree.defs.stream()
 214                 .filter(t -> t.hasTag(VARDEF))
 215                 .map(t -> (JCVariableDecl)t)
 216                 .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD)
 217                 .collect(List.collector());
 218     }
 219 
 220     public static List<Type> recordFieldTypes(JCClassDecl tree) {
 221         return tree.defs.stream()
 222                 .filter(t -> t.hasTag(VARDEF))
 223                 .map(t -> (JCVariableDecl)t)
 224                 .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD)
 225                 .map(vd -> vd.type)
 226                 .collect(List.collector());
 227     }
 228 
 229     /** Is this a constructor whose first (non-synthetic) statement is not
 230      *  of the form this(...)?
 231      */
 232     public static boolean isInitialConstructor(JCTree tree) {
 233         JCMethodInvocation app = firstConstructorCall(tree);
 234         if (app == null) return false;
 235         Name meth = name(app.meth);
 236         return meth == null || meth != meth.table.names._this;
 237     }
 238 
 239     /** Return the first call in a constructor definition. */
 240     public static JCMethodInvocation firstConstructorCall(JCTree tree) {
 241         if (!tree.hasTag(METHODDEF)) return null;
 242         JCMethodDecl md = (JCMethodDecl) tree;
 243         Names names = md.name.table.names;
 244         if (md.name != names.init) return null;
 245         if (md.body == null) return null;
 246         List<JCStatement> stats = md.body.stats;
 247         // Synthetic initializations can appear before the super call.
 248         while (stats.nonEmpty() && isSyntheticInit(stats.head))
 249             stats = stats.tail;
 250         if (stats.isEmpty()) return null;
 251         if (!stats.head.hasTag(EXEC)) return null;
 252         JCExpressionStatement exec = (JCExpressionStatement) stats.head;
 253         if (!exec.expr.hasTag(APPLY)) return null;
 254         return (JCMethodInvocation)exec.expr;
 255     }
 256 
 257     /** Return true if a tree represents a diamond new expr. */
 258     public static boolean isDiamond(JCTree tree) {
 259         switch(tree.getTag()) {
 260             case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty();
 261             case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz);
 262             case ANNOTATED_TYPE: return isDiamond(((JCAnnotatedType)tree).underlyingType);
 263             default: return false;
 264         }
 265     }
 266 
 267     public static boolean isEnumInit(JCTree tree) {
 268         switch (tree.getTag()) {
 269             case VARDEF:
 270                 return (((JCVariableDecl)tree).mods.flags & ENUM) != 0;
 271             default:
 272                 return false;
 273         }
 274     }
 275 
 276     /** set 'polyKind' on given tree */
 277     public static void setPolyKind(JCTree tree, PolyKind pkind) {
 278         switch (tree.getTag()) {
 279             case APPLY:
 280                 ((JCMethodInvocation)tree).polyKind = pkind;
 281                 break;
 282             case NEWCLASS:
 283                 ((JCNewClass)tree).polyKind = pkind;
 284                 break;
 285             case REFERENCE:
 286                 ((JCMemberReference)tree).refPolyKind = pkind;
 287                 break;
 288             default:
 289                 throw new AssertionError("Unexpected tree: " + tree);
 290         }
 291     }
 292 
 293     /** set 'varargsElement' on given tree */
 294     public static void setVarargsElement(JCTree tree, Type varargsElement) {
 295         switch (tree.getTag()) {
 296             case APPLY:
 297                 ((JCMethodInvocation)tree).varargsElement = varargsElement;
 298                 break;
 299             case NEWCLASS:
 300                 ((JCNewClass)tree).varargsElement = varargsElement;
 301                 break;
 302             case REFERENCE:
 303                 ((JCMemberReference)tree).varargsElement = varargsElement;
 304                 break;
 305             default:
 306                 throw new AssertionError("Unexpected tree: " + tree);
 307         }
 308     }
 309 
 310     /** Return true if the tree corresponds to an expression statement */
 311     public static boolean isExpressionStatement(JCExpression tree) {
 312         switch(tree.getTag()) {
 313             case PREINC: case PREDEC:
 314             case POSTINC: case POSTDEC:
 315             case ASSIGN:
 316             case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
 317             case SL_ASG: case SR_ASG: case USR_ASG:
 318             case PLUS_ASG: case MINUS_ASG:
 319             case MUL_ASG: case DIV_ASG: case MOD_ASG:
 320             case APPLY: case NEWCLASS:
 321             case ERRONEOUS:
 322                 return true;
 323             default:
 324                 return false;
 325         }
 326     }
 327 
 328     /** Return true if the tree corresponds to a statement */
 329     public static boolean isStatement(JCTree tree) {
 330         return (tree instanceof JCStatement) &&
 331                 !tree.hasTag(CLASSDEF) &&
 332                 !tree.hasTag(Tag.BLOCK) &&
 333                 !tree.hasTag(METHODDEF);
 334     }
 335 
 336     /**
 337      * Return true if the AST corresponds to a static select of the kind A.B
 338      */
 339     public static boolean isStaticSelector(JCTree base, Names names) {
 340         if (base == null)
 341             return false;
 342         switch (base.getTag()) {
 343             case IDENT:
 344                 JCIdent id = (JCIdent)base;
 345                 return id.name != names._this &&
 346                         id.name != names._super &&
 347                         isStaticSym(base);
 348             case SELECT:
 349                 return isStaticSym(base) &&
 350                     isStaticSelector(((JCFieldAccess)base).selected, names);
 351             case TYPEAPPLY:
 352             case TYPEARRAY:
 353                 return true;
 354             case ANNOTATED_TYPE:
 355                 return isStaticSelector(((JCAnnotatedType)base).underlyingType, names);
 356             default:
 357                 return false;
 358         }
 359     }
 360     //where
 361         private static boolean isStaticSym(JCTree tree) {
 362             Symbol sym = symbol(tree);
 363             return (sym.kind == TYP || sym.kind == PCK);
 364         }
 365 
 366     /** Return true if a tree represents the null literal. */
 367     public static boolean isNull(JCTree tree) {
 368         if (!tree.hasTag(LITERAL))
 369             return false;
 370         JCLiteral lit = (JCLiteral) tree;
 371         return (lit.typetag == BOT);
 372     }
 373 
 374     /** Return true iff this tree is a child of some annotation. */
 375     public static boolean isInAnnotation(Env<?> env, JCTree tree) {
 376         TreePath tp = TreePath.getPath(env.toplevel, tree);
 377         if (tp != null) {
 378             for (Tree t : tp) {
 379                 if (t.getKind() == Tree.Kind.ANNOTATION)
 380                     return true;
 381             }
 382         }
 383         return false;
 384     }
 385 
 386     public static String getCommentText(Env<?> env, JCTree tree) {
 387         DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
 388                 ? ((JCCompilationUnit) tree).docComments
 389                 : env.toplevel.docComments;
 390         return (docComments == null) ? null : docComments.getCommentText(tree);
 391     }
 392 
 393     public static DCTree.DCDocComment getCommentTree(Env<?> env, JCTree tree) {
 394         DocCommentTable docComments = (tree.hasTag(JCTree.Tag.TOPLEVEL))
 395                 ? ((JCCompilationUnit) tree).docComments
 396                 : env.toplevel.docComments;
 397         return (docComments == null) ? null : docComments.getCommentTree(tree);
 398     }
 399 
 400     /** The position of the first statement in a block, or the position of
 401      *  the block itself if it is empty.
 402      */
 403     public static int firstStatPos(JCTree tree) {
 404         if (tree.hasTag(BLOCK) && ((JCBlock) tree).stats.nonEmpty())
 405             return ((JCBlock) tree).stats.head.pos;
 406         else
 407             return tree.pos;
 408     }
 409 
 410     /** The end position of given tree, if it is a block with
 411      *  defined endpos.
 412      */
 413     public static int endPos(JCTree tree) {
 414         if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS)
 415             return ((JCBlock) tree).endpos;
 416         else if (tree.hasTag(SYNCHRONIZED))
 417             return endPos(((JCSynchronized) tree).body);
 418         else if (tree.hasTag(TRY)) {
 419             JCTry t = (JCTry) tree;
 420             return endPos((t.finalizer != null) ? t.finalizer
 421                           : (t.catchers.nonEmpty() ? t.catchers.last().body : t.body));
 422         } else if (tree.hasTag(SWITCH_EXPRESSION) &&
 423                    ((JCSwitchExpression) tree).endpos != Position.NOPOS) {
 424             return ((JCSwitchExpression) tree).endpos;
 425         } else
 426             return tree.pos;
 427     }
 428 
 429 
 430     /** Get the start position for a tree node.  The start position is
 431      * defined to be the position of the first character of the first
 432      * token of the node's source text.
 433      * @param tree  The tree node
 434      */
 435     public static int getStartPos(JCTree tree) {
 436         if (tree == null)
 437             return Position.NOPOS;
 438 
 439         switch(tree.getTag()) {
 440             case MODULEDEF: {
 441                 JCModuleDecl md = (JCModuleDecl)tree;
 442                 return md.mods.annotations.isEmpty() ? md.pos :
 443                        md.mods.annotations.head.pos;
 444             }
 445             case PACKAGEDEF: {
 446                 JCPackageDecl pd = (JCPackageDecl)tree;
 447                 return pd.annotations.isEmpty() ? pd.pos :
 448                        pd.annotations.head.pos;
 449             }
 450             case APPLY:
 451                 return getStartPos(((JCMethodInvocation) tree).meth);
 452             case ASSIGN:
 453                 return getStartPos(((JCAssign) tree).lhs);
 454             case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
 455             case SL_ASG: case SR_ASG: case USR_ASG:
 456             case PLUS_ASG: case MINUS_ASG: case MUL_ASG:
 457             case DIV_ASG: case MOD_ASG:
 458             case OR: case AND: case BITOR:
 459             case BITXOR: case BITAND: case EQ:
 460             case NE: case LT: case GT:
 461             case LE: case GE: case SL:
 462             case SR: case USR: case PLUS:
 463             case MINUS: case MUL: case DIV:
 464             case MOD:
 465             case POSTINC:
 466             case POSTDEC:
 467                 return getStartPos(((JCOperatorExpression) tree).getOperand(LEFT));
 468             case CLASSDEF: {
 469                 JCClassDecl node = (JCClassDecl)tree;
 470                 if (node.mods.pos != Position.NOPOS)
 471                     return node.mods.pos;
 472                 break;
 473             }
 474             case CONDEXPR:
 475                 return getStartPos(((JCConditional) tree).cond);
 476             case EXEC:
 477                 return getStartPos(((JCExpressionStatement) tree).expr);
 478             case INDEXED:
 479                 return getStartPos(((JCArrayAccess) tree).indexed);
 480             case METHODDEF: {
 481                 JCMethodDecl node = (JCMethodDecl)tree;
 482                 if (node.mods.pos != Position.NOPOS)
 483                     return node.mods.pos;
 484                 if (node.typarams.nonEmpty()) // List.nil() used for no typarams
 485                     return getStartPos(node.typarams.head);
 486                 return node.restype == null ? node.pos : getStartPos(node.restype);
 487             }
 488             case SELECT:
 489                 return getStartPos(((JCFieldAccess) tree).selected);
 490             case TYPEAPPLY:
 491                 return getStartPos(((JCTypeApply) tree).clazz);
 492             case TYPEARRAY:
 493                 return getStartPos(((JCArrayTypeTree) tree).elemtype);
 494             case TYPETEST:
 495                 return getStartPos(((JCInstanceOf) tree).expr);
 496             case ANNOTATED_TYPE: {
 497                 JCAnnotatedType node = (JCAnnotatedType) tree;
 498                 if (node.annotations.nonEmpty()) {
 499                     if (node.underlyingType.hasTag(TYPEARRAY) ||
 500                             node.underlyingType.hasTag(SELECT)) {
 501                         return getStartPos(node.underlyingType);
 502                     } else {
 503                         return getStartPos(node.annotations.head);
 504                     }
 505                 } else {
 506                     return getStartPos(node.underlyingType);
 507                 }
 508             }
 509             case NEWCLASS: {
 510                 JCNewClass node = (JCNewClass)tree;
 511                 if (node.encl != null)
 512                     return getStartPos(node.encl);
 513                 break;
 514             }
 515             case VARDEF: {
 516                 JCVariableDecl node = (JCVariableDecl)tree;
 517                 if (node.startPos != Position.NOPOS) {
 518                     return node.startPos;
 519                 } else if (node.mods.pos != Position.NOPOS) {
 520                     return node.mods.pos;
 521                 } else if (node.vartype == null || node.vartype.pos == Position.NOPOS) {
 522                     //if there's no type (partially typed lambda parameter)
 523                     //simply return node position
 524                     return node.pos;
 525                 } else {
 526                     return getStartPos(node.vartype);
 527                 }
 528             }
 529             case BINDINGPATTERN: {
 530                 JCBindingPattern node = (JCBindingPattern)tree;
 531                 return getStartPos(node.vartype);
 532             }
 533             case ERRONEOUS: {
 534                 JCErroneous node = (JCErroneous)tree;
 535                 if (node.errs != null && node.errs.nonEmpty())
 536                     return getStartPos(node.errs.head);
 537             }
 538         }
 539         return tree.pos;
 540     }
 541 
 542     /** The end position of given tree, given  a table of end positions generated by the parser
 543      */
 544     public static int getEndPos(JCTree tree, EndPosTable endPosTable) {
 545         if (tree == null)
 546             return Position.NOPOS;
 547 
 548         if (endPosTable == null) {
 549             // fall back on limited info in the tree
 550             return endPos(tree);
 551         }
 552 
 553         int mapPos = endPosTable.getEndPos(tree);
 554         if (mapPos != Position.NOPOS)
 555             return mapPos;
 556 
 557         switch(tree.getTag()) {
 558             case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG:
 559             case SL_ASG: case SR_ASG: case USR_ASG:
 560             case PLUS_ASG: case MINUS_ASG: case MUL_ASG:
 561             case DIV_ASG: case MOD_ASG:
 562             case OR: case AND: case BITOR:
 563             case BITXOR: case BITAND: case EQ:
 564             case NE: case LT: case GT:
 565             case LE: case GE: case SL:
 566             case SR: case USR: case PLUS:
 567             case MINUS: case MUL: case DIV:
 568             case MOD:
 569             case POS:
 570             case NEG:
 571             case NOT:
 572             case COMPL:
 573             case PREINC:
 574             case PREDEC:
 575                 return getEndPos(((JCOperatorExpression) tree).getOperand(RIGHT), endPosTable);
 576             case CASE:
 577                 return getEndPos(((JCCase) tree).stats.last(), endPosTable);
 578             case CATCH:
 579                 return getEndPos(((JCCatch) tree).body, endPosTable);
 580             case CONDEXPR:
 581                 return getEndPos(((JCConditional) tree).falsepart, endPosTable);
 582             case FORLOOP:
 583                 return getEndPos(((JCForLoop) tree).body, endPosTable);
 584             case FOREACHLOOP:
 585                 return getEndPos(((JCEnhancedForLoop) tree).body, endPosTable);
 586             case IF: {
 587                 JCIf node = (JCIf)tree;
 588                 if (node.elsepart == null) {
 589                     return getEndPos(node.thenpart, endPosTable);
 590                 } else {
 591                     return getEndPos(node.elsepart, endPosTable);
 592                 }
 593             }
 594             case LABELLED:
 595                 return getEndPos(((JCLabeledStatement) tree).body, endPosTable);
 596             case MODIFIERS:
 597                 return getEndPos(((JCModifiers) tree).annotations.last(), endPosTable);
 598             case SYNCHRONIZED:
 599                 return getEndPos(((JCSynchronized) tree).body, endPosTable);
 600             case TOPLEVEL:
 601                 return getEndPos(((JCCompilationUnit) tree).defs.last(), endPosTable);
 602             case TRY: {
 603                 JCTry node = (JCTry)tree;
 604                 if (node.finalizer != null) {
 605                     return getEndPos(node.finalizer, endPosTable);
 606                 } else if (!node.catchers.isEmpty()) {
 607                     return getEndPos(node.catchers.last(), endPosTable);
 608                 } else {
 609                     return getEndPos(node.body, endPosTable);
 610                 }
 611             }
 612             case WILDCARD:
 613                 return getEndPos(((JCWildcard) tree).inner, endPosTable);
 614             case TYPECAST:
 615                 return getEndPos(((JCTypeCast) tree).expr, endPosTable);
 616             case TYPETEST:
 617                 return getEndPos(((JCInstanceOf) tree).pattern, endPosTable);
 618             case WHILELOOP:
 619                 return getEndPos(((JCWhileLoop) tree).body, endPosTable);
 620             case ANNOTATED_TYPE:
 621                 return getEndPos(((JCAnnotatedType) tree).underlyingType, endPosTable);
 622             case ERRONEOUS: {
 623                 JCErroneous node = (JCErroneous)tree;
 624                 if (node.errs != null && node.errs.nonEmpty())
 625                     return getEndPos(node.errs.last(), endPosTable);
 626             }
 627         }
 628         return Position.NOPOS;
 629     }
 630 
 631 
 632     /** A DiagnosticPosition with the preferred position set to the
 633      *  end position of given tree, if it is a block with
 634      *  defined endpos.
 635      */
 636     public static DiagnosticPosition diagEndPos(final JCTree tree) {
 637         final int endPos = TreeInfo.endPos(tree);
 638         return new DiagnosticPosition() {
 639             public JCTree getTree() { return tree; }
 640             public int getStartPosition() { return TreeInfo.getStartPos(tree); }
 641             public int getPreferredPosition() { return endPos; }
 642             public int getEndPosition(EndPosTable endPosTable) {
 643                 return TreeInfo.getEndPos(tree, endPosTable);
 644             }
 645         };
 646     }
 647 
 648     public enum PosKind {
 649         START_POS(TreeInfo::getStartPos),
 650         FIRST_STAT_POS(TreeInfo::firstStatPos),
 651         END_POS(TreeInfo::endPos);
 652 
 653         final ToIntFunction<JCTree> posFunc;
 654 
 655         PosKind(ToIntFunction<JCTree> posFunc) {
 656             this.posFunc = posFunc;
 657         }
 658 
 659         int toPos(JCTree tree) {
 660             return posFunc.applyAsInt(tree);
 661         }
 662     }
 663 
 664     /** The position of the finalizer of given try/synchronized statement.
 665      */
 666     public static int finalizerPos(JCTree tree, PosKind posKind) {
 667         if (tree.hasTag(TRY)) {
 668             JCTry t = (JCTry) tree;
 669             Assert.checkNonNull(t.finalizer);
 670             return posKind.toPos(t.finalizer);
 671         } else if (tree.hasTag(SYNCHRONIZED)) {
 672             return endPos(((JCSynchronized) tree).body);
 673         } else {
 674             throw new AssertionError();
 675         }
 676     }
 677 
 678     /** Find the position for reporting an error about a symbol, where
 679      *  that symbol is defined somewhere in the given tree. */
 680     public static int positionFor(final Symbol sym, final JCTree tree) {
 681         JCTree decl = declarationFor(sym, tree);
 682         return ((decl != null) ? decl : tree).pos;
 683     }
 684 
 685     /** Find the position for reporting an error about a symbol, where
 686      *  that symbol is defined somewhere in the given tree. */
 687     public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
 688         JCTree decl = declarationFor(sym, tree);
 689         return ((decl != null) ? decl : tree).pos();
 690     }
 691 
 692     /** Find the declaration for a symbol, where
 693      *  that symbol is defined somewhere in the given tree. */
 694     public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
 695         class DeclScanner extends TreeScanner {
 696             JCTree result = null;
 697             public void scan(JCTree tree) {
 698                 if (tree!=null && result==null)
 699                     tree.accept(this);
 700             }
 701             public void visitTopLevel(JCCompilationUnit that) {
 702                 if (that.packge == sym) result = that;
 703                 else super.visitTopLevel(that);
 704             }
 705             public void visitModuleDef(JCModuleDecl that) {
 706                 if (that.sym == sym) result = that;
 707                 // no need to scan within module declaration
 708             }
 709             public void visitPackageDef(JCPackageDecl that) {
 710                 if (that.packge == sym) result = that;
 711                 else super.visitPackageDef(that);
 712             }
 713             public void visitClassDef(JCClassDecl that) {
 714                 if (that.sym == sym) result = that;
 715                 else super.visitClassDef(that);
 716             }
 717             public void visitMethodDef(JCMethodDecl that) {
 718                 if (that.sym == sym) result = that;
 719                 else super.visitMethodDef(that);
 720             }
 721             public void visitVarDef(JCVariableDecl that) {
 722                 if (that.sym == sym) result = that;
 723                 else super.visitVarDef(that);
 724             }
 725             public void visitTypeParameter(JCTypeParameter that) {
 726                 if (that.type != null && that.type.tsym == sym) result = that;
 727                 else super.visitTypeParameter(that);
 728             }
 729         }
 730         DeclScanner s = new DeclScanner();
 731         tree.accept(s);
 732         return s.result;
 733     }
 734 
 735     public static Env<AttrContext> scopeFor(JCTree node, JCCompilationUnit unit) {
 736         return scopeFor(pathFor(node, unit));
 737     }
 738 
 739     public static Env<AttrContext> scopeFor(List<JCTree> path) {
 740         // TODO: not implemented yet
 741         throw new UnsupportedOperationException("not implemented yet");
 742     }
 743 
 744     public static List<JCTree> pathFor(final JCTree node, final JCCompilationUnit unit) {
 745         class Result extends Error {
 746             static final long serialVersionUID = -5942088234594905625L;
 747             List<JCTree> path;
 748             Result(List<JCTree> path) {
 749                 this.path = path;
 750             }
 751         }
 752         class PathFinder extends TreeScanner {
 753             List<JCTree> path = List.nil();
 754             public void scan(JCTree tree) {
 755                 if (tree != null) {
 756                     path = path.prepend(tree);
 757                     if (tree == node)
 758                         throw new Result(path);
 759                     super.scan(tree);
 760                     path = path.tail;
 761                 }
 762             }
 763         }
 764         try {
 765             new PathFinder().scan(unit);
 766         } catch (Result result) {
 767             return result.path;
 768         }
 769         return List.nil();
 770     }
 771 
 772     /** Return the statement referenced by a label.
 773      *  If the label refers to a loop or switch, return that switch
 774      *  otherwise return the labelled statement itself
 775      */
 776     public static JCTree referencedStatement(JCLabeledStatement tree) {
 777         JCTree t = tree;
 778         do t = ((JCLabeledStatement) t).body;
 779         while (t.hasTag(LABELLED));
 780         switch (t.getTag()) {
 781         case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case SWITCH:
 782             return t;
 783         default:
 784             return tree;
 785         }
 786     }
 787 
 788     /** Skip parens and return the enclosed expression
 789      */
 790     public static JCExpression skipParens(JCExpression tree) {
 791         while (tree.hasTag(PARENS)) {
 792             tree = ((JCParens) tree).expr;
 793         }
 794         return tree;
 795     }
 796 
 797     /** Skip parens and return the enclosed expression
 798      */
 799     public static JCTree skipParens(JCTree tree) {
 800         if (tree.hasTag(PARENS))
 801             return skipParens((JCParens)tree);
 802         else
 803             return tree;
 804     }
 805 
 806     /** Return the types of a list of trees.
 807      */
 808     public static List<Type> types(List<? extends JCTree> trees) {
 809         ListBuffer<Type> ts = new ListBuffer<>();
 810         for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
 811             ts.append(l.head.type);
 812         return ts.toList();
 813     }
 814 
 815     /** If this tree is an identifier or a field or a parameterized type,
 816      *  return its name, otherwise return null.
 817      */
 818     public static Name name(JCTree tree) {
 819         switch (tree.getTag()) {
 820         case IDENT:
 821             return ((JCIdent) tree).name;
 822         case SELECT:
 823             return ((JCFieldAccess) tree).name;
 824         case TYPEAPPLY:
 825             return name(((JCTypeApply) tree).clazz);
 826         default:
 827             return null;
 828         }
 829     }
 830 
 831     /** If this tree is a qualified identifier, its return fully qualified name,
 832      *  otherwise return null.
 833      */
 834     public static Name fullName(JCTree tree) {
 835         tree = skipParens(tree);
 836         switch (tree.getTag()) {
 837         case IDENT:
 838             return ((JCIdent) tree).name;
 839         case SELECT:
 840             Name sname = fullName(((JCFieldAccess) tree).selected);
 841             return sname == null ? null : sname.append('.', name(tree));
 842         default:
 843             return null;
 844         }
 845     }
 846 
 847     public static Symbol symbolFor(JCTree node) {
 848         Symbol sym = symbolForImpl(node);
 849 
 850         return sym != null ? sym.baseSymbol() : null;
 851     }
 852 
 853     private static Symbol symbolForImpl(JCTree node) {
 854         node = skipParens(node);
 855         switch (node.getTag()) {
 856         case TOPLEVEL:
 857             JCCompilationUnit cut = (JCCompilationUnit) node;
 858             JCModuleDecl moduleDecl = cut.getModuleDecl();
 859             if (isModuleInfo(cut) && moduleDecl != null)
 860                 return symbolFor(moduleDecl);
 861             return cut.packge;
 862         case MODULEDEF:
 863             return ((JCModuleDecl) node).sym;
 864         case PACKAGEDEF:
 865             return ((JCPackageDecl) node).packge;
 866         case CLASSDEF:
 867             return ((JCClassDecl) node).sym;
 868         case METHODDEF:
 869             return ((JCMethodDecl) node).sym;
 870         case VARDEF:
 871             return ((JCVariableDecl) node).sym;
 872         case IDENT:
 873             return ((JCIdent) node).sym;
 874         case SELECT:
 875             return ((JCFieldAccess) node).sym;
 876         case REFERENCE:
 877             return ((JCMemberReference) node).sym;
 878         case NEWCLASS:
 879             return ((JCNewClass) node).constructor;
 880         case APPLY:
 881             return symbolFor(((JCMethodInvocation) node).meth);
 882         case TYPEAPPLY:
 883             return symbolFor(((JCTypeApply) node).clazz);
 884         case ANNOTATION:
 885         case TYPE_ANNOTATION:
 886         case TYPEPARAMETER:
 887             if (node.type != null)
 888                 return node.type.tsym;
 889             return null;
 890         case BINDINGPATTERN:
 891             return ((JCBindingPattern) node).symbol;
 892         default:
 893             return null;
 894         }
 895     }
 896 
 897     public static boolean isDeclaration(JCTree node) {
 898         node = skipParens(node);
 899         switch (node.getTag()) {
 900         case PACKAGEDEF:
 901         case CLASSDEF:
 902         case METHODDEF:
 903         case VARDEF:
 904             return true;
 905         default:
 906             return false;
 907         }
 908     }
 909 
 910     /** If this tree is an identifier or a field, return its symbol,
 911      *  otherwise return null.
 912      */
 913     public static Symbol symbol(JCTree tree) {
 914         tree = skipParens(tree);
 915         switch (tree.getTag()) {
 916         case IDENT:
 917             return ((JCIdent) tree).sym;
 918         case SELECT:
 919             return ((JCFieldAccess) tree).sym;
 920         case TYPEAPPLY:
 921             return symbol(((JCTypeApply) tree).clazz);
 922         case ANNOTATED_TYPE:
 923             return symbol(((JCAnnotatedType) tree).underlyingType);
 924         case REFERENCE:
 925             return ((JCMemberReference) tree).sym;
 926         default:
 927             return null;
 928         }
 929     }
 930 
 931     /** If this tree has a modifiers field, return it otherwise return null
 932      */
 933     public static JCModifiers getModifiers(JCTree tree) {
 934         tree = skipParens(tree);
 935         switch (tree.getTag()) {
 936             case VARDEF:
 937                 return ((JCVariableDecl) tree).mods;
 938             case METHODDEF:
 939                 return ((JCMethodDecl) tree).mods;
 940             case CLASSDEF:
 941                 return ((JCClassDecl) tree).mods;
 942             case MODULEDEF:
 943                 return ((JCModuleDecl) tree).mods;
 944             default:
 945                 return null;
 946         }
 947     }
 948 
 949     /** Return true if this is a nonstatic selection. */
 950     public static boolean nonstaticSelect(JCTree tree) {
 951         tree = skipParens(tree);
 952         if (!tree.hasTag(SELECT)) return false;
 953         JCFieldAccess s = (JCFieldAccess) tree;
 954         Symbol e = symbol(s.selected);
 955         return e == null || (e.kind != PCK && e.kind != TYP);
 956     }
 957 
 958     /** If this tree is an identifier or a field, set its symbol, otherwise skip.
 959      */
 960     public static void setSymbol(JCTree tree, Symbol sym) {
 961         tree = skipParens(tree);
 962         switch (tree.getTag()) {
 963         case IDENT:
 964             ((JCIdent) tree).sym = sym; break;
 965         case SELECT:
 966             ((JCFieldAccess) tree).sym = sym; break;
 967         default:
 968         }
 969     }
 970 
 971     /** If this tree is a declaration or a block, return its flags field,
 972      *  otherwise return 0.
 973      */
 974     public static long flags(JCTree tree) {
 975         switch (tree.getTag()) {
 976         case VARDEF:
 977             return ((JCVariableDecl) tree).mods.flags;
 978         case METHODDEF:
 979             return ((JCMethodDecl) tree).mods.flags;
 980         case CLASSDEF:
 981             return ((JCClassDecl) tree).mods.flags;
 982         case BLOCK:
 983             return ((JCBlock) tree).flags;
 984         default:
 985             return 0;
 986         }
 987     }
 988 
 989     /** Return first (smallest) flag in `flags':
 990      *  pre: flags != 0
 991      */
 992     public static long firstFlag(long flags) {
 993         long flag = 1;
 994         while ((flag & flags & ExtendedStandardFlags) == 0)
 995             flag = flag << 1;
 996         return flag;
 997     }
 998 
 999     /** Return flags as a string, separated by " ".
1000      */
1001     public static String flagNames(long flags) {
1002         return Flags.toString(flags & ExtendedStandardFlags).trim();
1003     }
1004 
1005     /** Operator precedences values.
1006      */
1007     public static final int
1008         notExpression = -1,   // not an expression
1009         noPrec = 0,           // no enclosing expression
1010         assignPrec = 1,
1011         assignopPrec = 2,
1012         condPrec = 3,
1013         orPrec = 4,
1014         andPrec = 5,
1015         bitorPrec = 6,
1016         bitxorPrec = 7,
1017         bitandPrec = 8,
1018         eqPrec = 9,
1019         ordPrec = 10,
1020         shiftPrec = 11,
1021         addPrec = 12,
1022         mulPrec = 13,
1023         prefixPrec = 14,
1024         postfixPrec = 15,
1025         precCount = 16;
1026 
1027 
1028     /** Map operators to their precedence levels.
1029      */
1030     public static int opPrec(JCTree.Tag op) {
1031         switch(op) {
1032         case POS:
1033         case NEG:
1034         case NOT:
1035         case COMPL:
1036         case PREINC:
1037         case PREDEC: return prefixPrec;
1038         case POSTINC:
1039         case POSTDEC:
1040         case NULLCHK: return postfixPrec;
1041         case ASSIGN: return assignPrec;
1042         case BITOR_ASG:
1043         case BITXOR_ASG:
1044         case BITAND_ASG:
1045         case SL_ASG:
1046         case SR_ASG:
1047         case USR_ASG:
1048         case PLUS_ASG:
1049         case MINUS_ASG:
1050         case MUL_ASG:
1051         case DIV_ASG:
1052         case MOD_ASG: return assignopPrec;
1053         case OR: return orPrec;
1054         case AND: return andPrec;
1055         case EQ:
1056         case NE: return eqPrec;
1057         case LT:
1058         case GT:
1059         case LE:
1060         case GE: return ordPrec;
1061         case BITOR: return bitorPrec;
1062         case BITXOR: return bitxorPrec;
1063         case BITAND: return bitandPrec;
1064         case SL:
1065         case SR:
1066         case USR: return shiftPrec;
1067         case PLUS:
1068         case MINUS: return addPrec;
1069         case MUL:
1070         case DIV:
1071         case MOD: return mulPrec;
1072         case TYPETEST: return ordPrec;
1073         default: throw new AssertionError();
1074         }
1075     }
1076 
1077     static Tree.Kind tagToKind(JCTree.Tag tag) {
1078         switch (tag) {
1079         // Postfix expressions
1080         case POSTINC:           // _ ++
1081             return Tree.Kind.POSTFIX_INCREMENT;
1082         case POSTDEC:           // _ --
1083             return Tree.Kind.POSTFIX_DECREMENT;
1084 
1085         // Unary operators
1086         case PREINC:            // ++ _
1087             return Tree.Kind.PREFIX_INCREMENT;
1088         case PREDEC:            // -- _
1089             return Tree.Kind.PREFIX_DECREMENT;
1090         case POS:               // +
1091             return Tree.Kind.UNARY_PLUS;
1092         case NEG:               // -
1093             return Tree.Kind.UNARY_MINUS;
1094         case COMPL:             // ~
1095             return Tree.Kind.BITWISE_COMPLEMENT;
1096         case NOT:               // !
1097             return Tree.Kind.LOGICAL_COMPLEMENT;
1098 
1099         // Binary operators
1100 
1101         // Multiplicative operators
1102         case MUL:               // *
1103             return Tree.Kind.MULTIPLY;
1104         case DIV:               // /
1105             return Tree.Kind.DIVIDE;
1106         case MOD:               // %
1107             return Tree.Kind.REMAINDER;
1108 
1109         // Additive operators
1110         case PLUS:              // +
1111             return Tree.Kind.PLUS;
1112         case MINUS:             // -
1113             return Tree.Kind.MINUS;
1114 
1115         // Shift operators
1116         case SL:                // <<
1117             return Tree.Kind.LEFT_SHIFT;
1118         case SR:                // >>
1119             return Tree.Kind.RIGHT_SHIFT;
1120         case USR:               // >>>
1121             return Tree.Kind.UNSIGNED_RIGHT_SHIFT;
1122 
1123         // Relational operators
1124         case LT:                // <
1125             return Tree.Kind.LESS_THAN;
1126         case GT:                // >
1127             return Tree.Kind.GREATER_THAN;
1128         case LE:                // <=
1129             return Tree.Kind.LESS_THAN_EQUAL;
1130         case GE:                // >=
1131             return Tree.Kind.GREATER_THAN_EQUAL;
1132 
1133         // Equality operators
1134         case EQ:                // ==
1135             return Tree.Kind.EQUAL_TO;
1136         case NE:                // !=
1137             return Tree.Kind.NOT_EQUAL_TO;
1138 
1139         // Bitwise and logical operators
1140         case BITAND:            // &
1141             return Tree.Kind.AND;
1142         case BITXOR:            // ^
1143             return Tree.Kind.XOR;
1144         case BITOR:             // |
1145             return Tree.Kind.OR;
1146 
1147         // Conditional operators
1148         case AND:               // &&
1149             return Tree.Kind.CONDITIONAL_AND;
1150         case OR:                // ||
1151             return Tree.Kind.CONDITIONAL_OR;
1152 
1153         // Assignment operators
1154         case MUL_ASG:           // *=
1155             return Tree.Kind.MULTIPLY_ASSIGNMENT;
1156         case DIV_ASG:           // /=
1157             return Tree.Kind.DIVIDE_ASSIGNMENT;
1158         case MOD_ASG:           // %=
1159             return Tree.Kind.REMAINDER_ASSIGNMENT;
1160         case PLUS_ASG:          // +=
1161             return Tree.Kind.PLUS_ASSIGNMENT;
1162         case MINUS_ASG:         // -=
1163             return Tree.Kind.MINUS_ASSIGNMENT;
1164         case SL_ASG:            // <<=
1165             return Tree.Kind.LEFT_SHIFT_ASSIGNMENT;
1166         case SR_ASG:            // >>=
1167             return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT;
1168         case USR_ASG:           // >>>=
1169             return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT;
1170         case BITAND_ASG:        // &=
1171             return Tree.Kind.AND_ASSIGNMENT;
1172         case BITXOR_ASG:        // ^=
1173             return Tree.Kind.XOR_ASSIGNMENT;
1174         case BITOR_ASG:         // |=
1175             return Tree.Kind.OR_ASSIGNMENT;
1176 
1177         // Null check (implementation detail), for example, __.getClass()
1178         case NULLCHK:
1179             return Tree.Kind.OTHER;
1180 
1181         case ANNOTATION:
1182             return Tree.Kind.ANNOTATION;
1183         case TYPE_ANNOTATION:
1184             return Tree.Kind.TYPE_ANNOTATION;
1185 
1186         case EXPORTS:
1187             return Tree.Kind.EXPORTS;
1188         case OPENS:
1189             return Tree.Kind.OPENS;
1190 
1191         default:
1192             return null;
1193         }
1194     }
1195 
1196     /**
1197      * Returns the underlying type of the tree if it is an annotated type,
1198      * or the tree itself otherwise.
1199      */
1200     public static JCExpression typeIn(JCExpression tree) {
1201         switch (tree.getTag()) {
1202         case ANNOTATED_TYPE:
1203             return ((JCAnnotatedType)tree).underlyingType;
1204         case IDENT: /* simple names */
1205         case TYPEIDENT: /* primitive name */
1206         case SELECT: /* qualified name */
1207         case TYPEARRAY: /* array types */
1208         case WILDCARD: /* wild cards */
1209         case TYPEPARAMETER: /* type parameters */
1210         case TYPEAPPLY: /* parameterized types */
1211         case ERRONEOUS: /* error tree TODO: needed for BadCast JSR308 test case. Better way? */
1212             return tree;
1213         default:
1214             throw new AssertionError("Unexpected type tree: " + tree);
1215         }
1216     }
1217 
1218     /* Return the inner-most type of a type tree.
1219      * For an array that contains an annotated type, return that annotated type.
1220      * TODO: currently only used by Pretty. Describe behavior better.
1221      */
1222     public static JCTree innermostType(JCTree type, boolean skipAnnos) {
1223         JCTree lastAnnotatedType = null;
1224         JCTree cur = type;
1225         loop: while (true) {
1226             switch (cur.getTag()) {
1227             case TYPEARRAY:
1228                 lastAnnotatedType = null;
1229                 cur = ((JCArrayTypeTree)cur).elemtype;
1230                 break;
1231             case WILDCARD:
1232                 lastAnnotatedType = null;
1233                 cur = ((JCWildcard)cur).inner;
1234                 break;
1235             case ANNOTATED_TYPE:
1236                 lastAnnotatedType = cur;
1237                 cur = ((JCAnnotatedType)cur).underlyingType;
1238                 break;
1239             default:
1240                 break loop;
1241             }
1242         }
1243         if (!skipAnnos && lastAnnotatedType!=null) {
1244             return lastAnnotatedType;
1245         } else {
1246             return cur;
1247         }
1248     }
1249 
1250     private static class TypeAnnotationFinder extends TreeScanner {
1251         public boolean foundTypeAnno = false;
1252 
1253         @Override
1254         public void scan(JCTree tree) {
1255             if (foundTypeAnno || tree == null)
1256                 return;
1257             super.scan(tree);
1258         }
1259 
1260         public void visitAnnotation(JCAnnotation tree) {
1261             foundTypeAnno = foundTypeAnno || tree.hasTag(TYPE_ANNOTATION);
1262         }
1263     }
1264 
1265     public static boolean containsTypeAnnotation(JCTree e) {
1266         TypeAnnotationFinder finder = new TypeAnnotationFinder();
1267         finder.scan(e);
1268         return finder.foundTypeAnno;
1269     }
1270 
1271     public static boolean isModuleInfo(JCCompilationUnit tree) {
1272         return tree.sourcefile.isNameCompatible("module-info", JavaFileObject.Kind.SOURCE)
1273                 && tree.getModuleDecl() != null;
1274     }
1275 
1276     public static JCModuleDecl getModule(JCCompilationUnit t) {
1277         if (t.defs.nonEmpty()) {
1278             JCTree def = t.defs.head;
1279             if (def.hasTag(MODULEDEF))
1280                 return (JCModuleDecl) def;
1281         }
1282         return null;
1283     }
1284 
1285     public static boolean isPackageInfo(JCCompilationUnit tree) {
1286         return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE);
1287     }
1288 
1289 }