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