283 }
284
285 protected Flow(Context context) {
286 context.put(flowKey, this);
287 names = Names.instance(context);
288 log = Log.instance(context);
289 syms = Symtab.instance(context);
290 types = Types.instance(context);
291 chk = Check.instance(context);
292 lint = Lint.instance(context);
293 rs = Resolve.instance(context);
294 diags = JCDiagnostic.Factory.instance(context);
295 Source source = Source.instance(context);
296 allowEffectivelyFinalInInnerClasses = Feature.EFFECTIVELY_FINAL_IN_INNER_CLASSES.allowedInSource(source);
297 }
298
299 /**
300 * Base visitor class for all visitors implementing dataflow analysis logic.
301 * This class define the shared logic for handling jumps (break/continue statements).
302 */
303 static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
304
305 enum JumpKind {
306 BREAK(JCTree.Tag.BREAK) {
307 @Override
308 JCTree getTarget(JCTree tree) {
309 return ((JCBreak)tree).target;
310 }
311 },
312 CONTINUE(JCTree.Tag.CONTINUE) {
313 @Override
314 JCTree getTarget(JCTree tree) {
315 return ((JCContinue)tree).target;
316 }
317 };
318
319 final JCTree.Tag treeTag;
320
321 private JumpKind(Tag treeTag) {
322 this.treeTag = treeTag;
323 }
324
325 abstract JCTree getTarget(JCTree tree);
326 }
327
328 /** The currently pending exits that go from current inner blocks
329 * to an enclosing block, in source order.
330 */
331 ListBuffer<P> pendingExits;
332
333 /** A pending exit. These are the statements return, break, and
334 * continue. In addition, exception-throwing expressions or
335 * statements are put here when not known to be caught. This
336 * will typically result in an error unless it is within a
337 * try-finally whose finally block cannot complete normally.
338 */
339 static class PendingExit {
340 JCTree tree;
341
342 PendingExit(JCTree tree) {
343 this.tree = tree;
344 }
345
346 void resolveJump() {
347 //do nothing
348 }
349 }
350
351 abstract void markDead();
352
353 /** Record an outward transfer of control. */
354 void recordExit(P pe) {
355 pendingExits.append(pe);
356 markDead();
357 }
358
359 /** Resolve all jumps of this statement. */
360 private Liveness resolveJump(JCTree tree,
361 ListBuffer<P> oldPendingExits,
362 JumpKind jk) {
363 boolean resolved = false;
364 List<P> exits = pendingExits.toList();
365 pendingExits = oldPendingExits;
366 for (; exits.nonEmpty(); exits = exits.tail) {
367 P exit = exits.head;
368 if (exit.tree.hasTag(jk.treeTag) &&
369 jk.getTarget(exit.tree) == tree) {
370 exit.resolveJump();
371 resolved = true;
372 } else {
373 pendingExits.append(exit);
374 }
375 }
376 return Liveness.from(resolved);
377 }
378
379 /** Resolve all continues of this statement. */
380 Liveness resolveContinues(JCTree tree) {
381 return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
382 }
383
384 /** Resolve all breaks of this statement. */
385 Liveness resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
386 return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
387 }
388
389 @Override
390 public void scan(JCTree tree) {
391 if (tree != null && (
392 tree.type == null ||
393 tree.type != Type.stuckType)) {
394 super.scan(tree);
395 }
396 }
397
398 public void visitPackageDef(JCPackageDecl tree) {
399 // Do nothing for PackageDecl
400 }
401
402 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
403 JCBreak brk = make.at(Position.NOPOS).Break(null);
404 brk.target = swtch;
405 scan(brk);
406 }
407 }
408
409 /**
410 * This pass implements the first step of the dataflow analysis, namely
411 * the liveness analysis check. This checks that every statement is reachable.
412 * The output of this analysis pass are used by other analyzers. This analyzer
413 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
414 */
415 class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
416
417 /** A flag that indicates whether the last statement could
418 * complete normally.
419 */
420 private Liveness alive;
421
422 @Override
423 void markDead() {
424 alive = Liveness.DEAD;
425 }
426
427 /*************************************************************************
428 * Visitor methods for statements and definitions
429 *************************************************************************/
430
431 /** Analyze a definition.
432 */
433 void scanDef(JCTree tree) {
434 scanStat(tree);
435 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && alive == Liveness.DEAD) {
814 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
815 try {
816 attrEnv = env;
817 Flow.this.make = make;
818 pendingExits = new ListBuffer<>();
819 alive = Liveness.ALIVE;
820 scan(tree);
821 } finally {
822 pendingExits = null;
823 Flow.this.make = null;
824 }
825 }
826 }
827
828 /**
829 * This pass implements the second step of the dataflow analysis, namely
830 * the exception analysis. This is to ensure that every checked exception that is
831 * thrown is declared or caught. The analyzer uses some info that has been set by
832 * the liveliness analyzer.
833 */
834 class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
835
836 /** A flag that indicates whether the last statement could
837 * complete normally.
838 */
839 HashMap<Symbol, List<Type>> preciseRethrowTypes;
840
841 /** The current class being defined.
842 */
843 JCClassDecl classDef;
844
845 /** The list of possibly thrown declarable exceptions.
846 */
847 List<Type> thrown;
848
849 /** The list of exceptions that are either caught or declared to be
850 * thrown.
851 */
852 List<Type> caught;
853
854 class FlowPendingExit extends BaseAnalyzer.PendingExit {
855
856 Type thrown;
857
858 FlowPendingExit(JCTree tree, Type thrown) {
859 super(tree);
860 this.thrown = thrown;
861 }
862 }
863
864 @Override
865 void markDead() {
866 //do nothing
867 }
868
869 /*-------------------- Exceptions ----------------------*/
870
871 /** Complain that pending exceptions are not caught.
872 */
873 void errorUncaught() {
874 for (FlowPendingExit exit = pendingExits.next();
875 exit != null;
876 exit = pendingExits.next()) {
877 if (classDef != null &&
878 classDef.pos == exit.tree.pos) {
879 log.error(exit.tree.pos(),
880 Errors.UnreportedExceptionDefaultConstructor(exit.thrown));
881 } else if (exit.tree.hasTag(VARDEF) &&
882 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
883 log.error(exit.tree.pos(),
884 Errors.UnreportedExceptionImplicitClose(exit.thrown,
885 ((JCVariableDecl)exit.tree).sym.name));
886 } else {
887 log.error(exit.tree.pos(),
888 Errors.UnreportedExceptionNeedToCatchOrThrow(exit.thrown));
889 }
890 }
891 }
892
893 /** Record that exception is potentially thrown and check that it
894 * is caught.
895 */
896 void markThrown(JCTree tree, Type exc) {
897 if (!chk.isUnchecked(tree.pos(), exc)) {
898 if (!chk.isHandled(exc, caught)) {
899 pendingExits.append(new FlowPendingExit(tree, exc));
900 }
901 thrown = chk.incl(exc, thrown);
902 }
903 }
904
905 /*************************************************************************
906 * Visitor methods for statements and definitions
907 *************************************************************************/
908
909 /* ------------ Visitor methods for various sorts of trees -------------*/
910
911 public void visitClassDef(JCClassDecl tree) {
912 if (tree.sym == null) return;
913
914 JCClassDecl classDefPrev = classDef;
915 List<Type> thrownPrev = thrown;
916 List<Type> caughtPrev = caught;
917 ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
918 Lint lintPrev = lint;
919 boolean anonymousClass = tree.name == names.empty;
920 pendingExits = new ListBuffer<>();
921 if (!anonymousClass) {
922 caught = List.nil();
923 }
924 classDef = tree;
925 thrown = List.nil();
926 lint = lint.augment(tree.sym);
927
928 try {
929 // process all the static initializers
930 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
931 if (!l.head.hasTag(METHODDEF) &&
932 (TreeInfo.flags(l.head) & STATIC) != 0) {
933 scan(l.head);
934 errorUncaught();
935 }
936 }
937
1007 Lint lintPrev = lint;
1008
1009 lint = lint.augment(tree.sym);
1010
1011 Assert.check(pendingExits.isEmpty());
1012
1013 try {
1014 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1015 JCVariableDecl def = l.head;
1016 scan(def);
1017 }
1018 if (TreeInfo.isInitialConstructor(tree))
1019 caught = chk.union(caught, mthrown);
1020 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
1021 caught = mthrown;
1022 // else we are in an instance initializer block;
1023 // leave caught unchanged.
1024
1025 scan(tree.body);
1026
1027 List<FlowPendingExit> exits = pendingExits.toList();
1028 pendingExits = new ListBuffer<>();
1029 while (exits.nonEmpty()) {
1030 FlowPendingExit exit = exits.head;
1031 exits = exits.tail;
1032 if (exit.thrown == null) {
1033 Assert.check(exit.tree.hasTag(RETURN));
1034 } else {
1035 // uncaught throws will be reported later
1036 pendingExits.append(exit);
1037 }
1038 }
1039 } finally {
1040 caught = caughtPrev;
1041 lint = lintPrev;
1042 }
1043 }
1044
1045 public void visitVarDef(JCVariableDecl tree) {
1046 if (tree.init != null) {
1047 Lint lintPrev = lint;
1048 lint = lint.augment(tree.sym);
1049 try{
1050 scan(tree.init);
1051 } finally {
1052 lint = lintPrev;
1053 }
1054 }
1055 }
1056
1057 public void visitBlock(JCBlock tree) {
1058 scan(tree.stats);
1059 }
1060
1061 public void visitDoLoop(JCDoWhileLoop tree) {
1062 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1063 pendingExits = new ListBuffer<>();
1064 scan(tree.body);
1065 resolveContinues(tree);
1066 scan(tree.cond);
1067 resolveBreaks(tree, prevPendingExits);
1068 }
1069
1070 public void visitWhileLoop(JCWhileLoop tree) {
1071 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1072 pendingExits = new ListBuffer<>();
1073 scan(tree.cond);
1074 scan(tree.body);
1075 resolveContinues(tree);
1076 resolveBreaks(tree, prevPendingExits);
1077 }
1078
1079 public void visitForLoop(JCForLoop tree) {
1080 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1081 scan(tree.init);
1082 pendingExits = new ListBuffer<>();
1083 if (tree.cond != null) {
1084 scan(tree.cond);
1085 }
1086 scan(tree.body);
1087 resolveContinues(tree);
1088 scan(tree.step);
1089 resolveBreaks(tree, prevPendingExits);
1090 }
1091
1092 public void visitForeachLoop(JCEnhancedForLoop tree) {
1093 visitVarDef(tree.var);
1094 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1095 scan(tree.expr);
1096 pendingExits = new ListBuffer<>();
1097 scan(tree.body);
1098 resolveContinues(tree);
1099 resolveBreaks(tree, prevPendingExits);
1100 }
1101
1102 public void visitLabelled(JCLabeledStatement tree) {
1103 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1104 pendingExits = new ListBuffer<>();
1105 scan(tree.body);
1106 resolveBreaks(tree, prevPendingExits);
1107 }
1108
1109 public void visitSwitch(JCSwitch tree) {
1110 handleSwitch(tree, tree.selector, tree.cases);
1111 }
1112
1113 @Override
1114 public void visitSwitchExpression(JCSwitchExpression tree) {
1115 handleSwitch(tree, tree.selector, tree.cases);
1116 }
1117
1118 private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
1119 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1120 pendingExits = new ListBuffer<>();
1121 scan(selector);
1122 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
1123 JCCase c = l.head;
1124 scan(c.pats);
1125 scan(c.stats);
1126 }
1127 resolveBreaks(tree, prevPendingExits);
1128 }
1129
1130 public void visitTry(JCTry tree) {
1131 List<Type> caughtPrev = caught;
1132 List<Type> thrownPrev = thrown;
1133 thrown = List.nil();
1134 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1135 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1136 ((JCTypeUnion)l.head.param.vartype).alternatives :
1137 List.of(l.head.param.vartype);
1138 for (JCExpression ct : subClauses) {
1139 caught = chk.incl(ct.type, caught);
1140 }
1141 }
1142
1143 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1144 pendingExits = new ListBuffer<>();
1145 for (JCTree resource : tree.resources) {
1146 if (resource instanceof JCVariableDecl) {
1147 JCVariableDecl vdecl = (JCVariableDecl) resource;
1148 visitVarDef(vdecl);
1149 } else if (resource instanceof JCExpression) {
1150 scan((JCExpression) resource);
1151 } else {
1152 throw new AssertionError(tree); // parser error
1153 }
1154 }
1155 for (JCTree resource : tree.resources) {
1156 List<Type> closeableSupertypes = resource.type.isCompound() ?
1157 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1158 List.of(resource.type);
1159 for (Type sup : closeableSupertypes) {
1160 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1161 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1162 attrEnv,
1163 types.skipTypeVars(sup, false),
1187 List<Type> ctypes = List.nil();
1188 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
1189 for (JCExpression ct : subClauses) {
1190 Type exc = ct.type;
1191 if (exc != syms.unknownType) {
1192 ctypes = ctypes.append(exc);
1193 if (types.isSameType(exc, syms.objectType))
1194 continue;
1195 checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
1196 caughtInTry = chk.incl(exc, caughtInTry);
1197 }
1198 }
1199 scan(param);
1200 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
1201 scan(l.head.body);
1202 preciseRethrowTypes.remove(param.sym);
1203 }
1204 if (tree.finalizer != null) {
1205 List<Type> savedThrown = thrown;
1206 thrown = List.nil();
1207 ListBuffer<FlowPendingExit> exits = pendingExits;
1208 pendingExits = prevPendingExits;
1209 scan(tree.finalizer);
1210 if (!tree.finallyCanCompleteNormally) {
1211 // discard exits and exceptions from try and finally
1212 thrown = chk.union(thrown, thrownPrev);
1213 } else {
1214 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1215 thrown = chk.union(thrown, savedThrown);
1216 // FIX: this doesn't preserve source order of exits in catch
1217 // versus finally!
1218 while (exits.nonEmpty()) {
1219 pendingExits.append(exits.next());
1220 }
1221 }
1222 } else {
1223 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1224 ListBuffer<FlowPendingExit> exits = pendingExits;
1225 pendingExits = prevPendingExits;
1226 while (exits.nonEmpty()) pendingExits.append(exits.next());
1227 }
1228 }
1229
1230 @Override
1231 public void visitIf(JCIf tree) {
1232 scan(tree.cond);
1233 scan(tree.thenpart);
1234 if (tree.elsepart != null) {
1235 scan(tree.elsepart);
1236 }
1237 }
1238
1239 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
1240 if (chk.subset(exc, caughtInTry)) {
1241 log.error(pos, Errors.ExceptAlreadyCaught(exc));
1242 } else if (!chk.isUnchecked(pos, exc) &&
1243 !isExceptionOrThrowable(exc) &&
1244 !chk.intersects(exc, thrownInTry)) {
1250 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
1251 // exception, that would have been covered in the branch above
1252 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
1253 !isExceptionOrThrowable(exc)) {
1254 Warning key = catchableThrownTypes.length() == 1 ?
1255 Warnings.UnreachableCatch(catchableThrownTypes) :
1256 Warnings.UnreachableCatch1(catchableThrownTypes);
1257 log.warning(pos, key);
1258 }
1259 }
1260 }
1261 //where
1262 private boolean isExceptionOrThrowable(Type exc) {
1263 return exc.tsym == syms.throwableType.tsym ||
1264 exc.tsym == syms.exceptionType.tsym;
1265 }
1266
1267 public void visitBreak(JCBreak tree) {
1268 if (tree.isValueBreak())
1269 scan(tree.value);
1270 recordExit(new FlowPendingExit(tree, null));
1271 }
1272
1273 public void visitContinue(JCContinue tree) {
1274 recordExit(new FlowPendingExit(tree, null));
1275 }
1276
1277 public void visitReturn(JCReturn tree) {
1278 scan(tree.expr);
1279 recordExit(new FlowPendingExit(tree, null));
1280 }
1281
1282 public void visitThrow(JCThrow tree) {
1283 scan(tree.expr);
1284 Symbol sym = TreeInfo.symbol(tree.expr);
1285 if (sym != null &&
1286 sym.kind == VAR &&
1287 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
1288 preciseRethrowTypes.get(sym) != null) {
1289 for (Type t : preciseRethrowTypes.get(sym)) {
1290 markThrown(tree, t);
1291 }
1292 }
1293 else {
1294 markThrown(tree, tree.expr.type);
1295 }
1296 markDead();
1297 }
1298
1299 public void visitApply(JCMethodInvocation tree) {
1326 for (List<Type> l = tree.constructor.type.getThrownTypes();
1327 l.nonEmpty();
1328 l = l.tail) {
1329 caught = chk.incl(l.head, caught);
1330 }
1331 scan(tree.def);
1332 }
1333 finally {
1334 caught = caughtPrev;
1335 }
1336 }
1337
1338 @Override
1339 public void visitLambda(JCLambda tree) {
1340 if (tree.type != null &&
1341 tree.type.isErroneous()) {
1342 return;
1343 }
1344 List<Type> prevCaught = caught;
1345 List<Type> prevThrown = thrown;
1346 ListBuffer<FlowPendingExit> prevPending = pendingExits;
1347 try {
1348 pendingExits = new ListBuffer<>();
1349 caught = tree.getDescriptorType(types).getThrownTypes();
1350 thrown = List.nil();
1351 scan(tree.body);
1352 List<FlowPendingExit> exits = pendingExits.toList();
1353 pendingExits = new ListBuffer<>();
1354 while (exits.nonEmpty()) {
1355 FlowPendingExit exit = exits.head;
1356 exits = exits.tail;
1357 if (exit.thrown == null) {
1358 Assert.check(exit.tree.hasTag(RETURN));
1359 } else {
1360 // uncaught throws will be reported later
1361 pendingExits.append(exit);
1362 }
1363 }
1364
1365 errorUncaught();
1366 } finally {
1367 pendingExits = prevPending;
1368 caught = prevCaught;
1369 thrown = prevThrown;
1370 }
1371 }
1372
1373 public void visitModuleDef(JCModuleDecl tree) {
1374 // Do nothing for modules
1375 }
1376
1377 /**************************************************************************
1471 @Override
1472 public void visitClassDef(JCClassDecl tree) {
1473 //skip
1474 }
1475 }
1476
1477 /**
1478 * Specialized pass that performs inference of thrown types for lambdas.
1479 */
1480 class LambdaFlowAnalyzer extends FlowAnalyzer {
1481 List<Type> inferredThrownTypes;
1482 boolean inLambda;
1483 @Override
1484 public void visitLambda(JCLambda tree) {
1485 if ((tree.type != null &&
1486 tree.type.isErroneous()) || inLambda) {
1487 return;
1488 }
1489 List<Type> prevCaught = caught;
1490 List<Type> prevThrown = thrown;
1491 ListBuffer<FlowPendingExit> prevPending = pendingExits;
1492 inLambda = true;
1493 try {
1494 pendingExits = new ListBuffer<>();
1495 caught = List.of(syms.throwableType);
1496 thrown = List.nil();
1497 scan(tree.body);
1498 inferredThrownTypes = thrown;
1499 } finally {
1500 pendingExits = prevPending;
1501 caught = prevCaught;
1502 thrown = prevThrown;
1503 inLambda = false;
1504 }
1505 }
1506 @Override
1507 public void visitClassDef(JCClassDecl tree) {
1508 //skip
1509 }
1510 }
1511
1512 /**
1513 * This pass implements (i) definite assignment analysis, which ensures that
1514 * each variable is assigned when used and (ii) definite unassignment analysis,
1515 * which ensures that no final variable is assigned more than once. This visitor
1516 * depends on the results of the liveliness analyzer. This pass is also used to mark
1517 * effectively-final local variables/parameters.
1518 */
1519
1520 public class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
1521
1522 /** The set of definitely assigned variables.
1523 */
1524 final Bits inits;
1525
1526 /** The set of definitely unassigned variables.
1527 */
1528 final Bits uninits;
1529
1530 /** The set of variables that are definitely unassigned everywhere
1531 * in current try block. This variable is maintained lazily; it is
1532 * updated only when something gets removed from uninits,
1533 * typically by being assigned in reachable code. To obtain the
1534 * correct set of variables which are definitely unassigned
1535 * anywhere in current try block, intersect uninitsTry and
1536 * uninits.
1537 */
1538 final Bits uninitsTry;
1539
1540 /** When analyzing a condition, inits and uninits are null.
1818 }
1819 }
1820
1821 /* ------------ Visitor methods for various sorts of trees -------------*/
1822
1823 public void visitClassDef(JCClassDecl tree) {
1824 if (tree.sym == null) {
1825 return;
1826 }
1827
1828 Lint lintPrev = lint;
1829 lint = lint.augment(tree.sym);
1830 try {
1831 if (tree.sym == null) {
1832 return;
1833 }
1834
1835 JCClassDecl classDefPrev = classDef;
1836 int firstadrPrev = firstadr;
1837 int nextadrPrev = nextadr;
1838 ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
1839
1840 pendingExits = new ListBuffer<>();
1841 if (tree.name != names.empty) {
1842 firstadr = nextadr;
1843 }
1844 classDef = tree;
1845 try {
1846 // define all the static fields
1847 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1848 if (l.head.hasTag(VARDEF)) {
1849 JCVariableDecl def = (JCVariableDecl)l.head;
1850 if ((def.mods.flags & STATIC) != 0) {
1851 VarSymbol sym = def.sym;
1852 if (trackable(sym)) {
1853 newVar(def);
1854 }
1855 }
1856 }
1857 }
1858
1953 scan(tree.body);
1954
1955 if (isInitialConstructor) {
1956 boolean isSynthesized = (tree.sym.flags() &
1957 GENERATEDCONSTR) != 0;
1958 for (int i = firstadr; i < nextadr; i++) {
1959 JCVariableDecl vardecl = vardecls[i];
1960 VarSymbol var = vardecl.sym;
1961 if (var.owner == classDef.sym) {
1962 // choose the diagnostic position based on whether
1963 // the ctor is default(synthesized) or not
1964 if (isSynthesized) {
1965 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
1966 var, Errors.VarNotInitializedInDefaultConstructor(var));
1967 } else {
1968 checkInit(TreeInfo.diagEndPos(tree.body), var);
1969 }
1970 }
1971 }
1972 }
1973 List<AssignPendingExit> exits = pendingExits.toList();
1974 pendingExits = new ListBuffer<>();
1975 while (exits.nonEmpty()) {
1976 AssignPendingExit exit = exits.head;
1977 exits = exits.tail;
1978 Assert.check(exit.tree.hasTag(RETURN), exit.tree);
1979 if (isInitialConstructor) {
1980 inits.assign(exit.exit_inits);
1981 for (int i = firstadr; i < nextadr; i++) {
1982 checkInit(exit.tree.pos(), vardecls[i].sym);
1983 }
1984 }
1985 }
1986 } finally {
1987 inits.assign(initsPrev);
1988 uninits.assign(uninitsPrev);
1989 nextadr = nextadrPrev;
1990 firstadr = firstadrPrev;
1991 returnadr = returnadrPrev;
1992 isInitialConstructor = lastInitialConstructor;
1993 }
1994 } finally {
1995 lint = lintPrev;
1996 }
1997 }
1998
1999 protected void initParam(JCVariableDecl def) {
2000 inits.incl(def.sym.adr);
2010 newVar(tree);
2011 }
2012 if (tree.init != null) {
2013 scanExpr(tree.init);
2014 if (track) {
2015 letInit(tree.pos(), tree.sym);
2016 }
2017 }
2018 } finally {
2019 lint = lintPrev;
2020 }
2021 }
2022
2023 public void visitBlock(JCBlock tree) {
2024 int nextadrPrev = nextadr;
2025 scan(tree.stats);
2026 nextadr = nextadrPrev;
2027 }
2028
2029 public void visitDoLoop(JCDoWhileLoop tree) {
2030 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2031 FlowKind prevFlowKind = flowKind;
2032 flowKind = FlowKind.NORMAL;
2033 final Bits initsSkip = new Bits(true);
2034 final Bits uninitsSkip = new Bits(true);
2035 pendingExits = new ListBuffer<>();
2036 int prevErrors = log.nerrors;
2037 do {
2038 final Bits uninitsEntry = new Bits(uninits);
2039 uninitsEntry.excludeFrom(nextadr);
2040 scan(tree.body);
2041 resolveContinues(tree);
2042 scanCond(tree.cond);
2043 if (!flowKind.isFinal()) {
2044 initsSkip.assign(initsWhenFalse);
2045 uninitsSkip.assign(uninitsWhenFalse);
2046 }
2047 if (log.nerrors != prevErrors ||
2048 flowKind.isFinal() ||
2049 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
2050 break;
2051 inits.assign(initsWhenTrue);
2052 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
2053 flowKind = FlowKind.SPECULATIVE_LOOP;
2054 } while (true);
2055 flowKind = prevFlowKind;
2056 inits.assign(initsSkip);
2057 uninits.assign(uninitsSkip);
2058 resolveBreaks(tree, prevPendingExits);
2059 }
2060
2061 public void visitWhileLoop(JCWhileLoop tree) {
2062 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2063 FlowKind prevFlowKind = flowKind;
2064 flowKind = FlowKind.NORMAL;
2065 final Bits initsSkip = new Bits(true);
2066 final Bits uninitsSkip = new Bits(true);
2067 pendingExits = new ListBuffer<>();
2068 int prevErrors = log.nerrors;
2069 final Bits uninitsEntry = new Bits(uninits);
2070 uninitsEntry.excludeFrom(nextadr);
2071 do {
2072 scanCond(tree.cond);
2073 if (!flowKind.isFinal()) {
2074 initsSkip.assign(initsWhenFalse) ;
2075 uninitsSkip.assign(uninitsWhenFalse);
2076 }
2077 inits.assign(initsWhenTrue);
2078 uninits.assign(uninitsWhenTrue);
2079 scan(tree.body);
2080 resolveContinues(tree);
2081 if (log.nerrors != prevErrors ||
2082 flowKind.isFinal() ||
2083 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
2084 break;
2085 }
2086 uninits.assign(uninitsEntry.andSet(uninits));
2087 flowKind = FlowKind.SPECULATIVE_LOOP;
2088 } while (true);
2089 flowKind = prevFlowKind;
2090 //a variable is DA/DU after the while statement, if it's DA/DU assuming the
2091 //branch is not taken AND if it's DA/DU before any break statement
2092 inits.assign(initsSkip);
2093 uninits.assign(uninitsSkip);
2094 resolveBreaks(tree, prevPendingExits);
2095 }
2096
2097 public void visitForLoop(JCForLoop tree) {
2098 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2099 FlowKind prevFlowKind = flowKind;
2100 flowKind = FlowKind.NORMAL;
2101 int nextadrPrev = nextadr;
2102 scan(tree.init);
2103 final Bits initsSkip = new Bits(true);
2104 final Bits uninitsSkip = new Bits(true);
2105 pendingExits = new ListBuffer<>();
2106 int prevErrors = log.nerrors;
2107 do {
2108 final Bits uninitsEntry = new Bits(uninits);
2109 uninitsEntry.excludeFrom(nextadr);
2110 if (tree.cond != null) {
2111 scanCond(tree.cond);
2112 if (!flowKind.isFinal()) {
2113 initsSkip.assign(initsWhenFalse);
2114 uninitsSkip.assign(uninitsWhenFalse);
2115 }
2116 inits.assign(initsWhenTrue);
2117 uninits.assign(uninitsWhenTrue);
2118 } else if (!flowKind.isFinal()) {
2126 scan(tree.step);
2127 if (log.nerrors != prevErrors ||
2128 flowKind.isFinal() ||
2129 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2130 break;
2131 uninits.assign(uninitsEntry.andSet(uninits));
2132 flowKind = FlowKind.SPECULATIVE_LOOP;
2133 } while (true);
2134 flowKind = prevFlowKind;
2135 //a variable is DA/DU after a for loop, if it's DA/DU assuming the
2136 //branch is not taken AND if it's DA/DU before any break statement
2137 inits.assign(initsSkip);
2138 uninits.assign(uninitsSkip);
2139 resolveBreaks(tree, prevPendingExits);
2140 nextadr = nextadrPrev;
2141 }
2142
2143 public void visitForeachLoop(JCEnhancedForLoop tree) {
2144 visitVarDef(tree.var);
2145
2146 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2147 FlowKind prevFlowKind = flowKind;
2148 flowKind = FlowKind.NORMAL;
2149 int nextadrPrev = nextadr;
2150 scan(tree.expr);
2151 final Bits initsStart = new Bits(inits);
2152 final Bits uninitsStart = new Bits(uninits);
2153
2154 letInit(tree.pos(), tree.var.sym);
2155 pendingExits = new ListBuffer<>();
2156 int prevErrors = log.nerrors;
2157 do {
2158 final Bits uninitsEntry = new Bits(uninits);
2159 uninitsEntry.excludeFrom(nextadr);
2160 scan(tree.body);
2161 resolveContinues(tree);
2162 if (log.nerrors != prevErrors ||
2163 flowKind.isFinal() ||
2164 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2165 break;
2166 uninits.assign(uninitsEntry.andSet(uninits));
2167 flowKind = FlowKind.SPECULATIVE_LOOP;
2168 } while (true);
2169 flowKind = prevFlowKind;
2170 inits.assign(initsStart);
2171 uninits.assign(uninitsStart.andSet(uninits));
2172 resolveBreaks(tree, prevPendingExits);
2173 nextadr = nextadrPrev;
2174 }
2175
2176 public void visitLabelled(JCLabeledStatement tree) {
2177 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2178 pendingExits = new ListBuffer<>();
2179 scan(tree.body);
2180 resolveBreaks(tree, prevPendingExits);
2181 }
2182
2183 public void visitSwitch(JCSwitch tree) {
2184 handleSwitch(tree, tree.selector, tree.cases);
2185 }
2186
2187 public void visitSwitchExpression(JCSwitchExpression tree) {
2188 handleSwitch(tree, tree.selector, tree.cases);
2189 }
2190
2191 private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
2192 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2193 pendingExits = new ListBuffer<>();
2194 int nextadrPrev = nextadr;
2195 scanExpr(selector);
2196 final Bits initsSwitch = new Bits(inits);
2197 final Bits uninitsSwitch = new Bits(uninits);
2198 boolean hasDefault = false;
2199 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
2200 inits.assign(initsSwitch);
2201 uninits.assign(uninits.andSet(uninitsSwitch));
2202 JCCase c = l.head;
2203 if (c.pats.isEmpty()) {
2204 hasDefault = true;
2205 } else {
2206 for (JCExpression pat : c.pats) {
2207 scanExpr(pat);
2208 }
2209 }
2210 if (hasDefault) {
2211 inits.assign(initsSwitch);
2212 uninits.assign(uninits.andSet(uninitsSwitch));
2228 resolveBreaks(tree, prevPendingExits);
2229 nextadr = nextadrPrev;
2230 }
2231 // where
2232 /** Add any variables defined in stats to inits and uninits. */
2233 private void addVars(List<JCStatement> stats, final Bits inits,
2234 final Bits uninits) {
2235 for (;stats.nonEmpty(); stats = stats.tail) {
2236 JCTree stat = stats.head;
2237 if (stat.hasTag(VARDEF)) {
2238 int adr = ((JCVariableDecl) stat).sym.adr;
2239 inits.excl(adr);
2240 uninits.incl(adr);
2241 }
2242 }
2243 }
2244
2245 public void visitTry(JCTry tree) {
2246 ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
2247 final Bits uninitsTryPrev = new Bits(uninitsTry);
2248 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
2249 pendingExits = new ListBuffer<>();
2250 final Bits initsTry = new Bits(inits);
2251 uninitsTry.assign(uninits);
2252 for (JCTree resource : tree.resources) {
2253 if (resource instanceof JCVariableDecl) {
2254 JCVariableDecl vdecl = (JCVariableDecl) resource;
2255 visitVarDef(vdecl);
2256 unrefdResources.enter(vdecl.sym);
2257 resourceVarDecls.append(vdecl);
2258 } else if (resource instanceof JCExpression) {
2259 scanExpr((JCExpression) resource);
2260 } else {
2261 throw new AssertionError(tree); // parser error
2262 }
2263 }
2264 scan(tree.body);
2265 uninitsTry.andSet(uninits);
2266 final Bits initsEnd = new Bits(inits);
2267 final Bits uninitsEnd = new Bits(uninits);
2268 int nextadrCatch = nextadr;
2285 final Bits initsCatchPrev = new Bits(initsTry);
2286 final Bits uninitsCatchPrev = new Bits(uninitsTry);
2287
2288 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
2289 JCVariableDecl param = l.head.param;
2290 inits.assign(initsCatchPrev);
2291 uninits.assign(uninitsCatchPrev);
2292 scan(param);
2293 /* If this is a TWR and we are executing the code from Gen,
2294 * then there can be synthetic variables, ignore them.
2295 */
2296 initParam(param);
2297 scan(l.head.body);
2298 initsEnd.andSet(inits);
2299 uninitsEnd.andSet(uninits);
2300 nextadr = nextadrCatch;
2301 }
2302 if (tree.finalizer != null) {
2303 inits.assign(initsTry);
2304 uninits.assign(uninitsTry);
2305 ListBuffer<AssignPendingExit> exits = pendingExits;
2306 pendingExits = prevPendingExits;
2307 scan(tree.finalizer);
2308 if (!tree.finallyCanCompleteNormally) {
2309 // discard exits and exceptions from try and finally
2310 } else {
2311 uninits.andSet(uninitsEnd);
2312 // FIX: this doesn't preserve source order of exits in catch
2313 // versus finally!
2314 while (exits.nonEmpty()) {
2315 AssignPendingExit exit = exits.next();
2316 if (exit.exit_inits != null) {
2317 exit.exit_inits.orSet(inits);
2318 exit.exit_uninits.andSet(uninits);
2319 }
2320 pendingExits.append(exit);
2321 }
2322 inits.orSet(initsEnd);
2323 }
2324 } else {
2325 inits.assign(initsEnd);
2326 uninits.assign(uninitsEnd);
2327 ListBuffer<AssignPendingExit> exits = pendingExits;
2328 pendingExits = prevPendingExits;
2329 while (exits.nonEmpty()) pendingExits.append(exits.next());
2330 }
2331 uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
2332 }
2333
2334 public void visitConditional(JCConditional tree) {
2335 scanCond(tree.cond);
2336 final Bits initsBeforeElse = new Bits(initsWhenFalse);
2337 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2338 inits.assign(initsWhenTrue);
2339 uninits.assign(uninitsWhenTrue);
2340 if (tree.truepart.type.hasTag(BOOLEAN) &&
2341 tree.falsepart.type.hasTag(BOOLEAN)) {
2342 // if b and c are boolean valued, then
2343 // v is (un)assigned after a?b:c when true iff
2344 // v is (un)assigned after b when true and
2345 // v is (un)assigned after c when true
2346 scanCond(tree.truepart);
2347 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
2373 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2374 inits.assign(initsWhenTrue);
2375 uninits.assign(uninitsWhenTrue);
2376 scan(tree.thenpart);
2377 if (tree.elsepart != null) {
2378 final Bits initsAfterThen = new Bits(inits);
2379 final Bits uninitsAfterThen = new Bits(uninits);
2380 inits.assign(initsBeforeElse);
2381 uninits.assign(uninitsBeforeElse);
2382 scan(tree.elsepart);
2383 inits.andSet(initsAfterThen);
2384 uninits.andSet(uninitsAfterThen);
2385 } else {
2386 inits.andSet(initsBeforeElse);
2387 uninits.andSet(uninitsBeforeElse);
2388 }
2389 }
2390
2391 @Override
2392 public void visitBreak(JCBreak tree) {
2393 if (tree.isValueBreak())
2394 scan(tree.value);
2395 recordExit(new AssignPendingExit(tree, inits, uninits));
2396 }
2397
2398 @Override
2399 public void visitContinue(JCContinue tree) {
2400 recordExit(new AssignPendingExit(tree, inits, uninits));
2401 }
2402
2403 @Override
2404 public void visitReturn(JCReturn tree) {
2405 scanExpr(tree.expr);
2406 recordExit(new AssignPendingExit(tree, inits, uninits));
2407 }
2408
2409 public void visitThrow(JCThrow tree) {
2410 scanExpr(tree.expr);
2411 markDead();
2412 }
2413
2414 public void visitApply(JCMethodInvocation tree) {
2415 scanExpr(tree.meth);
2416 scanExprs(tree.args);
2417 }
2418
2419 public void visitNewClass(JCNewClass tree) {
2420 scanExpr(tree.encl);
2421 scanExprs(tree.args);
2422 scan(tree.def);
2423 }
2424
2425 @Override
2426 public void visitLambda(JCLambda tree) {
2427 final Bits prevUninits = new Bits(uninits);
2428 final Bits prevInits = new Bits(inits);
2429 int returnadrPrev = returnadr;
2430 int nextadrPrev = nextadr;
2431 ListBuffer<AssignPendingExit> prevPending = pendingExits;
2432 try {
2433 returnadr = nextadr;
2434 pendingExits = new ListBuffer<>();
2435 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2436 JCVariableDecl def = l.head;
2437 scan(def);
2438 inits.incl(def.sym.adr);
2439 uninits.excl(def.sym.adr);
2440 }
2441 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2442 scanExpr(tree.body);
2443 } else {
2444 scan(tree.body);
2445 }
2446 }
2447 finally {
2448 returnadr = returnadrPrev;
2449 uninits.assign(prevUninits);
2450 inits.assign(prevInits);
2451 pendingExits = prevPending;
2601 }
2602 firstadr = 0;
2603 nextadr = 0;
2604 Flow.this.make = null;
2605 pendingExits = null;
2606 this.classDef = null;
2607 unrefdResources = null;
2608 }
2609 }
2610 }
2611
2612 /**
2613 * This pass implements the last step of the dataflow analysis, namely
2614 * the effectively-final analysis check. This checks that every local variable
2615 * reference from a lambda body/local inner class is either final or effectively final.
2616 * Additional this also checks that every variable that is used as an operand to
2617 * try-with-resources is final or effectively final.
2618 * As effectively final variables are marked as such during DA/DU, this pass must run after
2619 * AssignAnalyzer.
2620 */
2621 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
2622
2623 JCTree currentTree; //local class or lambda
2624
2625 @Override
2626 void markDead() {
2627 //do nothing
2628 }
2629
2630 @SuppressWarnings("fallthrough")
2631 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
2632 if (currentTree != null &&
2633 sym.owner.kind == MTH &&
2634 sym.pos < currentTree.getStartPosition()) {
2635 switch (currentTree.getTag()) {
2636 case CLASSDEF:
2637 if (!allowEffectivelyFinalInInnerClasses) {
2638 if ((sym.flags() & FINAL) == 0) {
2639 reportInnerClsNeedsFinalError(pos, sym);
2640 }
2641 break;
|
283 }
284
285 protected Flow(Context context) {
286 context.put(flowKey, this);
287 names = Names.instance(context);
288 log = Log.instance(context);
289 syms = Symtab.instance(context);
290 types = Types.instance(context);
291 chk = Check.instance(context);
292 lint = Lint.instance(context);
293 rs = Resolve.instance(context);
294 diags = JCDiagnostic.Factory.instance(context);
295 Source source = Source.instance(context);
296 allowEffectivelyFinalInInnerClasses = Feature.EFFECTIVELY_FINAL_IN_INNER_CLASSES.allowedInSource(source);
297 }
298
299 /**
300 * Base visitor class for all visitors implementing dataflow analysis logic.
301 * This class define the shared logic for handling jumps (break/continue statements).
302 */
303 static abstract class BaseAnalyzer extends TreeScanner {
304
305 enum JumpKind {
306 BREAK(JCTree.Tag.BREAK) {
307 @Override
308 JCTree getTarget(JCTree tree) {
309 return ((JCBreak)tree).target;
310 }
311 },
312 CONTINUE(JCTree.Tag.CONTINUE) {
313 @Override
314 JCTree getTarget(JCTree tree) {
315 return ((JCContinue)tree).target;
316 }
317 };
318
319 final JCTree.Tag treeTag;
320
321 private JumpKind(Tag treeTag) {
322 this.treeTag = treeTag;
323 }
324
325 abstract JCTree getTarget(JCTree tree);
326 }
327
328 /** The currently pending exits that go from current inner blocks
329 * to an enclosing block, in source order.
330 */
331 ListBuffer<PendingExit> pendingExits;
332
333 /** A pending exit. These are the statements return, break, and
334 * continue. In addition, exception-throwing expressions or
335 * statements are put here when not known to be caught. This
336 * will typically result in an error unless it is within a
337 * try-finally whose finally block cannot complete normally.
338 */
339 static class PendingExit {
340 JCTree tree;
341
342 PendingExit(JCTree tree) {
343 this.tree = tree;
344 }
345
346 void resolveJump() {
347 //do nothing
348 }
349 }
350
351 abstract void markDead();
352
353 /** Record an outward transfer of control. */
354 void recordExit(PendingExit pe) {
355 pendingExits.append(pe);
356 markDead();
357 }
358
359 /** Resolve all jumps of this statement. */
360 private Liveness resolveJump(JCTree tree,
361 ListBuffer<PendingExit> oldPendingExits,
362 JumpKind jk) {
363 boolean resolved = false;
364 List<PendingExit> exits = pendingExits.toList();
365 pendingExits = oldPendingExits;
366 for (; exits.nonEmpty(); exits = exits.tail) {
367 PendingExit exit = exits.head;
368 if (exit.tree.hasTag(jk.treeTag) &&
369 jk.getTarget(exit.tree) == tree) {
370 exit.resolveJump();
371 resolved = true;
372 } else {
373 pendingExits.append(exit);
374 }
375 }
376 return Liveness.from(resolved);
377 }
378
379 /** Resolve all continues of this statement. */
380 Liveness resolveContinues(JCTree tree) {
381 return resolveJump(tree, new ListBuffer<PendingExit>(), JumpKind.CONTINUE);
382 }
383
384 /** Resolve all breaks of this statement. */
385 Liveness resolveBreaks(JCTree tree, ListBuffer<PendingExit> oldPendingExits) {
386 return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
387 }
388
389 @Override
390 public void scan(JCTree tree) {
391 if (tree != null && (
392 tree.type == null ||
393 tree.type != Type.stuckType)) {
394 super.scan(tree);
395 }
396 }
397
398 public void visitPackageDef(JCPackageDecl tree) {
399 // Do nothing for PackageDecl
400 }
401
402 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
403 JCBreak brk = make.at(Position.NOPOS).Break(null);
404 brk.target = swtch;
405 scan(brk);
406 }
407 }
408
409 /**
410 * This pass implements the first step of the dataflow analysis, namely
411 * the liveness analysis check. This checks that every statement is reachable.
412 * The output of this analysis pass are used by other analyzers. This analyzer
413 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
414 */
415 class AliveAnalyzer extends BaseAnalyzer {
416
417 /** A flag that indicates whether the last statement could
418 * complete normally.
419 */
420 private Liveness alive;
421
422 @Override
423 void markDead() {
424 alive = Liveness.DEAD;
425 }
426
427 /*************************************************************************
428 * Visitor methods for statements and definitions
429 *************************************************************************/
430
431 /** Analyze a definition.
432 */
433 void scanDef(JCTree tree) {
434 scanStat(tree);
435 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && alive == Liveness.DEAD) {
814 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
815 try {
816 attrEnv = env;
817 Flow.this.make = make;
818 pendingExits = new ListBuffer<>();
819 alive = Liveness.ALIVE;
820 scan(tree);
821 } finally {
822 pendingExits = null;
823 Flow.this.make = null;
824 }
825 }
826 }
827
828 /**
829 * This pass implements the second step of the dataflow analysis, namely
830 * the exception analysis. This is to ensure that every checked exception that is
831 * thrown is declared or caught. The analyzer uses some info that has been set by
832 * the liveliness analyzer.
833 */
834 class FlowAnalyzer extends BaseAnalyzer {
835
836 /** A flag that indicates whether the last statement could
837 * complete normally.
838 */
839 HashMap<Symbol, List<Type>> preciseRethrowTypes;
840
841 /** The current class being defined.
842 */
843 JCClassDecl classDef;
844
845 /** The list of possibly thrown declarable exceptions.
846 */
847 List<Type> thrown;
848
849 /** The list of exceptions that are either caught or declared to be
850 * thrown.
851 */
852 List<Type> caught;
853
854 class ThrownPendingExit extends BaseAnalyzer.PendingExit {
855
856 Type thrown;
857
858 ThrownPendingExit(JCTree tree, Type thrown) {
859 super(tree);
860 this.thrown = thrown;
861 }
862 }
863
864 @Override
865 void markDead() {
866 //do nothing
867 }
868
869 /*-------------------- Exceptions ----------------------*/
870
871 /** Complain that pending exceptions are not caught.
872 */
873 void errorUncaught() {
874 for (PendingExit exit = pendingExits.next();
875 exit != null;
876 exit = pendingExits.next()) {
877 Assert.check(exit instanceof ThrownPendingExit);
878 ThrownPendingExit thrownExit = (ThrownPendingExit) exit;
879 if (classDef != null &&
880 classDef.pos == exit.tree.pos) {
881 log.error(exit.tree.pos(),
882 Errors.UnreportedExceptionDefaultConstructor(thrownExit.thrown));
883 } else if (exit.tree.hasTag(VARDEF) &&
884 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
885 log.error(exit.tree.pos(),
886 Errors.UnreportedExceptionImplicitClose(thrownExit.thrown,
887 ((JCVariableDecl)exit.tree).sym.name));
888 } else {
889 log.error(exit.tree.pos(),
890 Errors.UnreportedExceptionNeedToCatchOrThrow(thrownExit.thrown));
891 }
892 }
893 }
894
895 /** Record that exception is potentially thrown and check that it
896 * is caught.
897 */
898 void markThrown(JCTree tree, Type exc) {
899 if (!chk.isUnchecked(tree.pos(), exc)) {
900 if (!chk.isHandled(exc, caught)) {
901 pendingExits.append(new ThrownPendingExit(tree, exc));
902 }
903 thrown = chk.incl(exc, thrown);
904 }
905 }
906
907 /*************************************************************************
908 * Visitor methods for statements and definitions
909 *************************************************************************/
910
911 /* ------------ Visitor methods for various sorts of trees -------------*/
912
913 public void visitClassDef(JCClassDecl tree) {
914 if (tree.sym == null) return;
915
916 JCClassDecl classDefPrev = classDef;
917 List<Type> thrownPrev = thrown;
918 List<Type> caughtPrev = caught;
919 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
920 Lint lintPrev = lint;
921 boolean anonymousClass = tree.name == names.empty;
922 pendingExits = new ListBuffer<>();
923 if (!anonymousClass) {
924 caught = List.nil();
925 }
926 classDef = tree;
927 thrown = List.nil();
928 lint = lint.augment(tree.sym);
929
930 try {
931 // process all the static initializers
932 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
933 if (!l.head.hasTag(METHODDEF) &&
934 (TreeInfo.flags(l.head) & STATIC) != 0) {
935 scan(l.head);
936 errorUncaught();
937 }
938 }
939
1009 Lint lintPrev = lint;
1010
1011 lint = lint.augment(tree.sym);
1012
1013 Assert.check(pendingExits.isEmpty());
1014
1015 try {
1016 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1017 JCVariableDecl def = l.head;
1018 scan(def);
1019 }
1020 if (TreeInfo.isInitialConstructor(tree))
1021 caught = chk.union(caught, mthrown);
1022 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
1023 caught = mthrown;
1024 // else we are in an instance initializer block;
1025 // leave caught unchanged.
1026
1027 scan(tree.body);
1028
1029 List<PendingExit> exits = pendingExits.toList();
1030 pendingExits = new ListBuffer<>();
1031 while (exits.nonEmpty()) {
1032 PendingExit exit = exits.head;
1033 exits = exits.tail;
1034 if (!(exit instanceof ThrownPendingExit)) {
1035 Assert.check(exit.tree.hasTag(RETURN));
1036 } else {
1037 // uncaught throws will be reported later
1038 pendingExits.append(exit);
1039 }
1040 }
1041 } finally {
1042 caught = caughtPrev;
1043 lint = lintPrev;
1044 }
1045 }
1046
1047 public void visitVarDef(JCVariableDecl tree) {
1048 if (tree.init != null) {
1049 Lint lintPrev = lint;
1050 lint = lint.augment(tree.sym);
1051 try{
1052 scan(tree.init);
1053 } finally {
1054 lint = lintPrev;
1055 }
1056 }
1057 }
1058
1059 public void visitBlock(JCBlock tree) {
1060 scan(tree.stats);
1061 }
1062
1063 public void visitDoLoop(JCDoWhileLoop tree) {
1064 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1065 pendingExits = new ListBuffer<>();
1066 scan(tree.body);
1067 resolveContinues(tree);
1068 scan(tree.cond);
1069 resolveBreaks(tree, prevPendingExits);
1070 }
1071
1072 public void visitWhileLoop(JCWhileLoop tree) {
1073 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1074 pendingExits = new ListBuffer<>();
1075 scan(tree.cond);
1076 scan(tree.body);
1077 resolveContinues(tree);
1078 resolveBreaks(tree, prevPendingExits);
1079 }
1080
1081 public void visitForLoop(JCForLoop tree) {
1082 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1083 scan(tree.init);
1084 pendingExits = new ListBuffer<>();
1085 if (tree.cond != null) {
1086 scan(tree.cond);
1087 }
1088 scan(tree.body);
1089 resolveContinues(tree);
1090 scan(tree.step);
1091 resolveBreaks(tree, prevPendingExits);
1092 }
1093
1094 public void visitForeachLoop(JCEnhancedForLoop tree) {
1095 visitVarDef(tree.var);
1096 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1097 scan(tree.expr);
1098 pendingExits = new ListBuffer<>();
1099 scan(tree.body);
1100 resolveContinues(tree);
1101 resolveBreaks(tree, prevPendingExits);
1102 }
1103
1104 public void visitLabelled(JCLabeledStatement tree) {
1105 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1106 pendingExits = new ListBuffer<>();
1107 scan(tree.body);
1108 resolveBreaks(tree, prevPendingExits);
1109 }
1110
1111 public void visitSwitch(JCSwitch tree) {
1112 handleSwitch(tree, tree.selector, tree.cases);
1113 }
1114
1115 @Override
1116 public void visitSwitchExpression(JCSwitchExpression tree) {
1117 handleSwitch(tree, tree.selector, tree.cases);
1118 }
1119
1120 private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
1121 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1122 pendingExits = new ListBuffer<>();
1123 scan(selector);
1124 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
1125 JCCase c = l.head;
1126 scan(c.pats);
1127 scan(c.stats);
1128 }
1129 resolveBreaks(tree, prevPendingExits);
1130 }
1131
1132 public void visitTry(JCTry tree) {
1133 List<Type> caughtPrev = caught;
1134 List<Type> thrownPrev = thrown;
1135 thrown = List.nil();
1136 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1137 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1138 ((JCTypeUnion)l.head.param.vartype).alternatives :
1139 List.of(l.head.param.vartype);
1140 for (JCExpression ct : subClauses) {
1141 caught = chk.incl(ct.type, caught);
1142 }
1143 }
1144
1145 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1146 pendingExits = new ListBuffer<>();
1147 for (JCTree resource : tree.resources) {
1148 if (resource instanceof JCVariableDecl) {
1149 JCVariableDecl vdecl = (JCVariableDecl) resource;
1150 visitVarDef(vdecl);
1151 } else if (resource instanceof JCExpression) {
1152 scan((JCExpression) resource);
1153 } else {
1154 throw new AssertionError(tree); // parser error
1155 }
1156 }
1157 for (JCTree resource : tree.resources) {
1158 List<Type> closeableSupertypes = resource.type.isCompound() ?
1159 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1160 List.of(resource.type);
1161 for (Type sup : closeableSupertypes) {
1162 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1163 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1164 attrEnv,
1165 types.skipTypeVars(sup, false),
1189 List<Type> ctypes = List.nil();
1190 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
1191 for (JCExpression ct : subClauses) {
1192 Type exc = ct.type;
1193 if (exc != syms.unknownType) {
1194 ctypes = ctypes.append(exc);
1195 if (types.isSameType(exc, syms.objectType))
1196 continue;
1197 checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
1198 caughtInTry = chk.incl(exc, caughtInTry);
1199 }
1200 }
1201 scan(param);
1202 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
1203 scan(l.head.body);
1204 preciseRethrowTypes.remove(param.sym);
1205 }
1206 if (tree.finalizer != null) {
1207 List<Type> savedThrown = thrown;
1208 thrown = List.nil();
1209 ListBuffer<PendingExit> exits = pendingExits;
1210 pendingExits = prevPendingExits;
1211 scan(tree.finalizer);
1212 if (!tree.finallyCanCompleteNormally) {
1213 // discard exits and exceptions from try and finally
1214 thrown = chk.union(thrown, thrownPrev);
1215 } else {
1216 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1217 thrown = chk.union(thrown, savedThrown);
1218 // FIX: this doesn't preserve source order of exits in catch
1219 // versus finally!
1220 while (exits.nonEmpty()) {
1221 pendingExits.append(exits.next());
1222 }
1223 }
1224 } else {
1225 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1226 ListBuffer<PendingExit> exits = pendingExits;
1227 pendingExits = prevPendingExits;
1228 while (exits.nonEmpty()) pendingExits.append(exits.next());
1229 }
1230 }
1231
1232 @Override
1233 public void visitIf(JCIf tree) {
1234 scan(tree.cond);
1235 scan(tree.thenpart);
1236 if (tree.elsepart != null) {
1237 scan(tree.elsepart);
1238 }
1239 }
1240
1241 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
1242 if (chk.subset(exc, caughtInTry)) {
1243 log.error(pos, Errors.ExceptAlreadyCaught(exc));
1244 } else if (!chk.isUnchecked(pos, exc) &&
1245 !isExceptionOrThrowable(exc) &&
1246 !chk.intersects(exc, thrownInTry)) {
1252 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
1253 // exception, that would have been covered in the branch above
1254 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
1255 !isExceptionOrThrowable(exc)) {
1256 Warning key = catchableThrownTypes.length() == 1 ?
1257 Warnings.UnreachableCatch(catchableThrownTypes) :
1258 Warnings.UnreachableCatch1(catchableThrownTypes);
1259 log.warning(pos, key);
1260 }
1261 }
1262 }
1263 //where
1264 private boolean isExceptionOrThrowable(Type exc) {
1265 return exc.tsym == syms.throwableType.tsym ||
1266 exc.tsym == syms.exceptionType.tsym;
1267 }
1268
1269 public void visitBreak(JCBreak tree) {
1270 if (tree.isValueBreak())
1271 scan(tree.value);
1272 recordExit(new PendingExit(tree));
1273 }
1274
1275 public void visitContinue(JCContinue tree) {
1276 recordExit(new PendingExit(tree));
1277 }
1278
1279 public void visitReturn(JCReturn tree) {
1280 scan(tree.expr);
1281 recordExit(new PendingExit(tree));
1282 }
1283
1284 public void visitThrow(JCThrow tree) {
1285 scan(tree.expr);
1286 Symbol sym = TreeInfo.symbol(tree.expr);
1287 if (sym != null &&
1288 sym.kind == VAR &&
1289 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
1290 preciseRethrowTypes.get(sym) != null) {
1291 for (Type t : preciseRethrowTypes.get(sym)) {
1292 markThrown(tree, t);
1293 }
1294 }
1295 else {
1296 markThrown(tree, tree.expr.type);
1297 }
1298 markDead();
1299 }
1300
1301 public void visitApply(JCMethodInvocation tree) {
1328 for (List<Type> l = tree.constructor.type.getThrownTypes();
1329 l.nonEmpty();
1330 l = l.tail) {
1331 caught = chk.incl(l.head, caught);
1332 }
1333 scan(tree.def);
1334 }
1335 finally {
1336 caught = caughtPrev;
1337 }
1338 }
1339
1340 @Override
1341 public void visitLambda(JCLambda tree) {
1342 if (tree.type != null &&
1343 tree.type.isErroneous()) {
1344 return;
1345 }
1346 List<Type> prevCaught = caught;
1347 List<Type> prevThrown = thrown;
1348 ListBuffer<PendingExit> prevPending = pendingExits;
1349 try {
1350 pendingExits = new ListBuffer<>();
1351 caught = tree.getDescriptorType(types).getThrownTypes();
1352 thrown = List.nil();
1353 scan(tree.body);
1354 List<PendingExit> exits = pendingExits.toList();
1355 pendingExits = new ListBuffer<>();
1356 while (exits.nonEmpty()) {
1357 PendingExit exit = exits.head;
1358 exits = exits.tail;
1359 if (!(exit instanceof ThrownPendingExit)) {
1360 Assert.check(exit.tree.hasTag(RETURN));
1361 } else {
1362 // uncaught throws will be reported later
1363 pendingExits.append(exit);
1364 }
1365 }
1366
1367 errorUncaught();
1368 } finally {
1369 pendingExits = prevPending;
1370 caught = prevCaught;
1371 thrown = prevThrown;
1372 }
1373 }
1374
1375 public void visitModuleDef(JCModuleDecl tree) {
1376 // Do nothing for modules
1377 }
1378
1379 /**************************************************************************
1473 @Override
1474 public void visitClassDef(JCClassDecl tree) {
1475 //skip
1476 }
1477 }
1478
1479 /**
1480 * Specialized pass that performs inference of thrown types for lambdas.
1481 */
1482 class LambdaFlowAnalyzer extends FlowAnalyzer {
1483 List<Type> inferredThrownTypes;
1484 boolean inLambda;
1485 @Override
1486 public void visitLambda(JCLambda tree) {
1487 if ((tree.type != null &&
1488 tree.type.isErroneous()) || inLambda) {
1489 return;
1490 }
1491 List<Type> prevCaught = caught;
1492 List<Type> prevThrown = thrown;
1493 ListBuffer<PendingExit> prevPending = pendingExits;
1494 inLambda = true;
1495 try {
1496 pendingExits = new ListBuffer<>();
1497 caught = List.of(syms.throwableType);
1498 thrown = List.nil();
1499 scan(tree.body);
1500 inferredThrownTypes = thrown;
1501 } finally {
1502 pendingExits = prevPending;
1503 caught = prevCaught;
1504 thrown = prevThrown;
1505 inLambda = false;
1506 }
1507 }
1508 @Override
1509 public void visitClassDef(JCClassDecl tree) {
1510 //skip
1511 }
1512 }
1513
1514 /**
1515 * This pass implements (i) definite assignment analysis, which ensures that
1516 * each variable is assigned when used and (ii) definite unassignment analysis,
1517 * which ensures that no final variable is assigned more than once. This visitor
1518 * depends on the results of the liveliness analyzer. This pass is also used to mark
1519 * effectively-final local variables/parameters.
1520 */
1521
1522 public class AssignAnalyzer extends BaseAnalyzer {
1523
1524 /** The set of definitely assigned variables.
1525 */
1526 final Bits inits;
1527
1528 /** The set of definitely unassigned variables.
1529 */
1530 final Bits uninits;
1531
1532 /** The set of variables that are definitely unassigned everywhere
1533 * in current try block. This variable is maintained lazily; it is
1534 * updated only when something gets removed from uninits,
1535 * typically by being assigned in reachable code. To obtain the
1536 * correct set of variables which are definitely unassigned
1537 * anywhere in current try block, intersect uninitsTry and
1538 * uninits.
1539 */
1540 final Bits uninitsTry;
1541
1542 /** When analyzing a condition, inits and uninits are null.
1820 }
1821 }
1822
1823 /* ------------ Visitor methods for various sorts of trees -------------*/
1824
1825 public void visitClassDef(JCClassDecl tree) {
1826 if (tree.sym == null) {
1827 return;
1828 }
1829
1830 Lint lintPrev = lint;
1831 lint = lint.augment(tree.sym);
1832 try {
1833 if (tree.sym == null) {
1834 return;
1835 }
1836
1837 JCClassDecl classDefPrev = classDef;
1838 int firstadrPrev = firstadr;
1839 int nextadrPrev = nextadr;
1840 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1841
1842 pendingExits = new ListBuffer<>();
1843 if (tree.name != names.empty) {
1844 firstadr = nextadr;
1845 }
1846 classDef = tree;
1847 try {
1848 // define all the static fields
1849 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1850 if (l.head.hasTag(VARDEF)) {
1851 JCVariableDecl def = (JCVariableDecl)l.head;
1852 if ((def.mods.flags & STATIC) != 0) {
1853 VarSymbol sym = def.sym;
1854 if (trackable(sym)) {
1855 newVar(def);
1856 }
1857 }
1858 }
1859 }
1860
1955 scan(tree.body);
1956
1957 if (isInitialConstructor) {
1958 boolean isSynthesized = (tree.sym.flags() &
1959 GENERATEDCONSTR) != 0;
1960 for (int i = firstadr; i < nextadr; i++) {
1961 JCVariableDecl vardecl = vardecls[i];
1962 VarSymbol var = vardecl.sym;
1963 if (var.owner == classDef.sym) {
1964 // choose the diagnostic position based on whether
1965 // the ctor is default(synthesized) or not
1966 if (isSynthesized) {
1967 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
1968 var, Errors.VarNotInitializedInDefaultConstructor(var));
1969 } else {
1970 checkInit(TreeInfo.diagEndPos(tree.body), var);
1971 }
1972 }
1973 }
1974 }
1975 List<PendingExit> exits = pendingExits.toList();
1976 pendingExits = new ListBuffer<>();
1977 while (exits.nonEmpty()) {
1978 PendingExit exit = exits.head;
1979 exits = exits.tail;
1980 Assert.check(exit.tree.hasTag(RETURN), exit.tree);
1981 if (isInitialConstructor) {
1982 Assert.check(exit instanceof AssignPendingExit);
1983 inits.assign(((AssignPendingExit) exit).exit_inits);
1984 for (int i = firstadr; i < nextadr; i++) {
1985 checkInit(exit.tree.pos(), vardecls[i].sym);
1986 }
1987 }
1988 }
1989 } finally {
1990 inits.assign(initsPrev);
1991 uninits.assign(uninitsPrev);
1992 nextadr = nextadrPrev;
1993 firstadr = firstadrPrev;
1994 returnadr = returnadrPrev;
1995 isInitialConstructor = lastInitialConstructor;
1996 }
1997 } finally {
1998 lint = lintPrev;
1999 }
2000 }
2001
2002 protected void initParam(JCVariableDecl def) {
2003 inits.incl(def.sym.adr);
2013 newVar(tree);
2014 }
2015 if (tree.init != null) {
2016 scanExpr(tree.init);
2017 if (track) {
2018 letInit(tree.pos(), tree.sym);
2019 }
2020 }
2021 } finally {
2022 lint = lintPrev;
2023 }
2024 }
2025
2026 public void visitBlock(JCBlock tree) {
2027 int nextadrPrev = nextadr;
2028 scan(tree.stats);
2029 nextadr = nextadrPrev;
2030 }
2031
2032 public void visitDoLoop(JCDoWhileLoop tree) {
2033 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2034 FlowKind prevFlowKind = flowKind;
2035 flowKind = FlowKind.NORMAL;
2036 final Bits initsSkip = new Bits(true);
2037 final Bits uninitsSkip = new Bits(true);
2038 pendingExits = new ListBuffer<>();
2039 int prevErrors = log.nerrors;
2040 do {
2041 final Bits uninitsEntry = new Bits(uninits);
2042 uninitsEntry.excludeFrom(nextadr);
2043 scan(tree.body);
2044 resolveContinues(tree);
2045 scanCond(tree.cond);
2046 if (!flowKind.isFinal()) {
2047 initsSkip.assign(initsWhenFalse);
2048 uninitsSkip.assign(uninitsWhenFalse);
2049 }
2050 if (log.nerrors != prevErrors ||
2051 flowKind.isFinal() ||
2052 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
2053 break;
2054 inits.assign(initsWhenTrue);
2055 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
2056 flowKind = FlowKind.SPECULATIVE_LOOP;
2057 } while (true);
2058 flowKind = prevFlowKind;
2059 inits.assign(initsSkip);
2060 uninits.assign(uninitsSkip);
2061 resolveBreaks(tree, prevPendingExits);
2062 }
2063
2064 public void visitWhileLoop(JCWhileLoop tree) {
2065 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2066 FlowKind prevFlowKind = flowKind;
2067 flowKind = FlowKind.NORMAL;
2068 final Bits initsSkip = new Bits(true);
2069 final Bits uninitsSkip = new Bits(true);
2070 pendingExits = new ListBuffer<>();
2071 int prevErrors = log.nerrors;
2072 final Bits uninitsEntry = new Bits(uninits);
2073 uninitsEntry.excludeFrom(nextadr);
2074 do {
2075 scanCond(tree.cond);
2076 if (!flowKind.isFinal()) {
2077 initsSkip.assign(initsWhenFalse) ;
2078 uninitsSkip.assign(uninitsWhenFalse);
2079 }
2080 inits.assign(initsWhenTrue);
2081 uninits.assign(uninitsWhenTrue);
2082 scan(tree.body);
2083 resolveContinues(tree);
2084 if (log.nerrors != prevErrors ||
2085 flowKind.isFinal() ||
2086 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
2087 break;
2088 }
2089 uninits.assign(uninitsEntry.andSet(uninits));
2090 flowKind = FlowKind.SPECULATIVE_LOOP;
2091 } while (true);
2092 flowKind = prevFlowKind;
2093 //a variable is DA/DU after the while statement, if it's DA/DU assuming the
2094 //branch is not taken AND if it's DA/DU before any break statement
2095 inits.assign(initsSkip);
2096 uninits.assign(uninitsSkip);
2097 resolveBreaks(tree, prevPendingExits);
2098 }
2099
2100 public void visitForLoop(JCForLoop tree) {
2101 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2102 FlowKind prevFlowKind = flowKind;
2103 flowKind = FlowKind.NORMAL;
2104 int nextadrPrev = nextadr;
2105 scan(tree.init);
2106 final Bits initsSkip = new Bits(true);
2107 final Bits uninitsSkip = new Bits(true);
2108 pendingExits = new ListBuffer<>();
2109 int prevErrors = log.nerrors;
2110 do {
2111 final Bits uninitsEntry = new Bits(uninits);
2112 uninitsEntry.excludeFrom(nextadr);
2113 if (tree.cond != null) {
2114 scanCond(tree.cond);
2115 if (!flowKind.isFinal()) {
2116 initsSkip.assign(initsWhenFalse);
2117 uninitsSkip.assign(uninitsWhenFalse);
2118 }
2119 inits.assign(initsWhenTrue);
2120 uninits.assign(uninitsWhenTrue);
2121 } else if (!flowKind.isFinal()) {
2129 scan(tree.step);
2130 if (log.nerrors != prevErrors ||
2131 flowKind.isFinal() ||
2132 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2133 break;
2134 uninits.assign(uninitsEntry.andSet(uninits));
2135 flowKind = FlowKind.SPECULATIVE_LOOP;
2136 } while (true);
2137 flowKind = prevFlowKind;
2138 //a variable is DA/DU after a for loop, if it's DA/DU assuming the
2139 //branch is not taken AND if it's DA/DU before any break statement
2140 inits.assign(initsSkip);
2141 uninits.assign(uninitsSkip);
2142 resolveBreaks(tree, prevPendingExits);
2143 nextadr = nextadrPrev;
2144 }
2145
2146 public void visitForeachLoop(JCEnhancedForLoop tree) {
2147 visitVarDef(tree.var);
2148
2149 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2150 FlowKind prevFlowKind = flowKind;
2151 flowKind = FlowKind.NORMAL;
2152 int nextadrPrev = nextadr;
2153 scan(tree.expr);
2154 final Bits initsStart = new Bits(inits);
2155 final Bits uninitsStart = new Bits(uninits);
2156
2157 letInit(tree.pos(), tree.var.sym);
2158 pendingExits = new ListBuffer<>();
2159 int prevErrors = log.nerrors;
2160 do {
2161 final Bits uninitsEntry = new Bits(uninits);
2162 uninitsEntry.excludeFrom(nextadr);
2163 scan(tree.body);
2164 resolveContinues(tree);
2165 if (log.nerrors != prevErrors ||
2166 flowKind.isFinal() ||
2167 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2168 break;
2169 uninits.assign(uninitsEntry.andSet(uninits));
2170 flowKind = FlowKind.SPECULATIVE_LOOP;
2171 } while (true);
2172 flowKind = prevFlowKind;
2173 inits.assign(initsStart);
2174 uninits.assign(uninitsStart.andSet(uninits));
2175 resolveBreaks(tree, prevPendingExits);
2176 nextadr = nextadrPrev;
2177 }
2178
2179 public void visitLabelled(JCLabeledStatement tree) {
2180 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2181 pendingExits = new ListBuffer<>();
2182 scan(tree.body);
2183 resolveBreaks(tree, prevPendingExits);
2184 }
2185
2186 public void visitSwitch(JCSwitch tree) {
2187 handleSwitch(tree, tree.selector, tree.cases);
2188 }
2189
2190 public void visitSwitchExpression(JCSwitchExpression tree) {
2191 handleSwitch(tree, tree.selector, tree.cases);
2192 }
2193
2194 private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
2195 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2196 pendingExits = new ListBuffer<>();
2197 int nextadrPrev = nextadr;
2198 scanExpr(selector);
2199 final Bits initsSwitch = new Bits(inits);
2200 final Bits uninitsSwitch = new Bits(uninits);
2201 boolean hasDefault = false;
2202 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
2203 inits.assign(initsSwitch);
2204 uninits.assign(uninits.andSet(uninitsSwitch));
2205 JCCase c = l.head;
2206 if (c.pats.isEmpty()) {
2207 hasDefault = true;
2208 } else {
2209 for (JCExpression pat : c.pats) {
2210 scanExpr(pat);
2211 }
2212 }
2213 if (hasDefault) {
2214 inits.assign(initsSwitch);
2215 uninits.assign(uninits.andSet(uninitsSwitch));
2231 resolveBreaks(tree, prevPendingExits);
2232 nextadr = nextadrPrev;
2233 }
2234 // where
2235 /** Add any variables defined in stats to inits and uninits. */
2236 private void addVars(List<JCStatement> stats, final Bits inits,
2237 final Bits uninits) {
2238 for (;stats.nonEmpty(); stats = stats.tail) {
2239 JCTree stat = stats.head;
2240 if (stat.hasTag(VARDEF)) {
2241 int adr = ((JCVariableDecl) stat).sym.adr;
2242 inits.excl(adr);
2243 uninits.incl(adr);
2244 }
2245 }
2246 }
2247
2248 public void visitTry(JCTry tree) {
2249 ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
2250 final Bits uninitsTryPrev = new Bits(uninitsTry);
2251 ListBuffer<PendingExit> prevPendingExits = pendingExits;
2252 pendingExits = new ListBuffer<>();
2253 final Bits initsTry = new Bits(inits);
2254 uninitsTry.assign(uninits);
2255 for (JCTree resource : tree.resources) {
2256 if (resource instanceof JCVariableDecl) {
2257 JCVariableDecl vdecl = (JCVariableDecl) resource;
2258 visitVarDef(vdecl);
2259 unrefdResources.enter(vdecl.sym);
2260 resourceVarDecls.append(vdecl);
2261 } else if (resource instanceof JCExpression) {
2262 scanExpr((JCExpression) resource);
2263 } else {
2264 throw new AssertionError(tree); // parser error
2265 }
2266 }
2267 scan(tree.body);
2268 uninitsTry.andSet(uninits);
2269 final Bits initsEnd = new Bits(inits);
2270 final Bits uninitsEnd = new Bits(uninits);
2271 int nextadrCatch = nextadr;
2288 final Bits initsCatchPrev = new Bits(initsTry);
2289 final Bits uninitsCatchPrev = new Bits(uninitsTry);
2290
2291 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
2292 JCVariableDecl param = l.head.param;
2293 inits.assign(initsCatchPrev);
2294 uninits.assign(uninitsCatchPrev);
2295 scan(param);
2296 /* If this is a TWR and we are executing the code from Gen,
2297 * then there can be synthetic variables, ignore them.
2298 */
2299 initParam(param);
2300 scan(l.head.body);
2301 initsEnd.andSet(inits);
2302 uninitsEnd.andSet(uninits);
2303 nextadr = nextadrCatch;
2304 }
2305 if (tree.finalizer != null) {
2306 inits.assign(initsTry);
2307 uninits.assign(uninitsTry);
2308 ListBuffer<PendingExit> exits = pendingExits;
2309 pendingExits = prevPendingExits;
2310 scan(tree.finalizer);
2311 if (!tree.finallyCanCompleteNormally) {
2312 // discard exits and exceptions from try and finally
2313 } else {
2314 uninits.andSet(uninitsEnd);
2315 // FIX: this doesn't preserve source order of exits in catch
2316 // versus finally!
2317 while (exits.nonEmpty()) {
2318 PendingExit exit = exits.next();
2319 if (exit instanceof AssignPendingExit) {
2320 ((AssignPendingExit) exit).exit_inits.orSet(inits);
2321 ((AssignPendingExit) exit).exit_uninits.andSet(uninits);
2322 }
2323 pendingExits.append(exit);
2324 }
2325 inits.orSet(initsEnd);
2326 }
2327 } else {
2328 inits.assign(initsEnd);
2329 uninits.assign(uninitsEnd);
2330 ListBuffer<PendingExit> exits = pendingExits;
2331 pendingExits = prevPendingExits;
2332 while (exits.nonEmpty()) pendingExits.append(exits.next());
2333 }
2334 uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
2335 }
2336
2337 public void visitConditional(JCConditional tree) {
2338 scanCond(tree.cond);
2339 final Bits initsBeforeElse = new Bits(initsWhenFalse);
2340 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2341 inits.assign(initsWhenTrue);
2342 uninits.assign(uninitsWhenTrue);
2343 if (tree.truepart.type.hasTag(BOOLEAN) &&
2344 tree.falsepart.type.hasTag(BOOLEAN)) {
2345 // if b and c are boolean valued, then
2346 // v is (un)assigned after a?b:c when true iff
2347 // v is (un)assigned after b when true and
2348 // v is (un)assigned after c when true
2349 scanCond(tree.truepart);
2350 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
2376 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2377 inits.assign(initsWhenTrue);
2378 uninits.assign(uninitsWhenTrue);
2379 scan(tree.thenpart);
2380 if (tree.elsepart != null) {
2381 final Bits initsAfterThen = new Bits(inits);
2382 final Bits uninitsAfterThen = new Bits(uninits);
2383 inits.assign(initsBeforeElse);
2384 uninits.assign(uninitsBeforeElse);
2385 scan(tree.elsepart);
2386 inits.andSet(initsAfterThen);
2387 uninits.andSet(uninitsAfterThen);
2388 } else {
2389 inits.andSet(initsBeforeElse);
2390 uninits.andSet(uninitsBeforeElse);
2391 }
2392 }
2393
2394 @Override
2395 public void visitBreak(JCBreak tree) {
2396 if (tree.isValueBreak()) {
2397 if (tree.target.hasTag(SWITCH_EXPRESSION)) {
2398 JCSwitchExpression expr = (JCSwitchExpression) tree.target;
2399 if (expr.type.hasTag(BOOLEAN)) {
2400 scanCond(tree.value);
2401 Bits initsAfterBreakWhenTrue = new Bits(initsWhenTrue);
2402 Bits initsAfterBreakWhenFalse = new Bits(initsWhenFalse);
2403 Bits uninitsAfterBreakWhenTrue = new Bits(uninitsWhenTrue);
2404 Bits uninitsAfterBreakWhenFalse = new Bits(uninitsWhenFalse);
2405 PendingExit exit = new PendingExit(tree) {
2406 @Override
2407 void resolveJump() {
2408 if (!inits.isReset()) {
2409 split(true);
2410 }
2411 initsWhenTrue.andSet(initsAfterBreakWhenTrue);
2412 initsWhenFalse.andSet(initsAfterBreakWhenFalse);
2413 uninitsWhenTrue.andSet(uninitsAfterBreakWhenTrue);
2414 uninitsWhenFalse.andSet(uninitsAfterBreakWhenFalse);
2415 }
2416 };
2417 merge();
2418 recordExit(exit);
2419 return ;
2420 }
2421 }
2422 scan(tree.value);
2423 }
2424 recordExit(new AssignPendingExit(tree, inits, uninits));
2425 }
2426
2427 @Override
2428 public void visitContinue(JCContinue tree) {
2429 recordExit(new AssignPendingExit(tree, inits, uninits));
2430 }
2431
2432 @Override
2433 public void visitReturn(JCReturn tree) {
2434 scanExpr(tree.expr);
2435 recordExit(new AssignPendingExit(tree, inits, uninits));
2436 }
2437
2438 public void visitThrow(JCThrow tree) {
2439 scanExpr(tree.expr);
2440 markDead();
2441 }
2442
2443 public void visitApply(JCMethodInvocation tree) {
2444 scanExpr(tree.meth);
2445 scanExprs(tree.args);
2446 }
2447
2448 public void visitNewClass(JCNewClass tree) {
2449 scanExpr(tree.encl);
2450 scanExprs(tree.args);
2451 scan(tree.def);
2452 }
2453
2454 @Override
2455 public void visitLambda(JCLambda tree) {
2456 final Bits prevUninits = new Bits(uninits);
2457 final Bits prevInits = new Bits(inits);
2458 int returnadrPrev = returnadr;
2459 int nextadrPrev = nextadr;
2460 ListBuffer<PendingExit> prevPending = pendingExits;
2461 try {
2462 returnadr = nextadr;
2463 pendingExits = new ListBuffer<>();
2464 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2465 JCVariableDecl def = l.head;
2466 scan(def);
2467 inits.incl(def.sym.adr);
2468 uninits.excl(def.sym.adr);
2469 }
2470 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2471 scanExpr(tree.body);
2472 } else {
2473 scan(tree.body);
2474 }
2475 }
2476 finally {
2477 returnadr = returnadrPrev;
2478 uninits.assign(prevUninits);
2479 inits.assign(prevInits);
2480 pendingExits = prevPending;
2630 }
2631 firstadr = 0;
2632 nextadr = 0;
2633 Flow.this.make = null;
2634 pendingExits = null;
2635 this.classDef = null;
2636 unrefdResources = null;
2637 }
2638 }
2639 }
2640
2641 /**
2642 * This pass implements the last step of the dataflow analysis, namely
2643 * the effectively-final analysis check. This checks that every local variable
2644 * reference from a lambda body/local inner class is either final or effectively final.
2645 * Additional this also checks that every variable that is used as an operand to
2646 * try-with-resources is final or effectively final.
2647 * As effectively final variables are marked as such during DA/DU, this pass must run after
2648 * AssignAnalyzer.
2649 */
2650 class CaptureAnalyzer extends BaseAnalyzer {
2651
2652 JCTree currentTree; //local class or lambda
2653
2654 @Override
2655 void markDead() {
2656 //do nothing
2657 }
2658
2659 @SuppressWarnings("fallthrough")
2660 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
2661 if (currentTree != null &&
2662 sym.owner.kind == MTH &&
2663 sym.pos < currentTree.getStartPosition()) {
2664 switch (currentTree.getTag()) {
2665 case CLASSDEF:
2666 if (!allowEffectivelyFinalInInnerClasses) {
2667 if ((sym.flags() & FINAL) == 0) {
2668 reportInnerClsNeedsFinalError(pos, sym);
2669 }
2670 break;
|