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;
|