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

Print this page




  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.HashMap;
  31 
  32 import com.sun.tools.javac.code.*;
  33 import com.sun.tools.javac.tree.*;
  34 import com.sun.tools.javac.util.*;
  35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  36 
  37 import com.sun.tools.javac.code.Symbol.*;
  38 import com.sun.tools.javac.tree.JCTree.*;
  39 



  40 import static com.sun.tools.javac.code.Flags.*;
  41 import static com.sun.tools.javac.code.Kinds.*;
  42 import static com.sun.tools.javac.code.TypeTags.*;
  43 
  44 /** This pass implements dataflow analysis for Java programs.
  45  *  Liveness analysis checks that every statement is reachable.
  46  *  Exception analysis ensures that every checked exception that is
  47  *  thrown is declared or caught.  Definite assignment analysis
  48  *  ensures that each variable is assigned when used.  Definite
  49  *  unassignment analysis ensures that no final variable is assigned
  50  *  more than once.
  51  *
  52  *  <p>The second edition of the JLS has a number of problems in the
  53  *  specification of these flow analysis problems. This implementation
  54  *  attempts to address those issues.
  55  *
  56  *  <p>First, there is no accommodation for a finally clause that cannot
  57  *  complete normally. For liveness analysis, an intervening finally
  58  *  clause can cause a break, continue, or return not to reach its
  59  *  target.  For exception analysis, an intervening finally clause can


 248      */
 249     JCClassDecl classDef;
 250 
 251     /** The first variable sequence number in this class definition.
 252      */
 253     int firstadr;
 254 
 255     /** The next available variable sequence number.
 256      */
 257     int nextadr;
 258 
 259     /** The list of possibly thrown declarable exceptions.
 260      */
 261     List<Type> thrown;
 262 
 263     /** The list of exceptions that are either caught or declared to be
 264      *  thrown.
 265      */
 266     List<Type> caught;
 267 




 268     /** Set when processing a loop body the second time for DU analysis. */
 269     boolean loopPassTwo = false;
 270 
 271     /*-------------------- Environments ----------------------*/
 272 
 273     /** A pending exit.  These are the statements return, break, and
 274      *  continue.  In addition, exception-throwing expressions or
 275      *  statements are put here when not known to be caught.  This
 276      *  will typically result in an error unless it is within a
 277      *  try-finally whose finally block cannot complete normally.
 278      */
 279     static class PendingExit {
 280         JCTree tree;
 281         Bits inits;
 282         Bits uninits;
 283         Type thrown;
 284         PendingExit(JCTree tree, Bits inits, Bits uninits) {
 285             this.tree = tree;
 286             this.inits = inits.dup();
 287             this.uninits = uninits.dup();


 946         alive |= resolveBreaks(tree, prevPendingExits);
 947         nextadr = nextadrPrev;
 948     }
 949     // where
 950         /** Add any variables defined in stats to inits and uninits. */
 951         private static void addVars(List<JCStatement> stats, Bits inits,
 952                                     Bits uninits) {
 953             for (;stats.nonEmpty(); stats = stats.tail) {
 954                 JCTree stat = stats.head;
 955                 if (stat.getTag() == JCTree.VARDEF) {
 956                     int adr = ((JCVariableDecl) stat).sym.adr;
 957                     inits.excl(adr);
 958                     uninits.incl(adr);
 959                 }
 960             }
 961         }
 962 
 963     public void visitTry(JCTry tree) {
 964         List<Type> caughtPrev = caught;
 965         List<Type> thrownPrev = thrown;

 966         thrown = List.nil();
 967         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 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         }
 975         Bits uninitsTryPrev = uninitsTry;
 976         ListBuffer<PendingExit> prevPendingExits = pendingExits;
 977         pendingExits = new ListBuffer<PendingExit>();
 978         Bits initsTry = inits.dup();
 979         uninitsTry = uninits.dup();


























 980         scanStat(tree.body);
 981         List<Type> thrownInTry = thrown;
 982         thrown = thrownPrev;
 983         caught = caughtPrev;
 984         boolean aliveEnd = alive;
 985         uninitsTry.andSet(uninits);
 986         Bits initsEnd = inits;
 987         Bits uninitsEnd = uninits;
 988         int nextadrCatch = nextadr;
 989 








 990         List<Type> caughtInTry = List.nil();
 991         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 992             alive = true;
 993             JCVariableDecl param = l.head.param;
 994             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
 995                     ((JCTypeDisjoint)l.head.param.vartype).components :
 996                     List.of(l.head.param.vartype);
 997             List<Type> ctypes = List.nil();
 998             List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
 999             for (JCExpression ct : subClauses) {
1000                 Type exc = ct.type;
1001                 ctypes = ctypes.append(exc);
1002                 if (types.isSameType(exc, syms.objectType))
1003                     continue;
1004                 if (chk.subset(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 &&


1053                     PendingExit exit = exits.next();
1054                     if (exit.inits != null) {
1055                         exit.inits.orSet(inits);
1056                         exit.uninits.andSet(uninits);
1057                     }
1058                     pendingExits.append(exit);
1059                 }
1060                 inits.orSet(initsEnd);
1061                 alive = aliveEnd;
1062             }
1063         } else {
1064             thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1065             inits = initsEnd;
1066             uninits = uninitsEnd;
1067             alive = aliveEnd;
1068             ListBuffer<PendingExit> exits = pendingExits;
1069             pendingExits = prevPendingExits;
1070             while (exits.nonEmpty()) pendingExits.append(exits.next());
1071         }
1072         uninitsTry.andSet(uninitsTryPrev).andSet(uninits);

1073     }
1074 
1075     public void visitConditional(JCConditional tree) {
1076         scanCond(tree.cond);
1077         Bits initsBeforeElse = initsWhenFalse;
1078         Bits uninitsBeforeElse = uninitsWhenFalse;
1079         inits = initsWhenTrue;
1080         uninits = uninitsWhenTrue;
1081         if (tree.truepart.type.tag == BOOLEAN &&
1082             tree.falsepart.type.tag == BOOLEAN) {
1083             // if b and c are boolean valued, then
1084             // v is (un)assigned after a?b:c when true iff
1085             //    v is (un)assigned after b when true and
1086             //    v is (un)assigned after c when true
1087             scanCond(tree.truepart);
1088             Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
1089             Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
1090             Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
1091             Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
1092             inits = initsBeforeElse;


1276             Bits initsWhenTrueLeft = initsWhenTrue;
1277             Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1278             inits = initsWhenFalse;
1279             uninits = uninitsWhenFalse;
1280             scanCond(tree.rhs);
1281             initsWhenTrue.andSet(initsWhenTrueLeft);
1282             uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1283             break;
1284         default:
1285             scanExpr(tree.lhs);
1286             scanExpr(tree.rhs);
1287         }
1288     }
1289 
1290     public void visitAnnotatedType(JCAnnotatedType tree) {
1291         // annotations don't get scanned
1292         tree.underlyingType.accept(this);
1293     }
1294 
1295     public void visitIdent(JCIdent tree) {
1296         if (tree.sym.kind == VAR)
1297             checkInit(tree.pos(), (VarSymbol)tree.sym);








1298     }
1299 
1300     public void visitTypeCast(JCTypeCast tree) {
1301         super.visitTypeCast(tree);
1302         if (!tree.type.isErroneous()
1303             && lint.isEnabled(Lint.LintCategory.CAST)
1304             && types.isSameType(tree.expr.type, tree.clazz.type)
1305             && !(ignoreAnnotatedCasts && containsTypeAnnotation(tree.clazz))) {
1306             log.warning(tree.pos(), "redundant.cast", tree.expr.type);
1307         }
1308     }
1309 
1310     public void visitTopLevel(JCCompilationUnit tree) {
1311         // Do nothing for TopLevel since each class is visited individually
1312     }
1313 
1314 /**************************************************************************
1315  * utility methods for ignoring type-annotated casts lint checking
1316  *************************************************************************/
1317     private static final boolean ignoreAnnotatedCasts = true;




  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.HashMap;
  31 
  32 import com.sun.tools.javac.code.*;
  33 import com.sun.tools.javac.tree.*;
  34 import com.sun.tools.javac.util.*;
  35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  36 
  37 import com.sun.tools.javac.code.Symbol.*;
  38 import com.sun.tools.javac.tree.JCTree.*;
  39 
  40 import java.util.HashSet;
  41 import java.util.Set;
  42 
  43 import static com.sun.tools.javac.code.Flags.*;
  44 import static com.sun.tools.javac.code.Kinds.*;
  45 import static com.sun.tools.javac.code.TypeTags.*;
  46 
  47 /** This pass implements dataflow analysis for Java programs.
  48  *  Liveness analysis checks that every statement is reachable.
  49  *  Exception analysis ensures that every checked exception that is
  50  *  thrown is declared or caught.  Definite assignment analysis
  51  *  ensures that each variable is assigned when used.  Definite
  52  *  unassignment analysis ensures that no final variable is assigned
  53  *  more than once.
  54  *
  55  *  <p>The second edition of the JLS has a number of problems in the
  56  *  specification of these flow analysis problems. This implementation
  57  *  attempts to address those issues.
  58  *
  59  *  <p>First, there is no accommodation for a finally clause that cannot
  60  *  complete normally. For liveness analysis, an intervening finally
  61  *  clause can cause a break, continue, or return not to reach its
  62  *  target.  For exception analysis, an intervening finally clause can


 251      */
 252     JCClassDecl classDef;
 253 
 254     /** The first variable sequence number in this class definition.
 255      */
 256     int firstadr;
 257 
 258     /** The next available variable sequence number.
 259      */
 260     int nextadr;
 261 
 262     /** The list of possibly thrown declarable exceptions.
 263      */
 264     List<Type> thrown;
 265 
 266     /** The list of exceptions that are either caught or declared to be
 267      *  thrown.
 268      */
 269     List<Type> caught;
 270 
 271     /** The list of unreferenced automatic resources.
 272      */
 273     Set<VarSymbol> unrefdResources;
 274 
 275     /** Set when processing a loop body the second time for DU analysis. */
 276     boolean loopPassTwo = false;
 277 
 278     /*-------------------- Environments ----------------------*/
 279 
 280     /** A pending exit.  These are the statements return, break, and
 281      *  continue.  In addition, exception-throwing expressions or
 282      *  statements are put here when not known to be caught.  This
 283      *  will typically result in an error unless it is within a
 284      *  try-finally whose finally block cannot complete normally.
 285      */
 286     static class PendingExit {
 287         JCTree tree;
 288         Bits inits;
 289         Bits uninits;
 290         Type thrown;
 291         PendingExit(JCTree tree, Bits inits, Bits uninits) {
 292             this.tree = tree;
 293             this.inits = inits.dup();
 294             this.uninits = uninits.dup();


 953         alive |= resolveBreaks(tree, prevPendingExits);
 954         nextadr = nextadrPrev;
 955     }
 956     // where
 957         /** Add any variables defined in stats to inits and uninits. */
 958         private static void addVars(List<JCStatement> stats, Bits inits,
 959                                     Bits uninits) {
 960             for (;stats.nonEmpty(); stats = stats.tail) {
 961                 JCTree stat = stats.head;
 962                 if (stat.getTag() == JCTree.VARDEF) {
 963                     int adr = ((JCVariableDecl) stat).sym.adr;
 964                     inits.excl(adr);
 965                     uninits.incl(adr);
 966                 }
 967             }
 968         }
 969 
 970     public void visitTry(JCTry tree) {
 971         List<Type> caughtPrev = caught;
 972         List<Type> thrownPrev = thrown;
 973         Set<VarSymbol> unrefdResourcesPrev = unrefdResources;
 974         thrown = List.nil();
 975         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 976             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
 977                     ((JCTypeDisjoint)l.head.param.vartype).components :
 978                     List.of(l.head.param.vartype);
 979             for (JCExpression ct : subClauses) {
 980                 caught = chk.incl(ct.type, caught);
 981             }
 982         }
 983         Bits uninitsTryPrev = uninitsTry;
 984         ListBuffer<PendingExit> prevPendingExits = pendingExits;
 985         pendingExits = new ListBuffer<PendingExit>();
 986         Bits initsTry = inits.dup();
 987         uninitsTry = uninits.dup();
 988         unrefdResources = new HashSet<VarSymbol>();
 989         for (JCTree resource : tree.resources) {
 990             if (resource instanceof JCVariableDecl) {
 991                 JCVariableDecl vdecl = (JCVariableDecl) resource;
 992                 visitVarDef(vdecl);
 993                 unrefdResources.add(vdecl.sym);
 994             } else if (resource instanceof JCExpression) {
 995                 scanExpr((JCExpression) resource);
 996             } else {
 997                 throw new AssertionError(tree);  // parser error
 998             }
 999         }
1000         for (JCTree resource : tree.resources) {
1001             MethodSymbol topCloseMethod = (MethodSymbol)syms.autoCloseableType.tsym.members().lookup(names.close).sym;
1002             List<Type> closeableSupertypes = resource.type.isCompound() ?
1003                 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1004                 List.of(resource.type);
1005             for (Type sup : closeableSupertypes) {
1006                 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1007                     MethodSymbol closeMethod = types.implementation(topCloseMethod, sup.tsym, types, true);
1008                     for (Type t : closeMethod.getThrownTypes()) {
1009                         markThrown(tree.body, t);
1010                     }
1011                 }
1012             }
1013         }
1014         scanStat(tree.body);
1015         List<Type> thrownInTry = thrown;
1016         thrown = thrownPrev;
1017         caught = caughtPrev;
1018         boolean aliveEnd = alive;
1019         uninitsTry.andSet(uninits);
1020         Bits initsEnd = inits;
1021         Bits uninitsEnd = uninits;
1022         int nextadrCatch = nextadr;
1023 
1024         if (!unrefdResources.isEmpty() &&
1025                 lint.isEnabled(Lint.LintCategory.ARM)) {
1026             for (VarSymbol v : unrefdResources) {
1027                 log.warning(v.pos,
1028                             "automatic.resource.not.referenced", v);
1029             }
1030         }
1031 
1032         List<Type> caughtInTry = List.nil();
1033         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1034             alive = true;
1035             JCVariableDecl param = l.head.param;
1036             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1037                     ((JCTypeDisjoint)l.head.param.vartype).components :
1038                     List.of(l.head.param.vartype);
1039             List<Type> ctypes = List.nil();
1040             List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
1041             for (JCExpression ct : subClauses) {
1042                 Type exc = ct.type;
1043                 ctypes = ctypes.append(exc);
1044                 if (types.isSameType(exc, syms.objectType))
1045                     continue;
1046                 if (chk.subset(exc, caughtInTry)) {
1047                     log.error(l.head.pos(),
1048                               "except.already.caught", exc);
1049                 } else if (!chk.isUnchecked(l.head.pos(), exc) &&
1050                            exc.tsym != syms.throwableType.tsym &&
1051                            exc.tsym != syms.exceptionType.tsym &&


1095                     PendingExit exit = exits.next();
1096                     if (exit.inits != null) {
1097                         exit.inits.orSet(inits);
1098                         exit.uninits.andSet(uninits);
1099                     }
1100                     pendingExits.append(exit);
1101                 }
1102                 inits.orSet(initsEnd);
1103                 alive = aliveEnd;
1104             }
1105         } else {
1106             thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1107             inits = initsEnd;
1108             uninits = uninitsEnd;
1109             alive = aliveEnd;
1110             ListBuffer<PendingExit> exits = pendingExits;
1111             pendingExits = prevPendingExits;
1112             while (exits.nonEmpty()) pendingExits.append(exits.next());
1113         }
1114         uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
1115         unrefdResources = unrefdResourcesPrev;
1116     }
1117 
1118     public void visitConditional(JCConditional tree) {
1119         scanCond(tree.cond);
1120         Bits initsBeforeElse = initsWhenFalse;
1121         Bits uninitsBeforeElse = uninitsWhenFalse;
1122         inits = initsWhenTrue;
1123         uninits = uninitsWhenTrue;
1124         if (tree.truepart.type.tag == BOOLEAN &&
1125             tree.falsepart.type.tag == BOOLEAN) {
1126             // if b and c are boolean valued, then
1127             // v is (un)assigned after a?b:c when true iff
1128             //    v is (un)assigned after b when true and
1129             //    v is (un)assigned after c when true
1130             scanCond(tree.truepart);
1131             Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
1132             Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
1133             Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
1134             Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
1135             inits = initsBeforeElse;


1319             Bits initsWhenTrueLeft = initsWhenTrue;
1320             Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1321             inits = initsWhenFalse;
1322             uninits = uninitsWhenFalse;
1323             scanCond(tree.rhs);
1324             initsWhenTrue.andSet(initsWhenTrueLeft);
1325             uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1326             break;
1327         default:
1328             scanExpr(tree.lhs);
1329             scanExpr(tree.rhs);
1330         }
1331     }
1332 
1333     public void visitAnnotatedType(JCAnnotatedType tree) {
1334         // annotations don't get scanned
1335         tree.underlyingType.accept(this);
1336     }
1337 
1338     public void visitIdent(JCIdent tree) {
1339         if (tree.sym.kind == VAR) {
1340             checkInit(tree.pos(), (VarSymbol)tree.sym);
1341             referenced(tree.sym);
1342         }
1343     }
1344 
1345     void referenced(Symbol sym) {
1346         if (unrefdResources != null && unrefdResources.contains(sym)) {
1347             unrefdResources.remove(sym);
1348         }
1349     }
1350 
1351     public void visitTypeCast(JCTypeCast tree) {
1352         super.visitTypeCast(tree);
1353         if (!tree.type.isErroneous()
1354             && lint.isEnabled(Lint.LintCategory.CAST)
1355             && types.isSameType(tree.expr.type, tree.clazz.type)
1356             && !(ignoreAnnotatedCasts && containsTypeAnnotation(tree.clazz))) {
1357             log.warning(tree.pos(), "redundant.cast", tree.expr.type);
1358         }
1359     }
1360 
1361     public void visitTopLevel(JCCompilationUnit tree) {
1362         // Do nothing for TopLevel since each class is visited individually
1363     }
1364 
1365 /**************************************************************************
1366  * utility methods for ignoring type-annotated casts lint checking
1367  *************************************************************************/
1368     private static final boolean ignoreAnnotatedCasts = true;