Thu, 10 Jun 2010 17:09:56 -0700
6960407: Potential rebranding issues in openjdk/langtools repository sources
Reviewed-by: darcy
1 /*
2 * Copyright (c) 1999, 2009, Oracle and/or its affiliates. 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. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 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 */
26 //todo: one might eliminate uninits.andSets when monotonic
28 package com.sun.tools.javac.comp;
30 import java.util.HashMap;
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;
37 import com.sun.tools.javac.code.Symbol.*;
38 import com.sun.tools.javac.tree.JCTree.*;
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.*;
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
60 * cause any exception to be "caught". For DA/DU analysis, the finally
61 * clause can prevent a transfer of control from propagating DA/DU
62 * state to the target. In addition, code in the finally clause can
63 * affect the DA/DU status of variables.
64 *
65 * <p>For try statements, we introduce the idea of a variable being
66 * definitely unassigned "everywhere" in a block. A variable V is
67 * "unassigned everywhere" in a block iff it is unassigned at the
68 * beginning of the block and there is no reachable assignment to V
69 * in the block. An assignment V=e is reachable iff V is not DA
70 * after e. Then we can say that V is DU at the beginning of the
71 * catch block iff V is DU everywhere in the try block. Similarly, V
72 * is DU at the beginning of the finally block iff V is DU everywhere
73 * in the try block and in every catch block. Specifically, the
74 * following bullet is added to 16.2.2
75 * <pre>
76 * V is <em>unassigned everywhere</em> in a block if it is
77 * unassigned before the block and there is no reachable
78 * assignment to V within the block.
79 * </pre>
80 * <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
81 * try blocks is changed to
82 * <pre>
83 * V is definitely unassigned before a catch block iff V is
84 * definitely unassigned everywhere in the try block.
85 * </pre>
86 * <p>The last bullet (and all of its sub-bullets) for try blocks that
87 * have a finally block is changed to
88 * <pre>
89 * V is definitely unassigned before the finally block iff
90 * V is definitely unassigned everywhere in the try block
91 * and everywhere in each catch block of the try statement.
92 * </pre>
93 * <p>In addition,
94 * <pre>
95 * V is definitely assigned at the end of a constructor iff
96 * V is definitely assigned after the block that is the body
97 * of the constructor and V is definitely assigned at every
98 * return that can return from the constructor.
99 * </pre>
100 * <p>In addition, each continue statement with the loop as its target
101 * is treated as a jump to the end of the loop body, and "intervening"
102 * finally clauses are treated as follows: V is DA "due to the
103 * continue" iff V is DA before the continue statement or V is DA at
104 * the end of any intervening finally block. V is DU "due to the
105 * continue" iff any intervening finally cannot complete normally or V
106 * is DU at the end of every intervening finally block. This "due to
107 * the continue" concept is then used in the spec for the loops.
108 *
109 * <p>Similarly, break statements must consider intervening finally
110 * blocks. For liveness analysis, a break statement for which any
111 * intervening finally cannot complete normally is not considered to
112 * cause the target statement to be able to complete normally. Then
113 * we say V is DA "due to the break" iff V is DA before the break or
114 * V is DA at the end of any intervening finally block. V is DU "due
115 * to the break" iff any intervening finally cannot complete normally
116 * or V is DU at the break and at the end of every intervening
117 * finally block. (I suspect this latter condition can be
118 * simplified.) This "due to the break" is then used in the spec for
119 * all statements that can be "broken".
120 *
121 * <p>The return statement is treated similarly. V is DA "due to a
122 * return statement" iff V is DA before the return statement or V is
123 * DA at the end of any intervening finally block. Note that we
124 * don't have to worry about the return expression because this
125 * concept is only used for construcrors.
126 *
127 * <p>There is no spec in JLS2 for when a variable is definitely
128 * assigned at the end of a constructor, which is needed for final
129 * fields (8.3.1.2). We implement the rule that V is DA at the end
130 * of the constructor iff it is DA and the end of the body of the
131 * constructor and V is DA "due to" every return of the constructor.
132 *
133 * <p>Intervening finally blocks similarly affect exception analysis. An
134 * intervening finally that cannot complete normally allows us to ignore
135 * an otherwise uncaught exception.
136 *
137 * <p>To implement the semantics of intervening finally clauses, all
138 * nonlocal transfers (break, continue, return, throw, method call that
139 * can throw a checked exception, and a constructor invocation that can
140 * thrown a checked exception) are recorded in a queue, and removed
141 * from the queue when we complete processing the target of the
142 * nonlocal transfer. This allows us to modify the queue in accordance
143 * with the above rules when we encounter a finally clause. The only
144 * exception to this [no pun intended] is that checked exceptions that
145 * are known to be caught or declared to be caught in the enclosing
146 * method are not recorded in the queue, but instead are recorded in a
147 * global variable "Set<Type> thrown" that records the type of all
148 * exceptions that can be thrown.
149 *
150 * <p>Other minor issues the treatment of members of other classes
151 * (always considered DA except that within an anonymous class
152 * constructor, where DA status from the enclosing scope is
153 * preserved), treatment of the case expression (V is DA before the
154 * case expression iff V is DA after the switch expression),
155 * treatment of variables declared in a switch block (the implied
156 * DA/DU status after the switch expression is DU and not DA for
157 * variables defined in a switch block), the treatment of boolean ?:
158 * expressions (The JLS rules only handle b and c non-boolean; the
159 * new rule is that if b and c are boolean valued, then V is
160 * (un)assigned after a?b:c when true/false iff V is (un)assigned
161 * after b when true/false and V is (un)assigned after c when
162 * true/false).
163 *
164 * <p>There is the remaining question of what syntactic forms constitute a
165 * reference to a variable. It is conventional to allow this.x on the
166 * left-hand-side to initialize a final instance field named x, yet
167 * this.x isn't considered a "use" when appearing on a right-hand-side
168 * in most implementations. Should parentheses affect what is
169 * considered a variable reference? The simplest rule would be to
170 * allow unqualified forms only, parentheses optional, and phase out
171 * support for assigning to a final field via this.x.
172 *
173 * <p><b>This is NOT part of any supported API.
174 * If you write code that depends on this, you do so at your own risk.
175 * This code and its internal interfaces are subject to change or
176 * deletion without notice.</b>
177 */
178 public class Flow extends TreeScanner {
179 protected static final Context.Key<Flow> flowKey =
180 new Context.Key<Flow>();
182 private final Names names;
183 private final Log log;
184 private final Symtab syms;
185 private final Types types;
186 private final Check chk;
187 private TreeMaker make;
188 private Lint lint;
189 private final boolean allowRethrowAnalysis;
191 public static Flow instance(Context context) {
192 Flow instance = context.get(flowKey);
193 if (instance == null)
194 instance = new Flow(context);
195 return instance;
196 }
198 protected Flow(Context context) {
199 context.put(flowKey, this);
200 names = Names.instance(context);
201 log = Log.instance(context);
202 syms = Symtab.instance(context);
203 types = Types.instance(context);
204 chk = Check.instance(context);
205 lint = Lint.instance(context);
206 Source source = Source.instance(context);
207 allowRethrowAnalysis = source.allowMulticatch();
208 }
210 /** A flag that indicates whether the last statement could
211 * complete normally.
212 */
213 private boolean alive;
215 /** The set of definitely assigned variables.
216 */
217 Bits inits;
219 /** The set of definitely unassigned variables.
220 */
221 Bits uninits;
223 HashMap<Symbol, List<Type>> multicatchTypes;
225 /** The set of variables that are definitely unassigned everywhere
226 * in current try block. This variable is maintained lazily; it is
227 * updated only when something gets removed from uninits,
228 * typically by being assigned in reachable code. To obtain the
229 * correct set of variables which are definitely unassigned
230 * anywhere in current try block, intersect uninitsTry and
231 * uninits.
232 */
233 Bits uninitsTry;
235 /** When analyzing a condition, inits and uninits are null.
236 * Instead we have:
237 */
238 Bits initsWhenTrue;
239 Bits initsWhenFalse;
240 Bits uninitsWhenTrue;
241 Bits uninitsWhenFalse;
243 /** A mapping from addresses to variable symbols.
244 */
245 VarSymbol[] vars;
247 /** The current class being defined.
248 */
249 JCClassDecl classDef;
251 /** The first variable sequence number in this class definition.
252 */
253 int firstadr;
255 /** The next available variable sequence number.
256 */
257 int nextadr;
259 /** The list of possibly thrown declarable exceptions.
260 */
261 List<Type> thrown;
263 /** The list of exceptions that are either caught or declared to be
264 * thrown.
265 */
266 List<Type> caught;
268 /** Set when processing a loop body the second time for DU analysis. */
269 boolean loopPassTwo = false;
271 /*-------------------- Environments ----------------------*/
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();
288 }
289 PendingExit(JCTree tree, Type thrown) {
290 this.tree = tree;
291 this.thrown = thrown;
292 }
293 }
295 /** The currently pending exits that go from current inner blocks
296 * to an enclosing block, in source order.
297 */
298 ListBuffer<PendingExit> pendingExits;
300 /*-------------------- Exceptions ----------------------*/
302 /** Complain that pending exceptions are not caught.
303 */
304 void errorUncaught() {
305 for (PendingExit exit = pendingExits.next();
306 exit != null;
307 exit = pendingExits.next()) {
308 boolean synthetic = classDef != null &&
309 classDef.pos == exit.tree.pos;
310 log.error(exit.tree.pos(),
311 synthetic
312 ? "unreported.exception.default.constructor"
313 : "unreported.exception.need.to.catch.or.throw",
314 exit.thrown);
315 }
316 }
318 /** Record that exception is potentially thrown and check that it
319 * is caught.
320 */
321 void markThrown(JCTree tree, Type exc) {
322 if (!chk.isUnchecked(tree.pos(), exc)) {
323 if (!chk.isHandled(exc, caught))
324 pendingExits.append(new PendingExit(tree, exc));
325 thrown = chk.incl(exc, thrown);
326 }
327 }
329 /*-------------- Processing variables ----------------------*/
331 /** Do we need to track init/uninit state of this symbol?
332 * I.e. is symbol either a local or a blank final variable?
333 */
334 boolean trackable(VarSymbol sym) {
335 return
336 (sym.owner.kind == MTH ||
337 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
338 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
339 }
341 /** Initialize new trackable variable by setting its address field
342 * to the next available sequence number and entering it under that
343 * index into the vars array.
344 */
345 void newVar(VarSymbol sym) {
346 if (nextadr == vars.length) {
347 VarSymbol[] newvars = new VarSymbol[nextadr * 2];
348 System.arraycopy(vars, 0, newvars, 0, nextadr);
349 vars = newvars;
350 }
351 sym.adr = nextadr;
352 vars[nextadr] = sym;
353 inits.excl(nextadr);
354 uninits.incl(nextadr);
355 nextadr++;
356 }
358 /** Record an initialization of a trackable variable.
359 */
360 void letInit(DiagnosticPosition pos, VarSymbol sym) {
361 if (sym.adr >= firstadr && trackable(sym)) {
362 if ((sym.flags() & FINAL) != 0) {
363 if ((sym.flags() & PARAMETER) != 0) {
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",
370 sym);
371 }
372 } else if (!uninits.isMember(sym.adr)) {
373 log.error(pos,
374 loopPassTwo
375 ? "var.might.be.assigned.in.loop"
376 : "var.might.already.be.assigned",
377 sym);
378 } else if (!inits.isMember(sym.adr)) {
379 // reachable assignment
380 uninits.excl(sym.adr);
381 uninitsTry.excl(sym.adr);
382 } else {
383 //log.rawWarning(pos, "unreachable assignment");//DEBUG
384 uninits.excl(sym.adr);
385 }
386 }
387 inits.incl(sym.adr);
388 } else if ((sym.flags() & FINAL) != 0) {
389 log.error(pos, "var.might.already.be.assigned", sym);
390 }
391 }
393 /** If tree is either a simple name or of the form this.name or
394 * C.this.name, and tree represents a trackable variable,
395 * record an initialization of the variable.
396 */
397 void letInit(JCTree tree) {
398 tree = TreeInfo.skipParens(tree);
399 if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
400 Symbol sym = TreeInfo.symbol(tree);
401 letInit(tree.pos(), (VarSymbol)sym);
402 }
403 }
405 /** Check that trackable variable is initialized.
406 */
407 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
408 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
409 trackable(sym) &&
410 !inits.isMember(sym.adr)) {
411 log.error(pos, "var.might.not.have.been.initialized",
412 sym);
413 inits.incl(sym.adr);
414 }
415 }
417 /*-------------------- Handling jumps ----------------------*/
419 /** Record an outward transfer of control. */
420 void recordExit(JCTree tree) {
421 pendingExits.append(new PendingExit(tree, inits, uninits));
422 markDead();
423 }
425 /** Resolve all breaks of this statement. */
426 boolean resolveBreaks(JCTree tree,
427 ListBuffer<PendingExit> oldPendingExits) {
428 boolean result = false;
429 List<PendingExit> exits = pendingExits.toList();
430 pendingExits = oldPendingExits;
431 for (; exits.nonEmpty(); exits = exits.tail) {
432 PendingExit exit = exits.head;
433 if (exit.tree.getTag() == JCTree.BREAK &&
434 ((JCBreak) exit.tree).target == tree) {
435 inits.andSet(exit.inits);
436 uninits.andSet(exit.uninits);
437 result = true;
438 } else {
439 pendingExits.append(exit);
440 }
441 }
442 return result;
443 }
445 /** Resolve all continues of this statement. */
446 boolean resolveContinues(JCTree tree) {
447 boolean result = false;
448 List<PendingExit> exits = pendingExits.toList();
449 pendingExits = new ListBuffer<PendingExit>();
450 for (; exits.nonEmpty(); exits = exits.tail) {
451 PendingExit exit = exits.head;
452 if (exit.tree.getTag() == JCTree.CONTINUE &&
453 ((JCContinue) exit.tree).target == tree) {
454 inits.andSet(exit.inits);
455 uninits.andSet(exit.uninits);
456 result = true;
457 } else {
458 pendingExits.append(exit);
459 }
460 }
461 return result;
462 }
464 /** Record that statement is unreachable.
465 */
466 void markDead() {
467 inits.inclRange(firstadr, nextadr);
468 uninits.inclRange(firstadr, nextadr);
469 alive = false;
470 }
472 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
473 */
474 void split() {
475 initsWhenFalse = inits.dup();
476 uninitsWhenFalse = uninits.dup();
477 initsWhenTrue = inits;
478 uninitsWhenTrue = uninits;
479 inits = uninits = null;
480 }
482 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
483 */
484 void merge() {
485 inits = initsWhenFalse.andSet(initsWhenTrue);
486 uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
487 }
489 /* ************************************************************************
490 * Visitor methods for statements and definitions
491 *************************************************************************/
493 /** Analyze a definition.
494 */
495 void scanDef(JCTree tree) {
496 scanStat(tree);
497 if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) {
498 log.error(tree.pos(),
499 "initializer.must.be.able.to.complete.normally");
500 }
501 }
503 /** Analyze a statement. Check that statement is reachable.
504 */
505 void scanStat(JCTree tree) {
506 if (!alive && tree != null) {
507 log.error(tree.pos(), "unreachable.stmt");
508 if (tree.getTag() != JCTree.SKIP) alive = true;
509 }
510 scan(tree);
511 }
513 /** Analyze list of statements.
514 */
515 void scanStats(List<? extends JCStatement> trees) {
516 if (trees != null)
517 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
518 scanStat(l.head);
519 }
521 /** Analyze an expression. Make sure to set (un)inits rather than
522 * (un)initsWhenTrue(WhenFalse) on exit.
523 */
524 void scanExpr(JCTree tree) {
525 if (tree != null) {
526 scan(tree);
527 if (inits == null) merge();
528 }
529 }
531 /** Analyze a list of expressions.
532 */
533 void scanExprs(List<? extends JCExpression> trees) {
534 if (trees != null)
535 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
536 scanExpr(l.head);
537 }
539 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
540 * rather than (un)inits on exit.
541 */
542 void scanCond(JCTree tree) {
543 if (tree.type.isFalse()) {
544 if (inits == null) merge();
545 initsWhenTrue = inits.dup();
546 initsWhenTrue.inclRange(firstadr, nextadr);
547 uninitsWhenTrue = uninits.dup();
548 uninitsWhenTrue.inclRange(firstadr, nextadr);
549 initsWhenFalse = inits;
550 uninitsWhenFalse = uninits;
551 } else if (tree.type.isTrue()) {
552 if (inits == null) merge();
553 initsWhenFalse = inits.dup();
554 initsWhenFalse.inclRange(firstadr, nextadr);
555 uninitsWhenFalse = uninits.dup();
556 uninitsWhenFalse.inclRange(firstadr, nextadr);
557 initsWhenTrue = inits;
558 uninitsWhenTrue = uninits;
559 } else {
560 scan(tree);
561 if (inits != null) split();
562 }
563 inits = uninits = null;
564 }
566 /* ------------ Visitor methods for various sorts of trees -------------*/
568 public void visitClassDef(JCClassDecl tree) {
569 if (tree.sym == null) return;
571 JCClassDecl classDefPrev = classDef;
572 List<Type> thrownPrev = thrown;
573 List<Type> caughtPrev = caught;
574 boolean alivePrev = alive;
575 int firstadrPrev = firstadr;
576 int nextadrPrev = nextadr;
577 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
578 Lint lintPrev = lint;
580 pendingExits = new ListBuffer<PendingExit>();
581 if (tree.name != names.empty) {
582 caught = List.nil();
583 firstadr = nextadr;
584 }
585 classDef = tree;
586 thrown = List.nil();
587 lint = lint.augment(tree.sym.attributes_field);
589 try {
590 // define all the static fields
591 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
592 if (l.head.getTag() == JCTree.VARDEF) {
593 JCVariableDecl def = (JCVariableDecl)l.head;
594 if ((def.mods.flags & STATIC) != 0) {
595 VarSymbol sym = def.sym;
596 if (trackable(sym))
597 newVar(sym);
598 }
599 }
600 }
602 // process all the static initializers
603 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
604 if (l.head.getTag() != JCTree.METHODDEF &&
605 (TreeInfo.flags(l.head) & STATIC) != 0) {
606 scanDef(l.head);
607 errorUncaught();
608 }
609 }
611 // add intersection of all thrown clauses of initial constructors
612 // to set of caught exceptions, unless class is anonymous.
613 if (tree.name != names.empty) {
614 boolean firstConstructor = true;
615 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
616 if (TreeInfo.isInitialConstructor(l.head)) {
617 List<Type> mthrown =
618 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
619 if (firstConstructor) {
620 caught = mthrown;
621 firstConstructor = false;
622 } else {
623 caught = chk.intersect(mthrown, caught);
624 }
625 }
626 }
627 }
629 // define all the instance fields
630 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
631 if (l.head.getTag() == JCTree.VARDEF) {
632 JCVariableDecl def = (JCVariableDecl)l.head;
633 if ((def.mods.flags & STATIC) == 0) {
634 VarSymbol sym = def.sym;
635 if (trackable(sym))
636 newVar(sym);
637 }
638 }
639 }
641 // process all the instance initializers
642 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
643 if (l.head.getTag() != JCTree.METHODDEF &&
644 (TreeInfo.flags(l.head) & STATIC) == 0) {
645 scanDef(l.head);
646 errorUncaught();
647 }
648 }
650 // in an anonymous class, add the set of thrown exceptions to
651 // the throws clause of the synthetic constructor and propagate
652 // outwards.
653 if (tree.name == names.empty) {
654 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
655 if (TreeInfo.isInitialConstructor(l.head)) {
656 JCMethodDecl mdef = (JCMethodDecl)l.head;
657 mdef.thrown = make.Types(thrown);
658 mdef.sym.type.setThrown(thrown);
659 }
660 }
661 thrownPrev = chk.union(thrown, thrownPrev);
662 }
664 // process all the methods
665 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
666 if (l.head.getTag() == JCTree.METHODDEF) {
667 scan(l.head);
668 errorUncaught();
669 }
670 }
672 thrown = thrownPrev;
673 } finally {
674 pendingExits = pendingExitsPrev;
675 alive = alivePrev;
676 nextadr = nextadrPrev;
677 firstadr = firstadrPrev;
678 caught = caughtPrev;
679 classDef = classDefPrev;
680 lint = lintPrev;
681 }
682 }
684 public void visitMethodDef(JCMethodDecl tree) {
685 if (tree.body == null) return;
687 List<Type> caughtPrev = caught;
688 List<Type> mthrown = tree.sym.type.getThrownTypes();
689 Bits initsPrev = inits.dup();
690 Bits uninitsPrev = uninits.dup();
691 int nextadrPrev = nextadr;
692 int firstadrPrev = firstadr;
693 Lint lintPrev = lint;
695 lint = lint.augment(tree.sym.attributes_field);
697 assert pendingExits.isEmpty();
699 try {
700 boolean isInitialConstructor =
701 TreeInfo.isInitialConstructor(tree);
703 if (!isInitialConstructor)
704 firstadr = nextadr;
705 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
706 JCVariableDecl def = l.head;
707 scan(def);
708 inits.incl(def.sym.adr);
709 uninits.excl(def.sym.adr);
710 }
711 if (isInitialConstructor)
712 caught = chk.union(caught, mthrown);
713 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
714 caught = mthrown;
715 // else we are in an instance initializer block;
716 // leave caught unchanged.
718 alive = true;
719 scanStat(tree.body);
721 if (alive && tree.sym.type.getReturnType().tag != VOID)
722 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
724 if (isInitialConstructor) {
725 for (int i = firstadr; i < nextadr; i++)
726 if (vars[i].owner == classDef.sym)
727 checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
728 }
729 List<PendingExit> exits = pendingExits.toList();
730 pendingExits = new ListBuffer<PendingExit>();
731 while (exits.nonEmpty()) {
732 PendingExit exit = exits.head;
733 exits = exits.tail;
734 if (exit.thrown == null) {
735 assert exit.tree.getTag() == JCTree.RETURN;
736 if (isInitialConstructor) {
737 inits = exit.inits;
738 for (int i = firstadr; i < nextadr; i++)
739 checkInit(exit.tree.pos(), vars[i]);
740 }
741 } else {
742 // uncaught throws will be reported later
743 pendingExits.append(exit);
744 }
745 }
746 } finally {
747 inits = initsPrev;
748 uninits = uninitsPrev;
749 nextadr = nextadrPrev;
750 firstadr = firstadrPrev;
751 caught = caughtPrev;
752 lint = lintPrev;
753 }
754 }
756 public void visitVarDef(JCVariableDecl tree) {
757 boolean track = trackable(tree.sym);
758 if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
759 if (tree.init != null) {
760 Lint lintPrev = lint;
761 lint = lint.augment(tree.sym.attributes_field);
762 try{
763 scanExpr(tree.init);
764 if (track) letInit(tree.pos(), tree.sym);
765 } finally {
766 lint = lintPrev;
767 }
768 }
769 }
771 public void visitBlock(JCBlock tree) {
772 int nextadrPrev = nextadr;
773 scanStats(tree.stats);
774 nextadr = nextadrPrev;
775 }
777 public void visitDoLoop(JCDoWhileLoop tree) {
778 ListBuffer<PendingExit> prevPendingExits = pendingExits;
779 boolean prevLoopPassTwo = loopPassTwo;
780 pendingExits = new ListBuffer<PendingExit>();
781 do {
782 Bits uninitsEntry = uninits.dup();
783 scanStat(tree.body);
784 alive |= resolveContinues(tree);
785 scanCond(tree.cond);
786 if (log.nerrors != 0 ||
787 loopPassTwo ||
788 uninitsEntry.diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
789 break;
790 inits = initsWhenTrue;
791 uninits = uninitsEntry.andSet(uninitsWhenTrue);
792 loopPassTwo = true;
793 alive = true;
794 } while (true);
795 loopPassTwo = prevLoopPassTwo;
796 inits = initsWhenFalse;
797 uninits = uninitsWhenFalse;
798 alive = alive && !tree.cond.type.isTrue();
799 alive |= resolveBreaks(tree, prevPendingExits);
800 }
802 public void visitWhileLoop(JCWhileLoop tree) {
803 ListBuffer<PendingExit> prevPendingExits = pendingExits;
804 boolean prevLoopPassTwo = loopPassTwo;
805 Bits initsCond;
806 Bits uninitsCond;
807 pendingExits = new ListBuffer<PendingExit>();
808 do {
809 Bits uninitsEntry = uninits.dup();
810 scanCond(tree.cond);
811 initsCond = initsWhenFalse;
812 uninitsCond = uninitsWhenFalse;
813 inits = initsWhenTrue;
814 uninits = uninitsWhenTrue;
815 alive = !tree.cond.type.isFalse();
816 scanStat(tree.body);
817 alive |= resolveContinues(tree);
818 if (log.nerrors != 0 ||
819 loopPassTwo ||
820 uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1)
821 break;
822 uninits = uninitsEntry.andSet(uninits);
823 loopPassTwo = true;
824 alive = true;
825 } while (true);
826 loopPassTwo = prevLoopPassTwo;
827 inits = initsCond;
828 uninits = uninitsCond;
829 alive = resolveBreaks(tree, prevPendingExits) ||
830 !tree.cond.type.isTrue();
831 }
833 public void visitForLoop(JCForLoop tree) {
834 ListBuffer<PendingExit> prevPendingExits = pendingExits;
835 boolean prevLoopPassTwo = loopPassTwo;
836 int nextadrPrev = nextadr;
837 scanStats(tree.init);
838 Bits initsCond;
839 Bits uninitsCond;
840 pendingExits = new ListBuffer<PendingExit>();
841 do {
842 Bits uninitsEntry = uninits.dup();
843 if (tree.cond != null) {
844 scanCond(tree.cond);
845 initsCond = initsWhenFalse;
846 uninitsCond = uninitsWhenFalse;
847 inits = initsWhenTrue;
848 uninits = uninitsWhenTrue;
849 alive = !tree.cond.type.isFalse();
850 } else {
851 initsCond = inits.dup();
852 initsCond.inclRange(firstadr, nextadr);
853 uninitsCond = uninits.dup();
854 uninitsCond.inclRange(firstadr, nextadr);
855 alive = true;
856 }
857 scanStat(tree.body);
858 alive |= resolveContinues(tree);
859 scan(tree.step);
860 if (log.nerrors != 0 ||
861 loopPassTwo ||
862 uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
863 break;
864 uninits = uninitsEntry.andSet(uninits);
865 loopPassTwo = true;
866 alive = true;
867 } while (true);
868 loopPassTwo = prevLoopPassTwo;
869 inits = initsCond;
870 uninits = uninitsCond;
871 alive = resolveBreaks(tree, prevPendingExits) ||
872 tree.cond != null && !tree.cond.type.isTrue();
873 nextadr = nextadrPrev;
874 }
876 public void visitForeachLoop(JCEnhancedForLoop tree) {
877 visitVarDef(tree.var);
879 ListBuffer<PendingExit> prevPendingExits = pendingExits;
880 boolean prevLoopPassTwo = loopPassTwo;
881 int nextadrPrev = nextadr;
882 scan(tree.expr);
883 Bits initsStart = inits.dup();
884 Bits uninitsStart = uninits.dup();
886 letInit(tree.pos(), tree.var.sym);
887 pendingExits = new ListBuffer<PendingExit>();
888 do {
889 Bits uninitsEntry = uninits.dup();
890 scanStat(tree.body);
891 alive |= resolveContinues(tree);
892 if (log.nerrors != 0 ||
893 loopPassTwo ||
894 uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1)
895 break;
896 uninits = uninitsEntry.andSet(uninits);
897 loopPassTwo = true;
898 alive = true;
899 } while (true);
900 loopPassTwo = prevLoopPassTwo;
901 inits = initsStart;
902 uninits = uninitsStart.andSet(uninits);
903 resolveBreaks(tree, prevPendingExits);
904 alive = true;
905 nextadr = nextadrPrev;
906 }
908 public void visitLabelled(JCLabeledStatement tree) {
909 ListBuffer<PendingExit> prevPendingExits = pendingExits;
910 pendingExits = new ListBuffer<PendingExit>();
911 scanStat(tree.body);
912 alive |= resolveBreaks(tree, prevPendingExits);
913 }
915 public void visitSwitch(JCSwitch tree) {
916 ListBuffer<PendingExit> prevPendingExits = pendingExits;
917 pendingExits = new ListBuffer<PendingExit>();
918 int nextadrPrev = nextadr;
919 scanExpr(tree.selector);
920 Bits initsSwitch = inits;
921 Bits uninitsSwitch = uninits.dup();
922 boolean hasDefault = false;
923 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
924 alive = true;
925 inits = initsSwitch.dup();
926 uninits = uninits.andSet(uninitsSwitch);
927 JCCase c = l.head;
928 if (c.pat == null)
929 hasDefault = true;
930 else
931 scanExpr(c.pat);
932 scanStats(c.stats);
933 addVars(c.stats, initsSwitch, uninitsSwitch);
934 // Warn about fall-through if lint switch fallthrough enabled.
935 if (!loopPassTwo &&
936 alive &&
937 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
938 c.stats.nonEmpty() && l.tail.nonEmpty())
939 log.warning(l.tail.head.pos(),
940 "possible.fall-through.into.case");
941 }
942 if (!hasDefault) {
943 inits.andSet(initsSwitch);
944 alive = true;
945 }
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 }
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;
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 &&
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 }
1016 inits = initsTry.dup();
1017 uninits = uninitsTry.dup();
1018 scan(param);
1019 inits.incl(param.sym.adr);
1020 uninits.excl(param.sym.adr);
1021 multicatchTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
1022 scanStat(l.head.body);
1023 initsEnd.andSet(inits);
1024 uninitsEnd.andSet(uninits);
1025 nextadr = nextadrCatch;
1026 multicatchTypes.remove(param.sym);
1027 aliveEnd |= alive;
1028 }
1029 if (tree.finalizer != null) {
1030 List<Type> savedThrown = thrown;
1031 thrown = List.nil();
1032 inits = initsTry.dup();
1033 uninits = uninitsTry.dup();
1034 ListBuffer<PendingExit> exits = pendingExits;
1035 pendingExits = prevPendingExits;
1036 alive = true;
1037 scanStat(tree.finalizer);
1038 if (!alive) {
1039 // discard exits and exceptions from try and finally
1040 thrown = chk.union(thrown, thrownPrev);
1041 if (!loopPassTwo &&
1042 lint.isEnabled(Lint.LintCategory.FINALLY)) {
1043 log.warning(TreeInfo.diagEndPos(tree.finalizer),
1044 "finally.cannot.complete");
1045 }
1046 } else {
1047 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1048 thrown = chk.union(thrown, savedThrown);
1049 uninits.andSet(uninitsEnd);
1050 // FIX: this doesn't preserve source order of exits in catch
1051 // versus finally!
1052 while (exits.nonEmpty()) {
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 }
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;
1093 uninits = uninitsBeforeElse;
1094 scanCond(tree.falsepart);
1095 initsWhenTrue.andSet(initsAfterThenWhenTrue);
1096 initsWhenFalse.andSet(initsAfterThenWhenFalse);
1097 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
1098 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
1099 } else {
1100 scanExpr(tree.truepart);
1101 Bits initsAfterThen = inits.dup();
1102 Bits uninitsAfterThen = uninits.dup();
1103 inits = initsBeforeElse;
1104 uninits = uninitsBeforeElse;
1105 scanExpr(tree.falsepart);
1106 inits.andSet(initsAfterThen);
1107 uninits.andSet(uninitsAfterThen);
1108 }
1109 }
1111 public void visitIf(JCIf tree) {
1112 scanCond(tree.cond);
1113 Bits initsBeforeElse = initsWhenFalse;
1114 Bits uninitsBeforeElse = uninitsWhenFalse;
1115 inits = initsWhenTrue;
1116 uninits = uninitsWhenTrue;
1117 scanStat(tree.thenpart);
1118 if (tree.elsepart != null) {
1119 boolean aliveAfterThen = alive;
1120 alive = true;
1121 Bits initsAfterThen = inits.dup();
1122 Bits uninitsAfterThen = uninits.dup();
1123 inits = initsBeforeElse;
1124 uninits = uninitsBeforeElse;
1125 scanStat(tree.elsepart);
1126 inits.andSet(initsAfterThen);
1127 uninits.andSet(uninitsAfterThen);
1128 alive = alive | aliveAfterThen;
1129 } else {
1130 inits.andSet(initsBeforeElse);
1131 uninits.andSet(uninitsBeforeElse);
1132 alive = true;
1133 }
1134 }
1138 public void visitBreak(JCBreak tree) {
1139 recordExit(tree);
1140 }
1142 public void visitContinue(JCContinue tree) {
1143 recordExit(tree);
1144 }
1146 public void visitReturn(JCReturn tree) {
1147 scanExpr(tree.expr);
1148 // if not initial constructor, should markDead instead of recordExit
1149 recordExit(tree);
1150 }
1152 public void visitThrow(JCThrow tree) {
1153 scanExpr(tree.expr);
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 }
1167 markDead();
1168 }
1170 public void visitApply(JCMethodInvocation tree) {
1171 scanExpr(tree.meth);
1172 scanExprs(tree.args);
1173 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1174 markThrown(tree, l.head);
1175 }
1177 public void visitNewClass(JCNewClass tree) {
1178 scanExpr(tree.encl);
1179 scanExprs(tree.args);
1180 // scan(tree.def);
1181 for (List<Type> l = tree.constructorType.getThrownTypes();
1182 l.nonEmpty();
1183 l = l.tail) {
1184 markThrown(tree, l.head);
1185 }
1186 List<Type> caughtPrev = caught;
1187 try {
1188 // If the new class expression defines an anonymous class,
1189 // analysis of the anonymous constructor may encounter thrown
1190 // types which are unsubstituted type variables.
1191 // However, since the constructor's actual thrown types have
1192 // already been marked as thrown, it is safe to simply include
1193 // each of the constructor's formal thrown types in the set of
1194 // 'caught/declared to be thrown' types, for the duration of
1195 // the class def analysis.
1196 if (tree.def != null)
1197 for (List<Type> l = tree.constructor.type.getThrownTypes();
1198 l.nonEmpty();
1199 l = l.tail) {
1200 caught = chk.incl(l.head, caught);
1201 }
1202 scan(tree.def);
1203 }
1204 finally {
1205 caught = caughtPrev;
1206 }
1207 }
1209 public void visitNewArray(JCNewArray tree) {
1210 scanExprs(tree.dims);
1211 scanExprs(tree.elems);
1212 }
1214 public void visitAssert(JCAssert tree) {
1215 Bits initsExit = inits.dup();
1216 Bits uninitsExit = uninits.dup();
1217 scanCond(tree.cond);
1218 uninitsExit.andSet(uninitsWhenTrue);
1219 if (tree.detail != null) {
1220 inits = initsWhenFalse;
1221 uninits = uninitsWhenFalse;
1222 scanExpr(tree.detail);
1223 }
1224 inits = initsExit;
1225 uninits = uninitsExit;
1226 }
1228 public void visitAssign(JCAssign tree) {
1229 JCTree lhs = TreeInfo.skipParens(tree.lhs);
1230 if (!(lhs instanceof JCIdent)) scanExpr(lhs);
1231 scanExpr(tree.rhs);
1232 letInit(lhs);
1233 }
1235 public void visitAssignop(JCAssignOp tree) {
1236 scanExpr(tree.lhs);
1237 scanExpr(tree.rhs);
1238 letInit(tree.lhs);
1239 }
1241 public void visitUnary(JCUnary tree) {
1242 switch (tree.getTag()) {
1243 case JCTree.NOT:
1244 scanCond(tree.arg);
1245 Bits t = initsWhenFalse;
1246 initsWhenFalse = initsWhenTrue;
1247 initsWhenTrue = t;
1248 t = uninitsWhenFalse;
1249 uninitsWhenFalse = uninitsWhenTrue;
1250 uninitsWhenTrue = t;
1251 break;
1252 case JCTree.PREINC: case JCTree.POSTINC:
1253 case JCTree.PREDEC: case JCTree.POSTDEC:
1254 scanExpr(tree.arg);
1255 letInit(tree.arg);
1256 break;
1257 default:
1258 scanExpr(tree.arg);
1259 }
1260 }
1262 public void visitBinary(JCBinary tree) {
1263 switch (tree.getTag()) {
1264 case JCTree.AND:
1265 scanCond(tree.lhs);
1266 Bits initsWhenFalseLeft = initsWhenFalse;
1267 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
1268 inits = initsWhenTrue;
1269 uninits = uninitsWhenTrue;
1270 scanCond(tree.rhs);
1271 initsWhenFalse.andSet(initsWhenFalseLeft);
1272 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
1273 break;
1274 case JCTree.OR:
1275 scanCond(tree.lhs);
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 }
1290 public void visitAnnotatedType(JCAnnotatedType tree) {
1291 // annotations don't get scanned
1292 tree.underlyingType.accept(this);
1293 }
1295 public void visitIdent(JCIdent tree) {
1296 if (tree.sym.kind == VAR)
1297 checkInit(tree.pos(), (VarSymbol)tree.sym);
1298 }
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 }
1310 public void visitTopLevel(JCCompilationUnit tree) {
1311 // Do nothing for TopLevel since each class is visited individually
1312 }
1314 /**************************************************************************
1315 * utility methods for ignoring type-annotated casts lint checking
1316 *************************************************************************/
1317 private static final boolean ignoreAnnotatedCasts = true;
1318 private static class AnnotationFinder extends TreeScanner {
1319 public boolean foundTypeAnno = false;
1320 public void visitAnnotation(JCAnnotation tree) {
1321 foundTypeAnno = foundTypeAnno || (tree instanceof JCTypeAnnotation);
1322 }
1323 }
1325 private boolean containsTypeAnnotation(JCTree e) {
1326 AnnotationFinder finder = new AnnotationFinder();
1327 finder.scan(e);
1328 return finder.foundTypeAnno;
1329 }
1331 /**************************************************************************
1332 * main method
1333 *************************************************************************/
1335 /** Perform definite assignment/unassignment analysis on a tree.
1336 */
1337 public void analyzeTree(JCTree tree, TreeMaker make) {
1338 try {
1339 this.make = make;
1340 inits = new Bits();
1341 uninits = new Bits();
1342 uninitsTry = new Bits();
1343 initsWhenTrue = initsWhenFalse =
1344 uninitsWhenTrue = uninitsWhenFalse = null;
1345 if (vars == null)
1346 vars = new VarSymbol[32];
1347 else
1348 for (int i=0; i<vars.length; i++)
1349 vars[i] = null;
1350 firstadr = 0;
1351 nextadr = 0;
1352 pendingExits = new ListBuffer<PendingExit>();
1353 multicatchTypes = new HashMap<Symbol, List<Type>>();
1354 alive = true;
1355 this.thrown = this.caught = null;
1356 this.classDef = null;
1357 scan(tree);
1358 } finally {
1359 // note that recursive invocations of this method fail hard
1360 inits = uninits = uninitsTry = null;
1361 initsWhenTrue = initsWhenFalse =
1362 uninitsWhenTrue = uninitsWhenFalse = null;
1363 if (vars != null) for (int i=0; i<vars.length; i++)
1364 vars[i] = null;
1365 firstadr = 0;
1366 nextadr = 0;
1367 pendingExits = null;
1368 this.make = null;
1369 this.thrown = this.caught = null;
1370 this.classDef = null;
1371 }
1372 }
1373 }