langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
changeset 19941 8b91e8eb2d20
parent 19933 5182bc65845b
child 20249 93f8eae31092
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Sep 14 15:23:21 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java	Sat Sep 14 19:04:47 2013 +0100
@@ -207,7 +207,7 @@
 
     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
         new AliveAnalyzer().analyzeTree(env, make);
-        new AssignAnalyzer().analyzeTree(env, make);
+        new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
         new FlowAnalyzer().analyzeTree(env, make);
         new CaptureAnalyzer().analyzeTree(env, make);
     }
@@ -239,7 +239,7 @@
         //related errors, which will allow for more errors to be detected
         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
         try {
-            new AssignAnalyzer().analyzeTree(env, that, make);
+            new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
             flowAnalyzer.analyzeTree(env, that, make);
             return flowAnalyzer.inferredThrownTypes;
@@ -292,15 +292,6 @@
     }
 
     /**
-     * Utility method to reset several Bits instances.
-     */
-    private void resetBits(Bits... bits) {
-        for (Bits b : bits) {
-            b.reset();
-        }
-    }
-
-    /**
      * Base visitor class for all visitors implementing dataflow analysis logic.
      * This class define the shared logic for handling jumps (break/continue statements).
      */
@@ -347,17 +338,17 @@
                 this.tree = tree;
             }
 
-            void resolveJump() {
+            void resolveJump(JCTree tree) {
                 //do nothing
             }
         }
 
-        abstract void markDead();
+        abstract void markDead(JCTree tree);
 
         /** Record an outward transfer of control. */
         void recordExit(JCTree tree, P pe) {
             pendingExits.append(pe);
-            markDead();
+            markDead(tree);
         }
 
         /** Resolve all jumps of this statement. */
@@ -371,7 +362,7 @@
                 P exit = exits.head;
                 if (exit.tree.hasTag(jk.treeTag) &&
                         jk.getTarget(exit.tree) == tree) {
-                    exit.resolveJump();
+                    exit.resolveJump(tree);
                     resolved = true;
                 } else {
                     pendingExits.append(exit);
@@ -380,12 +371,12 @@
             return resolved;
         }
 
-        /** Resolve all breaks of this statement. */
+        /** Resolve all continues of this statement. */
         boolean resolveContinues(JCTree tree) {
             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
         }
 
-        /** Resolve all continues of this statement. */
+        /** Resolve all breaks of this statement. */
         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
         }
@@ -414,7 +405,7 @@
         private boolean alive;
 
         @Override
-        void markDead() {
+        void markDead(JCTree tree) {
             alive = false;
         }
 
@@ -696,7 +687,7 @@
 
         public void visitThrow(JCThrow tree) {
             scan(tree.expr);
-            markDead();
+            markDead(tree);
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -797,7 +788,7 @@
         }
 
         @Override
-        void markDead() {
+        void markDead(JCTree tree) {
             //do nothing
         }
 
@@ -1222,7 +1213,7 @@
             else {
                 markThrown(tree, tree.expr.type);
             }
-            markDead();
+            markDead(tree);
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -1372,11 +1363,13 @@
      * depends on the results of the liveliness analyzer. This pass is also used to mark
      * effectively-final local variables/parameters.
      */
-    class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+    public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
+        extends BaseAnalyzer<P> {
 
         /** The set of definitely assigned variables.
          */
-        final Bits inits;
+        protected final Bits inits;
 
         /** The set of definitely unassigned variables.
          */
@@ -1402,7 +1395,7 @@
 
         /** A mapping from addresses to variable symbols.
          */
-        JCVariableDecl[] vardecls;
+        protected JCVariableDecl[] vardecls;
 
         /** The current class being defined.
          */
@@ -1414,11 +1407,11 @@
 
         /** The next available variable sequence number.
          */
-        int nextadr;
+        protected int nextadr;
 
         /** The first variable sequence number in a block that can return.
          */
-        int returnadr;
+        protected int returnadr;
 
         /** The list of unreferenced automatic resources.
          */
@@ -1430,35 +1423,46 @@
         /** The starting position of the analysed tree */
         int startPos;
 
-        AssignAnalyzer() {
-            inits = new Bits();
+        final Symtab syms;
+
+        protected Names names;
+
+        public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
+
+            final Bits inits;
+            final Bits uninits;
+            final Bits exit_inits = new Bits(true);
+            final Bits exit_uninits = new Bits(true);
+
+            public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+                super(tree);
+                this.inits = inits;
+                this.uninits = uninits;
+                this.exit_inits.assign(inits);
+                this.exit_uninits.assign(uninits);
+            }
+
+            @Override
+            public void resolveJump(JCTree tree) {
+                inits.andSet(exit_inits);
+                uninits.andSet(exit_uninits);
+            }
+        }
+
+        public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
+            this.inits = inits;
             uninits = new Bits();
             uninitsTry = new Bits();
             initsWhenTrue = new Bits(true);
             initsWhenFalse = new Bits(true);
             uninitsWhenTrue = new Bits(true);
             uninitsWhenFalse = new Bits(true);
-        }
-
-        class AssignPendingExit extends BaseAnalyzer.PendingExit {
-
-            final Bits exit_inits = new Bits(true);
-            final Bits exit_uninits = new Bits(true);
-
-            AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
-                super(tree);
-                this.exit_inits.assign(inits);
-                this.exit_uninits.assign(uninits);
-            }
-
-            void resolveJump() {
-                inits.andSet(exit_inits);
-                uninits.andSet(exit_uninits);
-            }
+            this.syms = syms;
+            this.names = names;
         }
 
         @Override
-        void markDead() {
+        protected void markDead(JCTree tree) {
             inits.inclRange(returnadr, nextadr);
             uninits.inclRange(returnadr, nextadr);
         }
@@ -1468,7 +1472,7 @@
         /** Do we need to track init/uninit state of this symbol?
          *  I.e. is symbol either a local or a blank final variable?
          */
-        boolean trackable(VarSymbol sym) {
+        protected boolean trackable(VarSymbol sym) {
             return
                 sym.pos >= startPos &&
                 ((sym.owner.kind == MTH ||
@@ -1488,44 +1492,35 @@
             }
             sym.adr = nextadr;
             vardecls[nextadr] = varDecl;
-            inits.excl(nextadr);
+            exclVarFromInits(varDecl, nextadr);
             uninits.incl(nextadr);
             nextadr++;
         }
 
+        protected void exclVarFromInits(JCTree tree, int adr) {
+            inits.excl(adr);
+        }
+
+        protected void assignToInits(JCTree tree, Bits bits) {
+            inits.assign(bits);
+        }
+
+        protected void andSetInits(JCTree tree, Bits bits) {
+            inits.andSet(bits);
+        }
+
+        protected void orSetInits(JCTree tree, Bits bits) {
+            inits.orSet(bits);
+        }
+
         /** Record an initialization of a trackable variable.
          */
         void letInit(DiagnosticPosition pos, VarSymbol sym) {
             if (sym.adr >= firstadr && trackable(sym)) {
-                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
-                    if (!uninits.isMember(sym.adr)) {
-                        //assignment targeting an effectively final variable
-                        //makes the variable lose its status of effectively final
-                        //if the variable is _not_ definitively unassigned
-                        sym.flags_field &= ~EFFECTIVELY_FINAL;
-                    } else {
-                        uninit(sym);
-                    }
-                }
-                else if ((sym.flags() & FINAL) != 0) {
-                    if ((sym.flags() & PARAMETER) != 0) {
-                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
-                            log.error(pos, "multicatch.parameter.may.not.be.assigned",
-                                      sym);
-                        }
-                        else {
-                            log.error(pos, "final.parameter.may.not.be.assigned",
-                                  sym);
-                        }
-                    } else if (!uninits.isMember(sym.adr)) {
-                        log.error(pos, flowKind.errKey, sym);
-                    } else {
-                        uninit(sym);
-                    }
+                if (uninits.isMember(sym.adr)) {
+                    uninit(sym);
                 }
                 inits.incl(sym.adr);
-            } else if ((sym.flags() & FINAL) != 0) {
-                log.error(pos, "var.might.already.be.assigned", sym);
             }
         }
         //where
@@ -1559,12 +1554,14 @@
         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
             checkInit(pos, sym, "var.might.not.have.been.initialized");
         }
-        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
-            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
-                trackable(sym) &&
-                !inits.isMember(sym.adr)) {
-                log.error(pos, errkey, sym);
-                inits.incl(sym.adr);
+
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
+
+        /** Utility method to reset several Bits instances.
+         */
+        private void resetBits(Bits... bits) {
+            for (Bits b : bits) {
+                b.reset();
             }
         }
 
@@ -1582,7 +1579,7 @@
 
         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
          */
-        void merge() {
+        protected void merge(JCTree tree) {
             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
         }
@@ -1597,7 +1594,9 @@
         void scanExpr(JCTree tree) {
             if (tree != null) {
                 scan(tree);
-                if (inits.isReset()) merge();
+                if (inits.isReset()) {
+                    merge(tree);
+                }
             }
         }
 
@@ -1614,7 +1613,7 @@
          */
         void scanCond(JCTree tree) {
             if (tree.type.isFalse()) {
-                if (inits.isReset()) merge();
+                if (inits.isReset()) merge(tree);
                 initsWhenTrue.assign(inits);
                 initsWhenTrue.inclRange(firstadr, nextadr);
                 uninitsWhenTrue.assign(uninits);
@@ -1622,7 +1621,7 @@
                 initsWhenFalse.assign(inits);
                 uninitsWhenFalse.assign(uninits);
             } else if (tree.type.isTrue()) {
-                if (inits.isReset()) merge();
+                if (inits.isReset()) merge(tree);
                 initsWhenFalse.assign(inits);
                 initsWhenFalse.inclRange(firstadr, nextadr);
                 uninitsWhenFalse.assign(uninits);
@@ -1641,22 +1640,22 @@
 
         /* ------------ Visitor methods for various sorts of trees -------------*/
 
+        @Override
         public void visitClassDef(JCClassDecl tree) {
-            if (tree.sym == null) return;
+            if (tree.sym == null) {
+                return;
+            }
 
             JCClassDecl classDefPrev = classDef;
             int firstadrPrev = firstadr;
             int nextadrPrev = nextadr;
-            ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
-            Lint lintPrev = lint;
+            ListBuffer<P> pendingExitsPrev = pendingExits;
 
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            pendingExits = new ListBuffer<P>();
             if (tree.name != names.empty) {
                 firstadr = nextadr;
             }
             classDef = tree;
-            lint = lint.augment(tree.sym);
-
             try {
                 // define all the static fields
                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
@@ -1664,8 +1663,9 @@
                         JCVariableDecl def = (JCVariableDecl)l.head;
                         if ((def.mods.flags & STATIC) != 0) {
                             VarSymbol sym = def.sym;
-                            if (trackable(sym))
+                            if (trackable(sym)) {
                                 newVar(def);
+                            }
                         }
                     }
                 }
@@ -1684,8 +1684,9 @@
                         JCVariableDecl def = (JCVariableDecl)l.head;
                         if ((def.mods.flags & STATIC) == 0) {
                             VarSymbol sym = def.sym;
-                            if (trackable(sym))
+                            if (trackable(sym)) {
                                 newVar(def);
+                            }
                         }
                     }
                 }
@@ -1709,21 +1710,25 @@
                 nextadr = nextadrPrev;
                 firstadr = firstadrPrev;
                 classDef = classDefPrev;
-                lint = lintPrev;
             }
         }
 
+        @Override
         public void visitMethodDef(JCMethodDecl tree) {
-            if (tree.body == null) return;
+            if (tree.body == null) {
+                return;
+            }
+            /*  MemberEnter can generate synthetic methods, ignore them
+             */
+            if ((tree.sym.flags() & SYNTHETIC) != 0) {
+                return;
+            }
 
             final Bits initsPrev = new Bits(inits);
             final Bits uninitsPrev = new Bits(uninits);
             int nextadrPrev = nextadr;
             int firstadrPrev = firstadr;
             int returnadrPrev = returnadr;
-            Lint lintPrev = lint;
-
-            lint = lint.augment(tree.sym);
 
             Assert.check(pendingExits.isEmpty());
 
@@ -1731,13 +1736,17 @@
                 boolean isInitialConstructor =
                     TreeInfo.isInitialConstructor(tree);
 
-                if (!isInitialConstructor)
+                if (!isInitialConstructor) {
                     firstadr = nextadr;
+                }
                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
                     JCVariableDecl def = l.head;
                     scan(def);
-                    inits.incl(def.sym.adr);
-                    uninits.excl(def.sym.adr);
+                    Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
+                    /*  If we are executing the code from Gen, then there can be
+                     *  synthetic or mandated variables, ignore them.
+                     */
+                    initParam(def);
                 }
                 // else we are in an instance initializer block;
                 // leave caught unchanged.
@@ -1761,39 +1770,42 @@
                         }
                     }
                 }
-                List<AssignPendingExit> exits = pendingExits.toList();
-                pendingExits = new ListBuffer<AssignPendingExit>();
+                List<P> exits = pendingExits.toList();
+                pendingExits = new ListBuffer<>();
                 while (exits.nonEmpty()) {
-                    AssignPendingExit exit = exits.head;
+                    P exit = exits.head;
                     exits = exits.tail;
                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
                     if (isInitialConstructor) {
-                        inits.assign(exit.exit_inits);
-                        for (int i = firstadr; i < nextadr; i++)
+                        assignToInits(exit.tree, exit.exit_inits);
+                        for (int i = firstadr; i < nextadr; i++) {
                             checkInit(exit.tree.pos(), vardecls[i].sym);
+                        }
                     }
                 }
             } finally {
-                inits.assign(initsPrev);
+                assignToInits(tree, initsPrev);
                 uninits.assign(uninitsPrev);
                 nextadr = nextadrPrev;
                 firstadr = firstadrPrev;
                 returnadr = returnadrPrev;
-                lint = lintPrev;
             }
         }
 
+        protected void initParam(JCVariableDecl def) {
+            inits.incl(def.sym.adr);
+            uninits.excl(def.sym.adr);
+        }
+
         public void visitVarDef(JCVariableDecl tree) {
             boolean track = trackable(tree.sym);
-            if (track && tree.sym.owner.kind == MTH) newVar(tree);
+            if (track && tree.sym.owner.kind == MTH) {
+                newVar(tree);
+            }
             if (tree.init != null) {
-                Lint lintPrev = lint;
-                lint = lint.augment(tree.sym);
-                try{
-                    scanExpr(tree.init);
-                    if (track) letInit(tree.pos(), tree.sym);
-                } finally {
-                    lint = lintPrev;
+                scanExpr(tree.init);
+                if (track) {
+                    letInit(tree.pos(), tree.sym);
                 }
             }
         }
@@ -1804,14 +1816,18 @@
             nextadr = nextadrPrev;
         }
 
+        int getLogNumberOfErrors() {
+            return 0;
+        }
+
         public void visitDoLoop(JCDoWhileLoop tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<P>();
+            int prevErrors = getLogNumberOfErrors();
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
@@ -1822,28 +1838,28 @@
                     initsSkip.assign(initsWhenFalse);
                     uninitsSkip.assign(uninitsWhenFalse);
                 }
-                if (log.nerrors !=  prevErrors ||
+                if (getLogNumberOfErrors() !=  prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
                     break;
-                inits.assign(initsWhenTrue);
+                assignToInits(tree.cond, initsWhenTrue);
                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits.assign(initsSkip);
+            assignToInits(tree, initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitWhileLoop(JCWhileLoop tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<>();
+            int prevErrors = getLogNumberOfErrors();
             final Bits uninitsEntry = new Bits(uninits);
             uninitsEntry.excludeFrom(nextadr);
             do {
@@ -1852,35 +1868,36 @@
                     initsSkip.assign(initsWhenFalse) ;
                     uninitsSkip.assign(uninitsWhenFalse);
                 }
-                inits.assign(initsWhenTrue);
+                assignToInits(tree, initsWhenTrue);
                 uninits.assign(uninitsWhenTrue);
                 scan(tree.body);
                 resolveContinues(tree);
-                if (log.nerrors != prevErrors ||
+                if (getLogNumberOfErrors() != prevErrors ||
                     flowKind.isFinal() ||
-                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
+                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
                     break;
+                }
                 uninits.assign(uninitsEntry.andSet(uninits));
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits.assign(initsSkip);
+            assignToInits(tree.body, initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitForLoop(JCForLoop tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
             scan(tree.init);
             final Bits initsSkip = new Bits(true);
             final Bits uninitsSkip = new Bits(true);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<P>();
+            int prevErrors = getLogNumberOfErrors();
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
@@ -1890,7 +1907,7 @@
                         initsSkip.assign(initsWhenFalse);
                         uninitsSkip.assign(uninitsWhenFalse);
                     }
-                    inits.assign(initsWhenTrue);
+                    assignToInits(tree.body, initsWhenTrue);
                     uninits.assign(uninitsWhenTrue);
                 } else if (!flowKind.isFinal()) {
                     initsSkip.assign(inits);
@@ -1901,7 +1918,7 @@
                 scan(tree.body);
                 resolveContinues(tree);
                 scan(tree.step);
-                if (log.nerrors != prevErrors ||
+                if (getLogNumberOfErrors() != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
@@ -1911,7 +1928,7 @@
             flowKind = prevFlowKind;
             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
             //branch is not taken AND if it's DA/DU before any break statement
-            inits.assign(initsSkip);
+            assignToInits(tree.body, initsSkip);
             uninits.assign(uninitsSkip);
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
@@ -1920,7 +1937,7 @@
         public void visitForeachLoop(JCEnhancedForLoop tree) {
             visitVarDef(tree.var);
 
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+            ListBuffer<P> prevPendingExits = pendingExits;
             FlowKind prevFlowKind = flowKind;
             flowKind = FlowKind.NORMAL;
             int nextadrPrev = nextadr;
@@ -1929,14 +1946,14 @@
             final Bits uninitsStart = new Bits(uninits);
 
             letInit(tree.pos(), tree.var.sym);
-            pendingExits = new ListBuffer<AssignPendingExit>();
-            int prevErrors = log.nerrors;
+            pendingExits = new ListBuffer<P>();
+            int prevErrors = getLogNumberOfErrors();
             do {
                 final Bits uninitsEntry = new Bits(uninits);
                 uninitsEntry.excludeFrom(nextadr);
                 scan(tree.body);
                 resolveContinues(tree);
-                if (log.nerrors != prevErrors ||
+                if (getLogNumberOfErrors() != prevErrors ||
                     flowKind.isFinal() ||
                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
                     break;
@@ -1944,41 +1961,50 @@
                 flowKind = FlowKind.SPECULATIVE_LOOP;
             } while (true);
             flowKind = prevFlowKind;
-            inits.assign(initsStart);
+            assignToInits(tree.body, initsStart);
             uninits.assign(uninitsStart.andSet(uninits));
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
         }
 
         public void visitLabelled(JCLabeledStatement tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            ListBuffer<P> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<P>();
             scan(tree.body);
             resolveBreaks(tree, prevPendingExits);
         }
 
         public void visitSwitch(JCSwitch tree) {
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            ListBuffer<P> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<>();
             int nextadrPrev = nextadr;
             scanExpr(tree.selector);
             final Bits initsSwitch = new Bits(inits);
             final Bits uninitsSwitch = new Bits(uninits);
             boolean hasDefault = false;
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
-                inits.assign(initsSwitch);
+                assignToInits(l.head, initsSwitch);
                 uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
-                if (c.pat == null)
+                if (c.pat == null) {
                     hasDefault = true;
-                else
+                } else {
                     scanExpr(c.pat);
+                }
+                if (hasDefault) {
+                    assignToInits(null, initsSwitch);
+                    uninits.assign(uninits.andSet(uninitsSwitch));
+                }
                 scan(c.stats);
                 addVars(c.stats, initsSwitch, uninitsSwitch);
+                if (!hasDefault) {
+                    assignToInits(l.head.stats.last(), initsSwitch);
+                    uninits.assign(uninits.andSet(uninitsSwitch));
+                }
                 // Warn about fall-through if lint switch fallthrough enabled.
             }
             if (!hasDefault) {
-                inits.andSet(initsSwitch);
+                andSetInits(null, initsSwitch);
             }
             resolveBreaks(tree, prevPendingExits);
             nextadr = nextadrPrev;
@@ -1997,11 +2023,17 @@
                 }
             }
 
+        boolean isEnabled(Lint.LintCategory lc) {
+            return false;
+        }
+
+        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
+
         public void visitTry(JCTry tree) {
             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
             final Bits uninitsTryPrev = new Bits(uninitsTry);
-            ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
-            pendingExits = new ListBuffer<AssignPendingExit>();
+            ListBuffer<P> prevPendingExits = pendingExits;
+            pendingExits = new ListBuffer<>();
             final Bits initsTry = new Bits(inits);
             uninitsTry.assign(uninits);
             for (JCTree resource : tree.resources) {
@@ -2023,10 +2055,10 @@
             int nextadrCatch = nextadr;
 
             if (!resourceVarDecls.isEmpty() &&
-                    lint.isEnabled(Lint.LintCategory.TRY)) {
+                    isEnabled(Lint.LintCategory.TRY)) {
                 for (JCVariableDecl resVar : resourceVarDecls) {
                     if (unrefdResources.includes(resVar.sym)) {
-                        log.warning(Lint.LintCategory.TRY, resVar.pos(),
+                        reportWarning(Lint.LintCategory.TRY, resVar.pos(),
                                     "try.resource.not.referenced", resVar.sym);
                         unrefdResources.remove(resVar.sym);
                     }
@@ -2042,20 +2074,22 @@
 
             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
                 JCVariableDecl param = l.head.param;
-                inits.assign(initsCatchPrev);
+                assignToInits(tree.body, initsCatchPrev);
                 uninits.assign(uninitsCatchPrev);
                 scan(param);
-                inits.incl(param.sym.adr);
-                uninits.excl(param.sym.adr);
+                /* If this is a TWR and we are executing the code from Gen,
+                 * then there can be synthetic variables, ignore them.
+                 */
+                initParam(param);
                 scan(l.head.body);
                 initsEnd.andSet(inits);
                 uninitsEnd.andSet(uninits);
                 nextadr = nextadrCatch;
             }
             if (tree.finalizer != null) {
-                inits.assign(initsTry);
+                assignToInits(tree.finalizer, initsTry);
                 uninits.assign(uninitsTry);
-                ListBuffer<AssignPendingExit> exits = pendingExits;
+                ListBuffer<P> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 scan(tree.finalizer);
                 if (!tree.finallyCanCompleteNormally) {
@@ -2065,19 +2099,19 @@
                     // FIX: this doesn't preserve source order of exits in catch
                     // versus finally!
                     while (exits.nonEmpty()) {
-                        AssignPendingExit exit = exits.next();
+                        P exit = exits.next();
                         if (exit.exit_inits != null) {
                             exit.exit_inits.orSet(inits);
                             exit.exit_uninits.andSet(uninits);
                         }
                         pendingExits.append(exit);
                     }
-                    inits.orSet(initsEnd);
+                    orSetInits(tree, initsEnd);
                 }
             } else {
-                inits.assign(initsEnd);
+                assignToInits(tree, initsEnd);
                 uninits.assign(uninitsEnd);
-                ListBuffer<AssignPendingExit> exits = pendingExits;
+                ListBuffer<P> exits = pendingExits;
                 pendingExits = prevPendingExits;
                 while (exits.nonEmpty()) pendingExits.append(exits.next());
             }
@@ -2088,7 +2122,7 @@
             scanCond(tree.cond);
             final Bits initsBeforeElse = new Bits(initsWhenFalse);
             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
-            inits.assign(initsWhenTrue);
+            assignToInits(tree.cond, initsWhenTrue);
             uninits.assign(uninitsWhenTrue);
             if (tree.truepart.type.hasTag(BOOLEAN) &&
                 tree.falsepart.type.hasTag(BOOLEAN)) {
@@ -2101,7 +2135,7 @@
                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
-                inits.assign(initsBeforeElse);
+                assignToInits(tree.truepart, initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scanCond(tree.falsepart);
                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
@@ -2112,10 +2146,10 @@
                 scanExpr(tree.truepart);
                 final Bits initsAfterThen = new Bits(inits);
                 final Bits uninitsAfterThen = new Bits(uninits);
-                inits.assign(initsBeforeElse);
+                assignToInits(tree.truepart, initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scanExpr(tree.falsepart);
-                inits.andSet(initsAfterThen);
+                andSetInits(tree.falsepart, initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
             }
         }
@@ -2124,39 +2158,46 @@
             scanCond(tree.cond);
             final Bits initsBeforeElse = new Bits(initsWhenFalse);
             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
-            inits.assign(initsWhenTrue);
+            assignToInits(tree.cond, initsWhenTrue);
             uninits.assign(uninitsWhenTrue);
             scan(tree.thenpart);
             if (tree.elsepart != null) {
                 final Bits initsAfterThen = new Bits(inits);
                 final Bits uninitsAfterThen = new Bits(uninits);
-                inits.assign(initsBeforeElse);
+                assignToInits(tree.thenpart, initsBeforeElse);
                 uninits.assign(uninitsBeforeElse);
                 scan(tree.elsepart);
-                inits.andSet(initsAfterThen);
+                andSetInits(tree.elsepart, initsAfterThen);
                 uninits.andSet(uninitsAfterThen);
             } else {
-                inits.andSet(initsBeforeElse);
+                andSetInits(tree.thenpart, initsBeforeElse);
                 uninits.andSet(uninitsBeforeElse);
             }
         }
 
+        protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
+            return null;
+        }
+
+        @Override
         public void visitBreak(JCBreak tree) {
-            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+            recordExit(tree, createNewPendingExit(tree, inits, uninits));
         }
 
+        @Override
         public void visitContinue(JCContinue tree) {
-            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+            recordExit(tree, createNewPendingExit(tree, inits, uninits));
         }
 
+        @Override
         public void visitReturn(JCReturn tree) {
             scanExpr(tree.expr);
-            recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+            recordExit(tree, createNewPendingExit(tree, inits, uninits));
         }
 
         public void visitThrow(JCThrow tree) {
             scanExpr(tree.expr);
-            markDead();
+            markDead(tree.expr);
         }
 
         public void visitApply(JCMethodInvocation tree) {
@@ -2175,10 +2216,10 @@
             final Bits prevUninits = new Bits(uninits);
             final Bits prevInits = new Bits(inits);
             int returnadrPrev = returnadr;
-            ListBuffer<AssignPendingExit> prevPending = pendingExits;
+            ListBuffer<P> prevPending = pendingExits;
             try {
                 returnadr = nextadr;
-                pendingExits = new ListBuffer<AssignPendingExit>();
+                pendingExits = new ListBuffer<P>();
                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
                     JCVariableDecl def = l.head;
                     scan(def);
@@ -2194,7 +2235,7 @@
             finally {
                 returnadr = returnadrPrev;
                 uninits.assign(prevUninits);
-                inits.assign(prevInits);
+                assignToInits(tree, prevInits);
                 pendingExits = prevPending;
             }
         }
@@ -2210,11 +2251,11 @@
             scanCond(tree.cond);
             uninitsExit.andSet(uninitsWhenTrue);
             if (tree.detail != null) {
-                inits.assign(initsWhenFalse);
+                assignToInits(tree, initsWhenFalse);
                 uninits.assign(uninitsWhenFalse);
                 scanExpr(tree.detail);
             }
-            inits.assign(initsExit);
+            assignToInits(tree, initsExit);
             uninits.assign(uninitsExit);
         }
 
@@ -2260,7 +2301,7 @@
                 scanCond(tree.lhs);
                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
-                inits.assign(initsWhenTrue);
+                assignToInits(tree.lhs, initsWhenTrue);
                 uninits.assign(uninitsWhenTrue);
                 scanCond(tree.rhs);
                 initsWhenFalse.andSet(initsWhenFalseLeft);
@@ -2270,7 +2311,7 @@
                 scanCond(tree.lhs);
                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
-                inits.assign(initsWhenFalse);
+                assignToInits(tree.lhs, initsWhenFalse);
                 uninits.assign(uninitsWhenFalse);
                 scanCond(tree.rhs);
                 initsWhenTrue.andSet(initsWhenTrueLeft);
@@ -2308,14 +2349,12 @@
 
         /** Perform definite assignment/unassignment analysis on a tree.
          */
-        public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
-            analyzeTree(env, env.tree, make);
-        }
+        public void analyzeTree(Env<?> env) {
+            analyzeTree(env, env.tree);
+         }
 
-        public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
+        public void analyzeTree(Env<?> env, JCTree tree) {
             try {
-                attrEnv = env;
-                Flow.this.make = make;
                 startPos = tree.pos().getStartPosition();
 
                 if (vardecls == null)
@@ -2325,7 +2364,7 @@
                         vardecls[i] = null;
                 firstadr = 0;
                 nextadr = 0;
-                pendingExits = new ListBuffer<AssignPendingExit>();
+                pendingExits = new ListBuffer<>();
                 this.classDef = null;
                 unrefdResources = new Scope(env.enclClass.sym);
                 scan(tree);
@@ -2334,18 +2373,160 @@
                 startPos = -1;
                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
-                if (vardecls != null) for (int i=0; i<vardecls.length; i++)
-                    vardecls[i] = null;
+                if (vardecls != null) {
+                    for (int i=0; i<vardecls.length; i++)
+                        vardecls[i] = null;
+                }
                 firstadr = 0;
                 nextadr = 0;
                 pendingExits = null;
-                Flow.this.make = null;
                 this.classDef = null;
                 unrefdResources = null;
             }
         }
     }
 
+    public static class AssignAnalyzer
+        extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+        Log log;
+        Lint lint;
+
+        public static class AssignPendingExit
+            extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
+
+            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+                super(tree, inits, uninits);
+            }
+        }
+
+        public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
+            super(new Bits(), syms, names);
+            this.log = log;
+            this.lint = lint;
+        }
+
+        @Override
+        protected AssignPendingExit createNewPendingExit(JCTree tree,
+            Bits inits, Bits uninits) {
+            return new AssignPendingExit(tree, inits, uninits);
+        }
+
+        /** Record an initialization of a trackable variable.
+         */
+        @Override
+        void letInit(DiagnosticPosition pos, VarSymbol sym) {
+            if (sym.adr >= firstadr && trackable(sym)) {
+                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
+                    if (!uninits.isMember(sym.adr)) {
+                        //assignment targeting an effectively final variable
+                        //makes the variable lose its status of effectively final
+                        //if the variable is _not_ definitively unassigned
+                        sym.flags_field &= ~EFFECTIVELY_FINAL;
+                    } else {
+                        uninit(sym);
+                    }
+                }
+                else if ((sym.flags() & FINAL) != 0) {
+                    if ((sym.flags() & PARAMETER) != 0) {
+                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
+                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
+                        }
+                        else {
+                            log.error(pos, "final.parameter.may.not.be.assigned",
+                                  sym);
+                        }
+                    } else if (!uninits.isMember(sym.adr)) {
+                        log.error(pos, flowKind.errKey, sym);
+                    } else {
+                        uninit(sym);
+                    }
+                }
+                inits.incl(sym.adr);
+            } else if ((sym.flags() & FINAL) != 0) {
+                log.error(pos, "var.might.already.be.assigned", sym);
+            }
+        }
+
+        @Override
+        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
+            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
+                trackable(sym) &&
+                !inits.isMember(sym.adr)) {
+                log.error(pos, errkey, sym);
+                inits.incl(sym.adr);
+            }
+        }
+
+        @Override
+        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
+            String key, Object ... args) {
+            log.warning(lc, pos, key, args);
+        }
+
+        @Override
+        int getLogNumberOfErrors() {
+            return log.nerrors;
+        }
+
+        @Override
+        boolean isEnabled(Lint.LintCategory lc) {
+            return lint.isEnabled(lc);
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            if (tree.sym == null) {
+                return;
+            }
+
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try {
+                super.visitClassDef(tree);
+            } finally {
+                lint = lintPrev;
+            }
+        }
+
+        @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            if (tree.body == null) {
+                return;
+            }
+
+            /*  MemberEnter can generate synthetic methods ignore them
+             */
+            if ((tree.sym.flags() & SYNTHETIC) != 0) {
+                return;
+            }
+
+            Lint lintPrev = lint;
+            lint = lint.augment(tree.sym);
+            try {
+                super.visitMethodDef(tree);
+            } finally {
+                lint = lintPrev;
+            }
+        }
+
+        @Override
+        public void visitVarDef(JCVariableDecl tree) {
+            if (tree.init == null) {
+                super.visitVarDef(tree);
+            } else {
+                Lint lintPrev = lint;
+                lint = lint.augment(tree.sym);
+                try{
+                    super.visitVarDef(tree);
+                } finally {
+                    lint = lintPrev;
+                }
+            }
+        }
+
+    }
+
     /**
      * This pass implements the last step of the dataflow analysis, namely
      * the effectively-final analysis check. This checks that every local variable
@@ -2358,7 +2539,7 @@
         JCTree currentTree; //local class or lambda
 
         @Override
-        void markDead() {
+        void markDead(JCTree tree) {
             //do nothing
         }