| 1 | /* | 
| 2 |  * Copyright 1999-2006 Sun Microsystems, Inc.  All Rights Reserved. | 
| 3 |  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
| 4 |  * | 
| 5 |  * This code is free software; you can redistribute it and/or modify it | 
| 6 |  * under the terms of the GNU General Public License version 2 only, as | 
| 7 |  * published by the Free Software Foundation.  Sun designates this | 
| 8 |  * particular file as subject to the "Classpath" exception as provided | 
| 9 |  * by Sun in the LICENSE file that accompanied this code. | 
| 10 |  * | 
| 11 |  * This code is distributed in the hope that it will be useful, but WITHOUT | 
| 12 |  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
| 13 |  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
| 14 |  * version 2 for more details (a copy is included in the LICENSE file that | 
| 15 |  * accompanied this code). | 
| 16 |  * | 
| 17 |  * You should have received a copy of the GNU General Public License version | 
| 18 |  * 2 along with this work; if not, write to the Free Software Foundation, | 
| 19 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
| 20 |  * | 
| 21 |  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | 
| 22 |  * CA 95054 USA or visit www.sun.com if you need additional information or | 
| 23 |  * have any questions. | 
| 24 |  */ | 
| 25 |   | 
| 26 | //todo: one might eliminate uninits.andSets when monotonic | 
| 27 |   | 
| 28 | package com.sun.tools.javac.comp; | 
| 29 |   | 
| 30 | import com.sun.tools.javac.code.*; | 
| 31 | import com.sun.tools.javac.tree.*; | 
| 32 | import com.sun.tools.javac.util.*; | 
| 33 | import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; | 
| 34 |   | 
| 35 | import com.sun.tools.javac.code.Symbol.*; | 
| 36 | import com.sun.tools.javac.tree.JCTree.*; | 
| 37 |   | 
| 38 | import static com.sun.tools.javac.code.Flags.*; | 
| 39 | import static com.sun.tools.javac.code.Kinds.*; | 
| 40 | import static com.sun.tools.javac.code.TypeTags.*; | 
| 41 |   | 
| 42 | /** This pass implements dataflow analysis for Java programs. | 
| 43 |  *  Liveness analysis checks that every statement is reachable. | 
| 44 |  *  Exception analysis ensures that every checked exception that is | 
| 45 |  *  thrown is declared or caught.  Definite assignment analysis | 
| 46 |  *  ensures that each variable is assigned when used.  Definite | 
| 47 |  *  unassignment analysis ensures that no final variable is assigned | 
| 48 |  *  more than once. | 
| 49 |  * | 
| 50 |  *  <p>The second edition of the JLS has a number of problems in the | 
| 51 |  *  specification of these flow analysis problems. This implementation | 
| 52 |  *  attempts to address those issues. | 
| 53 |  * | 
| 54 |  *  <p>First, there is no accommodation for a finally clause that cannot | 
| 55 |  *  complete normally. For liveness analysis, an intervening finally | 
| 56 |  *  clause can cause a break, continue, or return not to reach its | 
| 57 |  *  target.  For exception analysis, an intervening finally clause can | 
| 58 |  *  cause any exception to be "caught".  For DA/DU analysis, the finally | 
| 59 |  *  clause can prevent a transfer of control from propagating DA/DU | 
| 60 |  *  state to the target.  In addition, code in the finally clause can | 
| 61 |  *  affect the DA/DU status of variables. | 
| 62 |  * | 
| 63 |  *  <p>For try statements, we introduce the idea of a variable being | 
| 64 |  *  definitely unassigned "everywhere" in a block.  A variable V is | 
| 65 |  *  "unassigned everywhere" in a block iff it is unassigned at the | 
| 66 |  *  beginning of the block and there is no reachable assignment to V | 
| 67 |  *  in the block.  An assignment V=e is reachable iff V is not DA | 
| 68 |  *  after e.  Then we can say that V is DU at the beginning of the | 
| 69 |  *  catch block iff V is DU everywhere in the try block.  Similarly, V | 
| 70 |  *  is DU at the beginning of the finally block iff V is DU everywhere | 
| 71 |  *  in the try block and in every catch block.  Specifically, the | 
| 72 |  *  following bullet is added to 16.2.2 | 
| 73 |  *  <pre> | 
| 74 |  *      V is <em>unassigned everywhere</em> in a block if it is | 
| 75 |  *      unassigned before the block and there is no reachable | 
| 76 |  *      assignment to V within the block. | 
| 77 |  *  </pre> | 
| 78 |  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all | 
| 79 |  *  try blocks is changed to | 
| 80 |  *  <pre> | 
| 81 |  *      V is definitely unassigned before a catch block iff V is | 
| 82 |  *      definitely unassigned everywhere in the try block. | 
| 83 |  *  </pre> | 
| 84 |  *  <p>The last bullet (and all of its sub-bullets) for try blocks that | 
| 85 |  *  have a finally block is changed to | 
| 86 |  *  <pre> | 
| 87 |  *      V is definitely unassigned before the finally block iff | 
| 88 |  *      V is definitely unassigned everywhere in the try block | 
| 89 |  *      and everywhere in each catch block of the try statement. | 
| 90 |  *  </pre> | 
| 91 |  *  <p>In addition, | 
| 92 |  *  <pre> | 
| 93 |  *      V is definitely assigned at the end of a constructor iff | 
| 94 |  *      V is definitely assigned after the block that is the body | 
| 95 |  *      of the constructor and V is definitely assigned at every | 
| 96 |  *      return that can return from the constructor. | 
| 97 |  *  </pre> | 
| 98 |  *  <p>In addition, each continue statement with the loop as its target | 
| 99 |  *  is treated as a jump to the end of the loop body, and "intervening" | 
| 100 |  *  finally clauses are treated as follows: V is DA "due to the | 
| 101 |  *  continue" iff V is DA before the continue statement or V is DA at | 
| 102 |  *  the end of any intervening finally block.  V is DU "due to the | 
| 103 |  *  continue" iff any intervening finally cannot complete normally or V | 
| 104 |  *  is DU at the end of every intervening finally block.  This "due to | 
| 105 |  *  the continue" concept is then used in the spec for the loops. | 
| 106 |  * | 
| 107 |  *  <p>Similarly, break statements must consider intervening finally | 
| 108 |  *  blocks.  For liveness analysis, a break statement for which any | 
| 109 |  *  intervening finally cannot complete normally is not considered to | 
| 110 |  *  cause the target statement to be able to complete normally. Then | 
| 111 |  *  we say V is DA "due to the break" iff V is DA before the break or | 
| 112 |  *  V is DA at the end of any intervening finally block.  V is DU "due | 
| 113 |  *  to the break" iff any intervening finally cannot complete normally | 
| 114 |  *  or V is DU at the break and at the end of every intervening | 
| 115 |  *  finally block.  (I suspect this latter condition can be | 
| 116 |  *  simplified.)  This "due to the break" is then used in the spec for | 
| 117 |  *  all statements that can be "broken". | 
| 118 |  * | 
| 119 |  *  <p>The return statement is treated similarly.  V is DA "due to a | 
| 120 |  *  return statement" iff V is DA before the return statement or V is | 
| 121 |  *  DA at the end of any intervening finally block.  Note that we | 
| 122 |  *  don't have to worry about the return expression because this | 
| 123 |  *  concept is only used for construcrors. | 
| 124 |  * | 
| 125 |  *  <p>There is no spec in JLS2 for when a variable is definitely | 
| 126 |  *  assigned at the end of a constructor, which is needed for final | 
| 127 |  *  fields (8.3.1.2).  We implement the rule that V is DA at the end | 
| 128 |  *  of the constructor iff it is DA and the end of the body of the | 
| 129 |  *  constructor and V is DA "due to" every return of the constructor. | 
| 130 |  * | 
| 131 |  *  <p>Intervening finally blocks similarly affect exception analysis.  An | 
| 132 |  *  intervening finally that cannot complete normally allows us to ignore | 
| 133 |  *  an otherwise uncaught exception. | 
| 134 |  * | 
| 135 |  *  <p>To implement the semantics of intervening finally clauses, all | 
| 136 |  *  nonlocal transfers (break, continue, return, throw, method call that | 
| 137 |  *  can throw a checked exception, and a constructor invocation that can | 
| 138 |  *  thrown a checked exception) are recorded in a queue, and removed | 
| 139 |  *  from the queue when we complete processing the target of the | 
| 140 |  *  nonlocal transfer.  This allows us to modify the queue in accordance | 
| 141 |  *  with the above rules when we encounter a finally clause.  The only | 
| 142 |  *  exception to this [no pun intended] is that checked exceptions that | 
| 143 |  *  are known to be caught or declared to be caught in the enclosing | 
| 144 |  *  method are not recorded in the queue, but instead are recorded in a | 
| 145 |  *  global variable "Set<Type> thrown" that records the type of all | 
| 146 |  *  exceptions that can be thrown. | 
| 147 |  * | 
| 148 |  *  <p>Other minor issues the treatment of members of other classes | 
| 149 |  *  (always considered DA except that within an anonymous class | 
| 150 |  *  constructor, where DA status from the enclosing scope is | 
| 151 |  *  preserved), treatment of the case expression (V is DA before the | 
| 152 |  *  case expression iff V is DA after the switch expression), | 
| 153 |  *  treatment of variables declared in a switch block (the implied | 
| 154 |  *  DA/DU status after the switch expression is DU and not DA for | 
| 155 |  *  variables defined in a switch block), the treatment of boolean ?: | 
| 156 |  *  expressions (The JLS rules only handle b and c non-boolean; the | 
| 157 |  *  new rule is that if b and c are boolean valued, then V is | 
| 158 |  *  (un)assigned after a?b:c when true/false iff V is (un)assigned | 
| 159 |  *  after b when true/false and V is (un)assigned after c when | 
| 160 |  *  true/false). | 
| 161 |  * | 
| 162 |  *  <p>There is the remaining question of what syntactic forms constitute a | 
| 163 |  *  reference to a variable.  It is conventional to allow this.x on the | 
| 164 |  *  left-hand-side to initialize a final instance field named x, yet | 
| 165 |  *  this.x isn't considered a "use" when appearing on a right-hand-side | 
| 166 |  *  in most implementations.  Should parentheses affect what is | 
| 167 |  *  considered a variable reference?  The simplest rule would be to | 
| 168 |  *  allow unqualified forms only, parentheses optional, and phase out | 
| 169 |  *  support for assigning to a final field via this.x. | 
| 170 |  * | 
| 171 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 172 |  *  you write code that depends on this, you do so at your own risk. | 
| 173 |  *  This code and its internal interfaces are subject to change or | 
| 174 |  *  deletion without notice.</b> | 
| 175 |  */ | 
| 176 | public class Flow extends TreeScanner { | 
| 177 |     protected static final Context.Key<Flow> flowKey = | 
| 178 |         new Context.Key<Flow>(); | 
| 179 |   | 
| 180 |     private final Name.Table names; | 
| 181 |     private final Log log; | 
| 182 |     private final Symtab syms; | 
| 183 |     private final Types types; | 
| 184 |     private final Check chk; | 
| 185 |     private       TreeMaker make; | 
| 186 |     private       Lint lint; | 
| 187 |   | 
| 188 |     public static Flow instance(Context context) { | 
| 189 |         Flow instance = context.get(flowKey); | 
| 190 |         if (instance == null) | 
| 191 |             instance = new Flow(context); | 
| 192 |         return instance; | 
| 193 |     } | 
| 194 |   | 
| 195 |     protected Flow(Context context) { | 
| 196 |         context.put(flowKey, this); | 
| 197 |   | 
| 198 |         names = Name.Table.instance(context); | 
| 199 |         log = Log.instance(context); | 
| 200 |         syms = Symtab.instance(context); | 
| 201 |         types = Types.instance(context); | 
| 202 |         chk = Check.instance(context); | 
| 203 |         lint = Lint.instance(context); | 
| 204 |     } | 
| 205 |   | 
| 206 |     /** A flag that indicates whether the last statement could | 
| 207 |      *  complete normally. | 
| 208 |      */ | 
| 209 |     private boolean alive; | 
| 210 |   | 
| 211 |     /** The set of definitely assigned variables. | 
| 212 |      */ | 
| 213 |     Bits inits; | 
| 214 |   | 
| 215 |     /** The set of definitely unassigned variables. | 
| 216 |      */ | 
| 217 |     Bits uninits; | 
| 218 |   | 
| 219 |     /** The set of variables that are definitely unassigned everywhere | 
| 220 |      *  in current try block. This variable is maintained lazily; it is | 
| 221 |      *  updated only when something gets removed from uninits, | 
| 222 |      *  typically by being assigned in reachable code.  To obtain the | 
| 223 |      *  correct set of variables which are definitely unassigned | 
| 224 |      *  anywhere in current try block, intersect uninitsTry and | 
| 225 |      *  uninits. | 
| 226 |      */ | 
| 227 |     Bits uninitsTry; | 
| 228 |   | 
| 229 |     /** When analyzing a condition, inits and uninits are null. | 
| 230 |      *  Instead we have: | 
| 231 |      */ | 
| 232 |     Bits initsWhenTrue; | 
| 233 |     Bits initsWhenFalse; | 
| 234 |     Bits uninitsWhenTrue; | 
| 235 |     Bits uninitsWhenFalse; | 
| 236 |   | 
| 237 |     /** A mapping from addresses to variable symbols. | 
| 238 |      */ | 
| 239 |     VarSymbol[] vars; | 
| 240 |   | 
| 241 |     /** The current class being defined. | 
| 242 |      */ | 
| 243 |     JCClassDecl classDef; | 
| 244 |   | 
| 245 |     /** The first variable sequence number in this class definition. | 
| 246 |      */ | 
| 247 |     int firstadr; | 
| 248 |   | 
| 249 |     /** The next available variable sequence number. | 
| 250 |      */ | 
| 251 |     int nextadr; | 
| 252 |   | 
| 253 |     /** The list of possibly thrown declarable exceptions. | 
| 254 |      */ | 
| 255 |     List<Type> thrown; | 
| 256 |   | 
| 257 |     /** The list of exceptions that are either caught or declared to be | 
| 258 |      *  thrown. | 
| 259 |      */ | 
| 260 |     List<Type> caught; | 
| 261 |   | 
| 262 |     /** Set when processing a loop body the second time for DU analysis. */ | 
| 263 |     boolean loopPassTwo = false; | 
| 264 |   | 
| 265 |     /*-------------------- Environments ----------------------*/ | 
| 266 |   | 
| 267 |     /** A pending exit.  These are the statements return, break, and | 
| 268 |      *  continue.  In addition, exception-throwing expressions or | 
| 269 |      *  statements are put here when not known to be caught.  This | 
| 270 |      *  will typically result in an error unless it is within a | 
| 271 |      *  try-finally whose finally block cannot complete normally. | 
| 272 |      */ | 
| 273 |     static class PendingExit { | 
| 274 |         JCTree tree; | 
| 275 |         Bits inits; | 
| 276 |         Bits uninits; | 
| 277 |         Type thrown; | 
| 278 |         PendingExit(JCTree tree, Bits inits, Bits uninits) { | 
| 279 |             this.tree = tree; | 
| 280 |             this.inits = inits.dup(); | 
| 281 |             this.uninits = uninits.dup(); | 
| 282 |         } | 
| 283 |         PendingExit(JCTree tree, Type thrown) { | 
| 284 |             this.tree = tree; | 
| 285 |             this.thrown = thrown; | 
| 286 |         } | 
| 287 |     } | 
| 288 |   | 
| 289 |     /** The currently pending exits that go from current inner blocks | 
| 290 |      *  to an enclosing block, in source order. | 
| 291 |      */ | 
| 292 |     ListBuffer<PendingExit> pendingExits; | 
| 293 |   | 
| 294 |     /*-------------------- Exceptions ----------------------*/ | 
| 295 |   | 
| 296 |     /** Complain that pending exceptions are not caught. | 
| 297 |      */ | 
| 298 |     void errorUncaught() { | 
| 299 |         for (PendingExit exit = pendingExits.next(); | 
| 300 |              exit != null; | 
| 301 |              exit = pendingExits.next()) { | 
| 302 |             boolean synthetic = classDef != null && | 
| 303 |                 classDef.pos == exit.tree.pos; | 
| 304 |             log.error(exit.tree.pos(), | 
| 305 |                       synthetic | 
| 306 |                       ? "unreported.exception.default.constructor" | 
| 307 |                       : "unreported.exception.need.to.catch.or.throw", | 
| 308 |                       exit.thrown); | 
| 309 |         } | 
| 310 |     } | 
| 311 |   | 
| 312 |     /** Record that exception is potentially thrown and check that it | 
| 313 |      *  is caught. | 
| 314 |      */ | 
| 315 |     void markThrown(JCTree tree, Type exc) { | 
| 316 |         if (!chk.isUnchecked(tree.pos(), exc)) { | 
| 317 |             if (!chk.isHandled(exc, caught)) | 
| 318 |                 pendingExits.append(new PendingExit(tree, exc)); | 
| 319 |             thrown = chk.incl(exc, thrown); | 
| 320 |         } | 
| 321 |     } | 
| 322 |   | 
| 323 |     /*-------------- Processing variables ----------------------*/ | 
| 324 |   | 
| 325 |     /** Do we need to track init/uninit state of this symbol? | 
| 326 |      *  I.e. is symbol either a local or a blank final variable? | 
| 327 |      */ | 
| 328 |     boolean trackable(VarSymbol sym) { | 
| 329 |         return | 
| 330 |             (sym.owner.kind == MTH || | 
| 331 |              ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL && | 
| 332 |               classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))); | 
| 333 |     } | 
| 334 |   | 
| 335 |     /** Initialize new trackable variable by setting its address field | 
| 336 |      *  to the next available sequence number and entering it under that | 
| 337 |      *  index into the vars array. | 
| 338 |      */ | 
| 339 |     void newVar(VarSymbol sym) { | 
| 340 |         if (nextadr == vars.length) { | 
| 341 |             VarSymbol[] newvars = new VarSymbol[nextadr * 2]; | 
| 342 |             System.arraycopy(vars, 0, newvars, 0, nextadr); | 
| 343 |             vars = newvars; | 
| 344 |         } | 
| 345 |         sym.adr = nextadr; | 
| 346 |         vars[nextadr] = sym; | 
| 347 |         inits.excl(nextadr); | 
| 348 |         uninits.incl(nextadr); | 
| 349 |         nextadr++; | 
| 350 |     } | 
| 351 |   | 
| 352 |     /** Record an initialization of a trackable variable. | 
| 353 |      */ | 
| 354 |     void letInit(DiagnosticPosition pos, VarSymbol sym) { | 
| 355 |         if (sym.adr >= firstadr && trackable(sym)) { | 
| 356 |             if ((sym.flags() & FINAL) != 0) { | 
| 357 |                 if ((sym.flags() & PARAMETER) != 0) { | 
| 358 |                     log.error(pos, "final.parameter.may.not.be.assigned", | 
| 359 |                               sym); | 
| 360 |                 } else if (!uninits.isMember(sym.adr)) { | 
| 361 |                     log.error(pos, | 
| 362 |                               loopPassTwo | 
| 363 |                               ? "var.might.be.assigned.in.loop" | 
| 364 |                               : "var.might.already.be.assigned", | 
| 365 |                               sym); | 
| 366 |                 } else if (!inits.isMember(sym.adr)) { | 
| 367 |                     // reachable assignment | 
| 368 |                     uninits.excl(sym.adr); | 
| 369 |                     uninitsTry.excl(sym.adr); | 
| 370 |                 } else { | 
| 371 |                     //log.rawWarning(pos, "unreachable assignment");//DEBUG | 
| 372 |                     uninits.excl(sym.adr); | 
| 373 |                 } | 
| 374 |             } | 
| 375 |             inits.incl(sym.adr); | 
| 376 |         } else if ((sym.flags() & FINAL) != 0) { | 
| 377 |             log.error(pos, "var.might.already.be.assigned", sym); | 
| 378 |         } | 
| 379 |     } | 
| 380 |   | 
| 381 |     /** If tree is either a simple name or of the form this.name or | 
| 382 |      *  C.this.name, and tree represents a trackable variable, | 
| 383 |      *  record an initialization of the variable. | 
| 384 |      */ | 
| 385 |     void letInit(JCTree tree) { | 
| 386 |         tree = TreeInfo.skipParens(tree); | 
| 387 |         if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) { | 
| 388 |             Symbol sym = TreeInfo.symbol(tree); | 
| 389 |             letInit(tree.pos(), (VarSymbol)sym); | 
| 390 |         } | 
| 391 |     } | 
| 392 |   | 
| 393 |     /** Check that trackable variable is initialized. | 
| 394 |      */ | 
| 395 |     void checkInit(DiagnosticPosition pos, VarSymbol sym) { | 
| 396 |         if ((sym.adr >= firstadr || sym.owner.kind != TYP) && | 
| 397 |             trackable(sym) && | 
| 398 |             !inits.isMember(sym.adr)) { | 
| 399 |             log.error(pos, "var.might.not.have.been.initialized", | 
| 400 |                       sym); | 
| 401 |             inits.incl(sym.adr); | 
| 402 |         } | 
| 403 |     } | 
| 404 |   | 
| 405 |     /*-------------------- Handling jumps ----------------------*/ | 
| 406 |   | 
| 407 |     /** Record an outward transfer of control. */ | 
| 408 |     void recordExit(JCTree tree) { | 
| 409 |         pendingExits.append(new PendingExit(tree, inits, uninits)); | 
| 410 |         markDead(); | 
| 411 |     } | 
| 412 |   | 
| 413 |     /** Resolve all breaks of this statement. */ | 
| 414 |     boolean resolveBreaks(JCTree tree, | 
| 415 |                           ListBuffer<PendingExit> oldPendingExits) { | 
| 416 |         boolean result = false; | 
| 417 |         List<PendingExit> exits = pendingExits.toList(); | 
| 418 |         pendingExits = oldPendingExits; | 
| 419 |         for (; exits.nonEmpty(); exits = exits.tail) { | 
| 420 |             PendingExit exit = exits.head; | 
| 421 |             if (exit.tree.getTag() == JCTree.BREAK && | 
| 422 |                 ((JCBreak) exit.tree).target == tree) { | 
| 423 |                 inits.andSet(exit.inits); | 
| 424 |                 uninits.andSet(exit.uninits); | 
| 425 |                 result = true; | 
| 426 |             } else { | 
| 427 |                 pendingExits.append(exit); | 
| 428 |             } | 
| 429 |         } | 
| 430 |         return result; | 
| 431 |     } | 
| 432 |   | 
| 433 |     /** Resolve all continues of this statement. */ | 
| 434 |     boolean resolveContinues(JCTree tree) { | 
| 435 |         boolean result = false; | 
| 436 |         List<PendingExit> exits = pendingExits.toList(); | 
| 437 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 438 |         for (; exits.nonEmpty(); exits = exits.tail) { | 
| 439 |             PendingExit exit = exits.head; | 
| 440 |             if (exit.tree.getTag() == JCTree.CONTINUE && | 
| 441 |                 ((JCContinue) exit.tree).target == tree) { | 
| 442 |                 inits.andSet(exit.inits); | 
| 443 |                 uninits.andSet(exit.uninits); | 
| 444 |                 result = true; | 
| 445 |             } else { | 
| 446 |                 pendingExits.append(exit); | 
| 447 |             } | 
| 448 |         } | 
| 449 |         return result; | 
| 450 |     } | 
| 451 |   | 
| 452 |     /** Record that statement is unreachable. | 
| 453 |      */ | 
| 454 |     void markDead() { | 
| 455 |         inits.inclRange(firstadr, nextadr); | 
| 456 |         uninits.inclRange(firstadr, nextadr); | 
| 457 |         alive = false; | 
| 458 |     } | 
| 459 |   | 
| 460 |     /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets | 
| 461 |      */ | 
| 462 |     void split() { | 
| 463 |         initsWhenFalse = inits.dup(); | 
| 464 |         uninitsWhenFalse = uninits.dup(); | 
| 465 |         initsWhenTrue = inits; | 
| 466 |         uninitsWhenTrue = uninits; | 
| 467 |         inits = uninits = null; | 
| 468 |     } | 
| 469 |   | 
| 470 |     /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. | 
| 471 |      */ | 
| 472 |     void merge() { | 
| 473 |         inits = initsWhenFalse.andSet(initsWhenTrue); | 
| 474 |         uninits = uninitsWhenFalse.andSet(uninitsWhenTrue); | 
| 475 |     } | 
| 476 |   | 
| 477 | /* ************************************************************************ | 
| 478 |  * Visitor methods for statements and definitions | 
| 479 |  *************************************************************************/ | 
| 480 |   | 
| 481 |     /** Analyze a definition. | 
| 482 |      */ | 
| 483 |     void scanDef(JCTree tree) { | 
| 484 |         scanStat(tree); | 
| 485 |         if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) { | 
| 486 |             log.error(tree.pos(), | 
| 487 |                       "initializer.must.be.able.to.complete.normally"); | 
| 488 |         } | 
| 489 |     } | 
| 490 |   | 
| 491 |     /** Analyze a statement. Check that statement is reachable. | 
| 492 |      */ | 
| 493 |     void scanStat(JCTree tree) { | 
| 494 |         if (!alive && tree != null) { | 
| 495 |             log.error(tree.pos(), "unreachable.stmt"); | 
| 496 |             if (tree.getTag() != JCTree.SKIP) alive = true; | 
| 497 |         } | 
| 498 |         scan(tree); | 
| 499 |     } | 
| 500 |   | 
| 501 |     /** Analyze list of statements. | 
| 502 |      */ | 
| 503 |     void scanStats(List<? extends JCStatement> trees) { | 
| 504 |         if (trees != null) | 
| 505 |             for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail) | 
| 506 |                 scanStat(l.head); | 
| 507 |     } | 
| 508 |   | 
| 509 |     /** Analyze an expression. Make sure to set (un)inits rather than | 
| 510 |      *  (un)initsWhenTrue(WhenFalse) on exit. | 
| 511 |      */ | 
| 512 |     void scanExpr(JCTree tree) { | 
| 513 |         if (tree != null) { | 
| 514 |             scan(tree); | 
| 515 |             if (inits == null) merge(); | 
| 516 |         } | 
| 517 |     } | 
| 518 |   | 
| 519 |     /** Analyze a list of expressions. | 
| 520 |      */ | 
| 521 |     void scanExprs(List<? extends JCExpression> trees) { | 
| 522 |         if (trees != null) | 
| 523 |             for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail) | 
| 524 |                 scanExpr(l.head); | 
| 525 |     } | 
| 526 |   | 
| 527 |     /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) | 
| 528 |      *  rather than (un)inits on exit. | 
| 529 |      */ | 
| 530 |     void scanCond(JCTree tree) { | 
| 531 |         if (tree.type.isFalse()) { | 
| 532 |             if (inits == null) merge(); | 
| 533 |             initsWhenTrue = inits.dup(); | 
| 534 |             initsWhenTrue.inclRange(firstadr, nextadr); | 
| 535 |             uninitsWhenTrue = uninits.dup(); | 
| 536 |             uninitsWhenTrue.inclRange(firstadr, nextadr); | 
| 537 |             initsWhenFalse = inits; | 
| 538 |             uninitsWhenFalse = uninits; | 
| 539 |         } else if (tree.type.isTrue()) { | 
| 540 |             if (inits == null) merge(); | 
| 541 |             initsWhenFalse = inits.dup(); | 
| 542 |             initsWhenFalse.inclRange(firstadr, nextadr); | 
| 543 |             uninitsWhenFalse = uninits.dup(); | 
| 544 |             uninitsWhenFalse.inclRange(firstadr, nextadr); | 
| 545 |             initsWhenTrue = inits; | 
| 546 |             uninitsWhenTrue = uninits; | 
| 547 |         } else { | 
| 548 |             scan(tree); | 
| 549 |             if (inits != null) split(); | 
| 550 |         } | 
| 551 |         inits = uninits = null; | 
| 552 |     } | 
| 553 |   | 
| 554 |     /* ------------ Visitor methods for various sorts of trees -------------*/ | 
| 555 |   | 
| 556 |     public void visitClassDef(JCClassDecl tree) { | 
| 557 |         if (tree.sym == null) return; | 
| 558 |   | 
| 559 |         JCClassDecl classDefPrev = classDef; | 
| 560 |         List<Type> thrownPrev = thrown; | 
| 561 |         List<Type> caughtPrev = caught; | 
| 562 |         boolean alivePrev = alive; | 
| 563 |         int firstadrPrev = firstadr; | 
| 564 |         int nextadrPrev = nextadr; | 
| 565 |         ListBuffer<PendingExit> pendingExitsPrev = pendingExits; | 
| 566 |         Lint lintPrev = lint; | 
| 567 |   | 
| 568 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 569 |         if (tree.name != names.empty) { | 
| 570 |             caught = List.nil(); | 
| 571 |             firstadr = nextadr; | 
| 572 |         } | 
| 573 |         classDef = tree; | 
| 574 |         thrown = List.nil(); | 
| 575 |         lint = lint.augment(tree.sym.attributes_field); | 
| 576 |   | 
| 577 |         try { | 
| 578 |             // define all the static fields | 
| 579 |             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 580 |                 if (l.head.getTag() == JCTree.VARDEF) { | 
| 581 |                     JCVariableDecl def = (JCVariableDecl)l.head; | 
| 582 |                     if ((def.mods.flags & STATIC) != 0) { | 
| 583 |                         VarSymbol sym = def.sym; | 
| 584 |                         if (trackable(sym)) | 
| 585 |                             newVar(sym); | 
| 586 |                     } | 
| 587 |                 } | 
| 588 |             } | 
| 589 |   | 
| 590 |             // process all the static initializers | 
| 591 |             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 592 |                 if (l.head.getTag() != JCTree.METHODDEF && | 
| 593 |                     (TreeInfo.flags(l.head) & STATIC) != 0) { | 
| 594 |                     scanDef(l.head); | 
| 595 |                     errorUncaught(); | 
| 596 |                 } | 
| 597 |             } | 
| 598 |   | 
| 599 |             // add intersection of all thrown clauses of initial constructors | 
| 600 |             // to set of caught exceptions, unless class is anonymous. | 
| 601 |             if (tree.name != names.empty) { | 
| 602 |                 boolean firstConstructor = true; | 
| 603 |                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 604 |                     if (TreeInfo.isInitialConstructor(l.head)) { | 
| 605 |                         List<Type> mthrown = | 
| 606 |                             ((JCMethodDecl) l.head).sym.type.getThrownTypes(); | 
| 607 |                         if (firstConstructor) { | 
| 608 |                             caught = mthrown; | 
| 609 |                             firstConstructor = false; | 
| 610 |                         } else { | 
| 611 |                             caught = chk.intersect(mthrown, caught); | 
| 612 |                         } | 
| 613 |                     } | 
| 614 |                 } | 
| 615 |             } | 
| 616 |   | 
| 617 |             // define all the instance fields | 
| 618 |             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 619 |                 if (l.head.getTag() == JCTree.VARDEF) { | 
| 620 |                     JCVariableDecl def = (JCVariableDecl)l.head; | 
| 621 |                     if ((def.mods.flags & STATIC) == 0) { | 
| 622 |                         VarSymbol sym = def.sym; | 
| 623 |                         if (trackable(sym)) | 
| 624 |                             newVar(sym); | 
| 625 |                     } | 
| 626 |                 } | 
| 627 |             } | 
| 628 |   | 
| 629 |             // process all the instance initializers | 
| 630 |             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 631 |                 if (l.head.getTag() != JCTree.METHODDEF && | 
| 632 |                     (TreeInfo.flags(l.head) & STATIC) == 0) { | 
| 633 |                     scanDef(l.head); | 
| 634 |                     errorUncaught(); | 
| 635 |                 } | 
| 636 |             } | 
| 637 |   | 
| 638 |             // in an anonymous class, add the set of thrown exceptions to | 
| 639 |             // the throws clause of the synthetic constructor and propagate | 
| 640 |             // outwards. | 
| 641 |             if (tree.name == names.empty) { | 
| 642 |                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 643 |                     if (TreeInfo.isInitialConstructor(l.head)) { | 
| 644 |                         JCMethodDecl mdef = (JCMethodDecl)l.head; | 
| 645 |                         mdef.thrown = make.Types(thrown); | 
| 646 |                         mdef.sym.type.setThrown(thrown); | 
| 647 |                     } | 
| 648 |                 } | 
| 649 |                 thrownPrev = chk.union(thrown, thrownPrev); | 
| 650 |             } | 
| 651 |   | 
| 652 |             // process all the methods | 
| 653 |             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { | 
| 654 |                 if (l.head.getTag() == JCTree.METHODDEF) { | 
| 655 |                     scan(l.head); | 
| 656 |                     errorUncaught(); | 
| 657 |                 } | 
| 658 |             } | 
| 659 |   | 
| 660 |             thrown = thrownPrev; | 
| 661 |         } finally { | 
| 662 |             pendingExits = pendingExitsPrev; | 
| 663 |             alive = alivePrev; | 
| 664 |             nextadr = nextadrPrev; | 
| 665 |             firstadr = firstadrPrev; | 
| 666 |             caught = caughtPrev; | 
| 667 |             classDef = classDefPrev; | 
| 668 |             lint = lintPrev; | 
| 669 |         } | 
| 670 |     } | 
| 671 |   | 
| 672 |     public void visitMethodDef(JCMethodDecl tree) { | 
| 673 |         if (tree.body == null) return; | 
| 674 |   | 
| 675 |         List<Type> caughtPrev = caught; | 
| 676 |         List<Type> mthrown = tree.sym.type.getThrownTypes(); | 
| 677 |         Bits initsPrev = inits.dup(); | 
| 678 |         Bits uninitsPrev = uninits.dup(); | 
| 679 |         int nextadrPrev = nextadr; | 
| 680 |         int firstadrPrev = firstadr; | 
| 681 |         Lint lintPrev = lint; | 
| 682 |   | 
| 683 |         lint = lint.augment(tree.sym.attributes_field); | 
| 684 |   | 
| 685 |         assert pendingExits.isEmpty(); | 
| 686 |   | 
| 687 |         try { | 
| 688 |             boolean isInitialConstructor = | 
| 689 |                 TreeInfo.isInitialConstructor(tree); | 
| 690 |   | 
| 691 |             if (!isInitialConstructor) | 
| 692 |                 firstadr = nextadr; | 
| 693 |             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { | 
| 694 |                 JCVariableDecl def = l.head; | 
| 695 |                 scan(def); | 
| 696 |                 inits.incl(def.sym.adr); | 
| 697 |                 uninits.excl(def.sym.adr); | 
| 698 |             } | 
| 699 |             if (isInitialConstructor) | 
| 700 |                 caught = chk.union(caught, mthrown); | 
| 701 |             else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK) | 
| 702 |                 caught = mthrown; | 
| 703 |             // else we are in an instance initializer block; | 
| 704 |             // leave caught unchanged. | 
| 705 |   | 
| 706 |             alive = true; | 
| 707 |             scanStat(tree.body); | 
| 708 |   | 
| 709 |             if (alive && tree.sym.type.getReturnType().tag != VOID) | 
| 710 |                 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt"); | 
| 711 |   | 
| 712 |             if (isInitialConstructor) { | 
| 713 |                 for (int i = firstadr; i < nextadr; i++) | 
| 714 |                     if (vars[i].owner == classDef.sym) | 
| 715 |                         checkInit(TreeInfo.diagEndPos(tree.body), vars[i]); | 
| 716 |             } | 
| 717 |             List<PendingExit> exits = pendingExits.toList(); | 
| 718 |             pendingExits = new ListBuffer<PendingExit>(); | 
| 719 |             while (exits.nonEmpty()) { | 
| 720 |                 PendingExit exit = exits.head; | 
| 721 |                 exits = exits.tail; | 
| 722 |                 if (exit.thrown == null) { | 
| 723 |                     assert exit.tree.getTag() == JCTree.RETURN; | 
| 724 |                     if (isInitialConstructor) { | 
| 725 |                         inits = exit.inits; | 
| 726 |                         for (int i = firstadr; i < nextadr; i++) | 
| 727 |                             checkInit(exit.tree.pos(), vars[i]); | 
| 728 |                     } | 
| 729 |                 } else { | 
| 730 |                     // uncaught throws will be reported later | 
| 731 |                     pendingExits.append(exit); | 
| 732 |                 } | 
| 733 |             } | 
| 734 |         } finally { | 
| 735 |             inits = initsPrev; | 
| 736 |             uninits = uninitsPrev; | 
| 737 |             nextadr = nextadrPrev; | 
| 738 |             firstadr = firstadrPrev; | 
| 739 |             caught = caughtPrev; | 
| 740 |             lint = lintPrev; | 
| 741 |         } | 
| 742 |     } | 
| 743 |   | 
| 744 |     public void visitVarDef(JCVariableDecl tree) { | 
| 745 |         boolean track = trackable(tree.sym); | 
| 746 |         if (track && tree.sym.owner.kind == MTH) newVar(tree.sym); | 
| 747 |         if (tree.init != null) { | 
| 748 |             Lint lintPrev = lint; | 
| 749 |             lint = lint.augment(tree.sym.attributes_field); | 
| 750 |             try{ | 
| 751 |                 scanExpr(tree.init); | 
| 752 |                 if (track) letInit(tree.pos(), tree.sym); | 
| 753 |             } finally { | 
| 754 |                 lint = lintPrev; | 
| 755 |             } | 
| 756 |         } | 
| 757 |     } | 
| 758 |   | 
| 759 |     public void visitBlock(JCBlock tree) { | 
| 760 |         int nextadrPrev = nextadr; | 
| 761 |         scanStats(tree.stats); | 
| 762 |         nextadr = nextadrPrev; | 
| 763 |     } | 
| 764 |   | 
| 765 |     public void visitDoLoop(JCDoWhileLoop tree) { | 
| 766 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 767 |         boolean prevLoopPassTwo = loopPassTwo; | 
| 768 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 769 |         do { | 
| 770 |             Bits uninitsEntry = uninits.dup(); | 
| 771 |             scanStat(tree.body); | 
| 772 |             alive |= resolveContinues(tree); | 
| 773 |             scanCond(tree.cond); | 
| 774 |             if (log.nerrors != 0 || | 
| 775 |                 loopPassTwo || | 
| 776 |                 uninitsEntry.diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) | 
| 777 |                 break; | 
| 778 |             inits = initsWhenTrue; | 
| 779 |             uninits = uninitsEntry.andSet(uninitsWhenTrue); | 
| 780 |             loopPassTwo = true; | 
| 781 |             alive = true; | 
| 782 |         } while (true); | 
| 783 |         loopPassTwo = prevLoopPassTwo; | 
| 784 |         inits = initsWhenFalse; | 
| 785 |         uninits = uninitsWhenFalse; | 
| 786 |         alive = alive && !tree.cond.type.isTrue(); | 
| 787 |         alive |= resolveBreaks(tree, prevPendingExits); | 
| 788 |     } | 
| 789 |   | 
| 790 |     public void visitWhileLoop(JCWhileLoop tree) { | 
| 791 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 792 |         boolean prevLoopPassTwo = loopPassTwo; | 
| 793 |         Bits initsCond; | 
| 794 |         Bits uninitsCond; | 
| 795 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 796 |         do { | 
| 797 |             Bits uninitsEntry = uninits.dup(); | 
| 798 |             scanCond(tree.cond); | 
| 799 |             initsCond = initsWhenFalse; | 
| 800 |             uninitsCond = uninitsWhenFalse; | 
| 801 |             inits = initsWhenTrue; | 
| 802 |             uninits = uninitsWhenTrue; | 
| 803 |             alive = !tree.cond.type.isFalse(); | 
| 804 |             scanStat(tree.body); | 
| 805 |             alive |= resolveContinues(tree); | 
| 806 |             if (log.nerrors != 0 || | 
| 807 |                 loopPassTwo || | 
| 808 |                 uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1) | 
| 809 |                 break; | 
| 810 |             uninits = uninitsEntry.andSet(uninits); | 
| 811 |             loopPassTwo = true; | 
| 812 |             alive = true; | 
| 813 |         } while (true); | 
| 814 |         loopPassTwo = prevLoopPassTwo; | 
| 815 |         inits = initsCond; | 
| 816 |         uninits = uninitsCond; | 
| 817 |         alive = resolveBreaks(tree, prevPendingExits) || | 
| 818 |             !tree.cond.type.isTrue(); | 
| 819 |     } | 
| 820 |   | 
| 821 |     public void visitForLoop(JCForLoop tree) { | 
| 822 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 823 |         boolean prevLoopPassTwo = loopPassTwo; | 
| 824 |         int nextadrPrev = nextadr; | 
| 825 |         scanStats(tree.init); | 
| 826 |         Bits initsCond; | 
| 827 |         Bits uninitsCond; | 
| 828 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 829 |         do { | 
| 830 |             Bits uninitsEntry = uninits.dup(); | 
| 831 |             if (tree.cond != null) { | 
| 832 |                 scanCond(tree.cond); | 
| 833 |                 initsCond = initsWhenFalse; | 
| 834 |                 uninitsCond = uninitsWhenFalse; | 
| 835 |                 inits = initsWhenTrue; | 
| 836 |                 uninits = uninitsWhenTrue; | 
| 837 |                 alive = !tree.cond.type.isFalse(); | 
| 838 |             } else { | 
| 839 |                 initsCond = inits.dup(); | 
| 840 |                 initsCond.inclRange(firstadr, nextadr); | 
| 841 |                 uninitsCond = uninits.dup(); | 
| 842 |                 uninitsCond.inclRange(firstadr, nextadr); | 
| 843 |                 alive = true; | 
| 844 |             } | 
| 845 |             scanStat(tree.body); | 
| 846 |             alive |= resolveContinues(tree); | 
| 847 |             scan(tree.step); | 
| 848 |             if (log.nerrors != 0 || | 
| 849 |                 loopPassTwo || | 
| 850 |                 uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1) | 
| 851 |                 break; | 
| 852 |             uninits = uninitsEntry.andSet(uninits); | 
| 853 |             loopPassTwo = true; | 
| 854 |             alive = true; | 
| 855 |         } while (true); | 
| 856 |         loopPassTwo = prevLoopPassTwo; | 
| 857 |         inits = initsCond; | 
| 858 |         uninits = uninitsCond; | 
| 859 |         alive = resolveBreaks(tree, prevPendingExits) || | 
| 860 |             tree.cond != null && !tree.cond.type.isTrue(); | 
| 861 |         nextadr = nextadrPrev; | 
| 862 |     } | 
| 863 |   | 
| 864 |     public void visitForeachLoop(JCEnhancedForLoop tree) { | 
| 865 |         visitVarDef(tree.var); | 
| 866 |   | 
| 867 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 868 |         boolean prevLoopPassTwo = loopPassTwo; | 
| 869 |         int nextadrPrev = nextadr; | 
| 870 |         scan(tree.expr); | 
| 871 |         Bits initsStart = inits.dup(); | 
| 872 |         Bits uninitsStart = uninits.dup(); | 
| 873 |   | 
| 874 |         letInit(tree.pos(), tree.var.sym); | 
| 875 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 876 |         do { | 
| 877 |             Bits uninitsEntry = uninits.dup(); | 
| 878 |             scanStat(tree.body); | 
| 879 |             alive |= resolveContinues(tree); | 
| 880 |             if (log.nerrors != 0 || | 
| 881 |                 loopPassTwo || | 
| 882 |                 uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1) | 
| 883 |                 break; | 
| 884 |             uninits = uninitsEntry.andSet(uninits); | 
| 885 |             loopPassTwo = true; | 
| 886 |             alive = true; | 
| 887 |         } while (true); | 
| 888 |         loopPassTwo = prevLoopPassTwo; | 
| 889 |         inits = initsStart; | 
| 890 |         uninits = uninitsStart.andSet(uninits); | 
| 891 |         resolveBreaks(tree, prevPendingExits); | 
| 892 |         alive = true; | 
| 893 |         nextadr = nextadrPrev; | 
| 894 |     } | 
| 895 |   | 
| 896 |     public void visitLabelled(JCLabeledStatement tree) { | 
| 897 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 898 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 899 |         scanStat(tree.body); | 
| 900 |         alive |= resolveBreaks(tree, prevPendingExits); | 
| 901 |     } | 
| 902 |   | 
| 903 |     public void visitSwitch(JCSwitch tree) { | 
| 904 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 905 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 906 |         int nextadrPrev = nextadr; | 
| 907 |         scanExpr(tree.selector); | 
| 908 |         Bits initsSwitch = inits; | 
| 909 |         Bits uninitsSwitch = uninits.dup(); | 
| 910 |         boolean hasDefault = false; | 
| 911 |         for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { | 
| 912 |             alive = true; | 
| 913 |             inits = initsSwitch.dup(); | 
| 914 |             uninits = uninits.andSet(uninitsSwitch); | 
| 915 |             JCCase c = l.head; | 
| 916 |             if (c.pat == null) | 
| 917 |                 hasDefault = true; | 
| 918 |             else | 
| 919 |                 scanExpr(c.pat); | 
| 920 |             scanStats(c.stats); | 
| 921 |             addVars(c.stats, initsSwitch, uninitsSwitch); | 
| 922 |             // Warn about fall-through if lint switch fallthrough enabled. | 
| 923 |             if (!loopPassTwo && | 
| 924 |                 alive && | 
| 925 |                 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) && | 
| 926 |                 c.stats.nonEmpty() && l.tail.nonEmpty()) | 
| 927 |                 log.warning(l.tail.head.pos(), | 
| 928 |                             "possible.fall-through.into.case"); | 
| 929 |         } | 
| 930 |         if (!hasDefault) { | 
| 931 |             inits.andSet(initsSwitch); | 
| 932 |             alive = true; | 
| 933 |         } | 
| 934 |         alive |= resolveBreaks(tree, prevPendingExits); | 
| 935 |         nextadr = nextadrPrev; | 
| 936 |     } | 
| 937 |     // where | 
| 938 |         /** Add any variables defined in stats to inits and uninits. */ | 
| 939 |         private static void addVars(List<JCStatement> stats, Bits inits, | 
| 940 |                                     Bits uninits) { | 
| 941 |             for (;stats.nonEmpty(); stats = stats.tail) { | 
| 942 |                 JCTree stat = stats.head; | 
| 943 |                 if (stat.getTag() == JCTree.VARDEF) { | 
| 944 |                     int adr = ((JCVariableDecl) stat).sym.adr; | 
| 945 |                     inits.excl(adr); | 
| 946 |                     uninits.incl(adr); | 
| 947 |                 } | 
| 948 |             } | 
| 949 |         } | 
| 950 |   | 
| 951 |     public void visitTry(JCTry tree) { | 
| 952 |         List<Type> caughtPrev = caught; | 
| 953 |         List<Type> thrownPrev = thrown; | 
| 954 |         thrown = List.nil(); | 
| 955 |         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) | 
| 956 |             caught = chk.incl(l.head.param.type, caught); | 
| 957 |         Bits uninitsTryPrev = uninitsTry; | 
| 958 |         ListBuffer<PendingExit> prevPendingExits = pendingExits; | 
| 959 |         pendingExits = new ListBuffer<PendingExit>(); | 
| 960 |         Bits initsTry = inits.dup(); | 
| 961 |         uninitsTry = uninits.dup(); | 
| 962 |         scanStat(tree.body); | 
| 963 |         List<Type> thrownInTry = thrown; | 
| 964 |         thrown = thrownPrev; | 
| 965 |         caught = caughtPrev; | 
| 966 |         boolean aliveEnd = alive; | 
| 967 |         uninitsTry.andSet(uninits); | 
| 968 |         Bits initsEnd = inits; | 
| 969 |         Bits uninitsEnd = uninits; | 
| 970 |         int nextadrCatch = nextadr; | 
| 971 |   | 
| 972 |         List<Type> caughtInTry = List.nil(); | 
| 973 |         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { | 
| 974 |             alive = true; | 
| 975 |             JCVariableDecl param = l.head.param; | 
| 976 |             Type exc = param.type; | 
| 977 |             if (chk.subset(exc, caughtInTry)) { | 
| 978 |                 log.error(l.head.pos(), | 
| 979 |                           "except.already.caught", exc); | 
| 980 |             } else if (!chk.isUnchecked(l.head.pos(), exc) && | 
| 981 |                        exc.tsym != syms.throwableType.tsym && | 
| 982 |                        exc.tsym != syms.exceptionType.tsym && | 
| 983 |                        !chk.intersects(exc, thrownInTry)) { | 
| 984 |                 log.error(l.head.pos(), | 
| 985 |                           "except.never.thrown.in.try", exc); | 
| 986 |             } | 
| 987 |             caughtInTry = chk.incl(exc, caughtInTry); | 
| 988 |             inits = initsTry.dup(); | 
| 989 |             uninits = uninitsTry.dup(); | 
| 990 |             scan(param); | 
| 991 |             inits.incl(param.sym.adr); | 
| 992 |             uninits.excl(param.sym.adr); | 
| 993 |             scanStat(l.head.body); | 
| 994 |             initsEnd.andSet(inits); | 
| 995 |             uninitsEnd.andSet(uninits); | 
| 996 |             nextadr = nextadrCatch; | 
| 997 |             aliveEnd |= alive; | 
| 998 |         } | 
| 999 |         if (tree.finalizer != null) { | 
| 1000 |             List<Type> savedThrown = thrown; | 
| 1001 |             thrown = List.nil(); | 
| 1002 |             inits = initsTry.dup(); | 
| 1003 |             uninits = uninitsTry.dup(); | 
| 1004 |             ListBuffer<PendingExit> exits = pendingExits; | 
| 1005 |             pendingExits = prevPendingExits; | 
| 1006 |             alive = true; | 
| 1007 |             scanStat(tree.finalizer); | 
| 1008 |             if (!alive) { | 
| 1009 |                 // discard exits and exceptions from try and finally | 
| 1010 |                 thrown = chk.union(thrown, thrownPrev); | 
| 1011 |                 if (!loopPassTwo && | 
| 1012 |                     lint.isEnabled(Lint.LintCategory.FINALLY)) { | 
| 1013 |                     log.warning(TreeInfo.diagEndPos(tree.finalizer), | 
| 1014 |                                 "finally.cannot.complete"); | 
| 1015 |                 } | 
| 1016 |             } else { | 
| 1017 |                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); | 
| 1018 |                 thrown = chk.union(thrown, savedThrown); | 
| 1019 |                 uninits.andSet(uninitsEnd); | 
| 1020 |                 // FIX: this doesn't preserve source order of exits in catch | 
| 1021 |                 // versus finally! | 
| 1022 |                 while (exits.nonEmpty()) { | 
| 1023 |                     PendingExit exit = exits.next(); | 
| 1024 |                     if (exit.inits != null) { | 
| 1025 |                         exit.inits.orSet(inits); | 
| 1026 |                         exit.uninits.andSet(uninits); | 
| 1027 |                     } | 
| 1028 |                     pendingExits.append(exit); | 
| 1029 |                 } | 
| 1030 |                 inits.orSet(initsEnd); | 
| 1031 |                 alive = aliveEnd; | 
| 1032 |             } | 
| 1033 |         } else { | 
| 1034 |             thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); | 
| 1035 |             inits = initsEnd; | 
| 1036 |             uninits = uninitsEnd; | 
| 1037 |             alive = aliveEnd; | 
| 1038 |             ListBuffer<PendingExit> exits = pendingExits; | 
| 1039 |             pendingExits = prevPendingExits; | 
| 1040 |             while (exits.nonEmpty()) pendingExits.append(exits.next()); | 
| 1041 |         } | 
| 1042 |         uninitsTry.andSet(uninitsTryPrev).andSet(uninits); | 
| 1043 |     } | 
| 1044 |   | 
| 1045 |     public void visitConditional(JCConditional tree) { | 
| 1046 |         scanCond(tree.cond); | 
| 1047 |         Bits initsBeforeElse = initsWhenFalse; | 
| 1048 |         Bits uninitsBeforeElse = uninitsWhenFalse; | 
| 1049 |         inits = initsWhenTrue; | 
| 1050 |         uninits = uninitsWhenTrue; | 
| 1051 |         if (tree.truepart.type.tag == BOOLEAN && | 
| 1052 |             tree.falsepart.type.tag == BOOLEAN) { | 
| 1053 |             // if b and c are boolean valued, then | 
| 1054 |             // v is (un)assigned after a?b:c when true iff | 
| 1055 |             //    v is (un)assigned after b when true and | 
| 1056 |             //    v is (un)assigned after c when true | 
| 1057 |             scanCond(tree.truepart); | 
| 1058 |             Bits initsAfterThenWhenTrue = initsWhenTrue.dup(); | 
| 1059 |             Bits initsAfterThenWhenFalse = initsWhenFalse.dup(); | 
| 1060 |             Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup(); | 
| 1061 |             Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup(); | 
| 1062 |             inits = initsBeforeElse; | 
| 1063 |             uninits = uninitsBeforeElse; | 
| 1064 |             scanCond(tree.falsepart); | 
| 1065 |             initsWhenTrue.andSet(initsAfterThenWhenTrue); | 
| 1066 |             initsWhenFalse.andSet(initsAfterThenWhenFalse); | 
| 1067 |             uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); | 
| 1068 |             uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); | 
| 1069 |         } else { | 
| 1070 |             scanExpr(tree.truepart); | 
| 1071 |             Bits initsAfterThen = inits.dup(); | 
| 1072 |             Bits uninitsAfterThen = uninits.dup(); | 
| 1073 |             inits = initsBeforeElse; | 
| 1074 |             uninits = uninitsBeforeElse; | 
| 1075 |             scanExpr(tree.falsepart); | 
| 1076 |             inits.andSet(initsAfterThen); | 
| 1077 |             uninits.andSet(uninitsAfterThen); | 
| 1078 |         } | 
| 1079 |     } | 
| 1080 |   | 
| 1081 |     public void visitIf(JCIf tree) { | 
| 1082 |         scanCond(tree.cond); | 
| 1083 |         Bits initsBeforeElse = initsWhenFalse; | 
| 1084 |         Bits uninitsBeforeElse = uninitsWhenFalse; | 
| 1085 |         inits = initsWhenTrue; | 
| 1086 |         uninits = uninitsWhenTrue; | 
| 1087 |         scanStat(tree.thenpart); | 
| 1088 |         if (tree.elsepart != null) { | 
| 1089 |             boolean aliveAfterThen = alive; | 
| 1090 |             alive = true; | 
| 1091 |             Bits initsAfterThen = inits.dup(); | 
| 1092 |             Bits uninitsAfterThen = uninits.dup(); | 
| 1093 |             inits = initsBeforeElse; | 
| 1094 |             uninits = uninitsBeforeElse; | 
| 1095 |             scanStat(tree.elsepart); | 
| 1096 |             inits.andSet(initsAfterThen); | 
| 1097 |             uninits.andSet(uninitsAfterThen); | 
| 1098 |             alive = alive | aliveAfterThen; | 
| 1099 |         } else { | 
| 1100 |             inits.andSet(initsBeforeElse); | 
| 1101 |             uninits.andSet(uninitsBeforeElse); | 
| 1102 |             alive = true; | 
| 1103 |         } | 
| 1104 |     } | 
| 1105 |   | 
| 1106 |   | 
| 1107 |   | 
| 1108 |     public void visitBreak(JCBreak tree) { | 
| 1109 |         recordExit(tree); | 
| 1110 |     } | 
| 1111 |   | 
| 1112 |     public void visitContinue(JCContinue tree) { | 
| 1113 |         recordExit(tree); | 
| 1114 |     } | 
| 1115 |   | 
| 1116 |     public void visitReturn(JCReturn tree) { | 
| 1117 |         scanExpr(tree.expr); | 
| 1118 |         // if not initial constructor, should markDead instead of recordExit | 
| 1119 |         recordExit(tree); | 
| 1120 |     } | 
| 1121 |   | 
| 1122 |     public void visitThrow(JCThrow tree) { | 
| 1123 |         scanExpr(tree.expr); | 
| 1124 |         markThrown(tree, tree.expr.type); | 
| 1125 |         markDead(); | 
| 1126 |     } | 
| 1127 |   | 
| 1128 |     public void visitApply(JCMethodInvocation tree) { | 
| 1129 |         scanExpr(tree.meth); | 
| 1130 |         scanExprs(tree.args); | 
| 1131 |         for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail) | 
| 1132 |             markThrown(tree, l.head); | 
| 1133 |     } | 
| 1134 |   | 
| 1135 |     public void visitNewClass(JCNewClass tree) { | 
| 1136 |         scanExpr(tree.encl); | 
| 1137 |         scanExprs(tree.args); | 
| 1138 |        // scan(tree.def); | 
| 1139 |         for (List<Type> l = tree.constructor.type.getThrownTypes(); | 
| 1140 |              l.nonEmpty(); | 
| 1141 |              l = l.tail) | 
| 1142 |             markThrown(tree, l.head); | 
| 1143 |         scan(tree.def); | 
| 1144 |     } | 
| 1145 |   | 
| 1146 |     public void visitNewArray(JCNewArray tree) { | 
| 1147 |         scanExprs(tree.dims); | 
| 1148 |         scanExprs(tree.elems); | 
| 1149 |     } | 
| 1150 |   | 
| 1151 |     public void visitAssert(JCAssert tree) { | 
| 1152 |         Bits initsExit = inits.dup(); | 
| 1153 |         Bits uninitsExit = uninits.dup(); | 
| 1154 |         scanCond(tree.cond); | 
| 1155 |         uninitsExit.andSet(uninitsWhenTrue); | 
| 1156 |         if (tree.detail != null) { | 
| 1157 |             inits = initsWhenFalse; | 
| 1158 |             uninits = uninitsWhenFalse; | 
| 1159 |             scanExpr(tree.detail); | 
| 1160 |         } | 
| 1161 |         inits = initsExit; | 
| 1162 |         uninits = uninitsExit; | 
| 1163 |     } | 
| 1164 |   | 
| 1165 |     public void visitAssign(JCAssign tree) { | 
| 1166 |         JCTree lhs = TreeInfo.skipParens(tree.lhs); | 
| 1167 |         if (!(lhs instanceof JCIdent)) scanExpr(lhs); | 
| 1168 |         scanExpr(tree.rhs); | 
| 1169 |         letInit(lhs); | 
| 1170 |     } | 
| 1171 |   | 
| 1172 |     public void visitAssignop(JCAssignOp tree) { | 
| 1173 |         scanExpr(tree.lhs); | 
| 1174 |         scanExpr(tree.rhs); | 
| 1175 |         letInit(tree.lhs); | 
| 1176 |     } | 
| 1177 |   | 
| 1178 |     public void visitUnary(JCUnary tree) { | 
| 1179 |         switch (tree.getTag()) { | 
| 1180 |         case JCTree.NOT: | 
| 1181 |             scanCond(tree.arg); | 
| 1182 |             Bits t = initsWhenFalse; | 
| 1183 |             initsWhenFalse = initsWhenTrue; | 
| 1184 |             initsWhenTrue = t; | 
| 1185 |             t = uninitsWhenFalse; | 
| 1186 |             uninitsWhenFalse = uninitsWhenTrue; | 
| 1187 |             uninitsWhenTrue = t; | 
| 1188 |             break; | 
| 1189 |         case JCTree.PREINC: case JCTree.POSTINC: | 
| 1190 |         case JCTree.PREDEC: case JCTree.POSTDEC: | 
| 1191 |             scanExpr(tree.arg); | 
| 1192 |             letInit(tree.arg); | 
| 1193 |             break; | 
| 1194 |         default: | 
| 1195 |             scanExpr(tree.arg); | 
| 1196 |         } | 
| 1197 |     } | 
| 1198 |   | 
| 1199 |     public void visitBinary(JCBinary tree) { | 
| 1200 |         switch (tree.getTag()) { | 
| 1201 |         case JCTree.AND: | 
| 1202 |             scanCond(tree.lhs); | 
| 1203 |             Bits initsWhenFalseLeft = initsWhenFalse; | 
| 1204 |             Bits uninitsWhenFalseLeft = uninitsWhenFalse; | 
| 1205 |             inits = initsWhenTrue; | 
| 1206 |             uninits = uninitsWhenTrue; | 
| 1207 |             scanCond(tree.rhs); | 
| 1208 |             initsWhenFalse.andSet(initsWhenFalseLeft); | 
| 1209 |             uninitsWhenFalse.andSet(uninitsWhenFalseLeft); | 
| 1210 |             break; | 
| 1211 |         case JCTree.OR: | 
| 1212 |             scanCond(tree.lhs); | 
| 1213 |             Bits initsWhenTrueLeft = initsWhenTrue; | 
| 1214 |             Bits uninitsWhenTrueLeft = uninitsWhenTrue; | 
| 1215 |             inits = initsWhenFalse; | 
| 1216 |             uninits = uninitsWhenFalse; | 
| 1217 |             scanCond(tree.rhs); | 
| 1218 |             initsWhenTrue.andSet(initsWhenTrueLeft); | 
| 1219 |             uninitsWhenTrue.andSet(uninitsWhenTrueLeft); | 
| 1220 |             break; | 
| 1221 |         default: | 
| 1222 |             scanExpr(tree.lhs); | 
| 1223 |             scanExpr(tree.rhs); | 
| 1224 |         } | 
| 1225 |     } | 
| 1226 |   | 
| 1227 |     public void visitIdent(JCIdent tree) { | 
| 1228 |         if (tree.sym.kind == VAR) | 
| 1229 |             checkInit(tree.pos(), (VarSymbol)tree.sym); | 
| 1230 |     } | 
| 1231 |   | 
| 1232 |     public void visitTypeCast(JCTypeCast tree) { | 
| 1233 |         super.visitTypeCast(tree); | 
| 1234 |         if (!tree.type.isErroneous() | 
| 1235 |             && lint.isEnabled(Lint.LintCategory.CAST) | 
| 1236 |             && types.isSameType(tree.expr.type, tree.clazz.type)) { | 
| 1237 |             log.warning(tree.pos(), "redundant.cast", tree.expr.type); | 
| 1238 |         } | 
| 1239 |     } | 
| 1240 |   | 
| 1241 |     public void visitTopLevel(JCCompilationUnit tree) { | 
| 1242 |         // Do nothing for TopLevel since each class is visited individually | 
| 1243 |     } | 
| 1244 |   | 
| 1245 | /************************************************************************** | 
| 1246 |  * main method | 
| 1247 |  *************************************************************************/ | 
| 1248 |   | 
| 1249 |     /** Perform definite assignment/unassignment analysis on a tree. | 
| 1250 |      */ | 
| 1251 |     public void analyzeTree(JCTree tree, TreeMaker make) { | 
| 1252 |         try { | 
| 1253 |             this.make = make; | 
| 1254 |             inits = new Bits(); | 
| 1255 |             uninits = new Bits(); | 
| 1256 |             uninitsTry = new Bits(); | 
| 1257 |             initsWhenTrue = initsWhenFalse = | 
| 1258 |                 uninitsWhenTrue = uninitsWhenFalse = null; | 
| 1259 |             if (vars == null) | 
| 1260 |                 vars = new VarSymbol[32]; | 
| 1261 |             else | 
| 1262 |                 for (int i=0; i<vars.length; i++) | 
| 1263 |                     vars[i] = null; | 
| 1264 |             firstadr = 0; | 
| 1265 |             nextadr = 0; | 
| 1266 |             pendingExits = new ListBuffer<PendingExit>(); | 
| 1267 |             alive = true; | 
| 1268 |             this.thrown = this.caught = null; | 
| 1269 |             this.classDef = null; | 
| 1270 |             scan(tree); | 
| 1271 |         } finally { | 
| 1272 |             // note that recursive invocations of this method fail hard | 
| 1273 |             inits = uninits = uninitsTry = null; | 
| 1274 |             initsWhenTrue = initsWhenFalse = | 
| 1275 |                 uninitsWhenTrue = uninitsWhenFalse = null; | 
| 1276 |             if (vars != null) for (int i=0; i<vars.length; i++) | 
| 1277 |                 vars[i] = null; | 
| 1278 |             firstadr = 0; | 
| 1279 |             nextadr = 0; | 
| 1280 |             pendingExits = null; | 
| 1281 |             this.make = null; | 
| 1282 |             this.thrown = this.caught = null; | 
| 1283 |             this.classDef = null; | 
| 1284 |         } | 
| 1285 |     } | 
| 1286 | } |