langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java
changeset 5492 515e4b33b335
parent 3149 0cd06d598d6f
child 5520 86e4b9a9da40
equal deleted inserted replaced
5491:899e1748bb17 5492:515e4b33b335
    24  */
    24  */
    25 
    25 
    26 //todo: one might eliminate uninits.andSets when monotonic
    26 //todo: one might eliminate uninits.andSets when monotonic
    27 
    27 
    28 package com.sun.tools.javac.comp;
    28 package com.sun.tools.javac.comp;
       
    29 
       
    30 import java.util.HashMap;
    29 
    31 
    30 import com.sun.tools.javac.code.*;
    32 import com.sun.tools.javac.code.*;
    31 import com.sun.tools.javac.tree.*;
    33 import com.sun.tools.javac.tree.*;
    32 import com.sun.tools.javac.util.*;
    34 import com.sun.tools.javac.util.*;
    33 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
   182     private final Symtab syms;
   184     private final Symtab syms;
   183     private final Types types;
   185     private final Types types;
   184     private final Check chk;
   186     private final Check chk;
   185     private       TreeMaker make;
   187     private       TreeMaker make;
   186     private       Lint lint;
   188     private       Lint lint;
       
   189     private final boolean allowRethrowAnalysis;
   187 
   190 
   188     public static Flow instance(Context context) {
   191     public static Flow instance(Context context) {
   189         Flow instance = context.get(flowKey);
   192         Flow instance = context.get(flowKey);
   190         if (instance == null)
   193         if (instance == null)
   191             instance = new Flow(context);
   194             instance = new Flow(context);
   192         return instance;
   195         return instance;
   193     }
   196     }
   194 
   197 
   195     protected Flow(Context context) {
   198     protected Flow(Context context) {
   196         context.put(flowKey, this);
   199         context.put(flowKey, this);
   197 
       
   198         names = Names.instance(context);
   200         names = Names.instance(context);
   199         log = Log.instance(context);
   201         log = Log.instance(context);
   200         syms = Symtab.instance(context);
   202         syms = Symtab.instance(context);
   201         types = Types.instance(context);
   203         types = Types.instance(context);
   202         chk = Check.instance(context);
   204         chk = Check.instance(context);
   203         lint = Lint.instance(context);
   205         lint = Lint.instance(context);
       
   206         Source source = Source.instance(context);
       
   207         allowRethrowAnalysis = source.allowMulticatch();
   204     }
   208     }
   205 
   209 
   206     /** A flag that indicates whether the last statement could
   210     /** A flag that indicates whether the last statement could
   207      *  complete normally.
   211      *  complete normally.
   208      */
   212      */
   213     Bits inits;
   217     Bits inits;
   214 
   218 
   215     /** The set of definitely unassigned variables.
   219     /** The set of definitely unassigned variables.
   216      */
   220      */
   217     Bits uninits;
   221     Bits uninits;
       
   222 
       
   223     HashMap<Symbol, List<Type>> multicatchTypes;
   218 
   224 
   219     /** The set of variables that are definitely unassigned everywhere
   225     /** The set of variables that are definitely unassigned everywhere
   220      *  in current try block. This variable is maintained lazily; it is
   226      *  in current try block. This variable is maintained lazily; it is
   221      *  updated only when something gets removed from uninits,
   227      *  updated only when something gets removed from uninits,
   222      *  typically by being assigned in reachable code.  To obtain the
   228      *  typically by being assigned in reachable code.  To obtain the
   353      */
   359      */
   354     void letInit(DiagnosticPosition pos, VarSymbol sym) {
   360     void letInit(DiagnosticPosition pos, VarSymbol sym) {
   355         if (sym.adr >= firstadr && trackable(sym)) {
   361         if (sym.adr >= firstadr && trackable(sym)) {
   356             if ((sym.flags() & FINAL) != 0) {
   362             if ((sym.flags() & FINAL) != 0) {
   357                 if ((sym.flags() & PARAMETER) != 0) {
   363                 if ((sym.flags() & PARAMETER) != 0) {
   358                     log.error(pos, "final.parameter.may.not.be.assigned",
   364                     if ((sym.flags() & DISJOINT) != 0) { //multi-catch parameter
       
   365                         log.error(pos, "multicatch.parameter.may.not.be.assigned",
       
   366                                   sym);
       
   367                     }
       
   368                     else {
       
   369                         log.error(pos, "final.parameter.may.not.be.assigned",
   359                               sym);
   370                               sym);
       
   371                     }
   360                 } else if (!uninits.isMember(sym.adr)) {
   372                 } else if (!uninits.isMember(sym.adr)) {
   361                     log.error(pos,
   373                     log.error(pos,
   362                               loopPassTwo
   374                               loopPassTwo
   363                               ? "var.might.be.assigned.in.loop"
   375                               ? "var.might.be.assigned.in.loop"
   364                               : "var.might.already.be.assigned",
   376                               : "var.might.already.be.assigned",
   950 
   962 
   951     public void visitTry(JCTry tree) {
   963     public void visitTry(JCTry tree) {
   952         List<Type> caughtPrev = caught;
   964         List<Type> caughtPrev = caught;
   953         List<Type> thrownPrev = thrown;
   965         List<Type> thrownPrev = thrown;
   954         thrown = List.nil();
   966         thrown = List.nil();
   955         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail)
   967         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   956             caught = chk.incl(l.head.param.type, caught);
   968             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
       
   969                     ((JCTypeDisjoint)l.head.param.vartype).components :
       
   970                     List.of(l.head.param.vartype);
       
   971             for (JCExpression ct : subClauses) {
       
   972                 caught = chk.incl(ct.type, caught);
       
   973             }
       
   974         }
   957         Bits uninitsTryPrev = uninitsTry;
   975         Bits uninitsTryPrev = uninitsTry;
   958         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   976         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   959         pendingExits = new ListBuffer<PendingExit>();
   977         pendingExits = new ListBuffer<PendingExit>();
   960         Bits initsTry = inits.dup();
   978         Bits initsTry = inits.dup();
   961         uninitsTry = uninits.dup();
   979         uninitsTry = uninits.dup();
   971 
   989 
   972         List<Type> caughtInTry = List.nil();
   990         List<Type> caughtInTry = List.nil();
   973         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   991         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   974             alive = true;
   992             alive = true;
   975             JCVariableDecl param = l.head.param;
   993             JCVariableDecl param = l.head.param;
   976             Type exc = param.type;
   994             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
   977             if (chk.subset(exc, caughtInTry)) {
   995                     ((JCTypeDisjoint)l.head.param.vartype).components :
   978                 log.error(l.head.pos(),
   996                     List.of(l.head.param.vartype);
   979                           "except.already.caught", exc);
   997             List<Type> ctypes = List.nil();
   980             } else if (!chk.isUnchecked(l.head.pos(), exc) &&
   998             List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
   981                        exc.tsym != syms.throwableType.tsym &&
   999             for (JCExpression ct : subClauses) {
   982                        exc.tsym != syms.exceptionType.tsym &&
  1000                 Type exc = ct.type;
   983                        !chk.intersects(exc, thrownInTry)) {
  1001                 ctypes = ctypes.append(exc);
   984                 log.error(l.head.pos(),
  1002                 if (types.isSameType(exc, syms.objectType))
   985                           "except.never.thrown.in.try", exc);
  1003                     continue;
   986             }
  1004                 if (chk.subset(exc, caughtInTry)) {
   987             caughtInTry = chk.incl(exc, caughtInTry);
  1005                     log.error(l.head.pos(),
       
  1006                               "except.already.caught", exc);
       
  1007                 } else if (!chk.isUnchecked(l.head.pos(), exc) &&
       
  1008                            exc.tsym != syms.throwableType.tsym &&
       
  1009                            exc.tsym != syms.exceptionType.tsym &&
       
  1010                            !chk.intersects(exc, thrownInTry)) {
       
  1011                     log.error(l.head.pos(),
       
  1012                               "except.never.thrown.in.try", exc);
       
  1013                 }
       
  1014                 caughtInTry = chk.incl(exc, caughtInTry);
       
  1015             }
   988             inits = initsTry.dup();
  1016             inits = initsTry.dup();
   989             uninits = uninitsTry.dup();
  1017             uninits = uninitsTry.dup();
   990             scan(param);
  1018             scan(param);
   991             inits.incl(param.sym.adr);
  1019             inits.incl(param.sym.adr);
   992             uninits.excl(param.sym.adr);
  1020             uninits.excl(param.sym.adr);
       
  1021             multicatchTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
   993             scanStat(l.head.body);
  1022             scanStat(l.head.body);
   994             initsEnd.andSet(inits);
  1023             initsEnd.andSet(inits);
   995             uninitsEnd.andSet(uninits);
  1024             uninitsEnd.andSet(uninits);
   996             nextadr = nextadrCatch;
  1025             nextadr = nextadrCatch;
       
  1026             multicatchTypes.remove(param.sym);
   997             aliveEnd |= alive;
  1027             aliveEnd |= alive;
   998         }
  1028         }
   999         if (tree.finalizer != null) {
  1029         if (tree.finalizer != null) {
  1000             List<Type> savedThrown = thrown;
  1030             List<Type> savedThrown = thrown;
  1001             thrown = List.nil();
  1031             thrown = List.nil();
  1119         recordExit(tree);
  1149         recordExit(tree);
  1120     }
  1150     }
  1121 
  1151 
  1122     public void visitThrow(JCThrow tree) {
  1152     public void visitThrow(JCThrow tree) {
  1123         scanExpr(tree.expr);
  1153         scanExpr(tree.expr);
  1124         markThrown(tree, tree.expr.type);
  1154         Symbol sym = TreeInfo.symbol(tree.expr);
       
  1155         if (sym != null &&
       
  1156             sym.kind == VAR &&
       
  1157             (sym.flags() & FINAL) != 0 &&
       
  1158             multicatchTypes.get(sym) != null &&
       
  1159             allowRethrowAnalysis) {
       
  1160             for (Type t : multicatchTypes.get(sym)) {
       
  1161                 markThrown(tree, t);
       
  1162             }
       
  1163         }
       
  1164         else {
       
  1165             markThrown(tree, tree.expr.type);
       
  1166         }
  1125         markDead();
  1167         markDead();
  1126     }
  1168     }
  1127 
  1169 
  1128     public void visitApply(JCMethodInvocation tree) {
  1170     public void visitApply(JCMethodInvocation tree) {
  1129         scanExpr(tree.meth);
  1171         scanExpr(tree.meth);
  1306                 for (int i=0; i<vars.length; i++)
  1348                 for (int i=0; i<vars.length; i++)
  1307                     vars[i] = null;
  1349                     vars[i] = null;
  1308             firstadr = 0;
  1350             firstadr = 0;
  1309             nextadr = 0;
  1351             nextadr = 0;
  1310             pendingExits = new ListBuffer<PendingExit>();
  1352             pendingExits = new ListBuffer<PendingExit>();
       
  1353             multicatchTypes = new HashMap<Symbol, List<Type>>();
  1311             alive = true;
  1354             alive = true;
  1312             this.thrown = this.caught = null;
  1355             this.thrown = this.caught = null;
  1313             this.classDef = null;
  1356             this.classDef = null;
  1314             scan(tree);
  1357             scan(tree);
  1315         } finally {
  1358         } finally {