langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
changeset 13439 3025d6ac1401
parent 13273 d597bc5e3935
child 13689 4d519199a6aa
equal deleted inserted replaced
13438:83729994273a 13439:3025d6ac1401
    41 import static com.sun.tools.javac.code.Flags.BLOCK;
    41 import static com.sun.tools.javac.code.Flags.BLOCK;
    42 import static com.sun.tools.javac.code.Kinds.*;
    42 import static com.sun.tools.javac.code.Kinds.*;
    43 import static com.sun.tools.javac.code.TypeTags.*;
    43 import static com.sun.tools.javac.code.TypeTags.*;
    44 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    44 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    45 
    45 
    46 /** This pass implements dataflow analysis for Java programs.
    46 /** This pass implements dataflow analysis for Java programs though
    47  *  Liveness analysis checks that every statement is reachable.
    47  *  different AST visitor steps. Liveness analysis (see AliveAlanyzer) checks that
    48  *  Exception analysis ensures that every checked exception that is
    48  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
    49  *  thrown is declared or caught.  Definite assignment analysis
    49  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
    50  *  ensures that each variable is assigned when used.  Definite
    50  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
    51  *  unassignment analysis ensures that no final variable is assigned
    51  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
    52  *  more than once.
    52  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
       
    53  *  determines that local variables accessed within the scope of an inner class are
       
    54  *  either final or effectively-final.
    53  *
    55  *
    54  *  <p>The JLS has a number of problems in the
    56  *  <p>The JLS has a number of problems in the
    55  *  specification of these flow analysis problems. This implementation
    57  *  specification of these flow analysis problems. This implementation
    56  *  attempts to address those issues.
    58  *  attempts to address those issues.
    57  *
    59  *
   186     private final Symtab syms;
   188     private final Symtab syms;
   187     private final Types types;
   189     private final Types types;
   188     private final Check chk;
   190     private final Check chk;
   189     private       TreeMaker make;
   191     private       TreeMaker make;
   190     private final Resolve rs;
   192     private final Resolve rs;
       
   193     private final JCDiagnostic.Factory diags;
   191     private Env<AttrContext> attrEnv;
   194     private Env<AttrContext> attrEnv;
   192     private       Lint lint;
   195     private       Lint lint;
   193     private final boolean allowImprovedRethrowAnalysis;
   196     private final boolean allowImprovedRethrowAnalysis;
   194     private final boolean allowImprovedCatchAnalysis;
   197     private final boolean allowImprovedCatchAnalysis;
       
   198     private final boolean allowEffectivelyFinalInInnerClasses;
   195 
   199 
   196     public static Flow instance(Context context) {
   200     public static Flow instance(Context context) {
   197         Flow instance = context.get(flowKey);
   201         Flow instance = context.get(flowKey);
   198         if (instance == null)
   202         if (instance == null)
   199             instance = new Flow(context);
   203             instance = new Flow(context);
   200         return instance;
   204         return instance;
   201     }
   205     }
   202 
   206 
   203     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   207     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
       
   208         new AliveAnalyzer().analyzeTree(env, make);
       
   209         new AssignAnalyzer().analyzeTree(env, make);
   204         new FlowAnalyzer().analyzeTree(env, make);
   210         new FlowAnalyzer().analyzeTree(env, make);
   205         new AssignAnalyzer().analyzeTree(env, make);
   211         new CaptureAnalyzer().analyzeTree(env, make);
       
   212     }
       
   213 
       
   214     /**
       
   215      * Definite assignment scan mode
       
   216      */
       
   217     enum FlowKind {
       
   218         /**
       
   219          * This is the normal DA/DU analysis mode
       
   220          */
       
   221         NORMAL("var.might.already.be.assigned", false),
       
   222         /**
       
   223          * This is the speculative DA/DU analysis mode used to speculatively
       
   224          * derive assertions within loop bodies
       
   225          */
       
   226         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
       
   227 
       
   228         String errKey;
       
   229         boolean isFinal;
       
   230 
       
   231         FlowKind(String errKey, boolean isFinal) {
       
   232             this.errKey = errKey;
       
   233             this.isFinal = isFinal;
       
   234         }
       
   235 
       
   236         boolean isFinal() {
       
   237             return isFinal;
       
   238         }
   206     }
   239     }
   207 
   240 
   208     protected Flow(Context context) {
   241     protected Flow(Context context) {
   209         context.put(flowKey, this);
   242         context.put(flowKey, this);
   210         names = Names.instance(context);
   243         names = Names.instance(context);
   212         syms = Symtab.instance(context);
   245         syms = Symtab.instance(context);
   213         types = Types.instance(context);
   246         types = Types.instance(context);
   214         chk = Check.instance(context);
   247         chk = Check.instance(context);
   215         lint = Lint.instance(context);
   248         lint = Lint.instance(context);
   216         rs = Resolve.instance(context);
   249         rs = Resolve.instance(context);
       
   250         diags = JCDiagnostic.Factory.instance(context);
   217         Source source = Source.instance(context);
   251         Source source = Source.instance(context);
   218         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   252         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   219         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   253         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
       
   254         Options options = Options.instance(context);
       
   255         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses() &&
       
   256                 options.isSet("allowEffectivelyFinalInInnerClasses"); //pre-lambda guard
   220     }
   257     }
   221 
   258 
   222     /**
   259     /**
   223      * Base visitor class for all visitors implementing dataflow analysis logic.
   260      * Base visitor class for all visitors implementing dataflow analysis logic.
   224      * This class define the shared logic for handling jumps (break/continue statements).
   261      * This class define the shared logic for handling jumps (break/continue statements).
   257          *  continue.  In addition, exception-throwing expressions or
   294          *  continue.  In addition, exception-throwing expressions or
   258          *  statements are put here when not known to be caught.  This
   295          *  statements are put here when not known to be caught.  This
   259          *  will typically result in an error unless it is within a
   296          *  will typically result in an error unless it is within a
   260          *  try-finally whose finally block cannot complete normally.
   297          *  try-finally whose finally block cannot complete normally.
   261          */
   298          */
   262         abstract static class PendingExit {
   299         static class PendingExit {
   263             JCTree tree;
   300             JCTree tree;
   264 
   301 
   265             PendingExit(JCTree tree) {
   302             PendingExit(JCTree tree) {
   266                 this.tree = tree;
   303                 this.tree = tree;
   267             }
   304             }
   268 
   305 
   269             abstract void resolveJump();
   306             void resolveJump() {
       
   307                 //do nothing
       
   308             }
   270         }
   309         }
   271 
   310 
   272         abstract void markDead();
   311         abstract void markDead();
   273 
   312 
   274         /** Record an outward transfer of control. */
   313         /** Record an outward transfer of control. */
   307             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   346             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   308         }
   347         }
   309     }
   348     }
   310 
   349 
   311     /**
   350     /**
   312      * This pass implements the first two steps of the dataflow analysis:
   351      * This pass implements the first step of the dataflow analysis, namely
   313      * (i) liveness analysis checks that every statement is reachable and (ii)
   352      * the liveness analysis check. This checks that every statement is reachable.
   314      *  exception analysis to ensure that every checked exception that is
   353      * The output of this analysis pass are used by other analyzers. This analyzer
   315      *  thrown is declared or caught.
   354      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
       
   355      */
       
   356     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
       
   357 
       
   358         /** A flag that indicates whether the last statement could
       
   359          *  complete normally.
       
   360          */
       
   361         private boolean alive;
       
   362 
       
   363         @Override
       
   364         void markDead() {
       
   365             alive = false;
       
   366         }
       
   367 
       
   368     /*************************************************************************
       
   369      * Visitor methods for statements and definitions
       
   370      *************************************************************************/
       
   371 
       
   372         /** Analyze a definition.
       
   373          */
       
   374         void scanDef(JCTree tree) {
       
   375             scanStat(tree);
       
   376             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
       
   377                 log.error(tree.pos(),
       
   378                           "initializer.must.be.able.to.complete.normally");
       
   379             }
       
   380         }
       
   381 
       
   382         /** Analyze a statement. Check that statement is reachable.
       
   383          */
       
   384         void scanStat(JCTree tree) {
       
   385             if (!alive && tree != null) {
       
   386                 log.error(tree.pos(), "unreachable.stmt");
       
   387                 if (!tree.hasTag(SKIP)) alive = true;
       
   388             }
       
   389             scan(tree);
       
   390         }
       
   391 
       
   392         /** Analyze list of statements.
       
   393          */
       
   394         void scanStats(List<? extends JCStatement> trees) {
       
   395             if (trees != null)
       
   396                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
       
   397                     scanStat(l.head);
       
   398         }
       
   399 
       
   400         /* ------------ Visitor methods for various sorts of trees -------------*/
       
   401 
       
   402         public void visitClassDef(JCClassDecl tree) {
       
   403             if (tree.sym == null) return;
       
   404             boolean alivePrev = alive;
       
   405             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
       
   406             Lint lintPrev = lint;
       
   407 
       
   408             pendingExits = new ListBuffer<PendingExit>();
       
   409             lint = lint.augment(tree.sym.attributes_field);
       
   410 
       
   411             try {
       
   412                 // process all the static initializers
       
   413                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
       
   414                     if (!l.head.hasTag(METHODDEF) &&
       
   415                         (TreeInfo.flags(l.head) & STATIC) != 0) {
       
   416                         scanDef(l.head);
       
   417                     }
       
   418                 }
       
   419 
       
   420                 // process all the instance initializers
       
   421                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
       
   422                     if (!l.head.hasTag(METHODDEF) &&
       
   423                         (TreeInfo.flags(l.head) & STATIC) == 0) {
       
   424                         scanDef(l.head);
       
   425                     }
       
   426                 }
       
   427 
       
   428                 // process all the methods
       
   429                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
       
   430                     if (l.head.hasTag(METHODDEF)) {
       
   431                         scan(l.head);
       
   432                     }
       
   433                 }
       
   434             } finally {
       
   435                 pendingExits = pendingExitsPrev;
       
   436                 alive = alivePrev;
       
   437                 lint = lintPrev;
       
   438             }
       
   439         }
       
   440 
       
   441         public void visitMethodDef(JCMethodDecl tree) {
       
   442             if (tree.body == null) return;
       
   443             Lint lintPrev = lint;
       
   444 
       
   445             lint = lint.augment(tree.sym.attributes_field);
       
   446 
       
   447             Assert.check(pendingExits.isEmpty());
       
   448 
       
   449             try {
       
   450                 alive = true;
       
   451                 scanStat(tree.body);
       
   452 
       
   453                 if (alive && tree.sym.type.getReturnType().tag != VOID)
       
   454                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
       
   455 
       
   456                 List<PendingExit> exits = pendingExits.toList();
       
   457                 pendingExits = new ListBuffer<PendingExit>();
       
   458                 while (exits.nonEmpty()) {
       
   459                     PendingExit exit = exits.head;
       
   460                     exits = exits.tail;
       
   461                     Assert.check(exit.tree.hasTag(RETURN));
       
   462                 }
       
   463             } finally {
       
   464                 lint = lintPrev;
       
   465             }
       
   466         }
       
   467 
       
   468         public void visitVarDef(JCVariableDecl tree) {
       
   469             if (tree.init != null) {
       
   470                 Lint lintPrev = lint;
       
   471                 lint = lint.augment(tree.sym.attributes_field);
       
   472                 try{
       
   473                     scan(tree.init);
       
   474                 } finally {
       
   475                     lint = lintPrev;
       
   476                 }
       
   477             }
       
   478         }
       
   479 
       
   480         public void visitBlock(JCBlock tree) {
       
   481             scanStats(tree.stats);
       
   482         }
       
   483 
       
   484         public void visitDoLoop(JCDoWhileLoop tree) {
       
   485             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   486             pendingExits = new ListBuffer<PendingExit>();
       
   487             scanStat(tree.body);
       
   488             alive |= resolveContinues(tree);
       
   489             scan(tree.cond);
       
   490             alive = alive && !tree.cond.type.isTrue();
       
   491             alive |= resolveBreaks(tree, prevPendingExits);
       
   492         }
       
   493 
       
   494         public void visitWhileLoop(JCWhileLoop tree) {
       
   495             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   496             pendingExits = new ListBuffer<PendingExit>();
       
   497             scan(tree.cond);
       
   498             alive = !tree.cond.type.isFalse();
       
   499             scanStat(tree.body);
       
   500             alive |= resolveContinues(tree);
       
   501             alive = resolveBreaks(tree, prevPendingExits) ||
       
   502                 !tree.cond.type.isTrue();
       
   503         }
       
   504 
       
   505         public void visitForLoop(JCForLoop tree) {
       
   506             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   507             scanStats(tree.init);
       
   508             pendingExits = new ListBuffer<PendingExit>();
       
   509             if (tree.cond != null) {
       
   510                 scan(tree.cond);
       
   511                 alive = !tree.cond.type.isFalse();
       
   512             } else {
       
   513                 alive = true;
       
   514             }
       
   515             scanStat(tree.body);
       
   516             alive |= resolveContinues(tree);
       
   517             scan(tree.step);
       
   518             alive = resolveBreaks(tree, prevPendingExits) ||
       
   519                 tree.cond != null && !tree.cond.type.isTrue();
       
   520         }
       
   521 
       
   522         public void visitForeachLoop(JCEnhancedForLoop tree) {
       
   523             visitVarDef(tree.var);
       
   524             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   525             scan(tree.expr);
       
   526             pendingExits = new ListBuffer<PendingExit>();
       
   527             scanStat(tree.body);
       
   528             alive |= resolveContinues(tree);
       
   529             resolveBreaks(tree, prevPendingExits);
       
   530             alive = true;
       
   531         }
       
   532 
       
   533         public void visitLabelled(JCLabeledStatement tree) {
       
   534             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   535             pendingExits = new ListBuffer<PendingExit>();
       
   536             scanStat(tree.body);
       
   537             alive |= resolveBreaks(tree, prevPendingExits);
       
   538         }
       
   539 
       
   540         public void visitSwitch(JCSwitch tree) {
       
   541             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   542             pendingExits = new ListBuffer<PendingExit>();
       
   543             scan(tree.selector);
       
   544             boolean hasDefault = false;
       
   545             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
       
   546                 alive = true;
       
   547                 JCCase c = l.head;
       
   548                 if (c.pat == null)
       
   549                     hasDefault = true;
       
   550                 else
       
   551                     scan(c.pat);
       
   552                 scanStats(c.stats);
       
   553                 // Warn about fall-through if lint switch fallthrough enabled.
       
   554                 if (alive &&
       
   555                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
       
   556                     c.stats.nonEmpty() && l.tail.nonEmpty())
       
   557                     log.warning(Lint.LintCategory.FALLTHROUGH,
       
   558                                 l.tail.head.pos(),
       
   559                                 "possible.fall-through.into.case");
       
   560             }
       
   561             if (!hasDefault) {
       
   562                 alive = true;
       
   563             }
       
   564             alive |= resolveBreaks(tree, prevPendingExits);
       
   565         }
       
   566 
       
   567         public void visitTry(JCTry tree) {
       
   568             ListBuffer<PendingExit> prevPendingExits = pendingExits;
       
   569             pendingExits = new ListBuffer<PendingExit>();
       
   570             for (JCTree resource : tree.resources) {
       
   571                 if (resource instanceof JCVariableDecl) {
       
   572                     JCVariableDecl vdecl = (JCVariableDecl) resource;
       
   573                     visitVarDef(vdecl);
       
   574                 } else if (resource instanceof JCExpression) {
       
   575                     scan((JCExpression) resource);
       
   576                 } else {
       
   577                     throw new AssertionError(tree);  // parser error
       
   578                 }
       
   579             }
       
   580 
       
   581             scanStat(tree.body);
       
   582             boolean aliveEnd = alive;
       
   583 
       
   584             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
       
   585                 alive = true;
       
   586                 JCVariableDecl param = l.head.param;
       
   587                 scan(param);
       
   588                 scanStat(l.head.body);
       
   589                 aliveEnd |= alive;
       
   590             }
       
   591             if (tree.finalizer != null) {
       
   592                 ListBuffer<PendingExit> exits = pendingExits;
       
   593                 pendingExits = prevPendingExits;
       
   594                 alive = true;
       
   595                 scanStat(tree.finalizer);
       
   596                 tree.finallyCanCompleteNormally = alive;
       
   597                 if (!alive) {
       
   598                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
       
   599                         log.warning(Lint.LintCategory.FINALLY,
       
   600                                 TreeInfo.diagEndPos(tree.finalizer),
       
   601                                 "finally.cannot.complete");
       
   602                     }
       
   603                 } else {
       
   604                     while (exits.nonEmpty()) {
       
   605                         pendingExits.append(exits.next());
       
   606                     }
       
   607                     alive = aliveEnd;
       
   608                 }
       
   609             } else {
       
   610                 alive = aliveEnd;
       
   611                 ListBuffer<PendingExit> exits = pendingExits;
       
   612                 pendingExits = prevPendingExits;
       
   613                 while (exits.nonEmpty()) pendingExits.append(exits.next());
       
   614             }
       
   615         }
       
   616 
       
   617         @Override
       
   618         public void visitIf(JCIf tree) {
       
   619             scan(tree.cond);
       
   620             scanStat(tree.thenpart);
       
   621             if (tree.elsepart != null) {
       
   622                 boolean aliveAfterThen = alive;
       
   623                 alive = true;
       
   624                 scanStat(tree.elsepart);
       
   625                 alive = alive | aliveAfterThen;
       
   626             } else {
       
   627                 alive = true;
       
   628             }
       
   629         }
       
   630 
       
   631         public void visitBreak(JCBreak tree) {
       
   632             recordExit(tree, new PendingExit(tree));
       
   633         }
       
   634 
       
   635         public void visitContinue(JCContinue tree) {
       
   636             recordExit(tree, new PendingExit(tree));
       
   637         }
       
   638 
       
   639         public void visitReturn(JCReturn tree) {
       
   640             scan(tree.expr);
       
   641             recordExit(tree, new PendingExit(tree));
       
   642         }
       
   643 
       
   644         public void visitThrow(JCThrow tree) {
       
   645             scan(tree.expr);
       
   646             markDead();
       
   647         }
       
   648 
       
   649         public void visitApply(JCMethodInvocation tree) {
       
   650             scan(tree.meth);
       
   651             scan(tree.args);
       
   652         }
       
   653 
       
   654         public void visitNewClass(JCNewClass tree) {
       
   655             scan(tree.encl);
       
   656             scan(tree.args);
       
   657             if (tree.def != null) {
       
   658                 scan(tree.def);
       
   659             }
       
   660         }
       
   661 
       
   662         public void visitTopLevel(JCCompilationUnit tree) {
       
   663             // Do nothing for TopLevel since each class is visited individually
       
   664         }
       
   665 
       
   666     /**************************************************************************
       
   667      * main method
       
   668      *************************************************************************/
       
   669 
       
   670         /** Perform definite assignment/unassignment analysis on a tree.
       
   671          */
       
   672         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
       
   673             try {
       
   674                 attrEnv = env;
       
   675                 Flow.this.make = make;
       
   676                 pendingExits = new ListBuffer<PendingExit>();
       
   677                 alive = true;
       
   678                 scan(env.tree);
       
   679             } finally {
       
   680                 pendingExits = null;
       
   681                 Flow.this.make = null;
       
   682             }
       
   683         }
       
   684     }
       
   685 
       
   686     /**
       
   687      * This pass implements the second step of the dataflow analysis, namely
       
   688      * the exception analysis. This is to ensure that every checked exception that is
       
   689      * thrown is declared or caught. The analyzer uses some info that has been set by
       
   690      * the liveliness analyzer.
   316      */
   691      */
   317     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   692     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   318 
   693 
   319         /** A flag that indicates whether the last statement could
   694         /** A flag that indicates whether the last statement could
   320          *  complete normally.
   695          *  complete normally.
   321          */
   696          */
   322         private boolean alive;
       
   323 
       
   324         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   697         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   325 
   698 
   326         /** The current class being defined.
   699         /** The current class being defined.
   327          */
   700          */
   328         JCClassDecl classDef;
   701         JCClassDecl classDef;
   342 
   715 
   343             FlowPendingExit(JCTree tree, Type thrown) {
   716             FlowPendingExit(JCTree tree, Type thrown) {
   344                 super(tree);
   717                 super(tree);
   345                 this.thrown = thrown;
   718                 this.thrown = thrown;
   346             }
   719             }
   347 
       
   348             void resolveJump() { /*do nothing*/ }
       
   349         }
   720         }
   350 
   721 
   351         @Override
   722         @Override
   352         void markDead() {
   723         void markDead() {
   353             alive = false;
   724             //do nothing
   354         }
   725         }
   355 
   726 
   356         /*-------------------- Exceptions ----------------------*/
   727         /*-------------------- Exceptions ----------------------*/
   357 
   728 
   358         /** Complain that pending exceptions are not caught.
   729         /** Complain that pending exceptions are not caught.
   393 
   764 
   394     /*************************************************************************
   765     /*************************************************************************
   395      * Visitor methods for statements and definitions
   766      * Visitor methods for statements and definitions
   396      *************************************************************************/
   767      *************************************************************************/
   397 
   768 
   398         /** Analyze a definition.
       
   399          */
       
   400         void scanDef(JCTree tree) {
       
   401             scanStat(tree);
       
   402             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
       
   403                 log.error(tree.pos(),
       
   404                           "initializer.must.be.able.to.complete.normally");
       
   405             }
       
   406         }
       
   407 
       
   408         /** Analyze a statement. Check that statement is reachable.
       
   409          */
       
   410         void scanStat(JCTree tree) {
       
   411             if (!alive && tree != null) {
       
   412                 log.error(tree.pos(), "unreachable.stmt");
       
   413                 if (!tree.hasTag(SKIP)) alive = true;
       
   414             }
       
   415             scan(tree);
       
   416         }
       
   417 
       
   418         /** Analyze list of statements.
       
   419          */
       
   420         void scanStats(List<? extends JCStatement> trees) {
       
   421             if (trees != null)
       
   422                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
       
   423                     scanStat(l.head);
       
   424         }
       
   425 
       
   426         /* ------------ Visitor methods for various sorts of trees -------------*/
   769         /* ------------ Visitor methods for various sorts of trees -------------*/
   427 
   770 
   428         public void visitClassDef(JCClassDecl tree) {
   771         public void visitClassDef(JCClassDecl tree) {
   429             if (tree.sym == null) return;
   772             if (tree.sym == null) return;
   430 
   773 
   431             JCClassDecl classDefPrev = classDef;
   774             JCClassDecl classDefPrev = classDef;
   432             List<Type> thrownPrev = thrown;
   775             List<Type> thrownPrev = thrown;
   433             List<Type> caughtPrev = caught;
   776             List<Type> caughtPrev = caught;
   434             boolean alivePrev = alive;
       
   435             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   777             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   436             Lint lintPrev = lint;
   778             Lint lintPrev = lint;
   437 
   779 
   438             pendingExits = new ListBuffer<FlowPendingExit>();
   780             pendingExits = new ListBuffer<FlowPendingExit>();
   439             if (tree.name != names.empty) {
   781             if (tree.name != names.empty) {
   446             try {
   788             try {
   447                 // process all the static initializers
   789                 // process all the static initializers
   448                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   790                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   449                     if (!l.head.hasTag(METHODDEF) &&
   791                     if (!l.head.hasTag(METHODDEF) &&
   450                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   792                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   451                         scanDef(l.head);
   793                         scan(l.head);
   452                         errorUncaught();
   794                         errorUncaught();
   453                     }
   795                     }
   454                 }
   796                 }
   455 
   797 
   456                 // add intersection of all thrown clauses of initial constructors
   798                 // add intersection of all thrown clauses of initial constructors
   473 
   815 
   474                 // process all the instance initializers
   816                 // process all the instance initializers
   475                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   817                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   476                     if (!l.head.hasTag(METHODDEF) &&
   818                     if (!l.head.hasTag(METHODDEF) &&
   477                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   819                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   478                         scanDef(l.head);
   820                         scan(l.head);
   479                         errorUncaught();
   821                         errorUncaught();
   480                     }
   822                     }
   481                 }
   823                 }
   482 
   824 
   483                 // in an anonymous class, add the set of thrown exceptions to
   825                 // in an anonymous class, add the set of thrown exceptions to
   506                 }
   848                 }
   507 
   849 
   508                 thrown = thrownPrev;
   850                 thrown = thrownPrev;
   509             } finally {
   851             } finally {
   510                 pendingExits = pendingExitsPrev;
   852                 pendingExits = pendingExitsPrev;
   511                 alive = alivePrev;
       
   512                 caught = caughtPrev;
   853                 caught = caughtPrev;
   513                 classDef = classDefPrev;
   854                 classDef = classDefPrev;
   514                 lint = lintPrev;
   855                 lint = lintPrev;
   515             }
   856             }
   516         }
   857         }
   536                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   877                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   537                     caught = mthrown;
   878                     caught = mthrown;
   538                 // else we are in an instance initializer block;
   879                 // else we are in an instance initializer block;
   539                 // leave caught unchanged.
   880                 // leave caught unchanged.
   540 
   881 
   541                 alive = true;
   882                 scan(tree.body);
   542                 scanStat(tree.body);
       
   543 
       
   544                 if (alive && tree.sym.type.getReturnType().tag != VOID)
       
   545                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
       
   546 
   883 
   547                 List<FlowPendingExit> exits = pendingExits.toList();
   884                 List<FlowPendingExit> exits = pendingExits.toList();
   548                 pendingExits = new ListBuffer<FlowPendingExit>();
   885                 pendingExits = new ListBuffer<FlowPendingExit>();
   549                 while (exits.nonEmpty()) {
   886                 while (exits.nonEmpty()) {
   550                     FlowPendingExit exit = exits.head;
   887                     FlowPendingExit exit = exits.head;
   573                 }
   910                 }
   574             }
   911             }
   575         }
   912         }
   576 
   913 
   577         public void visitBlock(JCBlock tree) {
   914         public void visitBlock(JCBlock tree) {
   578             scanStats(tree.stats);
   915             scan(tree.stats);
   579         }
   916         }
   580 
   917 
   581         public void visitDoLoop(JCDoWhileLoop tree) {
   918         public void visitDoLoop(JCDoWhileLoop tree) {
   582             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   919             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   583             pendingExits = new ListBuffer<FlowPendingExit>();
   920             pendingExits = new ListBuffer<FlowPendingExit>();
   584             scanStat(tree.body);
   921             scan(tree.body);
   585             alive |= resolveContinues(tree);
   922             resolveContinues(tree);
   586             scan(tree.cond);
   923             scan(tree.cond);
   587             alive = alive && !tree.cond.type.isTrue();
   924             resolveBreaks(tree, prevPendingExits);
   588             alive |= resolveBreaks(tree, prevPendingExits);
       
   589         }
   925         }
   590 
   926 
   591         public void visitWhileLoop(JCWhileLoop tree) {
   927         public void visitWhileLoop(JCWhileLoop tree) {
   592             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   928             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   593             pendingExits = new ListBuffer<FlowPendingExit>();
   929             pendingExits = new ListBuffer<FlowPendingExit>();
   594             scan(tree.cond);
   930             scan(tree.cond);
   595             alive = !tree.cond.type.isFalse();
   931             scan(tree.body);
   596             scanStat(tree.body);
   932             resolveContinues(tree);
   597             alive |= resolveContinues(tree);
   933             resolveBreaks(tree, prevPendingExits);
   598             alive = resolveBreaks(tree, prevPendingExits) ||
       
   599                 !tree.cond.type.isTrue();
       
   600         }
   934         }
   601 
   935 
   602         public void visitForLoop(JCForLoop tree) {
   936         public void visitForLoop(JCForLoop tree) {
   603             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   937             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   604             scanStats(tree.init);
   938             scan(tree.init);
   605             pendingExits = new ListBuffer<FlowPendingExit>();
   939             pendingExits = new ListBuffer<FlowPendingExit>();
   606             if (tree.cond != null) {
   940             if (tree.cond != null) {
   607                 scan(tree.cond);
   941                 scan(tree.cond);
   608                 alive = !tree.cond.type.isFalse();
   942             }
   609             } else {
   943             scan(tree.body);
   610                 alive = true;
   944             resolveContinues(tree);
   611             }
       
   612             scanStat(tree.body);
       
   613             alive |= resolveContinues(tree);
       
   614             scan(tree.step);
   945             scan(tree.step);
   615             alive = resolveBreaks(tree, prevPendingExits) ||
   946             resolveBreaks(tree, prevPendingExits);
   616                 tree.cond != null && !tree.cond.type.isTrue();
       
   617         }
   947         }
   618 
   948 
   619         public void visitForeachLoop(JCEnhancedForLoop tree) {
   949         public void visitForeachLoop(JCEnhancedForLoop tree) {
   620             visitVarDef(tree.var);
   950             visitVarDef(tree.var);
   621             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   951             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   622             scan(tree.expr);
   952             scan(tree.expr);
   623             pendingExits = new ListBuffer<FlowPendingExit>();
   953             pendingExits = new ListBuffer<FlowPendingExit>();
   624             scanStat(tree.body);
   954             scan(tree.body);
   625             alive |= resolveContinues(tree);
   955             resolveContinues(tree);
   626             resolveBreaks(tree, prevPendingExits);
   956             resolveBreaks(tree, prevPendingExits);
   627             alive = true;
       
   628         }
   957         }
   629 
   958 
   630         public void visitLabelled(JCLabeledStatement tree) {
   959         public void visitLabelled(JCLabeledStatement tree) {
   631             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   960             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   632             pendingExits = new ListBuffer<FlowPendingExit>();
   961             pendingExits = new ListBuffer<FlowPendingExit>();
   633             scanStat(tree.body);
   962             scan(tree.body);
   634             alive |= resolveBreaks(tree, prevPendingExits);
   963             resolveBreaks(tree, prevPendingExits);
   635         }
   964         }
   636 
   965 
   637         public void visitSwitch(JCSwitch tree) {
   966         public void visitSwitch(JCSwitch tree) {
   638             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   967             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   639             pendingExits = new ListBuffer<FlowPendingExit>();
   968             pendingExits = new ListBuffer<FlowPendingExit>();
   640             scan(tree.selector);
   969             scan(tree.selector);
   641             boolean hasDefault = false;
       
   642             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   970             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   643                 alive = true;
       
   644                 JCCase c = l.head;
   971                 JCCase c = l.head;
   645                 if (c.pat == null)
   972                 if (c.pat != null) {
   646                     hasDefault = true;
       
   647                 else
       
   648                     scan(c.pat);
   973                     scan(c.pat);
   649                 scanStats(c.stats);
   974                 }
   650                 // Warn about fall-through if lint switch fallthrough enabled.
   975                 scan(c.stats);
   651                 if (alive &&
   976             }
   652                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   977             resolveBreaks(tree, prevPendingExits);
   653                     c.stats.nonEmpty() && l.tail.nonEmpty())
       
   654                     log.warning(Lint.LintCategory.FALLTHROUGH,
       
   655                                 l.tail.head.pos(),
       
   656                                 "possible.fall-through.into.case");
       
   657             }
       
   658             if (!hasDefault) {
       
   659                 alive = true;
       
   660             }
       
   661             alive |= resolveBreaks(tree, prevPendingExits);
       
   662         }
   978         }
   663 
   979 
   664         public void visitTry(JCTry tree) {
   980         public void visitTry(JCTry tree) {
   665             List<Type> caughtPrev = caught;
   981             List<Type> caughtPrev = caught;
   666             List<Type> thrownPrev = thrown;
   982             List<Type> thrownPrev = thrown;
   704                             }
  1020                             }
   705                         }
  1021                         }
   706                     }
  1022                     }
   707                 }
  1023                 }
   708             }
  1024             }
   709             scanStat(tree.body);
  1025             scan(tree.body);
   710             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1026             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
   711                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1027                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
   712                 thrown;
  1028                 thrown;
   713             thrown = thrownPrev;
  1029             thrown = thrownPrev;
   714             caught = caughtPrev;
  1030             caught = caughtPrev;
   715             boolean aliveEnd = alive;
       
   716 
  1031 
   717             List<Type> caughtInTry = List.nil();
  1032             List<Type> caughtInTry = List.nil();
   718             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1033             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   719                 alive = true;
       
   720                 JCVariableDecl param = l.head.param;
  1034                 JCVariableDecl param = l.head.param;
   721                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1035                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
   722                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1036                         ((JCTypeUnion)l.head.param.vartype).alternatives :
   723                         List.of(l.head.param.vartype);
  1037                         List.of(l.head.param.vartype);
   724                 List<Type> ctypes = List.nil();
  1038                 List<Type> ctypes = List.nil();
   733                         caughtInTry = chk.incl(exc, caughtInTry);
  1047                         caughtInTry = chk.incl(exc, caughtInTry);
   734                     }
  1048                     }
   735                 }
  1049                 }
   736                 scan(param);
  1050                 scan(param);
   737                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1051                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
   738                 scanStat(l.head.body);
  1052                 scan(l.head.body);
   739                 preciseRethrowTypes.remove(param.sym);
  1053                 preciseRethrowTypes.remove(param.sym);
   740                 aliveEnd |= alive;
       
   741             }
  1054             }
   742             if (tree.finalizer != null) {
  1055             if (tree.finalizer != null) {
   743                 List<Type> savedThrown = thrown;
  1056                 List<Type> savedThrown = thrown;
   744                 thrown = List.nil();
  1057                 thrown = List.nil();
   745                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1058                 ListBuffer<FlowPendingExit> exits = pendingExits;
   746                 pendingExits = prevPendingExits;
  1059                 pendingExits = prevPendingExits;
   747                 alive = true;
  1060                 scan(tree.finalizer);
   748                 scanStat(tree.finalizer);
  1061                 if (!tree.finallyCanCompleteNormally) {
   749                 tree.finallyCanCompleteNormally = alive;
       
   750                 if (!alive) {
       
   751                     // discard exits and exceptions from try and finally
  1062                     // discard exits and exceptions from try and finally
   752                     thrown = chk.union(thrown, thrownPrev);
  1063                     thrown = chk.union(thrown, thrownPrev);
   753                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
       
   754                         log.warning(Lint.LintCategory.FINALLY,
       
   755                                 TreeInfo.diagEndPos(tree.finalizer),
       
   756                                 "finally.cannot.complete");
       
   757                     }
       
   758                 } else {
  1064                 } else {
   759                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1065                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
   760                     thrown = chk.union(thrown, savedThrown);
  1066                     thrown = chk.union(thrown, savedThrown);
   761                     // FIX: this doesn't preserve source order of exits in catch
  1067                     // FIX: this doesn't preserve source order of exits in catch
   762                     // versus finally!
  1068                     // versus finally!
   763                     while (exits.nonEmpty()) {
  1069                     while (exits.nonEmpty()) {
   764                         pendingExits.append(exits.next());
  1070                         pendingExits.append(exits.next());
   765                     }
  1071                     }
   766                     alive = aliveEnd;
       
   767                 }
  1072                 }
   768             } else {
  1073             } else {
   769                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1074                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
   770                 alive = aliveEnd;
       
   771                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1075                 ListBuffer<FlowPendingExit> exits = pendingExits;
   772                 pendingExits = prevPendingExits;
  1076                 pendingExits = prevPendingExits;
   773                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1077                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   774             }
  1078             }
   775         }
  1079         }
   776 
  1080 
   777         @Override
  1081         @Override
   778         public void visitIf(JCIf tree) {
  1082         public void visitIf(JCIf tree) {
   779             scan(tree.cond);
  1083             scan(tree.cond);
   780             scanStat(tree.thenpart);
  1084             scan(tree.thenpart);
   781             if (tree.elsepart != null) {
  1085             if (tree.elsepart != null) {
   782                 boolean aliveAfterThen = alive;
  1086                 scan(tree.elsepart);
   783                 alive = true;
       
   784                 scanStat(tree.elsepart);
       
   785                 alive = alive | aliveAfterThen;
       
   786             } else {
       
   787                 alive = true;
       
   788             }
  1087             }
   789         }
  1088         }
   790 
  1089 
   791         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1090         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
   792             if (chk.subset(exc, caughtInTry)) {
  1091             if (chk.subset(exc, caughtInTry)) {
   824             recordExit(tree, new FlowPendingExit(tree, null));
  1123             recordExit(tree, new FlowPendingExit(tree, null));
   825         }
  1124         }
   826 
  1125 
   827         public void visitReturn(JCReturn tree) {
  1126         public void visitReturn(JCReturn tree) {
   828             scan(tree.expr);
  1127             scan(tree.expr);
   829             // if not initial constructor, should markDead instead of recordExit
       
   830             recordExit(tree, new FlowPendingExit(tree, null));
  1128             recordExit(tree, new FlowPendingExit(tree, null));
   831         }
  1129         }
   832 
  1130 
   833         public void visitThrow(JCThrow tree) {
  1131         public void visitThrow(JCThrow tree) {
   834             scan(tree.expr);
  1132             scan(tree.expr);
   896      *************************************************************************/
  1194      *************************************************************************/
   897 
  1195 
   898         /** Perform definite assignment/unassignment analysis on a tree.
  1196         /** Perform definite assignment/unassignment analysis on a tree.
   899          */
  1197          */
   900         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1198         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
       
  1199             analyzeTree(env, env.tree, make);
       
  1200         }
       
  1201         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   901             try {
  1202             try {
   902                 attrEnv = env;
  1203                 attrEnv = env;
   903                 JCTree tree = env.tree;
       
   904                 Flow.this.make = make;
  1204                 Flow.this.make = make;
   905                 pendingExits = new ListBuffer<FlowPendingExit>();
  1205                 pendingExits = new ListBuffer<FlowPendingExit>();
   906                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1206                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
   907                 alive = true;
       
   908                 this.thrown = this.caught = null;
  1207                 this.thrown = this.caught = null;
   909                 this.classDef = null;
  1208                 this.classDef = null;
   910                 scan(tree);
  1209                 scan(tree);
   911             } finally {
  1210             } finally {
   912                 pendingExits = null;
  1211                 pendingExits = null;
   919 
  1218 
   920     /**
  1219     /**
   921      * This pass implements (i) definite assignment analysis, which ensures that
  1220      * This pass implements (i) definite assignment analysis, which ensures that
   922      * each variable is assigned when used and (ii) definite unassignment analysis,
  1221      * each variable is assigned when used and (ii) definite unassignment analysis,
   923      * which ensures that no final variable is assigned more than once. This visitor
  1222      * which ensures that no final variable is assigned more than once. This visitor
   924      * depends on the results of the liveliness analyzer.
  1223      * depends on the results of the liveliness analyzer. This pass is also used to mark
       
  1224      * effectively-final local variables/parameters.
   925      */
  1225      */
   926     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1226     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
   927 
  1227 
   928         /** The set of definitely assigned variables.
  1228         /** The set of definitely assigned variables.
   929          */
  1229          */
   970         /** The list of unreferenced automatic resources.
  1270         /** The list of unreferenced automatic resources.
   971          */
  1271          */
   972         Scope unrefdResources;
  1272         Scope unrefdResources;
   973 
  1273 
   974         /** Set when processing a loop body the second time for DU analysis. */
  1274         /** Set when processing a loop body the second time for DU analysis. */
   975         boolean loopPassTwo = false;
  1275         FlowKind flowKind = FlowKind.NORMAL;
       
  1276 
       
  1277         /** The starting position of the analysed tree */
       
  1278         int startPos;
   976 
  1279 
   977         class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1280         class AssignPendingExit extends BaseAnalyzer.PendingExit {
   978 
  1281 
   979             Bits exit_inits;
  1282             Bits exit_inits;
   980             Bits exit_uninits;
  1283             Bits exit_uninits;
  1002         /** Do we need to track init/uninit state of this symbol?
  1305         /** Do we need to track init/uninit state of this symbol?
  1003          *  I.e. is symbol either a local or a blank final variable?
  1306          *  I.e. is symbol either a local or a blank final variable?
  1004          */
  1307          */
  1005         boolean trackable(VarSymbol sym) {
  1308         boolean trackable(VarSymbol sym) {
  1006             return
  1309             return
  1007                 (sym.owner.kind == MTH ||
  1310                 sym.pos >= startPos &&
       
  1311                 ((sym.owner.kind == MTH ||
  1008                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1312                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1009                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
  1313                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
  1010         }
  1314         }
  1011 
  1315 
  1012         /** Initialize new trackable variable by setting its address field
  1316         /** Initialize new trackable variable by setting its address field
  1013          *  to the next available sequence number and entering it under that
  1317          *  to the next available sequence number and entering it under that
  1014          *  index into the vars array.
  1318          *  index into the vars array.
  1017             if (nextadr == vars.length) {
  1321             if (nextadr == vars.length) {
  1018                 VarSymbol[] newvars = new VarSymbol[nextadr * 2];
  1322                 VarSymbol[] newvars = new VarSymbol[nextadr * 2];
  1019                 System.arraycopy(vars, 0, newvars, 0, nextadr);
  1323                 System.arraycopy(vars, 0, newvars, 0, nextadr);
  1020                 vars = newvars;
  1324                 vars = newvars;
  1021             }
  1325             }
       
  1326             if ((sym.flags() & FINAL) == 0) {
       
  1327                 sym.flags_field |= EFFECTIVELY_FINAL;
       
  1328             }
  1022             sym.adr = nextadr;
  1329             sym.adr = nextadr;
  1023             vars[nextadr] = sym;
  1330             vars[nextadr] = sym;
  1024             inits.excl(nextadr);
  1331             inits.excl(nextadr);
  1025             uninits.incl(nextadr);
  1332             uninits.incl(nextadr);
  1026             nextadr++;
  1333             nextadr++;
  1028 
  1335 
  1029         /** Record an initialization of a trackable variable.
  1336         /** Record an initialization of a trackable variable.
  1030          */
  1337          */
  1031         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1338         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1032             if (sym.adr >= firstadr && trackable(sym)) {
  1339             if (sym.adr >= firstadr && trackable(sym)) {
  1033                 if ((sym.flags() & FINAL) != 0) {
  1340                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
       
  1341                     if (!uninits.isMember(sym.adr)) {
       
  1342                         //assignment targeting an effectively final variable
       
  1343                         //makes the variable lose its status of effectively final
       
  1344                         //if the variable is _not_ definitively unassigned
       
  1345                         sym.flags_field &= ~EFFECTIVELY_FINAL;
       
  1346                     } else {
       
  1347                         uninit(sym);
       
  1348                     }
       
  1349                 }
       
  1350                 else if ((sym.flags() & FINAL) != 0) {
  1034                     if ((sym.flags() & PARAMETER) != 0) {
  1351                     if ((sym.flags() & PARAMETER) != 0) {
  1035                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1352                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1036                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1353                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1037                                       sym);
  1354                                       sym);
  1038                         }
  1355                         }
  1039                         else {
  1356                         else {
  1040                             log.error(pos, "final.parameter.may.not.be.assigned",
  1357                             log.error(pos, "final.parameter.may.not.be.assigned",
  1041                                   sym);
  1358                                   sym);
  1042                         }
  1359                         }
  1043                     } else if (!uninits.isMember(sym.adr)) {
  1360                     } else if (!uninits.isMember(sym.adr)) {
  1044                         log.error(pos,
  1361                         log.error(pos, flowKind.errKey, sym);
  1045                                   loopPassTwo
       
  1046                                   ? "var.might.be.assigned.in.loop"
       
  1047                                   : "var.might.already.be.assigned",
       
  1048                                   sym);
       
  1049                     } else if (!inits.isMember(sym.adr)) {
       
  1050                         // reachable assignment
       
  1051                         uninits.excl(sym.adr);
       
  1052                         uninitsTry.excl(sym.adr);
       
  1053                     } else {
  1362                     } else {
  1054                         //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1363                         uninit(sym);
  1055                         uninits.excl(sym.adr);
       
  1056                     }
  1364                     }
  1057                 }
  1365                 }
  1058                 inits.incl(sym.adr);
  1366                 inits.incl(sym.adr);
  1059             } else if ((sym.flags() & FINAL) != 0) {
  1367             } else if ((sym.flags() & FINAL) != 0) {
  1060                 log.error(pos, "var.might.already.be.assigned", sym);
  1368                 log.error(pos, "var.might.already.be.assigned", sym);
  1061             }
  1369             }
  1062         }
  1370         }
       
  1371         //where
       
  1372             void uninit(VarSymbol sym) {
       
  1373                 if (!inits.isMember(sym.adr)) {
       
  1374                     // reachable assignment
       
  1375                     uninits.excl(sym.adr);
       
  1376                     uninitsTry.excl(sym.adr);
       
  1377                 } else {
       
  1378                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
       
  1379                     uninits.excl(sym.adr);
       
  1380                 }
       
  1381             }
  1063 
  1382 
  1064         /** If tree is either a simple name or of the form this.name or
  1383         /** If tree is either a simple name or of the form this.name or
  1065          *  C.this.name, and tree represents a trackable variable,
  1384          *  C.this.name, and tree represents a trackable variable,
  1066          *  record an initialization of the variable.
  1385          *  record an initialization of the variable.
  1067          */
  1386          */
  1306             nextadr = nextadrPrev;
  1625             nextadr = nextadrPrev;
  1307         }
  1626         }
  1308 
  1627 
  1309         public void visitDoLoop(JCDoWhileLoop tree) {
  1628         public void visitDoLoop(JCDoWhileLoop tree) {
  1310             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1629             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1311             boolean prevLoopPassTwo = loopPassTwo;
  1630             FlowKind prevFlowKind = flowKind;
       
  1631             flowKind = FlowKind.NORMAL;
       
  1632             Bits initsSkip = null;
       
  1633             Bits uninitsSkip = null;
  1312             pendingExits = new ListBuffer<AssignPendingExit>();
  1634             pendingExits = new ListBuffer<AssignPendingExit>();
  1313             int prevErrors = log.nerrors;
  1635             int prevErrors = log.nerrors;
  1314             do {
  1636             do {
  1315                 Bits uninitsEntry = uninits.dup();
  1637                 Bits uninitsEntry = uninits.dup();
  1316                 uninitsEntry.excludeFrom(nextadr);
  1638                 uninitsEntry.excludeFrom(nextadr);
  1317             scan(tree.body);
  1639                 scan(tree.body);
  1318             resolveContinues(tree);
  1640                 resolveContinues(tree);
  1319                 scanCond(tree.cond);
  1641                 scanCond(tree.cond);
       
  1642                 if (!flowKind.isFinal()) {
       
  1643                     initsSkip = initsWhenFalse;
       
  1644                     uninitsSkip = uninitsWhenFalse;
       
  1645                 }
  1320                 if (log.nerrors !=  prevErrors ||
  1646                 if (log.nerrors !=  prevErrors ||
  1321                     loopPassTwo ||
  1647                     flowKind.isFinal() ||
  1322                     uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1648                     uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1323                     break;
  1649                     break;
  1324                 inits = initsWhenTrue;
  1650                 inits = initsWhenTrue;
  1325                 uninits = uninitsEntry.andSet(uninitsWhenTrue);
  1651                 uninits = uninitsEntry.andSet(uninitsWhenTrue);
  1326                 loopPassTwo = true;
  1652                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1327             } while (true);
  1653             } while (true);
  1328             loopPassTwo = prevLoopPassTwo;
  1654             flowKind = prevFlowKind;
  1329             inits = initsWhenFalse;
  1655             inits = initsSkip;
  1330             uninits = uninitsWhenFalse;
  1656             uninits = uninitsSkip;
  1331             resolveBreaks(tree, prevPendingExits);
  1657             resolveBreaks(tree, prevPendingExits);
  1332         }
  1658         }
  1333 
  1659 
  1334         public void visitWhileLoop(JCWhileLoop tree) {
  1660         public void visitWhileLoop(JCWhileLoop tree) {
  1335             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1661             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1336             boolean prevLoopPassTwo = loopPassTwo;
  1662             FlowKind prevFlowKind = flowKind;
  1337             Bits initsCond;
  1663             flowKind = FlowKind.NORMAL;
  1338             Bits uninitsCond;
  1664             Bits initsSkip = null;
       
  1665             Bits uninitsSkip = null;
  1339             pendingExits = new ListBuffer<AssignPendingExit>();
  1666             pendingExits = new ListBuffer<AssignPendingExit>();
  1340             int prevErrors = log.nerrors;
  1667             int prevErrors = log.nerrors;
       
  1668             Bits uninitsEntry = uninits.dup();
       
  1669             uninitsEntry.excludeFrom(nextadr);
  1341             do {
  1670             do {
  1342                 Bits uninitsEntry = uninits.dup();
       
  1343                 uninitsEntry.excludeFrom(nextadr);
       
  1344                 scanCond(tree.cond);
  1671                 scanCond(tree.cond);
  1345                 initsCond = initsWhenFalse;
  1672                 if (!flowKind.isFinal()) {
  1346                 uninitsCond = uninitsWhenFalse;
  1673                     initsSkip = initsWhenFalse;
       
  1674                     uninitsSkip = uninitsWhenFalse;
       
  1675                 }
  1347                 inits = initsWhenTrue;
  1676                 inits = initsWhenTrue;
  1348                 uninits = uninitsWhenTrue;
  1677                 uninits = uninitsWhenTrue;
  1349                 scan(tree.body);
  1678                 scan(tree.body);
  1350                 resolveContinues(tree);
  1679                 resolveContinues(tree);
  1351                 if (log.nerrors != prevErrors ||
  1680                 if (log.nerrors != prevErrors ||
  1352                     loopPassTwo ||
  1681                     flowKind.isFinal() ||
  1353                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1682                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1354                     break;
  1683                     break;
  1355                 uninits = uninitsEntry.andSet(uninits);
  1684                 uninits = uninitsEntry.andSet(uninits);
  1356                 loopPassTwo = true;
  1685                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1357             } while (true);
  1686             } while (true);
  1358             loopPassTwo = prevLoopPassTwo;
  1687             flowKind = prevFlowKind;
  1359             inits = initsCond;
  1688             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1360             uninits = uninitsCond;
  1689             //branch is not taken AND if it's DA/DU before any break statement
       
  1690             inits = initsSkip;
       
  1691             uninits = uninitsSkip;
  1361             resolveBreaks(tree, prevPendingExits);
  1692             resolveBreaks(tree, prevPendingExits);
  1362         }
  1693         }
  1363 
  1694 
  1364         public void visitForLoop(JCForLoop tree) {
  1695         public void visitForLoop(JCForLoop tree) {
  1365             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1696             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1366             boolean prevLoopPassTwo = loopPassTwo;
  1697             FlowKind prevFlowKind = flowKind;
       
  1698             flowKind = FlowKind.NORMAL;
  1367             int nextadrPrev = nextadr;
  1699             int nextadrPrev = nextadr;
  1368             scan(tree.init);
  1700             scan(tree.init);
  1369             Bits initsCond;
  1701             Bits initsSkip = null;
  1370             Bits uninitsCond;
  1702             Bits uninitsSkip = null;
  1371             pendingExits = new ListBuffer<AssignPendingExit>();
  1703             pendingExits = new ListBuffer<AssignPendingExit>();
  1372             int prevErrors = log.nerrors;
  1704             int prevErrors = log.nerrors;
  1373             do {
  1705             do {
  1374                 Bits uninitsEntry = uninits.dup();
  1706                 Bits uninitsEntry = uninits.dup();
  1375                 uninitsEntry.excludeFrom(nextadr);
  1707                 uninitsEntry.excludeFrom(nextadr);
  1376                 if (tree.cond != null) {
  1708                 if (tree.cond != null) {
  1377                     scanCond(tree.cond);
  1709                     scanCond(tree.cond);
  1378                     initsCond = initsWhenFalse;
  1710                     if (!flowKind.isFinal()) {
  1379                     uninitsCond = uninitsWhenFalse;
  1711                         initsSkip = initsWhenFalse;
       
  1712                         uninitsSkip = uninitsWhenFalse;
       
  1713                     }
  1380                     inits = initsWhenTrue;
  1714                     inits = initsWhenTrue;
  1381                     uninits = uninitsWhenTrue;
  1715                     uninits = uninitsWhenTrue;
  1382                 } else {
  1716                 } else if (!flowKind.isFinal()) {
  1383                     initsCond = inits.dup();
  1717                     initsSkip = inits.dup();
  1384                     initsCond.inclRange(firstadr, nextadr);
  1718                     initsSkip.inclRange(firstadr, nextadr);
  1385                     uninitsCond = uninits.dup();
  1719                     uninitsSkip = uninits.dup();
  1386                     uninitsCond.inclRange(firstadr, nextadr);
  1720                     uninitsSkip.inclRange(firstadr, nextadr);
  1387                 }
  1721                 }
  1388                 scan(tree.body);
  1722                 scan(tree.body);
  1389                 resolveContinues(tree);
  1723                 resolveContinues(tree);
  1390                 scan(tree.step);
  1724                 scan(tree.step);
  1391                 if (log.nerrors != prevErrors ||
  1725                 if (log.nerrors != prevErrors ||
  1392                     loopPassTwo ||
  1726                     flowKind.isFinal() ||
  1393                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1727                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1394                     break;
  1728                     break;
  1395                 uninits = uninitsEntry.andSet(uninits);
  1729                 uninits = uninitsEntry.andSet(uninits);
  1396                 loopPassTwo = true;
  1730                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1397             } while (true);
  1731             } while (true);
  1398             loopPassTwo = prevLoopPassTwo;
  1732             flowKind = prevFlowKind;
  1399             inits = initsCond;
  1733             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1400             uninits = uninitsCond;
  1734             //branch is not taken AND if it's DA/DU before any break statement
       
  1735             inits = initsSkip;
       
  1736             uninits = uninitsSkip;
  1401             resolveBreaks(tree, prevPendingExits);
  1737             resolveBreaks(tree, prevPendingExits);
  1402             nextadr = nextadrPrev;
  1738             nextadr = nextadrPrev;
  1403         }
  1739         }
  1404 
  1740 
  1405         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1741         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1406             visitVarDef(tree.var);
  1742             visitVarDef(tree.var);
  1407 
  1743 
  1408             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1744             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1409             boolean prevLoopPassTwo = loopPassTwo;
  1745             FlowKind prevFlowKind = flowKind;
       
  1746             flowKind = FlowKind.NORMAL;
  1410             int nextadrPrev = nextadr;
  1747             int nextadrPrev = nextadr;
  1411             scan(tree.expr);
  1748             scan(tree.expr);
  1412             Bits initsStart = inits.dup();
  1749             Bits initsStart = inits.dup();
  1413             Bits uninitsStart = uninits.dup();
  1750             Bits uninitsStart = uninits.dup();
  1414 
  1751 
  1419                 Bits uninitsEntry = uninits.dup();
  1756                 Bits uninitsEntry = uninits.dup();
  1420                 uninitsEntry.excludeFrom(nextadr);
  1757                 uninitsEntry.excludeFrom(nextadr);
  1421                 scan(tree.body);
  1758                 scan(tree.body);
  1422                 resolveContinues(tree);
  1759                 resolveContinues(tree);
  1423                 if (log.nerrors != prevErrors ||
  1760                 if (log.nerrors != prevErrors ||
  1424                     loopPassTwo ||
  1761                     flowKind.isFinal() ||
  1425                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1762                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1426                     break;
  1763                     break;
  1427                 uninits = uninitsEntry.andSet(uninits);
  1764                 uninits = uninitsEntry.andSet(uninits);
  1428                 loopPassTwo = true;
  1765                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1429             } while (true);
  1766             } while (true);
  1430             loopPassTwo = prevLoopPassTwo;
  1767             flowKind = prevFlowKind;
  1431             inits = initsStart;
  1768             inits = initsStart;
  1432             uninits = uninitsStart.andSet(uninits);
  1769             uninits = uninitsStart.andSet(uninits);
  1433             resolveBreaks(tree, prevPendingExits);
  1770             resolveBreaks(tree, prevPendingExits);
  1434             nextadr = nextadrPrev;
  1771             nextadr = nextadrPrev;
  1435         }
  1772         }
  1626             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1963             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1627         }
  1964         }
  1628 
  1965 
  1629         public void visitReturn(JCReturn tree) {
  1966         public void visitReturn(JCReturn tree) {
  1630             scanExpr(tree.expr);
  1967             scanExpr(tree.expr);
  1631             // if not initial constructor, should markDead instead of recordExit
       
  1632             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1968             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1633         }
  1969         }
  1634 
  1970 
  1635         public void visitThrow(JCThrow tree) {
  1971         public void visitThrow(JCThrow tree) {
  1636             scanExpr(tree.expr);
  1972             scanExpr(tree.expr);
  1667             uninits = uninitsExit;
  2003             uninits = uninitsExit;
  1668         }
  2004         }
  1669 
  2005 
  1670         public void visitAssign(JCAssign tree) {
  2006         public void visitAssign(JCAssign tree) {
  1671             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2007             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  1672             if (!(lhs instanceof JCIdent)) scanExpr(lhs);
  2008             if (!(lhs instanceof JCIdent)) {
       
  2009                 scanExpr(lhs);
       
  2010             }
  1673             scanExpr(tree.rhs);
  2011             scanExpr(tree.rhs);
  1674             letInit(lhs);
  2012             letInit(lhs);
  1675         }
  2013         }
  1676 
  2014 
  1677         public void visitAssignop(JCAssignOp tree) {
  2015         public void visitAssignop(JCAssignOp tree) {
  1749      *************************************************************************/
  2087      *************************************************************************/
  1750 
  2088 
  1751         /** Perform definite assignment/unassignment analysis on a tree.
  2089         /** Perform definite assignment/unassignment analysis on a tree.
  1752          */
  2090          */
  1753         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2091         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
       
  2092             analyzeTree(env, env.tree, make);
       
  2093         }
       
  2094 
       
  2095         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1754             try {
  2096             try {
  1755                 attrEnv = env;
  2097                 attrEnv = env;
  1756                 JCTree tree = env.tree;
       
  1757                 Flow.this.make = make;
  2098                 Flow.this.make = make;
       
  2099                 startPos = tree.pos().getStartPosition();
  1758                 inits = new Bits();
  2100                 inits = new Bits();
  1759                 uninits = new Bits();
  2101                 uninits = new Bits();
  1760                 uninitsTry = new Bits();
  2102                 uninitsTry = new Bits();
  1761                 initsWhenTrue = initsWhenFalse =
  2103                 initsWhenTrue = initsWhenFalse =
  1762                     uninitsWhenTrue = uninitsWhenFalse = null;
  2104                     uninitsWhenTrue = uninitsWhenFalse = null;
  1771                 this.classDef = null;
  2113                 this.classDef = null;
  1772                 unrefdResources = new Scope(env.enclClass.sym);
  2114                 unrefdResources = new Scope(env.enclClass.sym);
  1773                 scan(tree);
  2115                 scan(tree);
  1774             } finally {
  2116             } finally {
  1775                 // note that recursive invocations of this method fail hard
  2117                 // note that recursive invocations of this method fail hard
       
  2118                 startPos = -1;
  1776                 inits = uninits = uninitsTry = null;
  2119                 inits = uninits = uninitsTry = null;
  1777                 initsWhenTrue = initsWhenFalse =
  2120                 initsWhenTrue = initsWhenFalse =
  1778                     uninitsWhenTrue = uninitsWhenFalse = null;
  2121                     uninitsWhenTrue = uninitsWhenFalse = null;
  1779                 if (vars != null) for (int i=0; i<vars.length; i++)
  2122                 if (vars != null) for (int i=0; i<vars.length; i++)
  1780                     vars[i] = null;
  2123                     vars[i] = null;
  1785                 this.classDef = null;
  2128                 this.classDef = null;
  1786                 unrefdResources = null;
  2129                 unrefdResources = null;
  1787             }
  2130             }
  1788         }
  2131         }
  1789     }
  2132     }
       
  2133 
       
  2134     /**
       
  2135      * This pass implements the last step of the dataflow analysis, namely
       
  2136      * the effectively-final analysis check. This checks that every local variable
       
  2137      * reference from a lambda body/local inner class is either final or effectively final.
       
  2138      * As effectively final variables are marked as such during DA/DU, this pass must run after
       
  2139      * AssignAnalyzer.
       
  2140      */
       
  2141     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
       
  2142 
       
  2143         JCTree currentTree; //local class or lambda
       
  2144 
       
  2145         @Override
       
  2146         void markDead() {
       
  2147             //do nothing
       
  2148         }
       
  2149 
       
  2150         @SuppressWarnings("fallthrough")
       
  2151         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
       
  2152             if (currentTree != null &&
       
  2153                     sym.owner.kind == MTH &&
       
  2154                     sym.pos < currentTree.getStartPosition()) {
       
  2155                 switch (currentTree.getTag()) {
       
  2156                     case CLASSDEF:
       
  2157                         if (!allowEffectivelyFinalInInnerClasses) {
       
  2158                             if ((sym.flags() & FINAL) == 0) {
       
  2159                                 reportInnerClsNeedsFinalError(pos, sym);
       
  2160                             }
       
  2161                             break;
       
  2162                         }
       
  2163                     case LAMBDA:
       
  2164                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
       
  2165                            reportEffectivelyFinalError(pos, sym);
       
  2166                         }
       
  2167                 }
       
  2168             }
       
  2169         }
       
  2170 
       
  2171         @SuppressWarnings("fallthrough")
       
  2172         void letInit(JCTree tree) {
       
  2173             tree = TreeInfo.skipParens(tree);
       
  2174             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
       
  2175                 Symbol sym = TreeInfo.symbol(tree);
       
  2176                 if (currentTree != null &&
       
  2177                         sym.kind == VAR &&
       
  2178                         sym.owner.kind == MTH &&
       
  2179                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
       
  2180                     switch (currentTree.getTag()) {
       
  2181                         case CLASSDEF:
       
  2182                             if (!allowEffectivelyFinalInInnerClasses) {
       
  2183                                 reportInnerClsNeedsFinalError(tree, sym);
       
  2184                                 break;
       
  2185                             }
       
  2186                         case LAMBDA:
       
  2187                             reportEffectivelyFinalError(tree, sym);
       
  2188                     }
       
  2189                 }
       
  2190             }
       
  2191         }
       
  2192 
       
  2193         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
       
  2194             String subKey = currentTree.hasTag(LAMBDA) ?
       
  2195                   "lambda"  : "inner.cls";
       
  2196             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
       
  2197         }
       
  2198 
       
  2199         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
       
  2200             log.error(pos,
       
  2201                     "local.var.accessed.from.icls.needs.final",
       
  2202                     sym);
       
  2203         }
       
  2204 
       
  2205     /*************************************************************************
       
  2206      * Visitor methods for statements and definitions
       
  2207      *************************************************************************/
       
  2208 
       
  2209         /* ------------ Visitor methods for various sorts of trees -------------*/
       
  2210 
       
  2211         public void visitClassDef(JCClassDecl tree) {
       
  2212             JCTree prevTree = currentTree;
       
  2213             try {
       
  2214                 currentTree = tree.sym.isLocal() ? tree : null;
       
  2215                 super.visitClassDef(tree);
       
  2216             } finally {
       
  2217                 currentTree = prevTree;
       
  2218             }
       
  2219         }
       
  2220 
       
  2221         @Override
       
  2222         public void visitLambda(JCLambda tree) {
       
  2223             JCTree prevTree = currentTree;
       
  2224             try {
       
  2225                 currentTree = tree;
       
  2226                 super.visitLambda(tree);
       
  2227             } finally {
       
  2228                 currentTree = prevTree;
       
  2229             }
       
  2230         }
       
  2231 
       
  2232         @Override
       
  2233         public void visitIdent(JCIdent tree) {
       
  2234             if (tree.sym.kind == VAR) {
       
  2235                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
       
  2236             }
       
  2237         }
       
  2238 
       
  2239         public void visitAssign(JCAssign tree) {
       
  2240             JCTree lhs = TreeInfo.skipParens(tree.lhs);
       
  2241             if (!(lhs instanceof JCIdent)) {
       
  2242                 scan(lhs);
       
  2243             }
       
  2244             scan(tree.rhs);
       
  2245             letInit(lhs);
       
  2246         }
       
  2247 
       
  2248         public void visitAssignop(JCAssignOp tree) {
       
  2249             scan(tree.lhs);
       
  2250             scan(tree.rhs);
       
  2251             letInit(tree.lhs);
       
  2252         }
       
  2253 
       
  2254         public void visitUnary(JCUnary tree) {
       
  2255             switch (tree.getTag()) {
       
  2256                 case PREINC: case POSTINC:
       
  2257                 case PREDEC: case POSTDEC:
       
  2258                     scan(tree.arg);
       
  2259                     letInit(tree.arg);
       
  2260                     break;
       
  2261                 default:
       
  2262                     scan(tree.arg);
       
  2263             }
       
  2264         }
       
  2265 
       
  2266         public void visitTopLevel(JCCompilationUnit tree) {
       
  2267             // Do nothing for TopLevel since each class is visited individually
       
  2268         }
       
  2269 
       
  2270     /**************************************************************************
       
  2271      * main method
       
  2272      *************************************************************************/
       
  2273 
       
  2274         /** Perform definite assignment/unassignment analysis on a tree.
       
  2275          */
       
  2276         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
       
  2277             analyzeTree(env, env.tree, make);
       
  2278         }
       
  2279         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
       
  2280             try {
       
  2281                 attrEnv = env;
       
  2282                 Flow.this.make = make;
       
  2283                 pendingExits = new ListBuffer<PendingExit>();
       
  2284                 scan(tree);
       
  2285             } finally {
       
  2286                 pendingExits = null;
       
  2287                 Flow.this.make = null;
       
  2288             }
       
  2289         }
       
  2290     }
  1790 }
  2291 }