src/share/classes/com/sun/tools/javac/comp/Flow.java

Print this page




  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.HashMap;
  31 import java.util.Map;
  32 import java.util.LinkedHashMap;
  33 
  34 import com.sun.tools.javac.code.*;
  35 import com.sun.tools.javac.tree.*;
  36 import com.sun.tools.javac.util.*;
  37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  38 
  39 import com.sun.tools.javac.code.Symbol.*;
  40 import com.sun.tools.javac.tree.JCTree.*;
  41 
  42 import static com.sun.tools.javac.code.Flags.*;

  43 import static com.sun.tools.javac.code.Kinds.*;
  44 import static com.sun.tools.javac.code.TypeTags.*;

  45 
  46 /** This pass implements dataflow analysis for Java programs.
  47  *  Liveness analysis checks that every statement is reachable.
  48  *  Exception analysis ensures that every checked exception that is
  49  *  thrown is declared or caught.  Definite assignment analysis
  50  *  ensures that each variable is assigned when used.  Definite
  51  *  unassignment analysis ensures that no final variable is assigned
  52  *  more than once.
  53  *
  54  *  <p>The JLS has a number of problems in the
  55  *  specification of these flow analysis problems. This implementation
  56  *  attempts to address those issues.
  57  *
  58  *  <p>First, there is no accommodation for a finally clause that cannot
  59  *  complete normally. For liveness analysis, an intervening finally
  60  *  clause can cause a break, continue, or return not to reach its
  61  *  target.  For exception analysis, an intervening finally clause can
  62  *  cause any exception to be "caught".  For DA/DU analysis, the finally
  63  *  clause can prevent a transfer of control from propagating DA/DU
  64  *  state to the target.  In addition, code in the finally clause can


 304     }
 305 
 306     /** The currently pending exits that go from current inner blocks
 307      *  to an enclosing block, in source order.
 308      */
 309     ListBuffer<PendingExit> pendingExits;
 310 
 311     /*-------------------- Exceptions ----------------------*/
 312 
 313     /** Complain that pending exceptions are not caught.
 314      */
 315     void errorUncaught() {
 316         for (PendingExit exit = pendingExits.next();
 317              exit != null;
 318              exit = pendingExits.next()) {
 319             if (classDef != null &&
 320                 classDef.pos == exit.tree.pos) {
 321                 log.error(exit.tree.pos(),
 322                         "unreported.exception.default.constructor",
 323                         exit.thrown);
 324             } else if (exit.tree.getTag() == JCTree.VARDEF &&
 325                     ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
 326                 log.error(exit.tree.pos(),
 327                         "unreported.exception.implicit.close",
 328                         exit.thrown,
 329                         ((JCVariableDecl)exit.tree).sym.name);
 330             } else {
 331                 log.error(exit.tree.pos(),
 332                         "unreported.exception.need.to.catch.or.throw",
 333                         exit.thrown);
 334             }
 335         }
 336     }
 337 
 338     /** Record that exception is potentially thrown and check that it
 339      *  is caught.
 340      */
 341     void markThrown(JCTree tree, Type exc) {
 342         if (!chk.isUnchecked(tree.pos(), exc)) {
 343             if (!chk.isHandled(exc, caught))
 344                 pendingExits.append(new PendingExit(tree, exc));


 399                     // reachable assignment
 400                     uninits.excl(sym.adr);
 401                     uninitsTry.excl(sym.adr);
 402                 } else {
 403                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
 404                     uninits.excl(sym.adr);
 405                 }
 406             }
 407             inits.incl(sym.adr);
 408         } else if ((sym.flags() & FINAL) != 0) {
 409             log.error(pos, "var.might.already.be.assigned", sym);
 410         }
 411     }
 412 
 413     /** If tree is either a simple name or of the form this.name or
 414      *  C.this.name, and tree represents a trackable variable,
 415      *  record an initialization of the variable.
 416      */
 417     void letInit(JCTree tree) {
 418         tree = TreeInfo.skipParens(tree);
 419         if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
 420             Symbol sym = TreeInfo.symbol(tree);
 421             if (sym.kind == VAR) {
 422                 letInit(tree.pos(), (VarSymbol)sym);
 423             }
 424         }
 425     }
 426 
 427     /** Check that trackable variable is initialized.
 428      */
 429     void checkInit(DiagnosticPosition pos, VarSymbol sym) {
 430         if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
 431             trackable(sym) &&
 432             !inits.isMember(sym.adr)) {
 433             log.error(pos, "var.might.not.have.been.initialized",
 434                       sym);
 435             inits.incl(sym.adr);
 436         }
 437     }
 438 
 439     /*-------------------- Handling jumps ----------------------*/
 440 
 441     /** Record an outward transfer of control. */
 442     void recordExit(JCTree tree) {
 443         pendingExits.append(new PendingExit(tree, inits, uninits));
 444         markDead();
 445     }
 446 
 447     /** Resolve all breaks of this statement. */
 448     boolean resolveBreaks(JCTree tree,
 449                           ListBuffer<PendingExit> oldPendingExits) {
 450         boolean result = false;
 451         List<PendingExit> exits = pendingExits.toList();
 452         pendingExits = oldPendingExits;
 453         for (; exits.nonEmpty(); exits = exits.tail) {
 454             PendingExit exit = exits.head;
 455             if (exit.tree.getTag() == JCTree.BREAK &&
 456                 ((JCBreak) exit.tree).target == tree) {
 457                 inits.andSet(exit.inits);
 458                 uninits.andSet(exit.uninits);
 459                 result = true;
 460             } else {
 461                 pendingExits.append(exit);
 462             }
 463         }
 464         return result;
 465     }
 466 
 467     /** Resolve all continues of this statement. */
 468     boolean resolveContinues(JCTree tree) {
 469         boolean result = false;
 470         List<PendingExit> exits = pendingExits.toList();
 471         pendingExits = new ListBuffer<PendingExit>();
 472         for (; exits.nonEmpty(); exits = exits.tail) {
 473             PendingExit exit = exits.head;
 474             if (exit.tree.getTag() == JCTree.CONTINUE &&
 475                 ((JCContinue) exit.tree).target == tree) {
 476                 inits.andSet(exit.inits);
 477                 uninits.andSet(exit.uninits);
 478                 result = true;
 479             } else {
 480                 pendingExits.append(exit);
 481             }
 482         }
 483         return result;
 484     }
 485 
 486     /** Record that statement is unreachable.
 487      */
 488     void markDead() {
 489         inits.inclRange(firstadr, nextadr);
 490         uninits.inclRange(firstadr, nextadr);
 491         alive = false;
 492     }
 493 
 494     /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets


 500         uninitsWhenTrue = uninits;
 501         if (setToNull)
 502             inits = uninits = null;
 503     }
 504 
 505     /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
 506      */
 507     void merge() {
 508         inits = initsWhenFalse.andSet(initsWhenTrue);
 509         uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
 510     }
 511 
 512 /* ************************************************************************
 513  * Visitor methods for statements and definitions
 514  *************************************************************************/
 515 
 516     /** Analyze a definition.
 517      */
 518     void scanDef(JCTree tree) {
 519         scanStat(tree);
 520         if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) {
 521             log.error(tree.pos(),
 522                       "initializer.must.be.able.to.complete.normally");
 523         }
 524     }
 525 
 526     /** Analyze a statement. Check that statement is reachable.
 527      */
 528     void scanStat(JCTree tree) {
 529         if (!alive && tree != null) {
 530             log.error(tree.pos(), "unreachable.stmt");
 531             if (tree.getTag() != JCTree.SKIP) alive = true;
 532         }
 533         scan(tree);
 534     }
 535 
 536     /** Analyze list of statements.
 537      */
 538     void scanStats(List<? extends JCStatement> trees) {
 539         if (trees != null)
 540             for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
 541                 scanStat(l.head);
 542     }
 543 
 544     /** Analyze an expression. Make sure to set (un)inits rather than
 545      *  (un)initsWhenTrue(WhenFalse) on exit.
 546      */
 547     void scanExpr(JCTree tree) {
 548         if (tree != null) {
 549             scan(tree);
 550             if (inits == null) merge();
 551         }


 597         List<Type> thrownPrev = thrown;
 598         List<Type> caughtPrev = caught;
 599         boolean alivePrev = alive;
 600         int firstadrPrev = firstadr;
 601         int nextadrPrev = nextadr;
 602         ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 603         Lint lintPrev = lint;
 604 
 605         pendingExits = new ListBuffer<PendingExit>();
 606         if (tree.name != names.empty) {
 607             caught = List.nil();
 608             firstadr = nextadr;
 609         }
 610         classDef = tree;
 611         thrown = List.nil();
 612         lint = lint.augment(tree.sym.attributes_field);
 613 
 614         try {
 615             // define all the static fields
 616             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 617                 if (l.head.getTag() == JCTree.VARDEF) {
 618                     JCVariableDecl def = (JCVariableDecl)l.head;
 619                     if ((def.mods.flags & STATIC) != 0) {
 620                         VarSymbol sym = def.sym;
 621                         if (trackable(sym))
 622                             newVar(sym);
 623                     }
 624                 }
 625             }
 626 
 627             // process all the static initializers
 628             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 629                 if (l.head.getTag() != JCTree.METHODDEF &&
 630                     (TreeInfo.flags(l.head) & STATIC) != 0) {
 631                     scanDef(l.head);
 632                     errorUncaught();
 633                 }
 634             }
 635 
 636             // add intersection of all thrown clauses of initial constructors
 637             // to set of caught exceptions, unless class is anonymous.
 638             if (tree.name != names.empty) {
 639                 boolean firstConstructor = true;
 640                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 641                     if (TreeInfo.isInitialConstructor(l.head)) {
 642                         List<Type> mthrown =
 643                             ((JCMethodDecl) l.head).sym.type.getThrownTypes();
 644                         if (firstConstructor) {
 645                             caught = mthrown;
 646                             firstConstructor = false;
 647                         } else {
 648                             caught = chk.intersect(mthrown, caught);
 649                         }
 650                     }
 651                 }
 652             }
 653 
 654             // define all the instance fields
 655             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 656                 if (l.head.getTag() == JCTree.VARDEF) {
 657                     JCVariableDecl def = (JCVariableDecl)l.head;
 658                     if ((def.mods.flags & STATIC) == 0) {
 659                         VarSymbol sym = def.sym;
 660                         if (trackable(sym))
 661                             newVar(sym);
 662                     }
 663                 }
 664             }
 665 
 666             // process all the instance initializers
 667             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 668                 if (l.head.getTag() != JCTree.METHODDEF &&
 669                     (TreeInfo.flags(l.head) & STATIC) == 0) {
 670                     scanDef(l.head);
 671                     errorUncaught();
 672                 }
 673             }
 674 
 675             // in an anonymous class, add the set of thrown exceptions to
 676             // the throws clause of the synthetic constructor and propagate
 677             // outwards.
 678             // Changing the throws clause on the fly is okay here because
 679             // the anonymous constructor can't be invoked anywhere else,
 680             // and its type hasn't been cached.
 681             if (tree.name == names.empty) {
 682                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 683                     if (TreeInfo.isInitialConstructor(l.head)) {
 684                         JCMethodDecl mdef = (JCMethodDecl)l.head;
 685                         mdef.thrown = make.Types(thrown);
 686                         mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
 687                     }
 688                 }
 689                 thrownPrev = chk.union(thrown, thrownPrev);
 690             }
 691 
 692             // process all the methods
 693             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 694                 if (l.head.getTag() == JCTree.METHODDEF) {
 695                     scan(l.head);
 696                     errorUncaught();
 697                 }
 698             }
 699 
 700             thrown = thrownPrev;
 701         } finally {
 702             pendingExits = pendingExitsPrev;
 703             alive = alivePrev;
 704             nextadr = nextadrPrev;
 705             firstadr = firstadrPrev;
 706             caught = caughtPrev;
 707             classDef = classDefPrev;
 708             lint = lintPrev;
 709         }
 710     }
 711 
 712     public void visitMethodDef(JCMethodDecl tree) {
 713         if (tree.body == null) return;
 714 


 743             // else we are in an instance initializer block;
 744             // leave caught unchanged.
 745 
 746             alive = true;
 747             scanStat(tree.body);
 748 
 749             if (alive && tree.sym.type.getReturnType().tag != VOID)
 750                 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
 751 
 752             if (isInitialConstructor) {
 753                 for (int i = firstadr; i < nextadr; i++)
 754                     if (vars[i].owner == classDef.sym)
 755                         checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
 756             }
 757             List<PendingExit> exits = pendingExits.toList();
 758             pendingExits = new ListBuffer<PendingExit>();
 759             while (exits.nonEmpty()) {
 760                 PendingExit exit = exits.head;
 761                 exits = exits.tail;
 762                 if (exit.thrown == null) {
 763                     Assert.check(exit.tree.getTag() == JCTree.RETURN);
 764                     if (isInitialConstructor) {
 765                         inits = exit.inits;
 766                         for (int i = firstadr; i < nextadr; i++)
 767                             checkInit(exit.tree.pos(), vars[i]);
 768                     }
 769                 } else {
 770                     // uncaught throws will be reported later
 771                     pendingExits.append(exit);
 772                 }
 773             }
 774         } finally {
 775             inits = initsPrev;
 776             uninits = uninitsPrev;
 777             nextadr = nextadrPrev;
 778             firstadr = firstadrPrev;
 779             caught = caughtPrev;
 780             lint = lintPrev;
 781         }
 782     }
 783 


 972                 alive &&
 973                 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
 974                 c.stats.nonEmpty() && l.tail.nonEmpty())
 975                 log.warning(Lint.LintCategory.FALLTHROUGH,
 976                             l.tail.head.pos(),
 977                             "possible.fall-through.into.case");
 978         }
 979         if (!hasDefault) {
 980             inits.andSet(initsSwitch);
 981             alive = true;
 982         }
 983         alive |= resolveBreaks(tree, prevPendingExits);
 984         nextadr = nextadrPrev;
 985     }
 986     // where
 987         /** Add any variables defined in stats to inits and uninits. */
 988         private static void addVars(List<JCStatement> stats, Bits inits,
 989                                     Bits uninits) {
 990             for (;stats.nonEmpty(); stats = stats.tail) {
 991                 JCTree stat = stats.head;
 992                 if (stat.getTag() == JCTree.VARDEF) {
 993                     int adr = ((JCVariableDecl) stat).sym.adr;
 994                     inits.excl(adr);
 995                     uninits.incl(adr);
 996                 }
 997             }
 998         }
 999 
1000     public void visitTry(JCTry tree) {
1001         List<Type> caughtPrev = caught;
1002         List<Type> thrownPrev = thrown;
1003         thrown = List.nil();
1004         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1005             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1006                     ((JCTypeUnion)l.head.param.vartype).alternatives :
1007                     List.of(l.head.param.vartype);
1008             for (JCExpression ct : subClauses) {
1009                 caught = chk.incl(ct.type, caught);
1010             }
1011         }
1012         ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();


1329         }
1330         inits = initsExit;
1331         uninits = uninitsExit;
1332     }
1333 
1334     public void visitAssign(JCAssign tree) {
1335         JCTree lhs = TreeInfo.skipParens(tree.lhs);
1336         if (!(lhs instanceof JCIdent)) scanExpr(lhs);
1337         scanExpr(tree.rhs);
1338         letInit(lhs);
1339     }
1340 
1341     public void visitAssignop(JCAssignOp tree) {
1342         scanExpr(tree.lhs);
1343         scanExpr(tree.rhs);
1344         letInit(tree.lhs);
1345     }
1346 
1347     public void visitUnary(JCUnary tree) {
1348         switch (tree.getTag()) {
1349         case JCTree.NOT:
1350             scanCond(tree.arg);
1351             Bits t = initsWhenFalse;
1352             initsWhenFalse = initsWhenTrue;
1353             initsWhenTrue = t;
1354             t = uninitsWhenFalse;
1355             uninitsWhenFalse = uninitsWhenTrue;
1356             uninitsWhenTrue = t;
1357             break;
1358         case JCTree.PREINC: case JCTree.POSTINC:
1359         case JCTree.PREDEC: case JCTree.POSTDEC:
1360             scanExpr(tree.arg);
1361             letInit(tree.arg);
1362             break;
1363         default:
1364             scanExpr(tree.arg);
1365         }
1366     }
1367 
1368     public void visitBinary(JCBinary tree) {
1369         switch (tree.getTag()) {
1370         case JCTree.AND:
1371             scanCond(tree.lhs);
1372             Bits initsWhenFalseLeft = initsWhenFalse;
1373             Bits uninitsWhenFalseLeft = uninitsWhenFalse;
1374             inits = initsWhenTrue;
1375             uninits = uninitsWhenTrue;
1376             scanCond(tree.rhs);
1377             initsWhenFalse.andSet(initsWhenFalseLeft);
1378             uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
1379             break;
1380         case JCTree.OR:
1381             scanCond(tree.lhs);
1382             Bits initsWhenTrueLeft = initsWhenTrue;
1383             Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1384             inits = initsWhenFalse;
1385             uninits = uninitsWhenFalse;
1386             scanCond(tree.rhs);
1387             initsWhenTrue.andSet(initsWhenTrueLeft);
1388             uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1389             break;
1390         default:
1391             scanExpr(tree.lhs);
1392             scanExpr(tree.rhs);
1393         }
1394     }
1395 
1396     public void visitIdent(JCIdent tree) {
1397         if (tree.sym.kind == VAR) {
1398             checkInit(tree.pos(), (VarSymbol)tree.sym);
1399             referenced(tree.sym);
1400         }
1401     }
1402 
1403     void referenced(Symbol sym) {
1404         unrefdResources.remove(sym);
1405     }
1406 
1407     public void visitTypeCast(JCTypeCast tree) {
1408         super.visitTypeCast(tree);
1409         if (!tree.type.isErroneous()
1410             && lint.isEnabled(Lint.LintCategory.CAST)
1411             && types.isSameType(tree.expr.type, tree.clazz.type)
1412             && !is292targetTypeCast(tree)) {
1413             log.warning(Lint.LintCategory.CAST,
1414                     tree.pos(), "redundant.cast", tree.expr.type);
1415         }
1416     }
1417     //where
1418         private boolean is292targetTypeCast(JCTypeCast tree) {
1419             boolean is292targetTypeCast = false;
1420             JCExpression expr = TreeInfo.skipParens(tree.expr);
1421             if (expr.getTag() == JCTree.APPLY) {
1422                 JCMethodInvocation apply = (JCMethodInvocation)expr;
1423                 Symbol sym = TreeInfo.symbol(apply.meth);
1424                 is292targetTypeCast = sym != null &&
1425                     sym.kind == MTH &&
1426                     (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
1427             }
1428             return is292targetTypeCast;
1429         }
1430 
1431     public void visitTopLevel(JCCompilationUnit tree) {
1432         // Do nothing for TopLevel since each class is visited individually
1433     }
1434 
1435 /**************************************************************************
1436  * main method
1437  *************************************************************************/
1438 
1439     /** Perform definite assignment/unassignment analysis on a tree.
1440      */
1441     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {




  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.HashMap;
  31 import java.util.Map;
  32 import java.util.LinkedHashMap;
  33 
  34 import com.sun.tools.javac.code.*;
  35 import com.sun.tools.javac.tree.*;
  36 import com.sun.tools.javac.util.*;
  37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  38 
  39 import com.sun.tools.javac.code.Symbol.*;
  40 import com.sun.tools.javac.tree.JCTree.*;
  41 
  42 import static com.sun.tools.javac.code.Flags.*;
  43 import static com.sun.tools.javac.code.Flags.BLOCK;
  44 import static com.sun.tools.javac.code.Kinds.*;
  45 import static com.sun.tools.javac.code.TypeTags.*;
  46 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  47 
  48 /** This pass implements dataflow analysis for Java programs.
  49  *  Liveness analysis checks that every statement is reachable.
  50  *  Exception analysis ensures that every checked exception that is
  51  *  thrown is declared or caught.  Definite assignment analysis
  52  *  ensures that each variable is assigned when used.  Definite
  53  *  unassignment analysis ensures that no final variable is assigned
  54  *  more than once.
  55  *
  56  *  <p>The JLS has a number of problems in the
  57  *  specification of these flow analysis problems. This implementation
  58  *  attempts to address those issues.
  59  *
  60  *  <p>First, there is no accommodation for a finally clause that cannot
  61  *  complete normally. For liveness analysis, an intervening finally
  62  *  clause can cause a break, continue, or return not to reach its
  63  *  target.  For exception analysis, an intervening finally clause can
  64  *  cause any exception to be "caught".  For DA/DU analysis, the finally
  65  *  clause can prevent a transfer of control from propagating DA/DU
  66  *  state to the target.  In addition, code in the finally clause can


 306     }
 307 
 308     /** The currently pending exits that go from current inner blocks
 309      *  to an enclosing block, in source order.
 310      */
 311     ListBuffer<PendingExit> pendingExits;
 312 
 313     /*-------------------- Exceptions ----------------------*/
 314 
 315     /** Complain that pending exceptions are not caught.
 316      */
 317     void errorUncaught() {
 318         for (PendingExit exit = pendingExits.next();
 319              exit != null;
 320              exit = pendingExits.next()) {
 321             if (classDef != null &&
 322                 classDef.pos == exit.tree.pos) {
 323                 log.error(exit.tree.pos(),
 324                         "unreported.exception.default.constructor",
 325                         exit.thrown);
 326             } else if (exit.tree.hasTag(VARDEF) &&
 327                     ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
 328                 log.error(exit.tree.pos(),
 329                         "unreported.exception.implicit.close",
 330                         exit.thrown,
 331                         ((JCVariableDecl)exit.tree).sym.name);
 332             } else {
 333                 log.error(exit.tree.pos(),
 334                         "unreported.exception.need.to.catch.or.throw",
 335                         exit.thrown);
 336             }
 337         }
 338     }
 339 
 340     /** Record that exception is potentially thrown and check that it
 341      *  is caught.
 342      */
 343     void markThrown(JCTree tree, Type exc) {
 344         if (!chk.isUnchecked(tree.pos(), exc)) {
 345             if (!chk.isHandled(exc, caught))
 346                 pendingExits.append(new PendingExit(tree, exc));


 401                     // reachable assignment
 402                     uninits.excl(sym.adr);
 403                     uninitsTry.excl(sym.adr);
 404                 } else {
 405                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
 406                     uninits.excl(sym.adr);
 407                 }
 408             }
 409             inits.incl(sym.adr);
 410         } else if ((sym.flags() & FINAL) != 0) {
 411             log.error(pos, "var.might.already.be.assigned", sym);
 412         }
 413     }
 414 
 415     /** If tree is either a simple name or of the form this.name or
 416      *  C.this.name, and tree represents a trackable variable,
 417      *  record an initialization of the variable.
 418      */
 419     void letInit(JCTree tree) {
 420         tree = TreeInfo.skipParens(tree);
 421         if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
 422             Symbol sym = TreeInfo.symbol(tree);
 423             if (sym.kind == VAR) {
 424                 letInit(tree.pos(), (VarSymbol)sym);
 425             }
 426         }
 427     }
 428 
 429     /** Check that trackable variable is initialized.
 430      */
 431     void checkInit(DiagnosticPosition pos, VarSymbol sym) {
 432         if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
 433             trackable(sym) &&
 434             !inits.isMember(sym.adr)) {
 435             log.error(pos, "var.might.not.have.been.initialized",
 436                       sym);
 437             inits.incl(sym.adr);
 438         }
 439     }
 440 
 441     /*-------------------- Handling jumps ----------------------*/
 442 
 443     /** Record an outward transfer of control. */
 444     void recordExit(JCTree tree) {
 445         pendingExits.append(new PendingExit(tree, inits, uninits));
 446         markDead();
 447     }
 448 
 449     /** Resolve all breaks of this statement. */
 450     boolean resolveBreaks(JCTree tree,
 451                           ListBuffer<PendingExit> oldPendingExits) {
 452         boolean result = false;
 453         List<PendingExit> exits = pendingExits.toList();
 454         pendingExits = oldPendingExits;
 455         for (; exits.nonEmpty(); exits = exits.tail) {
 456             PendingExit exit = exits.head;
 457             if (exit.tree.hasTag(BREAK) &&
 458                 ((JCBreak) exit.tree).target == tree) {
 459                 inits.andSet(exit.inits);
 460                 uninits.andSet(exit.uninits);
 461                 result = true;
 462             } else {
 463                 pendingExits.append(exit);
 464             }
 465         }
 466         return result;
 467     }
 468 
 469     /** Resolve all continues of this statement. */
 470     boolean resolveContinues(JCTree tree) {
 471         boolean result = false;
 472         List<PendingExit> exits = pendingExits.toList();
 473         pendingExits = new ListBuffer<PendingExit>();
 474         for (; exits.nonEmpty(); exits = exits.tail) {
 475             PendingExit exit = exits.head;
 476             if (exit.tree.hasTag(CONTINUE) &&
 477                 ((JCContinue) exit.tree).target == tree) {
 478                 inits.andSet(exit.inits);
 479                 uninits.andSet(exit.uninits);
 480                 result = true;
 481             } else {
 482                 pendingExits.append(exit);
 483             }
 484         }
 485         return result;
 486     }
 487 
 488     /** Record that statement is unreachable.
 489      */
 490     void markDead() {
 491         inits.inclRange(firstadr, nextadr);
 492         uninits.inclRange(firstadr, nextadr);
 493         alive = false;
 494     }
 495 
 496     /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets


 502         uninitsWhenTrue = uninits;
 503         if (setToNull)
 504             inits = uninits = null;
 505     }
 506 
 507     /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
 508      */
 509     void merge() {
 510         inits = initsWhenFalse.andSet(initsWhenTrue);
 511         uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
 512     }
 513 
 514 /* ************************************************************************
 515  * Visitor methods for statements and definitions
 516  *************************************************************************/
 517 
 518     /** Analyze a definition.
 519      */
 520     void scanDef(JCTree tree) {
 521         scanStat(tree);
 522         if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
 523             log.error(tree.pos(),
 524                       "initializer.must.be.able.to.complete.normally");
 525         }
 526     }
 527 
 528     /** Analyze a statement. Check that statement is reachable.
 529      */
 530     void scanStat(JCTree tree) {
 531         if (!alive && tree != null) {
 532             log.error(tree.pos(), "unreachable.stmt");
 533             if (!tree.hasTag(SKIP)) alive = true;
 534         }
 535         scan(tree);
 536     }
 537 
 538     /** Analyze list of statements.
 539      */
 540     void scanStats(List<? extends JCStatement> trees) {
 541         if (trees != null)
 542             for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
 543                 scanStat(l.head);
 544     }
 545 
 546     /** Analyze an expression. Make sure to set (un)inits rather than
 547      *  (un)initsWhenTrue(WhenFalse) on exit.
 548      */
 549     void scanExpr(JCTree tree) {
 550         if (tree != null) {
 551             scan(tree);
 552             if (inits == null) merge();
 553         }


 599         List<Type> thrownPrev = thrown;
 600         List<Type> caughtPrev = caught;
 601         boolean alivePrev = alive;
 602         int firstadrPrev = firstadr;
 603         int nextadrPrev = nextadr;
 604         ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 605         Lint lintPrev = lint;
 606 
 607         pendingExits = new ListBuffer<PendingExit>();
 608         if (tree.name != names.empty) {
 609             caught = List.nil();
 610             firstadr = nextadr;
 611         }
 612         classDef = tree;
 613         thrown = List.nil();
 614         lint = lint.augment(tree.sym.attributes_field);
 615 
 616         try {
 617             // define all the static fields
 618             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 619                 if (l.head.hasTag(VARDEF)) {
 620                     JCVariableDecl def = (JCVariableDecl)l.head;
 621                     if ((def.mods.flags & STATIC) != 0) {
 622                         VarSymbol sym = def.sym;
 623                         if (trackable(sym))
 624                             newVar(sym);
 625                     }
 626                 }
 627             }
 628 
 629             // process all the static initializers
 630             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 631                 if (!l.head.hasTag(METHODDEF) &&
 632                     (TreeInfo.flags(l.head) & STATIC) != 0) {
 633                     scanDef(l.head);
 634                     errorUncaught();
 635                 }
 636             }
 637 
 638             // add intersection of all thrown clauses of initial constructors
 639             // to set of caught exceptions, unless class is anonymous.
 640             if (tree.name != names.empty) {
 641                 boolean firstConstructor = true;
 642                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 643                     if (TreeInfo.isInitialConstructor(l.head)) {
 644                         List<Type> mthrown =
 645                             ((JCMethodDecl) l.head).sym.type.getThrownTypes();
 646                         if (firstConstructor) {
 647                             caught = mthrown;
 648                             firstConstructor = false;
 649                         } else {
 650                             caught = chk.intersect(mthrown, caught);
 651                         }
 652                     }
 653                 }
 654             }
 655 
 656             // define all the instance fields
 657             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 658                 if (l.head.hasTag(VARDEF)) {
 659                     JCVariableDecl def = (JCVariableDecl)l.head;
 660                     if ((def.mods.flags & STATIC) == 0) {
 661                         VarSymbol sym = def.sym;
 662                         if (trackable(sym))
 663                             newVar(sym);
 664                     }
 665                 }
 666             }
 667 
 668             // process all the instance initializers
 669             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 670                 if (!l.head.hasTag(METHODDEF) &&
 671                     (TreeInfo.flags(l.head) & STATIC) == 0) {
 672                     scanDef(l.head);
 673                     errorUncaught();
 674                 }
 675             }
 676 
 677             // in an anonymous class, add the set of thrown exceptions to
 678             // the throws clause of the synthetic constructor and propagate
 679             // outwards.
 680             // Changing the throws clause on the fly is okay here because
 681             // the anonymous constructor can't be invoked anywhere else,
 682             // and its type hasn't been cached.
 683             if (tree.name == names.empty) {
 684                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 685                     if (TreeInfo.isInitialConstructor(l.head)) {
 686                         JCMethodDecl mdef = (JCMethodDecl)l.head;
 687                         mdef.thrown = make.Types(thrown);
 688                         mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
 689                     }
 690                 }
 691                 thrownPrev = chk.union(thrown, thrownPrev);
 692             }
 693 
 694             // process all the methods
 695             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 696                 if (l.head.hasTag(METHODDEF)) {
 697                     scan(l.head);
 698                     errorUncaught();
 699                 }
 700             }
 701 
 702             thrown = thrownPrev;
 703         } finally {
 704             pendingExits = pendingExitsPrev;
 705             alive = alivePrev;
 706             nextadr = nextadrPrev;
 707             firstadr = firstadrPrev;
 708             caught = caughtPrev;
 709             classDef = classDefPrev;
 710             lint = lintPrev;
 711         }
 712     }
 713 
 714     public void visitMethodDef(JCMethodDecl tree) {
 715         if (tree.body == null) return;
 716 


 745             // else we are in an instance initializer block;
 746             // leave caught unchanged.
 747 
 748             alive = true;
 749             scanStat(tree.body);
 750 
 751             if (alive && tree.sym.type.getReturnType().tag != VOID)
 752                 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
 753 
 754             if (isInitialConstructor) {
 755                 for (int i = firstadr; i < nextadr; i++)
 756                     if (vars[i].owner == classDef.sym)
 757                         checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
 758             }
 759             List<PendingExit> exits = pendingExits.toList();
 760             pendingExits = new ListBuffer<PendingExit>();
 761             while (exits.nonEmpty()) {
 762                 PendingExit exit = exits.head;
 763                 exits = exits.tail;
 764                 if (exit.thrown == null) {
 765                     Assert.check(exit.tree.hasTag(RETURN));
 766                     if (isInitialConstructor) {
 767                         inits = exit.inits;
 768                         for (int i = firstadr; i < nextadr; i++)
 769                             checkInit(exit.tree.pos(), vars[i]);
 770                     }
 771                 } else {
 772                     // uncaught throws will be reported later
 773                     pendingExits.append(exit);
 774                 }
 775             }
 776         } finally {
 777             inits = initsPrev;
 778             uninits = uninitsPrev;
 779             nextadr = nextadrPrev;
 780             firstadr = firstadrPrev;
 781             caught = caughtPrev;
 782             lint = lintPrev;
 783         }
 784     }
 785 


 974                 alive &&
 975                 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
 976                 c.stats.nonEmpty() && l.tail.nonEmpty())
 977                 log.warning(Lint.LintCategory.FALLTHROUGH,
 978                             l.tail.head.pos(),
 979                             "possible.fall-through.into.case");
 980         }
 981         if (!hasDefault) {
 982             inits.andSet(initsSwitch);
 983             alive = true;
 984         }
 985         alive |= resolveBreaks(tree, prevPendingExits);
 986         nextadr = nextadrPrev;
 987     }
 988     // where
 989         /** Add any variables defined in stats to inits and uninits. */
 990         private static void addVars(List<JCStatement> stats, Bits inits,
 991                                     Bits uninits) {
 992             for (;stats.nonEmpty(); stats = stats.tail) {
 993                 JCTree stat = stats.head;
 994                 if (stat.hasTag(VARDEF)) {
 995                     int adr = ((JCVariableDecl) stat).sym.adr;
 996                     inits.excl(adr);
 997                     uninits.incl(adr);
 998                 }
 999             }
1000         }
1001 
1002     public void visitTry(JCTry tree) {
1003         List<Type> caughtPrev = caught;
1004         List<Type> thrownPrev = thrown;
1005         thrown = List.nil();
1006         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1007             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1008                     ((JCTypeUnion)l.head.param.vartype).alternatives :
1009                     List.of(l.head.param.vartype);
1010             for (JCExpression ct : subClauses) {
1011                 caught = chk.incl(ct.type, caught);
1012             }
1013         }
1014         ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();


1331         }
1332         inits = initsExit;
1333         uninits = uninitsExit;
1334     }
1335 
1336     public void visitAssign(JCAssign tree) {
1337         JCTree lhs = TreeInfo.skipParens(tree.lhs);
1338         if (!(lhs instanceof JCIdent)) scanExpr(lhs);
1339         scanExpr(tree.rhs);
1340         letInit(lhs);
1341     }
1342 
1343     public void visitAssignop(JCAssignOp tree) {
1344         scanExpr(tree.lhs);
1345         scanExpr(tree.rhs);
1346         letInit(tree.lhs);
1347     }
1348 
1349     public void visitUnary(JCUnary tree) {
1350         switch (tree.getTag()) {
1351         case NOT:
1352             scanCond(tree.arg);
1353             Bits t = initsWhenFalse;
1354             initsWhenFalse = initsWhenTrue;
1355             initsWhenTrue = t;
1356             t = uninitsWhenFalse;
1357             uninitsWhenFalse = uninitsWhenTrue;
1358             uninitsWhenTrue = t;
1359             break;
1360         case PREINC: case POSTINC:
1361         case PREDEC: case POSTDEC:
1362             scanExpr(tree.arg);
1363             letInit(tree.arg);
1364             break;
1365         default:
1366             scanExpr(tree.arg);
1367         }
1368     }
1369 
1370     public void visitBinary(JCBinary tree) {
1371         switch (tree.getTag()) {
1372         case AND:
1373             scanCond(tree.lhs);
1374             Bits initsWhenFalseLeft = initsWhenFalse;
1375             Bits uninitsWhenFalseLeft = uninitsWhenFalse;
1376             inits = initsWhenTrue;
1377             uninits = uninitsWhenTrue;
1378             scanCond(tree.rhs);
1379             initsWhenFalse.andSet(initsWhenFalseLeft);
1380             uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
1381             break;
1382         case OR:
1383             scanCond(tree.lhs);
1384             Bits initsWhenTrueLeft = initsWhenTrue;
1385             Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1386             inits = initsWhenFalse;
1387             uninits = uninitsWhenFalse;
1388             scanCond(tree.rhs);
1389             initsWhenTrue.andSet(initsWhenTrueLeft);
1390             uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1391             break;
1392         default:
1393             scanExpr(tree.lhs);
1394             scanExpr(tree.rhs);
1395         }
1396     }
1397 
1398     public void visitIdent(JCIdent tree) {
1399         if (tree.sym.kind == VAR) {
1400             checkInit(tree.pos(), (VarSymbol)tree.sym);
1401             referenced(tree.sym);
1402         }
1403     }
1404 
1405     void referenced(Symbol sym) {
1406         unrefdResources.remove(sym);
1407     }
1408 
1409     public void visitTypeCast(JCTypeCast tree) {
1410         super.visitTypeCast(tree);
1411         if (!tree.type.isErroneous()
1412             && lint.isEnabled(Lint.LintCategory.CAST)
1413             && types.isSameType(tree.expr.type, tree.clazz.type)
1414             && !is292targetTypeCast(tree)) {
1415             log.warning(Lint.LintCategory.CAST,
1416                     tree.pos(), "redundant.cast", tree.expr.type);
1417         }
1418     }
1419     //where
1420         private boolean is292targetTypeCast(JCTypeCast tree) {
1421             boolean is292targetTypeCast = false;
1422             JCExpression expr = TreeInfo.skipParens(tree.expr);
1423             if (expr.hasTag(APPLY)) {
1424                 JCMethodInvocation apply = (JCMethodInvocation)expr;
1425                 Symbol sym = TreeInfo.symbol(apply.meth);
1426                 is292targetTypeCast = sym != null &&
1427                     sym.kind == MTH &&
1428                     (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
1429             }
1430             return is292targetTypeCast;
1431         }
1432 
1433     public void visitTopLevel(JCCompilationUnit tree) {
1434         // Do nothing for TopLevel since each class is visited individually
1435     }
1436 
1437 /**************************************************************************
1438  * main method
1439  *************************************************************************/
1440 
1441     /** Perform definite assignment/unassignment analysis on a tree.
1442      */
1443     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {