0001: /*
0002: * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: //todo: one might eliminate uninits.andSets when monotonic
0027: package com.sun.tools.javac.comp;
0028:
0029: import com.sun.tools.javac.code.*;
0030: import com.sun.tools.javac.tree.*;
0031: import com.sun.tools.javac.util.*;
0032: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
0033:
0034: import com.sun.tools.javac.code.Symbol.*;
0035: import com.sun.tools.javac.tree.JCTree.*;
0036:
0037: import static com.sun.tools.javac.code.Flags.*;
0038: import static com.sun.tools.javac.code.Kinds.*;
0039: import static com.sun.tools.javac.code.TypeTags.*;
0040:
0041: /** This pass implements dataflow analysis for Java programs.
0042: * Liveness analysis checks that every statement is reachable.
0043: * Exception analysis ensures that every checked exception that is
0044: * thrown is declared or caught. Definite assignment analysis
0045: * ensures that each variable is assigned when used. Definite
0046: * unassignment analysis ensures that no final variable is assigned
0047: * more than once.
0048: *
0049: * <p>The second edition of the JLS has a number of problems in the
0050: * specification of these flow analysis problems. This implementation
0051: * attempts to address those issues.
0052: *
0053: * <p>First, there is no accommodation for a finally clause that cannot
0054: * complete normally. For liveness analysis, an intervening finally
0055: * clause can cause a break, continue, or return not to reach its
0056: * target. For exception analysis, an intervening finally clause can
0057: * cause any exception to be "caught". For DA/DU analysis, the finally
0058: * clause can prevent a transfer of control from propagating DA/DU
0059: * state to the target. In addition, code in the finally clause can
0060: * affect the DA/DU status of variables.
0061: *
0062: * <p>For try statements, we introduce the idea of a variable being
0063: * definitely unassigned "everywhere" in a block. A variable V is
0064: * "unassigned everywhere" in a block iff it is unassigned at the
0065: * beginning of the block and there is no reachable assignment to V
0066: * in the block. An assignment V=e is reachable iff V is not DA
0067: * after e. Then we can say that V is DU at the beginning of the
0068: * catch block iff V is DU everywhere in the try block. Similarly, V
0069: * is DU at the beginning of the finally block iff V is DU everywhere
0070: * in the try block and in every catch block. Specifically, the
0071: * following bullet is added to 16.2.2
0072: * <pre>
0073: * V is <em>unassigned everywhere</em> in a block if it is
0074: * unassigned before the block and there is no reachable
0075: * assignment to V within the block.
0076: * </pre>
0077: * <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
0078: * try blocks is changed to
0079: * <pre>
0080: * V is definitely unassigned before a catch block iff V is
0081: * definitely unassigned everywhere in the try block.
0082: * </pre>
0083: * <p>The last bullet (and all of its sub-bullets) for try blocks that
0084: * have a finally block is changed to
0085: * <pre>
0086: * V is definitely unassigned before the finally block iff
0087: * V is definitely unassigned everywhere in the try block
0088: * and everywhere in each catch block of the try statement.
0089: * </pre>
0090: * <p>In addition,
0091: * <pre>
0092: * V is definitely assigned at the end of a constructor iff
0093: * V is definitely assigned after the block that is the body
0094: * of the constructor and V is definitely assigned at every
0095: * return that can return from the constructor.
0096: * </pre>
0097: * <p>In addition, each continue statement with the loop as its target
0098: * is treated as a jump to the end of the loop body, and "intervening"
0099: * finally clauses are treated as follows: V is DA "due to the
0100: * continue" iff V is DA before the continue statement or V is DA at
0101: * the end of any intervening finally block. V is DU "due to the
0102: * continue" iff any intervening finally cannot complete normally or V
0103: * is DU at the end of every intervening finally block. This "due to
0104: * the continue" concept is then used in the spec for the loops.
0105: *
0106: * <p>Similarly, break statements must consider intervening finally
0107: * blocks. For liveness analysis, a break statement for which any
0108: * intervening finally cannot complete normally is not considered to
0109: * cause the target statement to be able to complete normally. Then
0110: * we say V is DA "due to the break" iff V is DA before the break or
0111: * V is DA at the end of any intervening finally block. V is DU "due
0112: * to the break" iff any intervening finally cannot complete normally
0113: * or V is DU at the break and at the end of every intervening
0114: * finally block. (I suspect this latter condition can be
0115: * simplified.) This "due to the break" is then used in the spec for
0116: * all statements that can be "broken".
0117: *
0118: * <p>The return statement is treated similarly. V is DA "due to a
0119: * return statement" iff V is DA before the return statement or V is
0120: * DA at the end of any intervening finally block. Note that we
0121: * don't have to worry about the return expression because this
0122: * concept is only used for construcrors.
0123: *
0124: * <p>There is no spec in JLS2 for when a variable is definitely
0125: * assigned at the end of a constructor, which is needed for final
0126: * fields (8.3.1.2). We implement the rule that V is DA at the end
0127: * of the constructor iff it is DA and the end of the body of the
0128: * constructor and V is DA "due to" every return of the constructor.
0129: *
0130: * <p>Intervening finally blocks similarly affect exception analysis. An
0131: * intervening finally that cannot complete normally allows us to ignore
0132: * an otherwise uncaught exception.
0133: *
0134: * <p>To implement the semantics of intervening finally clauses, all
0135: * nonlocal transfers (break, continue, return, throw, method call that
0136: * can throw a checked exception, and a constructor invocation that can
0137: * thrown a checked exception) are recorded in a queue, and removed
0138: * from the queue when we complete processing the target of the
0139: * nonlocal transfer. This allows us to modify the queue in accordance
0140: * with the above rules when we encounter a finally clause. The only
0141: * exception to this [no pun intended] is that checked exceptions that
0142: * are known to be caught or declared to be caught in the enclosing
0143: * method are not recorded in the queue, but instead are recorded in a
0144: * global variable "Set<Type> thrown" that records the type of all
0145: * exceptions that can be thrown.
0146: *
0147: * <p>Other minor issues the treatment of members of other classes
0148: * (always considered DA except that within an anonymous class
0149: * constructor, where DA status from the enclosing scope is
0150: * preserved), treatment of the case expression (V is DA before the
0151: * case expression iff V is DA after the switch expression),
0152: * treatment of variables declared in a switch block (the implied
0153: * DA/DU status after the switch expression is DU and not DA for
0154: * variables defined in a switch block), the treatment of boolean ?:
0155: * expressions (The JLS rules only handle b and c non-boolean; the
0156: * new rule is that if b and c are boolean valued, then V is
0157: * (un)assigned after a?b:c when true/false iff V is (un)assigned
0158: * after b when true/false and V is (un)assigned after c when
0159: * true/false).
0160: *
0161: * <p>There is the remaining question of what syntactic forms constitute a
0162: * reference to a variable. It is conventional to allow this.x on the
0163: * left-hand-side to initialize a final instance field named x, yet
0164: * this.x isn't considered a "use" when appearing on a right-hand-side
0165: * in most implementations. Should parentheses affect what is
0166: * considered a variable reference? The simplest rule would be to
0167: * allow unqualified forms only, parentheses optional, and phase out
0168: * support for assigning to a final field via this.x.
0169: *
0170: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
0171: * you write code that depends on this, you do so at your own risk.
0172: * This code and its internal interfaces are subject to change or
0173: * deletion without notice.</b>
0174: */
0175: @Version("@(#)Flow.java 1.96 07/06/14")
0176: public class Flow extends TreeScanner {
0177: protected static final Context.Key<Flow> flowKey = new Context.Key<Flow>();
0178:
0179: private final Name.Table names;
0180: private final Log log;
0181: private final Symtab syms;
0182: private final Types types;
0183: private final Check chk;
0184: private TreeMaker make;
0185: private Lint lint;
0186:
0187: public static Flow instance(Context context) {
0188: Flow instance = context.get(flowKey);
0189: if (instance == null)
0190: instance = new Flow(context);
0191: return instance;
0192: }
0193:
0194: protected Flow(Context context) {
0195: context.put(flowKey, this );
0196:
0197: names = Name.Table.instance(context);
0198: log = Log.instance(context);
0199: syms = Symtab.instance(context);
0200: types = Types.instance(context);
0201: chk = Check.instance(context);
0202: lint = Lint.instance(context);
0203: }
0204:
0205: /** A flag that indicates whether the last statement could
0206: * complete normally.
0207: */
0208: private boolean alive;
0209:
0210: /** The set of definitely assigned variables.
0211: */
0212: Bits inits;
0213:
0214: /** The set of definitely unassigned variables.
0215: */
0216: Bits uninits;
0217:
0218: /** The set of variables that are definitely unassigned everywhere
0219: * in current try block. This variable is maintained lazily; it is
0220: * updated only when something gets removed from uninits,
0221: * typically by being assigned in reachable code. To obtain the
0222: * correct set of variables which are definitely unassigned
0223: * anywhere in current try block, intersect uninitsTry and
0224: * uninits.
0225: */
0226: Bits uninitsTry;
0227:
0228: /** When analyzing a condition, inits and uninits are null.
0229: * Instead we have:
0230: */
0231: Bits initsWhenTrue;
0232: Bits initsWhenFalse;
0233: Bits uninitsWhenTrue;
0234: Bits uninitsWhenFalse;
0235:
0236: /** A mapping from addresses to variable symbols.
0237: */
0238: VarSymbol[] vars;
0239:
0240: /** The current class being defined.
0241: */
0242: JCClassDecl classDef;
0243:
0244: /** The first variable sequence number in this class definition.
0245: */
0246: int firstadr;
0247:
0248: /** The next available variable sequence number.
0249: */
0250: int nextadr;
0251:
0252: /** The list of possibly thrown declarable exceptions.
0253: */
0254: List<Type> thrown;
0255:
0256: /** The list of exceptions that are either caught or declared to be
0257: * thrown.
0258: */
0259: List<Type> caught;
0260:
0261: /** Set when processing a loop body the second time for DU analysis. */
0262: boolean loopPassTwo = false;
0263:
0264: /*-------------------- Environments ----------------------*/
0265:
0266: /** A pending exit. These are the statements return, break, and
0267: * continue. In addition, exception-throwing expressions or
0268: * statements are put here when not known to be caught. This
0269: * will typically result in an error unless it is within a
0270: * try-finally whose finally block cannot complete normally.
0271: */
0272: static class PendingExit {
0273: JCTree tree;
0274: Bits inits;
0275: Bits uninits;
0276: Type thrown;
0277:
0278: PendingExit(JCTree tree, Bits inits, Bits uninits) {
0279: this .tree = tree;
0280: this .inits = inits.dup();
0281: this .uninits = uninits.dup();
0282: }
0283:
0284: PendingExit(JCTree tree, Type thrown) {
0285: this .tree = tree;
0286: this .thrown = thrown;
0287: }
0288: }
0289:
0290: /** The currently pending exits that go from current inner blocks
0291: * to an enclosing block, in source order.
0292: */
0293: ListBuffer<PendingExit> pendingExits;
0294:
0295: /*-------------------- Exceptions ----------------------*/
0296:
0297: /** Complain that pending exceptions are not caught.
0298: */
0299: void errorUncaught() {
0300: for (PendingExit exit = pendingExits.next(); exit != null; exit = pendingExits
0301: .next()) {
0302: boolean synthetic = classDef != null
0303: && classDef.pos == exit.tree.pos;
0304: log
0305: .error(
0306: exit.tree.pos(),
0307: synthetic ? "unreported.exception.default.constructor"
0308: : "unreported.exception.need.to.catch.or.throw",
0309: exit.thrown);
0310: }
0311: }
0312:
0313: /** Record that exception is potentially thrown and check that it
0314: * is caught.
0315: */
0316: void markThrown(JCTree tree, Type exc) {
0317: if (!chk.isUnchecked(tree.pos(), exc)) {
0318: if (!chk.isHandled(exc, caught))
0319: pendingExits.append(new PendingExit(tree, exc));
0320: thrown = chk.incl(exc, thrown);
0321: }
0322: }
0323:
0324: /*-------------- Processing variables ----------------------*/
0325:
0326: /** Do we need to track init/uninit state of this symbol?
0327: * I.e. is symbol either a local or a blank final variable?
0328: */
0329: boolean trackable(VarSymbol sym) {
0330: return (sym.owner.kind == MTH || ((sym.flags() & (FINAL
0331: | HASINIT | PARAMETER)) == FINAL && classDef.sym
0332: .isEnclosedBy((ClassSymbol) sym.owner)));
0333: }
0334:
0335: /** Initialize new trackable variable by setting its address field
0336: * to the next available sequence number and entering it under that
0337: * index into the vars array.
0338: */
0339: void newVar(VarSymbol sym) {
0340: if (nextadr == vars.length) {
0341: VarSymbol[] newvars = new VarSymbol[nextadr * 2];
0342: System.arraycopy(vars, 0, newvars, 0, nextadr);
0343: vars = newvars;
0344: }
0345: sym.adr = nextadr;
0346: vars[nextadr] = sym;
0347: inits.excl(nextadr);
0348: uninits.incl(nextadr);
0349: nextadr++;
0350: }
0351:
0352: /** Record an initialization of a trackable variable.
0353: */
0354: void letInit(DiagnosticPosition pos, VarSymbol sym) {
0355: if (sym.adr >= firstadr && trackable(sym)) {
0356: if ((sym.flags() & FINAL) != 0) {
0357: if ((sym.flags() & PARAMETER) != 0) {
0358: log.error(pos,
0359: "final.parameter.may.not.be.assigned", sym);
0360: } else if (!uninits.isMember(sym.adr)) {
0361: log
0362: .error(
0363: pos,
0364: loopPassTwo ? "var.might.be.assigned.in.loop"
0365: : "var.might.already.be.assigned",
0366: sym);
0367: } else if (!inits.isMember(sym.adr)) {
0368: // reachable assignment
0369: uninits.excl(sym.adr);
0370: uninitsTry.excl(sym.adr);
0371: } else {
0372: //log.rawWarning(pos, "unreachable assignment");//DEBUG
0373: uninits.excl(sym.adr);
0374: }
0375: }
0376: inits.incl(sym.adr);
0377: } else if ((sym.flags() & FINAL) != 0) {
0378: log.error(pos, "var.might.already.be.assigned", sym);
0379: }
0380: }
0381:
0382: /** If tree is either a simple name or of the form this.name or
0383: * C.this.name, and tree represents a trackable variable,
0384: * record an initialization of the variable.
0385: */
0386: void letInit(JCTree tree) {
0387: tree = TreeInfo.skipParens(tree);
0388: if (tree.getTag() == JCTree.IDENT
0389: || tree.getTag() == JCTree.SELECT) {
0390: Symbol sym = TreeInfo.symbol(tree);
0391: letInit(tree.pos(), (VarSymbol) sym);
0392: }
0393: }
0394:
0395: /** Check that trackable variable is initialized.
0396: */
0397: void checkInit(DiagnosticPosition pos, VarSymbol sym) {
0398: if ((sym.adr >= firstadr || sym.owner.kind != TYP)
0399: && trackable(sym) && !inits.isMember(sym.adr)) {
0400: log.error(pos, "var.might.not.have.been.initialized", sym);
0401: inits.incl(sym.adr);
0402: }
0403: }
0404:
0405: /*-------------------- Handling jumps ----------------------*/
0406:
0407: /** Record an outward transfer of control. */
0408: void recordExit(JCTree tree) {
0409: pendingExits.append(new PendingExit(tree, inits, uninits));
0410: markDead();
0411: }
0412:
0413: /** Resolve all breaks of this statement. */
0414: boolean resolveBreaks(JCTree tree,
0415: ListBuffer<PendingExit> oldPendingExits) {
0416: boolean result = false;
0417: List<PendingExit> exits = pendingExits.toList();
0418: pendingExits = oldPendingExits;
0419: for (; exits.nonEmpty(); exits = exits.tail) {
0420: PendingExit exit = exits.head;
0421: if (exit.tree.getTag() == JCTree.BREAK
0422: && ((JCBreak) exit.tree).target == tree) {
0423: inits.andSet(exit.inits);
0424: uninits.andSet(exit.uninits);
0425: result = true;
0426: } else {
0427: pendingExits.append(exit);
0428: }
0429: }
0430: return result;
0431: }
0432:
0433: /** Resolve all continues of this statement. */
0434: boolean resolveContinues(JCTree tree) {
0435: boolean result = false;
0436: List<PendingExit> exits = pendingExits.toList();
0437: pendingExits = new ListBuffer<PendingExit>();
0438: for (; exits.nonEmpty(); exits = exits.tail) {
0439: PendingExit exit = exits.head;
0440: if (exit.tree.getTag() == JCTree.CONTINUE
0441: && ((JCContinue) exit.tree).target == tree) {
0442: inits.andSet(exit.inits);
0443: uninits.andSet(exit.uninits);
0444: result = true;
0445: } else {
0446: pendingExits.append(exit);
0447: }
0448: }
0449: return result;
0450: }
0451:
0452: /** Record that statement is unreachable.
0453: */
0454: void markDead() {
0455: inits.inclRange(firstadr, nextadr);
0456: uninits.inclRange(firstadr, nextadr);
0457: alive = false;
0458: }
0459:
0460: /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
0461: */
0462: void split() {
0463: initsWhenFalse = inits.dup();
0464: uninitsWhenFalse = uninits.dup();
0465: initsWhenTrue = inits;
0466: uninitsWhenTrue = uninits;
0467: inits = uninits = null;
0468: }
0469:
0470: /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
0471: */
0472: void merge() {
0473: inits = initsWhenFalse.andSet(initsWhenTrue);
0474: uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
0475: }
0476:
0477: /* ************************************************************************
0478: * Visitor methods for statements and definitions
0479: *************************************************************************/
0480:
0481: /** Analyze a definition.
0482: */
0483: void scanDef(JCTree tree) {
0484: scanStat(tree);
0485: if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) {
0486: log.error(tree.pos(),
0487: "initializer.must.be.able.to.complete.normally");
0488: }
0489: }
0490:
0491: /** Analyze a statement. Check that statement is reachable.
0492: */
0493: void scanStat(JCTree tree) {
0494: if (!alive && tree != null) {
0495: log.error(tree.pos(), "unreachable.stmt");
0496: if (tree.getTag() != JCTree.SKIP)
0497: alive = true;
0498: }
0499: scan(tree);
0500: }
0501:
0502: /** Analyze list of statements.
0503: */
0504: void scanStats(List<? extends JCStatement> trees) {
0505: if (trees != null)
0506: for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
0507: scanStat(l.head);
0508: }
0509:
0510: /** Analyze an expression. Make sure to set (un)inits rather than
0511: * (un)initsWhenTrue(WhenFalse) on exit.
0512: */
0513: void scanExpr(JCTree tree) {
0514: if (tree != null) {
0515: scan(tree);
0516: if (inits == null)
0517: merge();
0518: }
0519: }
0520:
0521: /** Analyze a list of expressions.
0522: */
0523: void scanExprs(List<? extends JCExpression> trees) {
0524: if (trees != null)
0525: for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
0526: scanExpr(l.head);
0527: }
0528:
0529: /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
0530: * rather than (un)inits on exit.
0531: */
0532: void scanCond(JCTree tree) {
0533: if (tree.type.isFalse()) {
0534: if (inits == null)
0535: merge();
0536: initsWhenTrue = inits.dup();
0537: initsWhenTrue.inclRange(firstadr, nextadr);
0538: uninitsWhenTrue = uninits.dup();
0539: uninitsWhenTrue.inclRange(firstadr, nextadr);
0540: initsWhenFalse = inits;
0541: uninitsWhenFalse = uninits;
0542: } else if (tree.type.isTrue()) {
0543: if (inits == null)
0544: merge();
0545: initsWhenFalse = inits.dup();
0546: initsWhenFalse.inclRange(firstadr, nextadr);
0547: uninitsWhenFalse = uninits.dup();
0548: uninitsWhenFalse.inclRange(firstadr, nextadr);
0549: initsWhenTrue = inits;
0550: uninitsWhenTrue = uninits;
0551: } else {
0552: scan(tree);
0553: if (inits != null)
0554: split();
0555: }
0556: inits = uninits = null;
0557: }
0558:
0559: /* ------------ Visitor methods for various sorts of trees -------------*/
0560:
0561: public void visitClassDef(JCClassDecl tree) {
0562: if (tree.sym == null)
0563: return;
0564:
0565: JCClassDecl classDefPrev = classDef;
0566: List<Type> thrownPrev = thrown;
0567: List<Type> caughtPrev = caught;
0568: boolean alivePrev = alive;
0569: int firstadrPrev = firstadr;
0570: int nextadrPrev = nextadr;
0571: ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
0572: Lint lintPrev = lint;
0573:
0574: pendingExits = new ListBuffer<PendingExit>();
0575: if (tree.name != names.empty) {
0576: caught = List.nil();
0577: firstadr = nextadr;
0578: }
0579: classDef = tree;
0580: thrown = List.nil();
0581: lint = lint.augment(tree.sym.attributes_field);
0582:
0583: try {
0584: // define all the static fields
0585: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0586: if (l.head.getTag() == JCTree.VARDEF) {
0587: JCVariableDecl def = (JCVariableDecl) l.head;
0588: if ((def.mods.flags & STATIC) != 0) {
0589: VarSymbol sym = def.sym;
0590: if (trackable(sym))
0591: newVar(sym);
0592: }
0593: }
0594: }
0595:
0596: // process all the static initializers
0597: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0598: if (l.head.getTag() != JCTree.METHODDEF
0599: && (TreeInfo.flags(l.head) & STATIC) != 0) {
0600: scanDef(l.head);
0601: errorUncaught();
0602: }
0603: }
0604:
0605: // add intersection of all thrown clauses of initial constructors
0606: // to set of caught exceptions, unless class is anonymous.
0607: if (tree.name != names.empty) {
0608: boolean firstConstructor = true;
0609: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0610: if (TreeInfo.isInitialConstructor(l.head)) {
0611: List<Type> mthrown = ((JCMethodDecl) l.head).sym.type
0612: .getThrownTypes();
0613: if (firstConstructor) {
0614: caught = mthrown;
0615: firstConstructor = false;
0616: } else {
0617: caught = chk.intersect(mthrown, caught);
0618: }
0619: }
0620: }
0621: }
0622:
0623: // define all the instance fields
0624: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0625: if (l.head.getTag() == JCTree.VARDEF) {
0626: JCVariableDecl def = (JCVariableDecl) l.head;
0627: if ((def.mods.flags & STATIC) == 0) {
0628: VarSymbol sym = def.sym;
0629: if (trackable(sym))
0630: newVar(sym);
0631: }
0632: }
0633: }
0634:
0635: // process all the instance initializers
0636: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0637: if (l.head.getTag() != JCTree.METHODDEF
0638: && (TreeInfo.flags(l.head) & STATIC) == 0) {
0639: scanDef(l.head);
0640: errorUncaught();
0641: }
0642: }
0643:
0644: // in an anonymous class, add the set of thrown exceptions to
0645: // the throws clause of the synthetic constructor and propagate
0646: // outwards.
0647: if (tree.name == names.empty) {
0648: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0649: if (TreeInfo.isInitialConstructor(l.head)) {
0650: JCMethodDecl mdef = (JCMethodDecl) l.head;
0651: mdef.thrown = make.Types(thrown);
0652: mdef.sym.type.setThrown(thrown);
0653: }
0654: }
0655: thrownPrev = chk.union(thrown, thrownPrev);
0656: }
0657:
0658: // process all the methods
0659: for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
0660: if (l.head.getTag() == JCTree.METHODDEF) {
0661: scan(l.head);
0662: errorUncaught();
0663: }
0664: }
0665:
0666: thrown = thrownPrev;
0667: } finally {
0668: pendingExits = pendingExitsPrev;
0669: alive = alivePrev;
0670: nextadr = nextadrPrev;
0671: firstadr = firstadrPrev;
0672: caught = caughtPrev;
0673: classDef = classDefPrev;
0674: lint = lintPrev;
0675: }
0676: }
0677:
0678: public void visitMethodDef(JCMethodDecl tree) {
0679: if (tree.body == null)
0680: return;
0681:
0682: List<Type> caughtPrev = caught;
0683: List<Type> mthrown = tree.sym.type.getThrownTypes();
0684: Bits initsPrev = inits.dup();
0685: Bits uninitsPrev = uninits.dup();
0686: int nextadrPrev = nextadr;
0687: int firstadrPrev = firstadr;
0688: Lint lintPrev = lint;
0689:
0690: lint = lint.augment(tree.sym.attributes_field);
0691:
0692: assert pendingExits.isEmpty();
0693:
0694: try {
0695: boolean isInitialConstructor = TreeInfo
0696: .isInitialConstructor(tree);
0697:
0698: if (!isInitialConstructor)
0699: firstadr = nextadr;
0700: for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
0701: JCVariableDecl def = l.head;
0702: scan(def);
0703: inits.incl(def.sym.adr);
0704: uninits.excl(def.sym.adr);
0705: }
0706: if (isInitialConstructor)
0707: caught = chk.union(caught, mthrown);
0708: else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
0709: caught = mthrown;
0710: // else we are in an instance initializer block;
0711: // leave caught unchanged.
0712:
0713: alive = true;
0714: scanStat(tree.body);
0715:
0716: if (alive && tree.sym.type.getReturnType().tag != VOID)
0717: log.error(TreeInfo.diagEndPos(tree.body),
0718: "missing.ret.stmt");
0719:
0720: if (isInitialConstructor) {
0721: for (int i = firstadr; i < nextadr; i++)
0722: if (vars[i].owner == classDef.sym)
0723: checkInit(TreeInfo.diagEndPos(tree.body),
0724: vars[i]);
0725: }
0726: List<PendingExit> exits = pendingExits.toList();
0727: pendingExits = new ListBuffer<PendingExit>();
0728: while (exits.nonEmpty()) {
0729: PendingExit exit = exits.head;
0730: exits = exits.tail;
0731: if (exit.thrown == null) {
0732: assert exit.tree.getTag() == JCTree.RETURN;
0733: if (isInitialConstructor) {
0734: inits = exit.inits;
0735: for (int i = firstadr; i < nextadr; i++)
0736: checkInit(exit.tree.pos(), vars[i]);
0737: }
0738: } else {
0739: // uncaught throws will be reported later
0740: pendingExits.append(exit);
0741: }
0742: }
0743: } finally {
0744: inits = initsPrev;
0745: uninits = uninitsPrev;
0746: nextadr = nextadrPrev;
0747: firstadr = firstadrPrev;
0748: caught = caughtPrev;
0749: lint = lintPrev;
0750: }
0751: }
0752:
0753: public void visitVarDef(JCVariableDecl tree) {
0754: boolean track = trackable(tree.sym);
0755: if (track && tree.sym.owner.kind == MTH)
0756: newVar(tree.sym);
0757: if (tree.init != null) {
0758: Lint lintPrev = lint;
0759: lint = lint.augment(tree.sym.attributes_field);
0760: try {
0761: scanExpr(tree.init);
0762: if (track)
0763: letInit(tree.pos(), tree.sym);
0764: } finally {
0765: lint = lintPrev;
0766: }
0767: }
0768: }
0769:
0770: public void visitBlock(JCBlock tree) {
0771: int nextadrPrev = nextadr;
0772: scanStats(tree.stats);
0773: nextadr = nextadrPrev;
0774: }
0775:
0776: public void visitDoLoop(JCDoWhileLoop tree) {
0777: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0778: boolean prevLoopPassTwo = loopPassTwo;
0779: pendingExits = new ListBuffer<PendingExit>();
0780: do {
0781: Bits uninitsEntry = uninits.dup();
0782: scanStat(tree.body);
0783: alive |= resolveContinues(tree);
0784: scanCond(tree.cond);
0785: if (log.nerrors != 0
0786: || loopPassTwo
0787: || uninitsEntry.diffSet(uninitsWhenTrue).nextBit(
0788: firstadr) == -1)
0789: break;
0790: inits = initsWhenTrue;
0791: uninits = uninitsEntry.andSet(uninitsWhenTrue);
0792: loopPassTwo = true;
0793: alive = true;
0794: } while (true);
0795: loopPassTwo = prevLoopPassTwo;
0796: inits = initsWhenFalse;
0797: uninits = uninitsWhenFalse;
0798: alive = alive && !tree.cond.type.isTrue();
0799: alive |= resolveBreaks(tree, prevPendingExits);
0800: }
0801:
0802: public void visitWhileLoop(JCWhileLoop tree) {
0803: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0804: boolean prevLoopPassTwo = loopPassTwo;
0805: Bits initsCond;
0806: Bits uninitsCond;
0807: pendingExits = new ListBuffer<PendingExit>();
0808: do {
0809: Bits uninitsEntry = uninits.dup();
0810: scanCond(tree.cond);
0811: initsCond = initsWhenFalse;
0812: uninitsCond = uninitsWhenFalse;
0813: inits = initsWhenTrue;
0814: uninits = uninitsWhenTrue;
0815: alive = !tree.cond.type.isFalse();
0816: scanStat(tree.body);
0817: alive |= resolveContinues(tree);
0818: if (log.nerrors != 0
0819: || loopPassTwo
0820: || uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1)
0821: break;
0822: uninits = uninitsEntry.andSet(uninits);
0823: loopPassTwo = true;
0824: alive = true;
0825: } while (true);
0826: loopPassTwo = prevLoopPassTwo;
0827: inits = initsCond;
0828: uninits = uninitsCond;
0829: alive = resolveBreaks(tree, prevPendingExits)
0830: || !tree.cond.type.isTrue();
0831: }
0832:
0833: public void visitForLoop(JCForLoop tree) {
0834: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0835: boolean prevLoopPassTwo = loopPassTwo;
0836: int nextadrPrev = nextadr;
0837: scanStats(tree.init);
0838: Bits initsCond;
0839: Bits uninitsCond;
0840: pendingExits = new ListBuffer<PendingExit>();
0841: do {
0842: Bits uninitsEntry = uninits.dup();
0843: if (tree.cond != null) {
0844: scanCond(tree.cond);
0845: initsCond = initsWhenFalse;
0846: uninitsCond = uninitsWhenFalse;
0847: inits = initsWhenTrue;
0848: uninits = uninitsWhenTrue;
0849: alive = !tree.cond.type.isFalse();
0850: } else {
0851: initsCond = inits.dup();
0852: initsCond.inclRange(firstadr, nextadr);
0853: uninitsCond = uninits.dup();
0854: uninitsCond.inclRange(firstadr, nextadr);
0855: alive = true;
0856: }
0857: scanStat(tree.body);
0858: alive |= resolveContinues(tree);
0859: scan(tree.step);
0860: if (log.nerrors != 0
0861: || loopPassTwo
0862: || uninitsEntry.dup().diffSet(uninits).nextBit(
0863: firstadr) == -1)
0864: break;
0865: uninits = uninitsEntry.andSet(uninits);
0866: loopPassTwo = true;
0867: alive = true;
0868: } while (true);
0869: loopPassTwo = prevLoopPassTwo;
0870: inits = initsCond;
0871: uninits = uninitsCond;
0872: alive = resolveBreaks(tree, prevPendingExits)
0873: || tree.cond != null && !tree.cond.type.isTrue();
0874: nextadr = nextadrPrev;
0875: }
0876:
0877: public void visitForeachLoop(JCEnhancedForLoop tree) {
0878: visitVarDef(tree.var);
0879:
0880: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0881: boolean prevLoopPassTwo = loopPassTwo;
0882: int nextadrPrev = nextadr;
0883: scan(tree.expr);
0884: Bits initsStart = inits.dup();
0885: Bits uninitsStart = uninits.dup();
0886:
0887: letInit(tree.pos(), tree.var.sym);
0888: pendingExits = new ListBuffer<PendingExit>();
0889: do {
0890: Bits uninitsEntry = uninits.dup();
0891: scanStat(tree.body);
0892: alive |= resolveContinues(tree);
0893: if (log.nerrors != 0
0894: || loopPassTwo
0895: || uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1)
0896: break;
0897: uninits = uninitsEntry.andSet(uninits);
0898: loopPassTwo = true;
0899: alive = true;
0900: } while (true);
0901: loopPassTwo = prevLoopPassTwo;
0902: inits = initsStart;
0903: uninits = uninitsStart.andSet(uninits);
0904: resolveBreaks(tree, prevPendingExits);
0905: alive = true;
0906: nextadr = nextadrPrev;
0907: }
0908:
0909: public void visitLabelled(JCLabeledStatement tree) {
0910: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0911: pendingExits = new ListBuffer<PendingExit>();
0912: scanStat(tree.body);
0913: alive |= resolveBreaks(tree, prevPendingExits);
0914: }
0915:
0916: public void visitSwitch(JCSwitch tree) {
0917: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0918: pendingExits = new ListBuffer<PendingExit>();
0919: int nextadrPrev = nextadr;
0920: scanExpr(tree.selector);
0921: Bits initsSwitch = inits;
0922: Bits uninitsSwitch = uninits.dup();
0923: boolean hasDefault = false;
0924: for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
0925: alive = true;
0926: inits = initsSwitch.dup();
0927: uninits = uninits.andSet(uninitsSwitch);
0928: JCCase c = l.head;
0929: if (c.pat == null)
0930: hasDefault = true;
0931: else
0932: scanExpr(c.pat);
0933: scanStats(c.stats);
0934: addVars(c.stats, initsSwitch, uninitsSwitch);
0935: // Warn about fall-through if lint switch fallthrough enabled.
0936: if (!loopPassTwo && alive
0937: && lint.isEnabled(Lint.LintCategory.FALLTHROUGH)
0938: && c.stats.nonEmpty() && l.tail.nonEmpty())
0939: log.warning(l.tail.head.pos(),
0940: "possible.fall-through.into.case");
0941: }
0942: if (!hasDefault) {
0943: inits.andSet(initsSwitch);
0944: alive = true;
0945: }
0946: alive |= resolveBreaks(tree, prevPendingExits);
0947: nextadr = nextadrPrev;
0948: }
0949:
0950: // where
0951: /** Add any variables defined in stats to inits and uninits. */
0952: private static void addVars(List<JCStatement> stats, Bits inits,
0953: Bits uninits) {
0954: for (; stats.nonEmpty(); stats = stats.tail) {
0955: JCTree stat = stats.head;
0956: if (stat.getTag() == JCTree.VARDEF) {
0957: int adr = ((JCVariableDecl) stat).sym.adr;
0958: inits.excl(adr);
0959: uninits.incl(adr);
0960: }
0961: }
0962: }
0963:
0964: public void visitTry(JCTry tree) {
0965: List<Type> caughtPrev = caught;
0966: List<Type> thrownPrev = thrown;
0967: thrown = List.nil();
0968: for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail)
0969: caught = chk.incl(l.head.param.type, caught);
0970: Bits uninitsTryPrev = uninitsTry;
0971: ListBuffer<PendingExit> prevPendingExits = pendingExits;
0972: pendingExits = new ListBuffer<PendingExit>();
0973: Bits initsTry = inits.dup();
0974: uninitsTry = uninits.dup();
0975: scanStat(tree.body);
0976: List<Type> thrownInTry = thrown;
0977: thrown = thrownPrev;
0978: caught = caughtPrev;
0979: boolean aliveEnd = alive;
0980: uninitsTry.andSet(uninits);
0981: Bits initsEnd = inits;
0982: Bits uninitsEnd = uninits;
0983: int nextadrCatch = nextadr;
0984:
0985: List<Type> caughtInTry = List.nil();
0986: for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
0987: alive = true;
0988: JCVariableDecl param = l.head.param;
0989: Type exc = param.type;
0990: if (chk.subset(exc, caughtInTry)) {
0991: log.error(l.head.pos(), "except.already.caught", exc);
0992: } else if (!chk.isUnchecked(l.head.pos(), exc)
0993: && exc.tsym != syms.throwableType.tsym
0994: && exc.tsym != syms.exceptionType.tsym
0995: && !chk.intersects(exc, thrownInTry)) {
0996: log.error(l.head.pos(), "except.never.thrown.in.try",
0997: exc);
0998: }
0999: caughtInTry = chk.incl(exc, caughtInTry);
1000: inits = initsTry.dup();
1001: uninits = uninitsTry.dup();
1002: scan(param);
1003: inits.incl(param.sym.adr);
1004: uninits.excl(param.sym.adr);
1005: scanStat(l.head.body);
1006: initsEnd.andSet(inits);
1007: uninitsEnd.andSet(uninits);
1008: nextadr = nextadrCatch;
1009: aliveEnd |= alive;
1010: }
1011: if (tree.finalizer != null) {
1012: List<Type> savedThrown = thrown;
1013: thrown = List.nil();
1014: inits = initsTry.dup();
1015: uninits = uninitsTry.dup();
1016: ListBuffer<PendingExit> exits = pendingExits;
1017: pendingExits = prevPendingExits;
1018: alive = true;
1019: scanStat(tree.finalizer);
1020: if (!alive) {
1021: // discard exits and exceptions from try and finally
1022: thrown = chk.union(thrown, thrownPrev);
1023: if (!loopPassTwo
1024: && lint.isEnabled(Lint.LintCategory.FINALLY)) {
1025: log.warning(TreeInfo.diagEndPos(tree.finalizer),
1026: "finally.cannot.complete");
1027: }
1028: } else {
1029: thrown = chk.union(thrown, chk.diff(thrownInTry,
1030: caughtInTry));
1031: thrown = chk.union(thrown, savedThrown);
1032: uninits.andSet(uninitsEnd);
1033: // FIX: this doesn't preserve source order of exits in catch
1034: // versus finally!
1035: while (exits.nonEmpty()) {
1036: PendingExit exit = exits.next();
1037: if (exit.inits != null) {
1038: exit.inits.orSet(inits);
1039: exit.uninits.andSet(uninits);
1040: }
1041: pendingExits.append(exit);
1042: }
1043: inits.orSet(initsEnd);
1044: alive = aliveEnd;
1045: }
1046: } else {
1047: thrown = chk.union(thrown, chk.diff(thrownInTry,
1048: caughtInTry));
1049: inits = initsEnd;
1050: uninits = uninitsEnd;
1051: alive = aliveEnd;
1052: ListBuffer<PendingExit> exits = pendingExits;
1053: pendingExits = prevPendingExits;
1054: while (exits.nonEmpty())
1055: pendingExits.append(exits.next());
1056: }
1057: uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
1058: }
1059:
1060: public void visitConditional(JCConditional tree) {
1061: scanCond(tree.cond);
1062: Bits initsBeforeElse = initsWhenFalse;
1063: Bits uninitsBeforeElse = uninitsWhenFalse;
1064: inits = initsWhenTrue;
1065: uninits = uninitsWhenTrue;
1066: if (tree.truepart.type.tag == BOOLEAN
1067: && tree.falsepart.type.tag == BOOLEAN) {
1068: // if b and c are boolean valued, then
1069: // v is (un)assigned after a?b:c when true iff
1070: // v is (un)assigned after b when true and
1071: // v is (un)assigned after c when true
1072: scanCond(tree.truepart);
1073: Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
1074: Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
1075: Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
1076: Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
1077: inits = initsBeforeElse;
1078: uninits = uninitsBeforeElse;
1079: scanCond(tree.falsepart);
1080: initsWhenTrue.andSet(initsAfterThenWhenTrue);
1081: initsWhenFalse.andSet(initsAfterThenWhenFalse);
1082: uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
1083: uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
1084: } else {
1085: scanExpr(tree.truepart);
1086: Bits initsAfterThen = inits.dup();
1087: Bits uninitsAfterThen = uninits.dup();
1088: inits = initsBeforeElse;
1089: uninits = uninitsBeforeElse;
1090: scanExpr(tree.falsepart);
1091: inits.andSet(initsAfterThen);
1092: uninits.andSet(uninitsAfterThen);
1093: }
1094: }
1095:
1096: public void visitIf(JCIf tree) {
1097: scanCond(tree.cond);
1098: Bits initsBeforeElse = initsWhenFalse;
1099: Bits uninitsBeforeElse = uninitsWhenFalse;
1100: inits = initsWhenTrue;
1101: uninits = uninitsWhenTrue;
1102: scanStat(tree.thenpart);
1103: if (tree.elsepart != null) {
1104: boolean aliveAfterThen = alive;
1105: alive = true;
1106: Bits initsAfterThen = inits.dup();
1107: Bits uninitsAfterThen = uninits.dup();
1108: inits = initsBeforeElse;
1109: uninits = uninitsBeforeElse;
1110: scanStat(tree.elsepart);
1111: inits.andSet(initsAfterThen);
1112: uninits.andSet(uninitsAfterThen);
1113: alive = alive | aliveAfterThen;
1114: } else {
1115: inits.andSet(initsBeforeElse);
1116: uninits.andSet(uninitsBeforeElse);
1117: alive = true;
1118: }
1119: }
1120:
1121: public void visitBreak(JCBreak tree) {
1122: recordExit(tree);
1123: }
1124:
1125: public void visitContinue(JCContinue tree) {
1126: recordExit(tree);
1127: }
1128:
1129: public void visitReturn(JCReturn tree) {
1130: scanExpr(tree.expr);
1131: // if not initial constructor, should markDead instead of recordExit
1132: recordExit(tree);
1133: }
1134:
1135: public void visitThrow(JCThrow tree) {
1136: scanExpr(tree.expr);
1137: markThrown(tree, tree.expr.type);
1138: markDead();
1139: }
1140:
1141: public void visitApply(JCMethodInvocation tree) {
1142: scanExpr(tree.meth);
1143: scanExprs(tree.args);
1144: for (List<Type> l = tree.meth.type.getThrownTypes(); l
1145: .nonEmpty(); l = l.tail)
1146: markThrown(tree, l.head);
1147: }
1148:
1149: public void visitNewClass(JCNewClass tree) {
1150: scanExpr(tree.encl);
1151: scanExprs(tree.args);
1152: // scan(tree.def);
1153: for (List<Type> l = tree.constructor.type.getThrownTypes(); l
1154: .nonEmpty(); l = l.tail)
1155: markThrown(tree, l.head);
1156: scan(tree.def);
1157: }
1158:
1159: public void visitNewArray(JCNewArray tree) {
1160: scanExprs(tree.dims);
1161: scanExprs(tree.elems);
1162: }
1163:
1164: public void visitAssert(JCAssert tree) {
1165: Bits initsExit = inits.dup();
1166: Bits uninitsExit = uninits.dup();
1167: scanCond(tree.cond);
1168: uninitsExit.andSet(uninitsWhenTrue);
1169: if (tree.detail != null) {
1170: inits = initsWhenFalse;
1171: uninits = uninitsWhenFalse;
1172: scanExpr(tree.detail);
1173: }
1174: inits = initsExit;
1175: uninits = uninitsExit;
1176: }
1177:
1178: public void visitAssign(JCAssign tree) {
1179: JCTree lhs = TreeInfo.skipParens(tree.lhs);
1180: if (!(lhs instanceof JCIdent))
1181: scanExpr(lhs);
1182: scanExpr(tree.rhs);
1183: letInit(lhs);
1184: }
1185:
1186: public void visitAssignop(JCAssignOp tree) {
1187: scanExpr(tree.lhs);
1188: scanExpr(tree.rhs);
1189: letInit(tree.lhs);
1190: }
1191:
1192: public void visitUnary(JCUnary tree) {
1193: switch (tree.getTag()) {
1194: case JCTree.NOT:
1195: scanCond(tree.arg);
1196: Bits t = initsWhenFalse;
1197: initsWhenFalse = initsWhenTrue;
1198: initsWhenTrue = t;
1199: t = uninitsWhenFalse;
1200: uninitsWhenFalse = uninitsWhenTrue;
1201: uninitsWhenTrue = t;
1202: break;
1203: case JCTree.PREINC:
1204: case JCTree.POSTINC:
1205: case JCTree.PREDEC:
1206: case JCTree.POSTDEC:
1207: scanExpr(tree.arg);
1208: letInit(tree.arg);
1209: break;
1210: default:
1211: scanExpr(tree.arg);
1212: }
1213: }
1214:
1215: public void visitBinary(JCBinary tree) {
1216: switch (tree.getTag()) {
1217: case JCTree.AND:
1218: scanCond(tree.lhs);
1219: Bits initsWhenFalseLeft = initsWhenFalse;
1220: Bits uninitsWhenFalseLeft = uninitsWhenFalse;
1221: inits = initsWhenTrue;
1222: uninits = uninitsWhenTrue;
1223: scanCond(tree.rhs);
1224: initsWhenFalse.andSet(initsWhenFalseLeft);
1225: uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
1226: break;
1227: case JCTree.OR:
1228: scanCond(tree.lhs);
1229: Bits initsWhenTrueLeft = initsWhenTrue;
1230: Bits uninitsWhenTrueLeft = uninitsWhenTrue;
1231: inits = initsWhenFalse;
1232: uninits = uninitsWhenFalse;
1233: scanCond(tree.rhs);
1234: initsWhenTrue.andSet(initsWhenTrueLeft);
1235: uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
1236: break;
1237: default:
1238: scanExpr(tree.lhs);
1239: scanExpr(tree.rhs);
1240: }
1241: }
1242:
1243: public void visitIdent(JCIdent tree) {
1244: if (tree.sym.kind == VAR)
1245: checkInit(tree.pos(), (VarSymbol) tree.sym);
1246: }
1247:
1248: public void visitTypeCast(JCTypeCast tree) {
1249: super .visitTypeCast(tree);
1250: if (!tree.type.isErroneous()
1251: && lint.isEnabled(Lint.LintCategory.CAST)
1252: && types.isSameType(tree.expr.type, tree.clazz.type)) {
1253: log.warning(tree.pos(), "redundant.cast", tree.expr.type);
1254: }
1255: }
1256:
1257: public void visitTopLevel(JCCompilationUnit tree) {
1258: // Do nothing for TopLevel since each class is visited individually
1259: }
1260:
1261: /**************************************************************************
1262: * main method
1263: *************************************************************************/
1264:
1265: /** Perform definite assignment/unassignment analysis on a tree.
1266: */
1267: public void analyzeTree(JCTree tree, TreeMaker make) {
1268: try {
1269: this .make = make;
1270: inits = new Bits();
1271: uninits = new Bits();
1272: uninitsTry = new Bits();
1273: initsWhenTrue = initsWhenFalse = uninitsWhenTrue = uninitsWhenFalse = null;
1274: if (vars == null)
1275: vars = new VarSymbol[32];
1276: else
1277: for (int i = 0; i < vars.length; i++)
1278: vars[i] = null;
1279: firstadr = 0;
1280: nextadr = 0;
1281: pendingExits = new ListBuffer<PendingExit>();
1282: alive = true;
1283: this .thrown = this .caught = null;
1284: this .classDef = null;
1285: scan(tree);
1286: } finally {
1287: // note that recursive invocations of this method fail hard
1288: inits = uninits = uninitsTry = null;
1289: initsWhenTrue = initsWhenFalse = uninitsWhenTrue = uninitsWhenFalse = null;
1290: if (vars != null)
1291: for (int i = 0; i < vars.length; i++)
1292: vars[i] = null;
1293: firstadr = 0;
1294: nextadr = 0;
1295: pendingExits = null;
1296: this.make = null;
1297: this.thrown = this.caught = null;
1298: this.classDef = null;
1299: }
1300: }
1301: }
|