188 private final Check chk; |
188 private final Check chk; |
189 private TreeMaker make; |
189 private TreeMaker make; |
190 private final Resolve rs; |
190 private final Resolve rs; |
191 private Env<AttrContext> attrEnv; |
191 private Env<AttrContext> attrEnv; |
192 private Lint lint; |
192 private Lint lint; |
193 private final boolean allowRethrowAnalysis; |
193 private final boolean allowImprovedRethrowAnalysis; |
|
194 private final boolean allowImprovedCatchAnalysis; |
194 |
195 |
195 public static Flow instance(Context context) { |
196 public static Flow instance(Context context) { |
196 Flow instance = context.get(flowKey); |
197 Flow instance = context.get(flowKey); |
197 if (instance == null) |
198 if (instance == null) |
198 instance = new Flow(context); |
199 instance = new Flow(context); |
207 types = Types.instance(context); |
208 types = Types.instance(context); |
208 chk = Check.instance(context); |
209 chk = Check.instance(context); |
209 lint = Lint.instance(context); |
210 lint = Lint.instance(context); |
210 rs = Resolve.instance(context); |
211 rs = Resolve.instance(context); |
211 Source source = Source.instance(context); |
212 Source source = Source.instance(context); |
212 allowRethrowAnalysis = source.allowMulticatch(); |
213 allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis(); |
|
214 allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); |
213 } |
215 } |
214 |
216 |
215 /** A flag that indicates whether the last statement could |
217 /** A flag that indicates whether the last statement could |
216 * complete normally. |
218 * complete normally. |
217 */ |
219 */ |
1044 } |
1046 } |
1045 } |
1047 } |
1046 } |
1048 } |
1047 } |
1049 } |
1048 scanStat(tree.body); |
1050 scanStat(tree.body); |
1049 List<Type> thrownInTry = thrown; |
1051 List<Type> thrownInTry = allowImprovedCatchAnalysis ? |
|
1052 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) : |
|
1053 thrown; |
1050 thrown = thrownPrev; |
1054 thrown = thrownPrev; |
1051 caught = caughtPrev; |
1055 caught = caughtPrev; |
1052 boolean aliveEnd = alive; |
1056 boolean aliveEnd = alive; |
1053 uninitsTry.andSet(uninits); |
1057 uninitsTry.andSet(uninits); |
1054 Bits initsEnd = inits; |
1058 Bits initsEnd = inits; |
1079 Type exc = ct.type; |
1083 Type exc = ct.type; |
1080 if (exc != syms.unknownType) { |
1084 if (exc != syms.unknownType) { |
1081 ctypes = ctypes.append(exc); |
1085 ctypes = ctypes.append(exc); |
1082 if (types.isSameType(exc, syms.objectType)) |
1086 if (types.isSameType(exc, syms.objectType)) |
1083 continue; |
1087 continue; |
1084 if (chk.subset(exc, caughtInTry)) { |
1088 checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry); |
1085 log.error(l.head.pos(), |
|
1086 "except.already.caught", exc); |
|
1087 } else if (!chk.isUnchecked(l.head.pos(), exc) && |
|
1088 exc.tsym != syms.throwableType.tsym && |
|
1089 exc.tsym != syms.exceptionType.tsym && |
|
1090 !chk.intersects(exc, thrownInTry)) { |
|
1091 log.error(l.head.pos(), |
|
1092 "except.never.thrown.in.try", exc); |
|
1093 } |
|
1094 caughtInTry = chk.incl(exc, caughtInTry); |
1089 caughtInTry = chk.incl(exc, caughtInTry); |
1095 } |
1090 } |
1096 } |
1091 } |
1097 inits = initsTry.dup(); |
1092 inits = initsTry.dup(); |
1098 uninits = uninitsTry.dup(); |
1093 uninits = uninitsTry.dup(); |
1150 ListBuffer<PendingExit> exits = pendingExits; |
1145 ListBuffer<PendingExit> exits = pendingExits; |
1151 pendingExits = prevPendingExits; |
1146 pendingExits = prevPendingExits; |
1152 while (exits.nonEmpty()) pendingExits.append(exits.next()); |
1147 while (exits.nonEmpty()) pendingExits.append(exits.next()); |
1153 } |
1148 } |
1154 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); |
1149 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); |
|
1150 } |
|
1151 |
|
1152 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) { |
|
1153 if (chk.subset(exc, caughtInTry)) { |
|
1154 log.error(pos, "except.already.caught", exc); |
|
1155 } else if (!chk.isUnchecked(pos, exc) && |
|
1156 exc.tsym != syms.throwableType.tsym && |
|
1157 exc.tsym != syms.exceptionType.tsym && |
|
1158 !chk.intersects(exc, thrownInTry)) { |
|
1159 log.error(pos, "except.never.thrown.in.try", exc); |
|
1160 } else if (allowImprovedCatchAnalysis) { |
|
1161 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry); |
|
1162 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an |
|
1163 // unchecked exception, the result list would not be empty, as the augmented |
|
1164 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked |
|
1165 // exception, that would have been covered in the branch above |
|
1166 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty()) { |
|
1167 String key = catchableThrownTypes.length() == 1 ? |
|
1168 "unreachable.catch" : |
|
1169 "unreachable.catch.1"; |
|
1170 log.warning(pos, key, catchableThrownTypes); |
|
1171 } |
|
1172 } |
1155 } |
1173 } |
1156 |
1174 |
1157 public void visitConditional(JCConditional tree) { |
1175 public void visitConditional(JCConditional tree) { |
1158 scanCond(tree.cond); |
1176 scanCond(tree.cond); |
1159 Bits initsBeforeElse = initsWhenFalse; |
1177 Bits initsBeforeElse = initsWhenFalse; |
1236 Symbol sym = TreeInfo.symbol(tree.expr); |
1254 Symbol sym = TreeInfo.symbol(tree.expr); |
1237 if (sym != null && |
1255 if (sym != null && |
1238 sym.kind == VAR && |
1256 sym.kind == VAR && |
1239 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 && |
1257 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 && |
1240 preciseRethrowTypes.get(sym) != null && |
1258 preciseRethrowTypes.get(sym) != null && |
1241 allowRethrowAnalysis) { |
1259 allowImprovedRethrowAnalysis) { |
1242 for (Type t : preciseRethrowTypes.get(sym)) { |
1260 for (Type t : preciseRethrowTypes.get(sym)) { |
1243 markThrown(tree, t); |
1261 markThrown(tree, t); |
1244 } |
1262 } |
1245 } |
1263 } |
1246 else { |
1264 else { |