Flow.java revision 2723:0b467b70ad82
1139825Simp/* 21541Srgrimes * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 51541Srgrimes * This code is free software; you can redistribute it and/or modify it 61541Srgrimes * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. Oracle designates this 81541Srgrimes * particular file as subject to the "Classpath" exception as provided 91541Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101541Srgrimes * 111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151541Srgrimes * accompanied this code). 161541Srgrimes * 171541Srgrimes * You should have received a copy of the GNU General Public License version 181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201541Srgrimes * 211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221541Srgrimes * or visit www.oracle.com if you need additional information or have any 231541Srgrimes * questions. 241541Srgrimes */ 251541Srgrimes 261541Srgrimes//todo: one might eliminate uninits.andSets when monotonic 271541Srgrimes 281541Srgrimespackage com.sun.tools.javac.comp; 291541Srgrimes 301541Srgrimesimport java.util.HashMap; 311541Srgrimes 321541Srgrimesimport com.sun.tools.javac.code.*; 3350477Speterimport com.sun.tools.javac.code.Scope.WriteableScope; 341541Srgrimesimport com.sun.tools.javac.tree.*; 351541Srgrimesimport com.sun.tools.javac.util.*; 361541Srgrimesimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 371541Srgrimes 381541Srgrimesimport com.sun.tools.javac.code.Symbol.*; 3950520Sphkimport com.sun.tools.javac.tree.JCTree.*; 4034925Sdufault 4183366Sjulianimport static com.sun.tools.javac.code.Flags.*; 421541Srgrimesimport static com.sun.tools.javac.code.Flags.BLOCK; 431541Srgrimesimport static com.sun.tools.javac.code.Kinds.Kind.*; 441541Srgrimesimport static com.sun.tools.javac.code.TypeTag.BOOLEAN; 451541Srgrimesimport static com.sun.tools.javac.code.TypeTag.VOID; 461541Srgrimesimport static com.sun.tools.javac.tree.JCTree.Tag.*; 471541Srgrimes 481541Srgrimes/** This pass implements dataflow analysis for Java programs though 491541Srgrimes * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that 501541Srgrimes * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that 51126293Sdes * every checked exception that is thrown is declared or caught. Definite assignment analysis 521541Srgrimes * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite 531541Srgrimes * unassignment analysis (see AssignAnalyzer) in ensures that no final variable 541541Srgrimes * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer) 558876Srgrimes * determines that local variables accessed within the scope of an inner class/lambda 561541Srgrimes * are either final or effectively-final. 571541Srgrimes * 58122707Strhodes * <p>The JLS has a number of problems in the 591541Srgrimes * specification of these flow analysis problems. This implementation 601541Srgrimes * attempts to address those issues. 611541Srgrimes * 621541Srgrimes * <p>First, there is no accommodation for a finally clause that cannot 631541Srgrimes * complete normally. For liveness analysis, an intervening finally 6411863Sphk * clause can cause a break, continue, or return not to reach its 6511865Sphk * target. For exception analysis, an intervening finally clause can 661541Srgrimes * cause any exception to be "caught". For DA/DU analysis, the finally 671541Srgrimes * clause can prevent a transfer of control from propagating DA/DU 681541Srgrimes * state to the target. In addition, code in the finally clause can 691541Srgrimes * affect the DA/DU status of variables. 7011863Sphk * 7111863Sphk * <p>For try statements, we introduce the idea of a variable being 7278435Spirzyk * definitely unassigned "everywhere" in a block. A variable V is 7378435Spirzyk * "unassigned everywhere" in a block iff it is unassigned at the 7478435Spirzyk * beginning of the block and there is no reachable assignment to V 751541Srgrimes * in the block. An assignment V=e is reachable iff V is not DA 7611863Sphk * after e. Then we can say that V is DU at the beginning of the 7711863Sphk * catch block iff V is DU everywhere in the try block. Similarly, V 7811863Sphk * is DU at the beginning of the finally block iff V is DU everywhere 7911865Sphk * in the try block and in every catch block. Specifically, the 8012910Sphk * following bullet is added to 16.2.2 8141728Struckman * <pre> 8246155Sphk * V is <em>unassigned everywhere</em> in a block if it is 8363212Sabial * unassigned before the block and there is no reachable 84101650Smux * assignment to V within the block. 85109246Sdillon * </pre> 86121305Ssilby * <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all 87121305Ssilby * try blocks is changed to 8811863Sphk * <pre> 8919268Sjulian * V is definitely unassigned before a catch block iff V is 90109246Sdillon * definitely unassigned everywhere in the try block. 91109246Sdillon * </pre> 92109246Sdillon * <p>The last bullet (and all of its sub-bullets) for try blocks that 93109246Sdillon * have a finally block is changed to 94109246Sdillon * <pre> 95109246Sdillon * V is definitely unassigned before the finally block iff 96109246Sdillon * V is definitely unassigned everywhere in the try block 97109246Sdillon * and everywhere in each catch block of the try statement. 98109246Sdillon * </pre> 99109246Sdillon * <p>In addition, 10019268Sjulian * <pre> 10119268Sjulian * V is definitely assigned at the end of a constructor iff 10219268Sjulian * V is definitely assigned after the block that is the body 10334925Sdufault * of the constructor and V is definitely assigned at every 10419268Sjulian * return that can return from the constructor. 10519268Sjulian * </pre> 10612582Sphk * <p>In addition, each continue statement with the loop as its target 10712582Sphk * is treated as a jump to the end of the loop body, and "intervening" 10880339Sroam * finally clauses are treated as follows: V is DA "due to the 10980339Sroam * continue" iff V is DA before the continue statement or V is DA at 11080339Sroam * the end of any intervening finally block. V is DU "due to the 11180339Sroam * continue" iff any intervening finally cannot complete normally or V 11280339Sroam * is DU at the end of every intervening finally block. This "due to 11380339Sroam * the continue" concept is then used in the spec for the loops. 11455205Speter * 11562454Sphk * <p>Similarly, break statements must consider intervening finally 11662454Sphk * blocks. For liveness analysis, a break statement for which any 11711863Sphk * intervening finally cannot complete normally is not considered to 118120781Sbms * cause the target statement to be able to complete normally. Then 119120781Sbms * we say V is DA "due to the break" iff V is DA before the break or 120120781Sbms * V is DA at the end of any intervening finally block. V is DU "due 121120781Sbms * to the break" iff any intervening finally cannot complete normally 122120781Sbms * or V is DU at the break and at the end of every intervening 123136404Speter * finally block. (I suspect this latter condition can be 124136404Speter * simplified.) This "due to the break" is then used in the spec for 125136404Speter * all statements that can be "broken". 126136404Speter * 127136404Speter * <p>The return statement is treated similarly. V is DA "due to a 12812243Sphk * return statement" iff V is DA before the return statement or V is 12912243Sphk * DA at the end of any intervening finally block. Note that we 13012243Sphk * don't have to worry about the return expression because this 13112243Sphk * concept is only used for construcrors. 13212243Sphk * 13386183Srwatson * <p>There is no spec in the JLS for when a variable is definitely 134120781Sbms * assigned at the end of a constructor, which is needed for final 13512243Sphk * fields (8.3.1.2). We implement the rule that V is DA at the end 13638517Sdfr * of the constructor iff it is DA and the end of the body of the 13738517Sdfr * constructor and V is DA "due to" every return of the constructor. 13838517Sdfr * 13912243Sphk * <p>Intervening finally blocks similarly affect exception analysis. An 14038517Sdfr * intervening finally that cannot complete normally allows us to ignore 14138517Sdfr * an otherwise uncaught exception. 14238517Sdfr * 143127052Struckman * <p>To implement the semantics of intervening finally clauses, all 144136404Speter * nonlocal transfers (break, continue, return, throw, method call that 14512243Sphk * can throw a checked exception, and a constructor invocation that can 14612243Sphk * thrown a checked exception) are recorded in a queue, and removed 14760938Sjake * from the queue when we complete processing the target of the 14844078Sdfr * nonlocal transfer. This allows us to modify the queue in accordance 14912243Sphk * with the above rules when we encounter a finally clause. The only 15012243Sphk * exception to this [no pun intended] is that checked exceptions that 15112243Sphk * are known to be caught or declared to be caught in the enclosing 15212243Sphk * method are not recorded in the queue, but instead are recorded in a 15311863Sphk * global variable "{@code Set<Type> thrown}" that records the type of all 15444078Sdfr * exceptions that can be thrown. 15560938Sjake * 15611863Sphk * <p>Other minor issues the treatment of members of other classes 157100113Smarkm * (always considered DA except that within an anonymous class 15811863Sphk * constructor, where DA status from the enclosing scope is 15911863Sphk * preserved), treatment of the case expression (V is DA before the 16012623Sphk * case expression iff V is DA after the switch expression), 16162573Sphk * treatment of variables declared in a switch block (the implied 16212623Sphk * DA/DU status after the switch expression is DU and not DA for 16363212Sabial * variables defined in a switch block), the treatment of boolean ?: 164100113Smarkm * expressions (The JLS rules only handle b and c non-boolean; the 16511863Sphk * new rule is that if b and c are boolean valued, then V is 16611863Sphk * (un)assigned after a?b:c when true/false iff V is (un)assigned 16712243Sphk * after b when true/false and V is (un)assigned after c when 16812243Sphk * true/false). 16912243Sphk * 17062573Sphk * <p>There is the remaining question of what syntactic forms constitute a 17162573Sphk * reference to a variable. It is conventional to allow this.x on the 17262573Sphk * left-hand-side to initialize a final instance field named x, yet 17362573Sphk * this.x isn't considered a "use" when appearing on a right-hand-side 17462573Sphk * in most implementations. Should parentheses affect what is 17511865Sphk * considered a variable reference? The simplest rule would be to 17644078Sdfr * allow unqualified forms only, parentheses optional, and phase out 17744078Sdfr * support for assigning to a final field via this.x. 17844078Sdfr * 17944078Sdfr * <p><b>This is NOT part of any supported API. 18044078Sdfr * If you write code that depends on this, you do so at your own risk. 18144078Sdfr * This code and its internal interfaces are subject to change or 18263212Sabial * deletion without notice.</b> 18344078Sdfr */ 18444078Sdfrpublic class Flow { 18544078Sdfr protected static final Context.Key<Flow> flowKey = new Context.Key<>(); 18663212Sabial 18763212Sabial private final Names names; 18863212Sabial private final Log log; 189132784Skan private final Symtab syms; 190132784Skan private final Types types; 19163212Sabial private final Check chk; 19263212Sabial private TreeMaker make; 19363212Sabial private final Resolve rs; 19463212Sabial private final JCDiagnostic.Factory diags; 19563212Sabial private Env<AttrContext> attrEnv; 19663212Sabial private Lint lint; 19763212Sabial private final boolean allowImprovedRethrowAnalysis; 19863212Sabial private final boolean allowImprovedCatchAnalysis; 19963212Sabial private final boolean allowEffectivelyFinalInInnerClasses; 20063212Sabial private final boolean enforceThisDotInit; 20163212Sabial 20263212Sabial public static Flow instance(Context context) { 20363212Sabial Flow instance = context.get(flowKey); 204108649Sjake if (instance == null) 205108649Sjake instance = new Flow(context); 206108649Sjake return instance; 20738859Sbde } 20812623Sphk 20944078Sdfr public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 21044078Sdfr new AliveAnalyzer().analyzeTree(env, make); 21188006Sluigi new AssignAnalyzer().analyzeTree(env); 212100113Smarkm new FlowAnalyzer().analyzeTree(env, make); 21311863Sphk new CaptureAnalyzer().analyzeTree(env, make); 21463212Sabial } 215100113Smarkm 21663212Sabial public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) { 21738859Sbde Log.DiagnosticHandler diagHandler = null; 21844078Sdfr //we need to disable diagnostics temporarily; the problem is that if 219108649Sjake //a lambda expression contains e.g. an unreachable statement, an error 220105582Sphk //message will be reported and will cause compilation to skip the flow analyis 221108649Sjake //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis 222100113Smarkm //related errors, which will allow for more errors to be detected 22311863Sphk if (!speculative) { 22463212Sabial diagHandler = new Log.DiscardDiagnosticHandler(log); 225105582Sphk } 226100113Smarkm try { 22763212Sabial new AliveAnalyzer().analyzeTree(env, that, make); 22838859Sbde } finally { 22912623Sphk if (!speculative) { 230105582Sphk log.popDiagnosticHandler(diagHandler); 23129210Sbde } 23211863Sphk } 23363212Sabial } 234105582Sphk 235100113Smarkm public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env, 23663212Sabial JCLambda that, TreeMaker make) { 23738859Sbde //we need to disable diagnostics temporarily; the problem is that if 23812623Sphk //a lambda expression contains e.g. an unreachable statement, an error 239105582Sphk //message will be reported and will cause compilation to skip the flow analyis 24029210Sbde //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis 24111863Sphk //related errors, which will allow for more errors to be detected 24263212Sabial Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 243105582Sphk try { 244100113Smarkm new AssignAnalyzer() { 24563212Sabial WriteableScope enclosedSymbols = WriteableScope.create(env.enclClass.sym); 24662622Sjhb @Override 24762622Sjhb public void visitVarDef(JCVariableDecl tree) { 248105582Sphk enclosedSymbols.enter(tree.sym); 24962622Sjhb super.visitVarDef(tree); 25062622Sjhb } 25163212Sabial @Override 252105582Sphk protected boolean trackable(VarSymbol sym) { 253100113Smarkm return enclosedSymbols.includes(sym) && 25463212Sabial sym.owner.kind == MTH; 25542095Sdfr } 25662622Sjhb }.analyzeTree(env, that); 257105582Sphk LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); 25862622Sjhb flowAnalyzer.analyzeTree(env, that, make); 25938517Sdfr return flowAnalyzer.inferredThrownTypes; 26063212Sabial } finally { 261105582Sphk log.popDiagnosticHandler(diagHandler); 262100113Smarkm } 26363212Sabial } 264112744Srobert 26562622Sjhb /** 266105582Sphk * Definite assignment scan mode 26762622Sjhb */ 26862622Sjhb enum FlowKind { 26963212Sabial /** 270105582Sphk * This is the normal DA/DU analysis mode 271100113Smarkm */ 27263212Sabial NORMAL("var.might.already.be.assigned", false), 27338859Sbde /** 27412705Sphk * This is the speculative DA/DU analysis mode used to speculatively 275105582Sphk * derive assertions within loop bodies 27629210Sbde */ 27711863Sphk SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true); 27863212Sabial 279105582Sphk final String errKey; 280100113Smarkm final boolean isFinal; 28163212Sabial 28238859Sbde FlowKind(String errKey, boolean isFinal) { 28312623Sphk this.errKey = errKey; 284105582Sphk this.isFinal = isFinal; 28512623Sphk } 28629210Sbde 28711863Sphk boolean isFinal() { 28863212Sabial return isFinal; 289105582Sphk } 290100113Smarkm } 29163212Sabial 29238859Sbde protected Flow(Context context) { 29312623Sphk context.put(flowKey, this); 294105582Sphk names = Names.instance(context); 29529210Sbde log = Log.instance(context); 29663212Sabial syms = Symtab.instance(context); 29763212Sabial types = Types.instance(context); 298105582Sphk chk = Check.instance(context); 299100113Smarkm lint = Lint.instance(context); 30063212Sabial rs = Resolve.instance(context); 30155205Speter diags = JCDiagnostic.Factory.instance(context); 30211863Sphk Source source = Source.instance(context); 3031541Srgrimes allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis(); 3041541Srgrimes allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); 3051541Srgrimes allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); 3061541Srgrimes enforceThisDotInit = source.enforceThisDotInit(); 3071541Srgrimes } 3081541Srgrimes 30996755Strhodes /** 3101541Srgrimes * Base visitor class for all visitors implementing dataflow analysis logic. 3111541Srgrimes * This class define the shared logic for handling jumps (break/continue statements). 3121541Srgrimes */ 3131541Srgrimes static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner { 3141541Srgrimes 31534925Sdufault enum JumpKind { 31634030Sdufault BREAK(JCTree.Tag.BREAK) { 31734030Sdufault @Override 3181541Srgrimes JCTree getTarget(JCTree tree) { 3191541Srgrimes return ((JCBreak)tree).target; 3201541Srgrimes } 3211541Srgrimes }, 32214498Shsu CONTINUE(JCTree.Tag.CONTINUE) { 3231541Srgrimes @Override 3241541Srgrimes JCTree getTarget(JCTree tree) { 3251541Srgrimes return ((JCContinue)tree).target; 3261541Srgrimes } 3271541Srgrimes }; 32834925Sdufault 3291541Srgrimes final JCTree.Tag treeTag; 3301541Srgrimes 3311541Srgrimes private JumpKind(Tag treeTag) { 3321541Srgrimes this.treeTag = treeTag; 3331541Srgrimes } 3341541Srgrimes 3351541Srgrimes abstract JCTree getTarget(JCTree tree); 3361541Srgrimes } 3371541Srgrimes 3381541Srgrimes /** The currently pending exits that go from current inner blocks 3391541Srgrimes * to an enclosing block, in source order. 3401541Srgrimes */ 3411541Srgrimes ListBuffer<P> pendingExits; 3421541Srgrimes 3431541Srgrimes /** A pending exit. These are the statements return, break, and 3441541Srgrimes * continue. In addition, exception-throwing expressions or 3451541Srgrimes * statements are put here when not known to be caught. This 3461541Srgrimes * will typically result in an error unless it is within a 3471541Srgrimes * try-finally whose finally block cannot complete normally. 3481541Srgrimes */ 3491541Srgrimes static class PendingExit { 3501541Srgrimes JCTree tree; 3511541Srgrimes 3521541Srgrimes PendingExit(JCTree tree) { 3531541Srgrimes this.tree = tree; 3541541Srgrimes } 35517281Swollman 3561952Swollman void resolveJump(JCTree tree) { 357119212Seivind //do nothing 3582858Swollman } 3593038Swollman } 3606577Sguido 3616577Sguido abstract void markDead(JCTree tree); 362130585Sphk 36323083Swollman /** Record an outward transfer of control. */ 36423083Swollman void recordExit(JCTree tree, P pe) { 36514235Speter pendingExits.append(pe); 36614235Speter markDead(tree); 36737931Sjoerg } 36878431Swollman 369116090Sjmallett /** Resolve all jumps of this statement. */ 3701541Srgrimes private boolean resolveJump(JCTree tree, 3711541Srgrimes ListBuffer<P> oldPendingExits, 3721541Srgrimes JumpKind jk) { 3731541Srgrimes boolean resolved = false; 3741541Srgrimes List<P> exits = pendingExits.toList(); 3751541Srgrimes pendingExits = oldPendingExits; 3761541Srgrimes for (; exits.nonEmpty(); exits = exits.tail) { 3771541Srgrimes P exit = exits.head; 3781541Srgrimes if (exit.tree.hasTag(jk.treeTag) && 3791541Srgrimes jk.getTarget(exit.tree) == tree) { 3801541Srgrimes exit.resolveJump(tree); 3811541Srgrimes resolved = true; 3821541Srgrimes } else { 38378435Spirzyk pendingExits.append(exit); 3841541Srgrimes } 3851541Srgrimes } 3861541Srgrimes return resolved; 3871541Srgrimes } 3881541Srgrimes 3891541Srgrimes /** Resolve all continues of this statement. */ 3901541Srgrimes boolean resolveContinues(JCTree tree) { 3911541Srgrimes return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE); 3921541Srgrimes } 3931541Srgrimes 39417281Swollman /** Resolve all breaks of this statement. */ 3951952Swollman boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) { 3962004Swollman return resolveJump(tree, oldPendingExits, JumpKind.BREAK); 39772857Sjhb } 3983038Swollman 3996577Sguido @Override 4006577Sguido public void scan(JCTree tree) { 40123083Swollman if (tree != null && ( 40223083Swollman tree.type == null || 40314235Speter tree.type != Type.stuckType)) { 40414235Speter super.scan(tree); 40537931Sjoerg } 40678431Swollman } 4071541Srgrimes 4081541Srgrimes public void visitPackageDef(JCPackageDecl tree) { 4092946Swollman // Do nothing for PackageDecl 41014498Shsu } 4112946Swollman } 41214498Shsu 4132946Swollman /** 4142946Swollman * This pass implements the first step of the dataflow analysis, namely 4152946Swollman * the liveness analysis check. This checks that every statement is reachable. 4168876Srgrimes * The output of this analysis pass are used by other analyzers. This analyzer 4171541Srgrimes * sets the 'finallyCanCompleteNormally' field in the JCTry class. 4181541Srgrimes */ 4191541Srgrimes class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { 4201541Srgrimes 4211541Srgrimes /** A flag that indicates whether the last statement could 4221541Srgrimes * complete normally. 4231541Srgrimes */ 4241541Srgrimes private boolean alive; 4251541Srgrimes 42653239Sphk @Override 427116261Sscottl void markDead(JCTree tree) { 428117464Srobert alive = false; 429129597Sgad } 430130725Sgad 431126125Sdeischen /************************************************************************* 432126125Sdeischen * Visitor methods for statements and definitions 433130725Sgad *************************************************************************/ 434126125Sdeischen 4351541Srgrimes /** Analyze a definition. 4368876Srgrimes */ 43723083Swollman void scanDef(JCTree tree) { 43823083Swollman scanStat(tree); 43923083Swollman if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) { 44023083Swollman log.error(tree.pos(), 44123083Swollman "initializer.must.be.able.to.complete.normally"); 44223083Swollman } 44323083Swollman } 44423083Swollman 44523083Swollman /** Analyze a statement. Check that statement is reachable. 44623083Swollman */ 44723083Swollman void scanStat(JCTree tree) { 4481541Srgrimes if (!alive && tree != null) { 4491541Srgrimes log.error(tree.pos(), "unreachable.stmt"); 4501541Srgrimes if (!tree.hasTag(SKIP)) alive = true; 4511541Srgrimes } 4521541Srgrimes scan(tree); 4531541Srgrimes } 4541541Srgrimes 4551541Srgrimes /** Analyze list of statements. 4561541Srgrimes */ 4571541Srgrimes void scanStats(List<? extends JCStatement> trees) { 4581541Srgrimes if (trees != null) 4592631Swollman for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail) 46028885Skato scanStat(l.head); 46128885Skato } 4621541Srgrimes 4631541Srgrimes /* ------------ Visitor methods for various sorts of trees -------------*/ 4641541Srgrimes 4651541Srgrimes public void visitClassDef(JCClassDecl tree) { 4661541Srgrimes if (tree.sym == null) return; 4671541Srgrimes boolean alivePrev = alive; 4681541Srgrimes ListBuffer<PendingExit> pendingExitsPrev = pendingExits; 46978435Spirzyk Lint lintPrev = lint; 47078435Spirzyk 4711541Srgrimes pendingExits = new ListBuffer<>(); 4721541Srgrimes lint = lint.augment(tree.sym); 4731541Srgrimes 4742631Swollman try { 4751541Srgrimes // process all the static initializers 4761541Srgrimes for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 4771541Srgrimes if (!l.head.hasTag(METHODDEF) && 4781541Srgrimes (TreeInfo.flags(l.head) & STATIC) != 0) { 4791541Srgrimes scanDef(l.head); 4801541Srgrimes } 4811541Srgrimes } 4821541Srgrimes 4831541Srgrimes // process all the instance initializers 4841541Srgrimes for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 4851541Srgrimes if (!l.head.hasTag(METHODDEF) && 4861541Srgrimes (TreeInfo.flags(l.head) & STATIC) == 0) { 4871541Srgrimes scanDef(l.head); 4881541Srgrimes } 4891541Srgrimes } 4901541Srgrimes 4911541Srgrimes // process all the methods 4921541Srgrimes for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 4931541Srgrimes if (l.head.hasTag(METHODDEF)) { 4941541Srgrimes scan(l.head); 4951541Srgrimes } 4961541Srgrimes } 4971541Srgrimes } finally { 4981541Srgrimes pendingExits = pendingExitsPrev; 4991541Srgrimes alive = alivePrev; 5001541Srgrimes lint = lintPrev; 5011541Srgrimes } 5021541Srgrimes } 5031541Srgrimes 5041541Srgrimes public void visitMethodDef(JCMethodDecl tree) { 5051541Srgrimes if (tree.body == null) return; 5061541Srgrimes Lint lintPrev = lint; 5071541Srgrimes 5081541Srgrimes lint = lint.augment(tree.sym); 5091541Srgrimes 5101541Srgrimes Assert.check(pendingExits.isEmpty()); 5111541Srgrimes 5121541Srgrimes try { 5131541Srgrimes alive = true; 5141541Srgrimes scanStat(tree.body); 5151541Srgrimes 5161541Srgrimes if (alive && !tree.sym.type.getReturnType().hasTag(VOID)) 5171541Srgrimes log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt"); 5181541Srgrimes 5191541Srgrimes List<PendingExit> exits = pendingExits.toList(); 5201541Srgrimes pendingExits = new ListBuffer<>(); 5211541Srgrimes while (exits.nonEmpty()) { 5221541Srgrimes PendingExit exit = exits.head; 5231541Srgrimes exits = exits.tail; 5241541Srgrimes Assert.check(exit.tree.hasTag(RETURN)); 5251541Srgrimes } 52634925Sdufault } finally { 52734925Sdufault lint = lintPrev; 52834925Sdufault } 52934925Sdufault } 53034925Sdufault 53134925Sdufault public void visitVarDef(JCVariableDecl tree) { 53234925Sdufault if (tree.init != null) { 53334925Sdufault Lint lintPrev = lint; 53434925Sdufault lint = lint.augment(tree.sym); 53534925Sdufault try{ 53634925Sdufault scan(tree.init); 53734925Sdufault } finally { 53834925Sdufault lint = lintPrev; 53934925Sdufault } 54034925Sdufault } 54134925Sdufault } 54234925Sdufault 54334925Sdufault public void visitBlock(JCBlock tree) { 54434925Sdufault scanStats(tree.stats); 54534925Sdufault } 54634925Sdufault 54734925Sdufault public void visitDoLoop(JCDoWhileLoop tree) { 54834925Sdufault ListBuffer<PendingExit> prevPendingExits = pendingExits; 54934925Sdufault pendingExits = new ListBuffer<>(); 55034925Sdufault scanStat(tree.body); 55134925Sdufault alive |= resolveContinues(tree); 55234925Sdufault scan(tree.cond); 55334925Sdufault alive = alive && !tree.cond.type.isTrue(); 55434925Sdufault alive |= resolveBreaks(tree, prevPendingExits); 55534925Sdufault } 55634925Sdufault 55734925Sdufault public void visitWhileLoop(JCWhileLoop tree) { 55834925Sdufault ListBuffer<PendingExit> prevPendingExits = pendingExits; 55934925Sdufault pendingExits = new ListBuffer<>(); 56034925Sdufault scan(tree.cond); 56134925Sdufault alive = !tree.cond.type.isFalse(); 56234925Sdufault scanStat(tree.body); 56334925Sdufault alive |= resolveContinues(tree); 56434925Sdufault alive = resolveBreaks(tree, prevPendingExits) || 56534925Sdufault !tree.cond.type.isTrue(); 56634925Sdufault } 56734925Sdufault 56834925Sdufault public void visitForLoop(JCForLoop tree) { 56934925Sdufault ListBuffer<PendingExit> prevPendingExits = pendingExits; 57034925Sdufault scanStats(tree.init); 57134925Sdufault pendingExits = new ListBuffer<>(); 57234925Sdufault if (tree.cond != null) { 57334925Sdufault scan(tree.cond); 57434925Sdufault alive = !tree.cond.type.isFalse(); 57534925Sdufault } else { 57634925Sdufault alive = true; 57734925Sdufault } 57834925Sdufault scanStat(tree.body); 57934925Sdufault alive |= resolveContinues(tree); 58034925Sdufault scan(tree.step); 58134925Sdufault alive = resolveBreaks(tree, prevPendingExits) || 58234925Sdufault tree.cond != null && !tree.cond.type.isTrue(); 58355205Speter } 5841541Srgrimes 58544078Sdfr public void visitForeachLoop(JCEnhancedForLoop tree) { 58644078Sdfr visitVarDef(tree.var); 58744078Sdfr ListBuffer<PendingExit> prevPendingExits = pendingExits; 58844078Sdfr scan(tree.expr); 58944078Sdfr pendingExits = new ListBuffer<>(); 59044078Sdfr scanStat(tree.body); 59144078Sdfr alive |= resolveContinues(tree); 59244078Sdfr resolveBreaks(tree, prevPendingExits); 59344078Sdfr alive = true; 59444078Sdfr } 59591687Sphk 59644078Sdfr public void visitLabelled(JCLabeledStatement tree) { 59744078Sdfr ListBuffer<PendingExit> prevPendingExits = pendingExits; 59844078Sdfr pendingExits = new ListBuffer<>(); 59950465Smarcel scanStat(tree.body); 60044078Sdfr alive |= resolveBreaks(tree, prevPendingExits); 6017090Sbde } 6027090Sbde 6037090Sbde public void visitSwitch(JCSwitch tree) { 604116105Sjmallett ListBuffer<PendingExit> prevPendingExits = pendingExits; 6057090Sbde pendingExits = new ListBuffer<>(); 60663212Sabial scan(tree.selector); 60763212Sabial boolean hasDefault = false; 60870679Sjhb for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 60963212Sabial alive = true; 61063212Sabial JCCase c = l.head; 61170679Sjhb if (c.pat == null) 612126319Sdes hasDefault = true; 613126319Sdes else 61463212Sabial scan(c.pat); 61563212Sabial scanStats(c.stats); 61663212Sabial // Warn about fall-through if lint switch fallthrough enabled. 61763212Sabial if (alive && 61863212Sabial lint.isEnabled(Lint.LintCategory.FALLTHROUGH) && 61963212Sabial c.stats.nonEmpty() && l.tail.nonEmpty()) 62063212Sabial log.warning(Lint.LintCategory.FALLTHROUGH, 62163212Sabial l.tail.head.pos(), 62263212Sabial "possible.fall-through.into.case"); 62363212Sabial } 62483366Sjulian if (!hasDefault) { 62538859Sbde alive = true; 626136404Speter } 62783366Sjulian alive |= resolveBreaks(tree, prevPendingExits); 62876834Sjlemon } 629136404Speter 63083366Sjulian public void visitTry(JCTry tree) { 63138859Sbde ListBuffer<PendingExit> prevPendingExits = pendingExits; 632136404Speter pendingExits = new ListBuffer<>(); 63353977Sgreen for (JCTree resource : tree.resources) { 63453977Sgreen if (resource instanceof JCVariableDecl) { 635126253Struckman JCVariableDecl vdecl = (JCVariableDecl) resource; 6363421Sphk visitVarDef(vdecl); 63755205Speter } else if (resource instanceof JCExpression) { 6381541Srgrimes scan((JCExpression) resource); 6391541Srgrimes } else { 6401541Srgrimes throw new AssertionError(tree); // parser error 64192719Salfred } 64292719Salfred } 64392719Salfred 6441541Srgrimes scanStat(tree.body); 64555205Speter boolean aliveEnd = alive; 6464468Sbde 6471541Srgrimes for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 648 alive = true; 649 JCVariableDecl param = l.head.param; 650 scan(param); 651 scanStat(l.head.body); 652 aliveEnd |= alive; 653 } 654 if (tree.finalizer != null) { 655 ListBuffer<PendingExit> exits = pendingExits; 656 pendingExits = prevPendingExits; 657 alive = true; 658 scanStat(tree.finalizer); 659 tree.finallyCanCompleteNormally = alive; 660 if (!alive) { 661 if (lint.isEnabled(Lint.LintCategory.FINALLY)) { 662 log.warning(Lint.LintCategory.FINALLY, 663 TreeInfo.diagEndPos(tree.finalizer), 664 "finally.cannot.complete"); 665 } 666 } else { 667 while (exits.nonEmpty()) { 668 pendingExits.append(exits.next()); 669 } 670 alive = aliveEnd; 671 } 672 } else { 673 alive = aliveEnd; 674 ListBuffer<PendingExit> exits = pendingExits; 675 pendingExits = prevPendingExits; 676 while (exits.nonEmpty()) pendingExits.append(exits.next()); 677 } 678 } 679 680 @Override 681 public void visitIf(JCIf tree) { 682 scan(tree.cond); 683 scanStat(tree.thenpart); 684 if (tree.elsepart != null) { 685 boolean aliveAfterThen = alive; 686 alive = true; 687 scanStat(tree.elsepart); 688 alive = alive | aliveAfterThen; 689 } else { 690 alive = true; 691 } 692 } 693 694 public void visitBreak(JCBreak tree) { 695 recordExit(tree, new PendingExit(tree)); 696 } 697 698 public void visitContinue(JCContinue tree) { 699 recordExit(tree, new PendingExit(tree)); 700 } 701 702 public void visitReturn(JCReturn tree) { 703 scan(tree.expr); 704 recordExit(tree, new PendingExit(tree)); 705 } 706 707 public void visitThrow(JCThrow tree) { 708 scan(tree.expr); 709 markDead(tree); 710 } 711 712 public void visitApply(JCMethodInvocation tree) { 713 scan(tree.meth); 714 scan(tree.args); 715 } 716 717 public void visitNewClass(JCNewClass tree) { 718 scan(tree.encl); 719 scan(tree.args); 720 if (tree.def != null) { 721 scan(tree.def); 722 } 723 } 724 725 @Override 726 public void visitLambda(JCLambda tree) { 727 if (tree.type != null && 728 tree.type.isErroneous()) { 729 return; 730 } 731 732 ListBuffer<PendingExit> prevPending = pendingExits; 733 boolean prevAlive = alive; 734 try { 735 pendingExits = new ListBuffer<>(); 736 alive = true; 737 scanStat(tree.body); 738 tree.canCompleteNormally = alive; 739 } 740 finally { 741 pendingExits = prevPending; 742 alive = prevAlive; 743 } 744 } 745 746 /************************************************************************** 747 * main method 748 *************************************************************************/ 749 750 /** Perform definite assignment/unassignment analysis on a tree. 751 */ 752 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 753 analyzeTree(env, env.tree, make); 754 } 755 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { 756 try { 757 attrEnv = env; 758 Flow.this.make = make; 759 pendingExits = new ListBuffer<>(); 760 alive = true; 761 scan(tree); 762 } finally { 763 pendingExits = null; 764 Flow.this.make = null; 765 } 766 } 767 } 768 769 /** 770 * This pass implements the second step of the dataflow analysis, namely 771 * the exception analysis. This is to ensure that every checked exception that is 772 * thrown is declared or caught. The analyzer uses some info that has been set by 773 * the liveliness analyzer. 774 */ 775 class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> { 776 777 /** A flag that indicates whether the last statement could 778 * complete normally. 779 */ 780 HashMap<Symbol, List<Type>> preciseRethrowTypes; 781 782 /** The current class being defined. 783 */ 784 JCClassDecl classDef; 785 786 /** The list of possibly thrown declarable exceptions. 787 */ 788 List<Type> thrown; 789 790 /** The list of exceptions that are either caught or declared to be 791 * thrown. 792 */ 793 List<Type> caught; 794 795 class FlowPendingExit extends BaseAnalyzer.PendingExit { 796 797 Type thrown; 798 799 FlowPendingExit(JCTree tree, Type thrown) { 800 super(tree); 801 this.thrown = thrown; 802 } 803 } 804 805 @Override 806 void markDead(JCTree tree) { 807 //do nothing 808 } 809 810 /*-------------------- Exceptions ----------------------*/ 811 812 /** Complain that pending exceptions are not caught. 813 */ 814 void errorUncaught() { 815 for (FlowPendingExit exit = pendingExits.next(); 816 exit != null; 817 exit = pendingExits.next()) { 818 if (classDef != null && 819 classDef.pos == exit.tree.pos) { 820 log.error(exit.tree.pos(), 821 "unreported.exception.default.constructor", 822 exit.thrown); 823 } else if (exit.tree.hasTag(VARDEF) && 824 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { 825 log.error(exit.tree.pos(), 826 "unreported.exception.implicit.close", 827 exit.thrown, 828 ((JCVariableDecl)exit.tree).sym.name); 829 } else { 830 log.error(exit.tree.pos(), 831 "unreported.exception.need.to.catch.or.throw", 832 exit.thrown); 833 } 834 } 835 } 836 837 /** Record that exception is potentially thrown and check that it 838 * is caught. 839 */ 840 void markThrown(JCTree tree, Type exc) { 841 if (!chk.isUnchecked(tree.pos(), exc)) { 842 if (!chk.isHandled(exc, caught)) { 843 pendingExits.append(new FlowPendingExit(tree, exc)); 844 } 845 thrown = chk.incl(exc, thrown); 846 } 847 } 848 849 /************************************************************************* 850 * Visitor methods for statements and definitions 851 *************************************************************************/ 852 853 /* ------------ Visitor methods for various sorts of trees -------------*/ 854 855 public void visitClassDef(JCClassDecl tree) { 856 if (tree.sym == null) return; 857 858 JCClassDecl classDefPrev = classDef; 859 List<Type> thrownPrev = thrown; 860 List<Type> caughtPrev = caught; 861 ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits; 862 Lint lintPrev = lint; 863 864 pendingExits = new ListBuffer<>(); 865 if (tree.name != names.empty) { 866 caught = List.nil(); 867 } 868 classDef = tree; 869 thrown = List.nil(); 870 lint = lint.augment(tree.sym); 871 872 try { 873 // process all the static initializers 874 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 875 if (!l.head.hasTag(METHODDEF) && 876 (TreeInfo.flags(l.head) & STATIC) != 0) { 877 scan(l.head); 878 errorUncaught(); 879 } 880 } 881 882 // add intersection of all thrown clauses of initial constructors 883 // to set of caught exceptions, unless class is anonymous. 884 if (tree.name != names.empty) { 885 boolean firstConstructor = true; 886 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 887 if (TreeInfo.isInitialConstructor(l.head)) { 888 List<Type> mthrown = 889 ((JCMethodDecl) l.head).sym.type.getThrownTypes(); 890 if (firstConstructor) { 891 caught = mthrown; 892 firstConstructor = false; 893 } else { 894 caught = chk.intersect(mthrown, caught); 895 } 896 } 897 } 898 } 899 900 // process all the instance initializers 901 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 902 if (!l.head.hasTag(METHODDEF) && 903 (TreeInfo.flags(l.head) & STATIC) == 0) { 904 scan(l.head); 905 errorUncaught(); 906 } 907 } 908 909 // in an anonymous class, add the set of thrown exceptions to 910 // the throws clause of the synthetic constructor and propagate 911 // outwards. 912 // Changing the throws clause on the fly is okay here because 913 // the anonymous constructor can't be invoked anywhere else, 914 // and its type hasn't been cached. 915 if (tree.name == names.empty) { 916 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 917 if (TreeInfo.isInitialConstructor(l.head)) { 918 JCMethodDecl mdef = (JCMethodDecl)l.head; 919 mdef.thrown = make.Types(thrown); 920 mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown); 921 } 922 } 923 thrownPrev = chk.union(thrown, thrownPrev); 924 } 925 926 // process all the methods 927 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 928 if (l.head.hasTag(METHODDEF)) { 929 scan(l.head); 930 errorUncaught(); 931 } 932 } 933 934 thrown = thrownPrev; 935 } finally { 936 pendingExits = pendingExitsPrev; 937 caught = caughtPrev; 938 classDef = classDefPrev; 939 lint = lintPrev; 940 } 941 } 942 943 public void visitMethodDef(JCMethodDecl tree) { 944 if (tree.body == null) return; 945 946 List<Type> caughtPrev = caught; 947 List<Type> mthrown = tree.sym.type.getThrownTypes(); 948 Lint lintPrev = lint; 949 950 lint = lint.augment(tree.sym); 951 952 Assert.check(pendingExits.isEmpty()); 953 954 try { 955 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 956 JCVariableDecl def = l.head; 957 scan(def); 958 } 959 if (TreeInfo.isInitialConstructor(tree)) 960 caught = chk.union(caught, mthrown); 961 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK) 962 caught = mthrown; 963 // else we are in an instance initializer block; 964 // leave caught unchanged. 965 966 scan(tree.body); 967 968 List<FlowPendingExit> exits = pendingExits.toList(); 969 pendingExits = new ListBuffer<>(); 970 while (exits.nonEmpty()) { 971 FlowPendingExit exit = exits.head; 972 exits = exits.tail; 973 if (exit.thrown == null) { 974 Assert.check(exit.tree.hasTag(RETURN)); 975 } else { 976 // uncaught throws will be reported later 977 pendingExits.append(exit); 978 } 979 } 980 } finally { 981 caught = caughtPrev; 982 lint = lintPrev; 983 } 984 } 985 986 public void visitVarDef(JCVariableDecl tree) { 987 if (tree.init != null) { 988 Lint lintPrev = lint; 989 lint = lint.augment(tree.sym); 990 try{ 991 scan(tree.init); 992 } finally { 993 lint = lintPrev; 994 } 995 } 996 } 997 998 public void visitBlock(JCBlock tree) { 999 scan(tree.stats); 1000 } 1001 1002 public void visitDoLoop(JCDoWhileLoop tree) { 1003 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1004 pendingExits = new ListBuffer<>(); 1005 scan(tree.body); 1006 resolveContinues(tree); 1007 scan(tree.cond); 1008 resolveBreaks(tree, prevPendingExits); 1009 } 1010 1011 public void visitWhileLoop(JCWhileLoop tree) { 1012 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1013 pendingExits = new ListBuffer<>(); 1014 scan(tree.cond); 1015 scan(tree.body); 1016 resolveContinues(tree); 1017 resolveBreaks(tree, prevPendingExits); 1018 } 1019 1020 public void visitForLoop(JCForLoop tree) { 1021 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1022 scan(tree.init); 1023 pendingExits = new ListBuffer<>(); 1024 if (tree.cond != null) { 1025 scan(tree.cond); 1026 } 1027 scan(tree.body); 1028 resolveContinues(tree); 1029 scan(tree.step); 1030 resolveBreaks(tree, prevPendingExits); 1031 } 1032 1033 public void visitForeachLoop(JCEnhancedForLoop tree) { 1034 visitVarDef(tree.var); 1035 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1036 scan(tree.expr); 1037 pendingExits = new ListBuffer<>(); 1038 scan(tree.body); 1039 resolveContinues(tree); 1040 resolveBreaks(tree, prevPendingExits); 1041 } 1042 1043 public void visitLabelled(JCLabeledStatement tree) { 1044 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1045 pendingExits = new ListBuffer<>(); 1046 scan(tree.body); 1047 resolveBreaks(tree, prevPendingExits); 1048 } 1049 1050 public void visitSwitch(JCSwitch tree) { 1051 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1052 pendingExits = new ListBuffer<>(); 1053 scan(tree.selector); 1054 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 1055 JCCase c = l.head; 1056 if (c.pat != null) { 1057 scan(c.pat); 1058 } 1059 scan(c.stats); 1060 } 1061 resolveBreaks(tree, prevPendingExits); 1062 } 1063 1064 public void visitTry(JCTry tree) { 1065 List<Type> caughtPrev = caught; 1066 List<Type> thrownPrev = thrown; 1067 thrown = List.nil(); 1068 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 1069 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 1070 ((JCTypeUnion)l.head.param.vartype).alternatives : 1071 List.of(l.head.param.vartype); 1072 for (JCExpression ct : subClauses) { 1073 caught = chk.incl(ct.type, caught); 1074 } 1075 } 1076 1077 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1078 pendingExits = new ListBuffer<>(); 1079 for (JCTree resource : tree.resources) { 1080 if (resource instanceof JCVariableDecl) { 1081 JCVariableDecl vdecl = (JCVariableDecl) resource; 1082 visitVarDef(vdecl); 1083 } else if (resource instanceof JCExpression) { 1084 scan((JCExpression) resource); 1085 } else { 1086 throw new AssertionError(tree); // parser error 1087 } 1088 } 1089 for (JCTree resource : tree.resources) { 1090 List<Type> closeableSupertypes = resource.type.isCompound() ? 1091 types.interfaces(resource.type).prepend(types.supertype(resource.type)) : 1092 List.of(resource.type); 1093 for (Type sup : closeableSupertypes) { 1094 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) { 1095 Symbol closeMethod = rs.resolveQualifiedMethod(tree, 1096 attrEnv, 1097 sup, 1098 names.close, 1099 List.<Type>nil(), 1100 List.<Type>nil()); 1101 Type mt = types.memberType(resource.type, closeMethod); 1102 if (closeMethod.kind == MTH) { 1103 for (Type t : mt.getThrownTypes()) { 1104 markThrown(resource, t); 1105 } 1106 } 1107 } 1108 } 1109 } 1110 scan(tree.body); 1111 List<Type> thrownInTry = allowImprovedCatchAnalysis ? 1112 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) : 1113 thrown; 1114 thrown = thrownPrev; 1115 caught = caughtPrev; 1116 1117 List<Type> caughtInTry = List.nil(); 1118 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 1119 JCVariableDecl param = l.head.param; 1120 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 1121 ((JCTypeUnion)l.head.param.vartype).alternatives : 1122 List.of(l.head.param.vartype); 1123 List<Type> ctypes = List.nil(); 1124 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry); 1125 for (JCExpression ct : subClauses) { 1126 Type exc = ct.type; 1127 if (exc != syms.unknownType) { 1128 ctypes = ctypes.append(exc); 1129 if (types.isSameType(exc, syms.objectType)) 1130 continue; 1131 checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry); 1132 caughtInTry = chk.incl(exc, caughtInTry); 1133 } 1134 } 1135 scan(param); 1136 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes)); 1137 scan(l.head.body); 1138 preciseRethrowTypes.remove(param.sym); 1139 } 1140 if (tree.finalizer != null) { 1141 List<Type> savedThrown = thrown; 1142 thrown = List.nil(); 1143 ListBuffer<FlowPendingExit> exits = pendingExits; 1144 pendingExits = prevPendingExits; 1145 scan(tree.finalizer); 1146 if (!tree.finallyCanCompleteNormally) { 1147 // discard exits and exceptions from try and finally 1148 thrown = chk.union(thrown, thrownPrev); 1149 } else { 1150 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1151 thrown = chk.union(thrown, savedThrown); 1152 // FIX: this doesn't preserve source order of exits in catch 1153 // versus finally! 1154 while (exits.nonEmpty()) { 1155 pendingExits.append(exits.next()); 1156 } 1157 } 1158 } else { 1159 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1160 ListBuffer<FlowPendingExit> exits = pendingExits; 1161 pendingExits = prevPendingExits; 1162 while (exits.nonEmpty()) pendingExits.append(exits.next()); 1163 } 1164 } 1165 1166 @Override 1167 public void visitIf(JCIf tree) { 1168 scan(tree.cond); 1169 scan(tree.thenpart); 1170 if (tree.elsepart != null) { 1171 scan(tree.elsepart); 1172 } 1173 } 1174 1175 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) { 1176 if (chk.subset(exc, caughtInTry)) { 1177 log.error(pos, "except.already.caught", exc); 1178 } else if (!chk.isUnchecked(pos, exc) && 1179 !isExceptionOrThrowable(exc) && 1180 !chk.intersects(exc, thrownInTry)) { 1181 log.error(pos, "except.never.thrown.in.try", exc); 1182 } else if (allowImprovedCatchAnalysis) { 1183 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry); 1184 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an 1185 // unchecked exception, the result list would not be empty, as the augmented 1186 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked 1187 // exception, that would have been covered in the branch above 1188 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() && 1189 !isExceptionOrThrowable(exc)) { 1190 String key = catchableThrownTypes.length() == 1 ? 1191 "unreachable.catch" : 1192 "unreachable.catch.1"; 1193 log.warning(pos, key, catchableThrownTypes); 1194 } 1195 } 1196 } 1197 //where 1198 private boolean isExceptionOrThrowable(Type exc) { 1199 return exc.tsym == syms.throwableType.tsym || 1200 exc.tsym == syms.exceptionType.tsym; 1201 } 1202 1203 public void visitBreak(JCBreak tree) { 1204 recordExit(tree, new FlowPendingExit(tree, null)); 1205 } 1206 1207 public void visitContinue(JCContinue tree) { 1208 recordExit(tree, new FlowPendingExit(tree, null)); 1209 } 1210 1211 public void visitReturn(JCReturn tree) { 1212 scan(tree.expr); 1213 recordExit(tree, new FlowPendingExit(tree, null)); 1214 } 1215 1216 public void visitThrow(JCThrow tree) { 1217 scan(tree.expr); 1218 Symbol sym = TreeInfo.symbol(tree.expr); 1219 if (sym != null && 1220 sym.kind == VAR && 1221 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 && 1222 preciseRethrowTypes.get(sym) != null && 1223 allowImprovedRethrowAnalysis) { 1224 for (Type t : preciseRethrowTypes.get(sym)) { 1225 markThrown(tree, t); 1226 } 1227 } 1228 else { 1229 markThrown(tree, tree.expr.type); 1230 } 1231 markDead(tree); 1232 } 1233 1234 public void visitApply(JCMethodInvocation tree) { 1235 scan(tree.meth); 1236 scan(tree.args); 1237 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail) 1238 markThrown(tree, l.head); 1239 } 1240 1241 public void visitNewClass(JCNewClass tree) { 1242 scan(tree.encl); 1243 scan(tree.args); 1244 // scan(tree.def); 1245 for (List<Type> l = tree.constructorType.getThrownTypes(); 1246 l.nonEmpty(); 1247 l = l.tail) { 1248 markThrown(tree, l.head); 1249 } 1250 List<Type> caughtPrev = caught; 1251 try { 1252 // If the new class expression defines an anonymous class, 1253 // analysis of the anonymous constructor may encounter thrown 1254 // types which are unsubstituted type variables. 1255 // However, since the constructor's actual thrown types have 1256 // already been marked as thrown, it is safe to simply include 1257 // each of the constructor's formal thrown types in the set of 1258 // 'caught/declared to be thrown' types, for the duration of 1259 // the class def analysis. 1260 if (tree.def != null) 1261 for (List<Type> l = tree.constructor.type.getThrownTypes(); 1262 l.nonEmpty(); 1263 l = l.tail) { 1264 caught = chk.incl(l.head, caught); 1265 } 1266 scan(tree.def); 1267 } 1268 finally { 1269 caught = caughtPrev; 1270 } 1271 } 1272 1273 @Override 1274 public void visitLambda(JCLambda tree) { 1275 if (tree.type != null && 1276 tree.type.isErroneous()) { 1277 return; 1278 } 1279 List<Type> prevCaught = caught; 1280 List<Type> prevThrown = thrown; 1281 ListBuffer<FlowPendingExit> prevPending = pendingExits; 1282 try { 1283 pendingExits = new ListBuffer<>(); 1284 caught = tree.getDescriptorType(types).getThrownTypes(); 1285 thrown = List.nil(); 1286 scan(tree.body); 1287 List<FlowPendingExit> exits = pendingExits.toList(); 1288 pendingExits = new ListBuffer<>(); 1289 while (exits.nonEmpty()) { 1290 FlowPendingExit exit = exits.head; 1291 exits = exits.tail; 1292 if (exit.thrown == null) { 1293 Assert.check(exit.tree.hasTag(RETURN)); 1294 } else { 1295 // uncaught throws will be reported later 1296 pendingExits.append(exit); 1297 } 1298 } 1299 1300 errorUncaught(); 1301 } finally { 1302 pendingExits = prevPending; 1303 caught = prevCaught; 1304 thrown = prevThrown; 1305 } 1306 } 1307 1308 /************************************************************************** 1309 * main method 1310 *************************************************************************/ 1311 1312 /** Perform definite assignment/unassignment analysis on a tree. 1313 */ 1314 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 1315 analyzeTree(env, env.tree, make); 1316 } 1317 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { 1318 try { 1319 attrEnv = env; 1320 Flow.this.make = make; 1321 pendingExits = new ListBuffer<>(); 1322 preciseRethrowTypes = new HashMap<>(); 1323 this.thrown = this.caught = null; 1324 this.classDef = null; 1325 scan(tree); 1326 } finally { 1327 pendingExits = null; 1328 Flow.this.make = null; 1329 this.thrown = this.caught = null; 1330 this.classDef = null; 1331 } 1332 } 1333 } 1334 1335 /** 1336 * Specialized pass that performs inference of thrown types for lambdas. 1337 */ 1338 class LambdaFlowAnalyzer extends FlowAnalyzer { 1339 List<Type> inferredThrownTypes; 1340 boolean inLambda; 1341 @Override 1342 public void visitLambda(JCLambda tree) { 1343 if ((tree.type != null && 1344 tree.type.isErroneous()) || inLambda) { 1345 return; 1346 } 1347 List<Type> prevCaught = caught; 1348 List<Type> prevThrown = thrown; 1349 ListBuffer<FlowPendingExit> prevPending = pendingExits; 1350 inLambda = true; 1351 try { 1352 pendingExits = new ListBuffer<>(); 1353 caught = List.of(syms.throwableType); 1354 thrown = List.nil(); 1355 scan(tree.body); 1356 inferredThrownTypes = thrown; 1357 } finally { 1358 pendingExits = prevPending; 1359 caught = prevCaught; 1360 thrown = prevThrown; 1361 inLambda = false; 1362 } 1363 } 1364 @Override 1365 public void visitClassDef(JCClassDecl tree) { 1366 //skip 1367 } 1368 } 1369 1370 /** 1371 * This pass implements (i) definite assignment analysis, which ensures that 1372 * each variable is assigned when used and (ii) definite unassignment analysis, 1373 * which ensures that no final variable is assigned more than once. This visitor 1374 * depends on the results of the liveliness analyzer. This pass is also used to mark 1375 * effectively-final local variables/parameters. 1376 */ 1377 1378 public abstract class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer<P>.AbstractAssignPendingExit> 1379 extends BaseAnalyzer<P> { 1380 1381 /** The set of definitely assigned variables. 1382 */ 1383 protected Bits inits; 1384 1385 /** The set of definitely unassigned variables. 1386 */ 1387 final Bits uninits; 1388 1389 /** The set of variables that are definitely unassigned everywhere 1390 * in current try block. This variable is maintained lazily; it is 1391 * updated only when something gets removed from uninits, 1392 * typically by being assigned in reachable code. To obtain the 1393 * correct set of variables which are definitely unassigned 1394 * anywhere in current try block, intersect uninitsTry and 1395 * uninits. 1396 */ 1397 final Bits uninitsTry; 1398 1399 /** When analyzing a condition, inits and uninits are null. 1400 * Instead we have: 1401 */ 1402 final Bits initsWhenTrue; 1403 final Bits initsWhenFalse; 1404 final Bits uninitsWhenTrue; 1405 final Bits uninitsWhenFalse; 1406 1407 /** A mapping from addresses to variable symbols. 1408 */ 1409 protected JCVariableDecl[] vardecls; 1410 1411 /** The current class being defined. 1412 */ 1413 JCClassDecl classDef; 1414 1415 /** The first variable sequence number in this class definition. 1416 */ 1417 int firstadr; 1418 1419 /** The next available variable sequence number. 1420 */ 1421 protected int nextadr; 1422 1423 /** The first variable sequence number in a block that can return. 1424 */ 1425 protected int returnadr; 1426 1427 /** The list of unreferenced automatic resources. 1428 */ 1429 WriteableScope unrefdResources; 1430 1431 /** Set when processing a loop body the second time for DU analysis. */ 1432 FlowKind flowKind = FlowKind.NORMAL; 1433 1434 /** The starting position of the analysed tree */ 1435 int startPos; 1436 1437 public class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit { 1438 1439 final Bits inits; 1440 final Bits uninits; 1441 final Bits exit_inits = new Bits(true); 1442 final Bits exit_uninits = new Bits(true); 1443 1444 public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { 1445 super(tree); 1446 this.inits = inits; 1447 this.uninits = uninits; 1448 this.exit_inits.assign(inits); 1449 this.exit_uninits.assign(uninits); 1450 } 1451 1452 @Override 1453 public void resolveJump(JCTree tree) { 1454 inits.andSet(exit_inits); 1455 uninits.andSet(exit_uninits); 1456 } 1457 } 1458 1459 public AbstractAssignAnalyzer() { 1460 this.inits = new Bits(); 1461 uninits = new Bits(); 1462 uninitsTry = new Bits(); 1463 initsWhenTrue = new Bits(true); 1464 initsWhenFalse = new Bits(true); 1465 uninitsWhenTrue = new Bits(true); 1466 uninitsWhenFalse = new Bits(true); 1467 } 1468 1469 private boolean isInitialConstructor = false; 1470 1471 @Override 1472 protected void markDead(JCTree tree) { 1473 if (!isInitialConstructor) { 1474 inits.inclRange(returnadr, nextadr); 1475 } else { 1476 for (int address = returnadr; address < nextadr; address++) { 1477 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) { 1478 inits.incl(address); 1479 } 1480 } 1481 } 1482 uninits.inclRange(returnadr, nextadr); 1483 } 1484 1485 /*-------------- Processing variables ----------------------*/ 1486 1487 /** Do we need to track init/uninit state of this symbol? 1488 * I.e. is symbol either a local or a blank final variable? 1489 */ 1490 protected boolean trackable(VarSymbol sym) { 1491 return 1492 sym.pos >= startPos && 1493 ((sym.owner.kind == MTH || 1494 isFinalUninitializedField(sym))); 1495 } 1496 1497 boolean isFinalUninitializedField(VarSymbol sym) { 1498 return sym.owner.kind == TYP && 1499 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL && 1500 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)); 1501 } 1502 1503 boolean isFinalUninitializedStaticField(VarSymbol sym) { 1504 return isFinalUninitializedField(sym) && sym.isStatic(); 1505 } 1506 1507 /** Initialize new trackable variable by setting its address field 1508 * to the next available sequence number and entering it under that 1509 * index into the vars array. 1510 */ 1511 void newVar(JCVariableDecl varDecl) { 1512 VarSymbol sym = varDecl.sym; 1513 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr); 1514 if ((sym.flags() & FINAL) == 0) { 1515 sym.flags_field |= EFFECTIVELY_FINAL; 1516 } 1517 sym.adr = nextadr; 1518 vardecls[nextadr] = varDecl; 1519 exclVarFromInits(varDecl, nextadr); 1520 uninits.incl(nextadr); 1521 nextadr++; 1522 } 1523 1524 protected void exclVarFromInits(JCTree tree, int adr) { 1525 inits.excl(adr); 1526 } 1527 1528 protected void assignToInits(JCTree tree, Bits bits) { 1529 inits.assign(bits); 1530 } 1531 1532 protected void andSetInits(JCTree tree, Bits bits) { 1533 inits.andSet(bits); 1534 } 1535 1536 protected void orSetInits(JCTree tree, Bits bits) { 1537 inits.orSet(bits); 1538 } 1539 1540 /** Record an initialization of a trackable variable. 1541 */ 1542 void letInit(DiagnosticPosition pos, VarSymbol sym) { 1543 if (sym.adr >= firstadr && trackable(sym)) { 1544 if (uninits.isMember(sym.adr)) { 1545 uninit(sym); 1546 } 1547 inits.incl(sym.adr); 1548 } 1549 } 1550 //where 1551 void uninit(VarSymbol sym) { 1552 if (!inits.isMember(sym.adr)) { 1553 // reachable assignment 1554 uninits.excl(sym.adr); 1555 uninitsTry.excl(sym.adr); 1556 } else { 1557 //log.rawWarning(pos, "unreachable assignment");//DEBUG 1558 uninits.excl(sym.adr); 1559 } 1560 } 1561 1562 /** If tree is either a simple name or of the form this.name or 1563 * C.this.name, and tree represents a trackable variable, 1564 * record an initialization of the variable. 1565 */ 1566 void letInit(JCTree tree) { 1567 tree = TreeInfo.skipParens(tree); 1568 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) { 1569 Symbol sym = TreeInfo.symbol(tree); 1570 if (sym.kind == VAR) { 1571 letInit(tree.pos(), (VarSymbol)sym); 1572 } 1573 } 1574 } 1575 1576 /** Check that trackable variable is initialized. 1577 */ 1578 void checkInit(DiagnosticPosition pos, VarSymbol sym) { 1579 checkInit(pos, sym, "var.might.not.have.been.initialized"); 1580 } 1581 1582 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {} 1583 1584 /** Utility method to reset several Bits instances. 1585 */ 1586 private void resetBits(Bits... bits) { 1587 for (Bits b : bits) { 1588 b.reset(); 1589 } 1590 } 1591 1592 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets 1593 */ 1594 void split(boolean setToNull) { 1595 initsWhenFalse.assign(inits); 1596 uninitsWhenFalse.assign(uninits); 1597 initsWhenTrue.assign(inits); 1598 uninitsWhenTrue.assign(uninits); 1599 if (setToNull) { 1600 resetBits(inits, uninits); 1601 } 1602 } 1603 1604 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. 1605 */ 1606 protected void merge(JCTree tree) { 1607 inits.assign(initsWhenFalse.andSet(initsWhenTrue)); 1608 uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); 1609 } 1610 1611 /* ************************************************************************ 1612 * Visitor methods for statements and definitions 1613 *************************************************************************/ 1614 1615 /** Analyze an expression. Make sure to set (un)inits rather than 1616 * (un)initsWhenTrue(WhenFalse) on exit. 1617 */ 1618 void scanExpr(JCTree tree) { 1619 if (tree != null) { 1620 scan(tree); 1621 if (inits.isReset()) { 1622 merge(tree); 1623 } 1624 } 1625 } 1626 1627 /** Analyze a list of expressions. 1628 */ 1629 void scanExprs(List<? extends JCExpression> trees) { 1630 if (trees != null) 1631 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail) 1632 scanExpr(l.head); 1633 } 1634 1635 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) 1636 * rather than (un)inits on exit. 1637 */ 1638 void scanCond(JCTree tree) { 1639 if (tree.type.isFalse()) { 1640 if (inits.isReset()) merge(tree); 1641 initsWhenTrue.assign(inits); 1642 initsWhenTrue.inclRange(firstadr, nextadr); 1643 uninitsWhenTrue.assign(uninits); 1644 uninitsWhenTrue.inclRange(firstadr, nextadr); 1645 initsWhenFalse.assign(inits); 1646 uninitsWhenFalse.assign(uninits); 1647 } else if (tree.type.isTrue()) { 1648 if (inits.isReset()) merge(tree); 1649 initsWhenFalse.assign(inits); 1650 initsWhenFalse.inclRange(firstadr, nextadr); 1651 uninitsWhenFalse.assign(uninits); 1652 uninitsWhenFalse.inclRange(firstadr, nextadr); 1653 initsWhenTrue.assign(inits); 1654 uninitsWhenTrue.assign(uninits); 1655 } else { 1656 scan(tree); 1657 if (!inits.isReset()) 1658 split(tree.type != syms.unknownType); 1659 } 1660 if (tree.type != syms.unknownType) { 1661 resetBits(inits, uninits); 1662 } 1663 } 1664 1665 /* ------------ Visitor methods for various sorts of trees -------------*/ 1666 1667 @Override 1668 public void visitClassDef(JCClassDecl tree) { 1669 if (tree.sym == null) { 1670 return; 1671 } 1672 1673 JCClassDecl classDefPrev = classDef; 1674 int firstadrPrev = firstadr; 1675 int nextadrPrev = nextadr; 1676 ListBuffer<P> pendingExitsPrev = pendingExits; 1677 1678 pendingExits = new ListBuffer<>(); 1679 if (tree.name != names.empty) { 1680 firstadr = nextadr; 1681 } 1682 classDef = tree; 1683 try { 1684 // define all the static fields 1685 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1686 if (l.head.hasTag(VARDEF)) { 1687 JCVariableDecl def = (JCVariableDecl)l.head; 1688 if ((def.mods.flags & STATIC) != 0) { 1689 VarSymbol sym = def.sym; 1690 if (trackable(sym)) { 1691 newVar(def); 1692 } 1693 } 1694 } 1695 } 1696 1697 // process all the static initializers 1698 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1699 if (!l.head.hasTag(METHODDEF) && 1700 (TreeInfo.flags(l.head) & STATIC) != 0) { 1701 scan(l.head); 1702 } 1703 } 1704 1705 // define all the instance fields 1706 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1707 if (l.head.hasTag(VARDEF)) { 1708 JCVariableDecl def = (JCVariableDecl)l.head; 1709 if ((def.mods.flags & STATIC) == 0) { 1710 VarSymbol sym = def.sym; 1711 if (trackable(sym)) { 1712 newVar(def); 1713 } 1714 } 1715 } 1716 } 1717 1718 // process all the instance initializers 1719 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1720 if (!l.head.hasTag(METHODDEF) && 1721 (TreeInfo.flags(l.head) & STATIC) == 0) { 1722 scan(l.head); 1723 } 1724 } 1725 1726 // process all the methods 1727 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1728 if (l.head.hasTag(METHODDEF)) { 1729 scan(l.head); 1730 } 1731 } 1732 } finally { 1733 pendingExits = pendingExitsPrev; 1734 nextadr = nextadrPrev; 1735 firstadr = firstadrPrev; 1736 classDef = classDefPrev; 1737 } 1738 } 1739 1740 @Override 1741 public void visitMethodDef(JCMethodDecl tree) { 1742 if (tree.body == null) { 1743 return; 1744 } 1745 /* Ignore synthetic methods, except for translated lambda methods. 1746 */ 1747 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) { 1748 return; 1749 } 1750 1751 final Bits initsPrev = new Bits(inits); 1752 final Bits uninitsPrev = new Bits(uninits); 1753 int nextadrPrev = nextadr; 1754 int firstadrPrev = firstadr; 1755 int returnadrPrev = returnadr; 1756 1757 Assert.check(pendingExits.isEmpty()); 1758 boolean lastInitialConstructor = isInitialConstructor; 1759 try { 1760 isInitialConstructor = TreeInfo.isInitialConstructor(tree); 1761 1762 if (!isInitialConstructor) { 1763 firstadr = nextadr; 1764 } 1765 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 1766 JCVariableDecl def = l.head; 1767 scan(def); 1768 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); 1769 /* If we are executing the code from Gen, then there can be 1770 * synthetic or mandated variables, ignore them. 1771 */ 1772 initParam(def); 1773 } 1774 // else we are in an instance initializer block; 1775 // leave caught unchanged. 1776 scan(tree.body); 1777 1778 if (isInitialConstructor) { 1779 boolean isSynthesized = (tree.sym.flags() & 1780 GENERATEDCONSTR) != 0; 1781 for (int i = firstadr; i < nextadr; i++) { 1782 JCVariableDecl vardecl = vardecls[i]; 1783 VarSymbol var = vardecl.sym; 1784 if (var.owner == classDef.sym) { 1785 // choose the diagnostic position based on whether 1786 // the ctor is default(synthesized) or not 1787 if (isSynthesized) { 1788 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), 1789 var, "var.not.initialized.in.default.constructor"); 1790 } else { 1791 checkInit(TreeInfo.diagEndPos(tree.body), var); 1792 } 1793 } 1794 } 1795 } 1796 List<P> exits = pendingExits.toList(); 1797 pendingExits = new ListBuffer<>(); 1798 while (exits.nonEmpty()) { 1799 P exit = exits.head; 1800 exits = exits.tail; 1801 Assert.check(exit.tree.hasTag(RETURN), exit.tree); 1802 if (isInitialConstructor) { 1803 assignToInits(exit.tree, exit.exit_inits); 1804 for (int i = firstadr; i < nextadr; i++) { 1805 checkInit(exit.tree.pos(), vardecls[i].sym); 1806 } 1807 } 1808 } 1809 } finally { 1810 assignToInits(tree, initsPrev); 1811 uninits.assign(uninitsPrev); 1812 nextadr = nextadrPrev; 1813 firstadr = firstadrPrev; 1814 returnadr = returnadrPrev; 1815 isInitialConstructor = lastInitialConstructor; 1816 } 1817 } 1818 1819 protected void initParam(JCVariableDecl def) { 1820 inits.incl(def.sym.adr); 1821 uninits.excl(def.sym.adr); 1822 } 1823 1824 public void visitVarDef(JCVariableDecl tree) { 1825 boolean track = trackable(tree.sym); 1826 if (track && tree.sym.owner.kind == MTH) { 1827 newVar(tree); 1828 } 1829 if (tree.init != null) { 1830 scanExpr(tree.init); 1831 if (track) { 1832 letInit(tree.pos(), tree.sym); 1833 } 1834 } 1835 } 1836 1837 public void visitBlock(JCBlock tree) { 1838 int nextadrPrev = nextadr; 1839 scan(tree.stats); 1840 nextadr = nextadrPrev; 1841 } 1842 1843 int getLogNumberOfErrors() { 1844 return 0; 1845 } 1846 1847 public void visitDoLoop(JCDoWhileLoop tree) { 1848 ListBuffer<P> prevPendingExits = pendingExits; 1849 FlowKind prevFlowKind = flowKind; 1850 flowKind = FlowKind.NORMAL; 1851 final Bits initsSkip = new Bits(true); 1852 final Bits uninitsSkip = new Bits(true); 1853 pendingExits = new ListBuffer<>(); 1854 int prevErrors = getLogNumberOfErrors(); 1855 do { 1856 final Bits uninitsEntry = new Bits(uninits); 1857 uninitsEntry.excludeFrom(nextadr); 1858 scan(tree.body); 1859 resolveContinues(tree); 1860 scanCond(tree.cond); 1861 if (!flowKind.isFinal()) { 1862 initsSkip.assign(initsWhenFalse); 1863 uninitsSkip.assign(uninitsWhenFalse); 1864 } 1865 if (getLogNumberOfErrors() != prevErrors || 1866 flowKind.isFinal() || 1867 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) 1868 break; 1869 assignToInits(tree.cond, initsWhenTrue); 1870 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); 1871 flowKind = FlowKind.SPECULATIVE_LOOP; 1872 } while (true); 1873 flowKind = prevFlowKind; 1874 assignToInits(tree, initsSkip); 1875 uninits.assign(uninitsSkip); 1876 resolveBreaks(tree, prevPendingExits); 1877 } 1878 1879 public void visitWhileLoop(JCWhileLoop tree) { 1880 ListBuffer<P> prevPendingExits = pendingExits; 1881 FlowKind prevFlowKind = flowKind; 1882 flowKind = FlowKind.NORMAL; 1883 final Bits initsSkip = new Bits(true); 1884 final Bits uninitsSkip = new Bits(true); 1885 pendingExits = new ListBuffer<>(); 1886 int prevErrors = getLogNumberOfErrors(); 1887 final Bits uninitsEntry = new Bits(uninits); 1888 uninitsEntry.excludeFrom(nextadr); 1889 do { 1890 scanCond(tree.cond); 1891 if (!flowKind.isFinal()) { 1892 initsSkip.assign(initsWhenFalse) ; 1893 uninitsSkip.assign(uninitsWhenFalse); 1894 } 1895 assignToInits(tree, initsWhenTrue); 1896 uninits.assign(uninitsWhenTrue); 1897 scan(tree.body); 1898 resolveContinues(tree); 1899 if (getLogNumberOfErrors() != prevErrors || 1900 flowKind.isFinal() || 1901 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) { 1902 break; 1903 } 1904 uninits.assign(uninitsEntry.andSet(uninits)); 1905 flowKind = FlowKind.SPECULATIVE_LOOP; 1906 } while (true); 1907 flowKind = prevFlowKind; 1908 //a variable is DA/DU after the while statement, if it's DA/DU assuming the 1909 //branch is not taken AND if it's DA/DU before any break statement 1910 assignToInits(tree.body, initsSkip); 1911 uninits.assign(uninitsSkip); 1912 resolveBreaks(tree, prevPendingExits); 1913 } 1914 1915 public void visitForLoop(JCForLoop tree) { 1916 ListBuffer<P> prevPendingExits = pendingExits; 1917 FlowKind prevFlowKind = flowKind; 1918 flowKind = FlowKind.NORMAL; 1919 int nextadrPrev = nextadr; 1920 scan(tree.init); 1921 final Bits initsSkip = new Bits(true); 1922 final Bits uninitsSkip = new Bits(true); 1923 pendingExits = new ListBuffer<>(); 1924 int prevErrors = getLogNumberOfErrors(); 1925 do { 1926 final Bits uninitsEntry = new Bits(uninits); 1927 uninitsEntry.excludeFrom(nextadr); 1928 if (tree.cond != null) { 1929 scanCond(tree.cond); 1930 if (!flowKind.isFinal()) { 1931 initsSkip.assign(initsWhenFalse); 1932 uninitsSkip.assign(uninitsWhenFalse); 1933 } 1934 assignToInits(tree.body, initsWhenTrue); 1935 uninits.assign(uninitsWhenTrue); 1936 } else if (!flowKind.isFinal()) { 1937 initsSkip.assign(inits); 1938 initsSkip.inclRange(firstadr, nextadr); 1939 uninitsSkip.assign(uninits); 1940 uninitsSkip.inclRange(firstadr, nextadr); 1941 } 1942 scan(tree.body); 1943 resolveContinues(tree); 1944 scan(tree.step); 1945 if (getLogNumberOfErrors() != prevErrors || 1946 flowKind.isFinal() || 1947 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) 1948 break; 1949 uninits.assign(uninitsEntry.andSet(uninits)); 1950 flowKind = FlowKind.SPECULATIVE_LOOP; 1951 } while (true); 1952 flowKind = prevFlowKind; 1953 //a variable is DA/DU after a for loop, if it's DA/DU assuming the 1954 //branch is not taken AND if it's DA/DU before any break statement 1955 assignToInits(tree.body, initsSkip); 1956 uninits.assign(uninitsSkip); 1957 resolveBreaks(tree, prevPendingExits); 1958 nextadr = nextadrPrev; 1959 } 1960 1961 public void visitForeachLoop(JCEnhancedForLoop tree) { 1962 visitVarDef(tree.var); 1963 1964 ListBuffer<P> prevPendingExits = pendingExits; 1965 FlowKind prevFlowKind = flowKind; 1966 flowKind = FlowKind.NORMAL; 1967 int nextadrPrev = nextadr; 1968 scan(tree.expr); 1969 final Bits initsStart = new Bits(inits); 1970 final Bits uninitsStart = new Bits(uninits); 1971 1972 letInit(tree.pos(), tree.var.sym); 1973 pendingExits = new ListBuffer<>(); 1974 int prevErrors = getLogNumberOfErrors(); 1975 do { 1976 final Bits uninitsEntry = new Bits(uninits); 1977 uninitsEntry.excludeFrom(nextadr); 1978 scan(tree.body); 1979 resolveContinues(tree); 1980 if (getLogNumberOfErrors() != prevErrors || 1981 flowKind.isFinal() || 1982 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) 1983 break; 1984 uninits.assign(uninitsEntry.andSet(uninits)); 1985 flowKind = FlowKind.SPECULATIVE_LOOP; 1986 } while (true); 1987 flowKind = prevFlowKind; 1988 assignToInits(tree.body, initsStart); 1989 uninits.assign(uninitsStart.andSet(uninits)); 1990 resolveBreaks(tree, prevPendingExits); 1991 nextadr = nextadrPrev; 1992 } 1993 1994 public void visitLabelled(JCLabeledStatement tree) { 1995 ListBuffer<P> prevPendingExits = pendingExits; 1996 pendingExits = new ListBuffer<>(); 1997 scan(tree.body); 1998 resolveBreaks(tree, prevPendingExits); 1999 } 2000 2001 public void visitSwitch(JCSwitch tree) { 2002 ListBuffer<P> prevPendingExits = pendingExits; 2003 pendingExits = new ListBuffer<>(); 2004 int nextadrPrev = nextadr; 2005 scanExpr(tree.selector); 2006 final Bits initsSwitch = new Bits(inits); 2007 final Bits uninitsSwitch = new Bits(uninits); 2008 boolean hasDefault = false; 2009 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 2010 assignToInits(l.head, initsSwitch); 2011 uninits.assign(uninits.andSet(uninitsSwitch)); 2012 JCCase c = l.head; 2013 if (c.pat == null) { 2014 hasDefault = true; 2015 } else { 2016 scanExpr(c.pat); 2017 } 2018 if (hasDefault) { 2019 assignToInits(null, initsSwitch); 2020 uninits.assign(uninits.andSet(uninitsSwitch)); 2021 } 2022 scan(c.stats); 2023 addVars(c.stats, initsSwitch, uninitsSwitch); 2024 if (!hasDefault) { 2025 assignToInits(l.head.stats.last(), initsSwitch); 2026 uninits.assign(uninits.andSet(uninitsSwitch)); 2027 } 2028 // Warn about fall-through if lint switch fallthrough enabled. 2029 } 2030 if (!hasDefault) { 2031 andSetInits(null, initsSwitch); 2032 } 2033 resolveBreaks(tree, prevPendingExits); 2034 nextadr = nextadrPrev; 2035 } 2036 // where 2037 /** Add any variables defined in stats to inits and uninits. */ 2038 private void addVars(List<JCStatement> stats, final Bits inits, 2039 final Bits uninits) { 2040 for (;stats.nonEmpty(); stats = stats.tail) { 2041 JCTree stat = stats.head; 2042 if (stat.hasTag(VARDEF)) { 2043 int adr = ((JCVariableDecl) stat).sym.adr; 2044 inits.excl(adr); 2045 uninits.incl(adr); 2046 } 2047 } 2048 } 2049 2050 boolean isEnabled(Lint.LintCategory lc) { 2051 return false; 2052 } 2053 2054 void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {} 2055 2056 public void visitTry(JCTry tree) { 2057 ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>(); 2058 final Bits uninitsTryPrev = new Bits(uninitsTry); 2059 ListBuffer<P> prevPendingExits = pendingExits; 2060 pendingExits = new ListBuffer<>(); 2061 final Bits initsTry = new Bits(inits); 2062 uninitsTry.assign(uninits); 2063 for (JCTree resource : tree.resources) { 2064 if (resource instanceof JCVariableDecl) { 2065 JCVariableDecl vdecl = (JCVariableDecl) resource; 2066 visitVarDef(vdecl); 2067 unrefdResources.enter(vdecl.sym); 2068 resourceVarDecls.append(vdecl); 2069 } else if (resource instanceof JCExpression) { 2070 scanExpr((JCExpression) resource); 2071 } else { 2072 throw new AssertionError(tree); // parser error 2073 } 2074 } 2075 scan(tree.body); 2076 uninitsTry.andSet(uninits); 2077 final Bits initsEnd = new Bits(inits); 2078 final Bits uninitsEnd = new Bits(uninits); 2079 int nextadrCatch = nextadr; 2080 2081 if (!resourceVarDecls.isEmpty() && 2082 isEnabled(Lint.LintCategory.TRY)) { 2083 for (JCVariableDecl resVar : resourceVarDecls) { 2084 if (unrefdResources.includes(resVar.sym)) { 2085 reportWarning(Lint.LintCategory.TRY, resVar.pos(), 2086 "try.resource.not.referenced", resVar.sym); 2087 unrefdResources.remove(resVar.sym); 2088 } 2089 } 2090 } 2091 2092 /* The analysis of each catch should be independent. 2093 * Each one should have the same initial values of inits and 2094 * uninits. 2095 */ 2096 final Bits initsCatchPrev = new Bits(initsTry); 2097 final Bits uninitsCatchPrev = new Bits(uninitsTry); 2098 2099 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 2100 JCVariableDecl param = l.head.param; 2101 assignToInits(tree.body, initsCatchPrev); 2102 uninits.assign(uninitsCatchPrev); 2103 scan(param); 2104 /* If this is a TWR and we are executing the code from Gen, 2105 * then there can be synthetic variables, ignore them. 2106 */ 2107 initParam(param); 2108 scan(l.head.body); 2109 initsEnd.andSet(inits); 2110 uninitsEnd.andSet(uninits); 2111 nextadr = nextadrCatch; 2112 } 2113 if (tree.finalizer != null) { 2114 assignToInits(tree.finalizer, initsTry); 2115 uninits.assign(uninitsTry); 2116 ListBuffer<P> exits = pendingExits; 2117 pendingExits = prevPendingExits; 2118 scan(tree.finalizer); 2119 if (!tree.finallyCanCompleteNormally) { 2120 // discard exits and exceptions from try and finally 2121 } else { 2122 uninits.andSet(uninitsEnd); 2123 // FIX: this doesn't preserve source order of exits in catch 2124 // versus finally! 2125 while (exits.nonEmpty()) { 2126 P exit = exits.next(); 2127 if (exit.exit_inits != null) { 2128 exit.exit_inits.orSet(inits); 2129 exit.exit_uninits.andSet(uninits); 2130 } 2131 pendingExits.append(exit); 2132 } 2133 orSetInits(tree, initsEnd); 2134 } 2135 } else { 2136 assignToInits(tree, initsEnd); 2137 uninits.assign(uninitsEnd); 2138 ListBuffer<P> exits = pendingExits; 2139 pendingExits = prevPendingExits; 2140 while (exits.nonEmpty()) pendingExits.append(exits.next()); 2141 } 2142 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); 2143 } 2144 2145 public void visitConditional(JCConditional tree) { 2146 scanCond(tree.cond); 2147 final Bits initsBeforeElse = new Bits(initsWhenFalse); 2148 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); 2149 assignToInits(tree.cond, initsWhenTrue); 2150 uninits.assign(uninitsWhenTrue); 2151 if (tree.truepart.type.hasTag(BOOLEAN) && 2152 tree.falsepart.type.hasTag(BOOLEAN)) { 2153 // if b and c are boolean valued, then 2154 // v is (un)assigned after a?b:c when true iff 2155 // v is (un)assigned after b when true and 2156 // v is (un)assigned after c when true 2157 scanCond(tree.truepart); 2158 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); 2159 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); 2160 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); 2161 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); 2162 assignToInits(tree.truepart, initsBeforeElse); 2163 uninits.assign(uninitsBeforeElse); 2164 scanCond(tree.falsepart); 2165 initsWhenTrue.andSet(initsAfterThenWhenTrue); 2166 initsWhenFalse.andSet(initsAfterThenWhenFalse); 2167 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); 2168 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); 2169 } else { 2170 scanExpr(tree.truepart); 2171 final Bits initsAfterThen = new Bits(inits); 2172 final Bits uninitsAfterThen = new Bits(uninits); 2173 assignToInits(tree.truepart, initsBeforeElse); 2174 uninits.assign(uninitsBeforeElse); 2175 scanExpr(tree.falsepart); 2176 andSetInits(tree.falsepart, initsAfterThen); 2177 uninits.andSet(uninitsAfterThen); 2178 } 2179 } 2180 2181 public void visitIf(JCIf tree) { 2182 scanCond(tree.cond); 2183 final Bits initsBeforeElse = new Bits(initsWhenFalse); 2184 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); 2185 assignToInits(tree.cond, initsWhenTrue); 2186 uninits.assign(uninitsWhenTrue); 2187 scan(tree.thenpart); 2188 if (tree.elsepart != null) { 2189 final Bits initsAfterThen = new Bits(inits); 2190 final Bits uninitsAfterThen = new Bits(uninits); 2191 assignToInits(tree.thenpart, initsBeforeElse); 2192 uninits.assign(uninitsBeforeElse); 2193 scan(tree.elsepart); 2194 andSetInits(tree.elsepart, initsAfterThen); 2195 uninits.andSet(uninitsAfterThen); 2196 } else { 2197 andSetInits(tree.thenpart, initsBeforeElse); 2198 uninits.andSet(uninitsBeforeElse); 2199 } 2200 } 2201 2202 protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) { 2203 return null; 2204 } 2205 2206 @Override 2207 public void visitBreak(JCBreak tree) { 2208 recordExit(tree, createNewPendingExit(tree, inits, uninits)); 2209 } 2210 2211 @Override 2212 public void visitContinue(JCContinue tree) { 2213 recordExit(tree, createNewPendingExit(tree, inits, uninits)); 2214 } 2215 2216 @Override 2217 public void visitReturn(JCReturn tree) { 2218 scanExpr(tree.expr); 2219 recordExit(tree, createNewPendingExit(tree, inits, uninits)); 2220 } 2221 2222 public void visitThrow(JCThrow tree) { 2223 scanExpr(tree.expr); 2224 markDead(tree.expr); 2225 } 2226 2227 public void visitApply(JCMethodInvocation tree) { 2228 scanExpr(tree.meth); 2229 scanExprs(tree.args); 2230 } 2231 2232 public void visitNewClass(JCNewClass tree) { 2233 scanExpr(tree.encl); 2234 scanExprs(tree.args); 2235 scan(tree.def); 2236 } 2237 2238 @Override 2239 public void visitLambda(JCLambda tree) { 2240 final Bits prevUninits = new Bits(uninits); 2241 final Bits prevInits = new Bits(inits); 2242 int returnadrPrev = returnadr; 2243 ListBuffer<P> prevPending = pendingExits; 2244 try { 2245 returnadr = nextadr; 2246 pendingExits = new ListBuffer<>(); 2247 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 2248 JCVariableDecl def = l.head; 2249 scan(def); 2250 inits.incl(def.sym.adr); 2251 uninits.excl(def.sym.adr); 2252 } 2253 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) { 2254 scanExpr(tree.body); 2255 } else { 2256 scan(tree.body); 2257 } 2258 } 2259 finally { 2260 returnadr = returnadrPrev; 2261 uninits.assign(prevUninits); 2262 assignToInits(tree, prevInits); 2263 pendingExits = prevPending; 2264 } 2265 } 2266 2267 public void visitNewArray(JCNewArray tree) { 2268 scanExprs(tree.dims); 2269 scanExprs(tree.elems); 2270 } 2271 2272 public void visitAssert(JCAssert tree) { 2273 final Bits initsExit = new Bits(inits); 2274 final Bits uninitsExit = new Bits(uninits); 2275 scanCond(tree.cond); 2276 uninitsExit.andSet(uninitsWhenTrue); 2277 if (tree.detail != null) { 2278 assignToInits(tree, initsWhenFalse); 2279 uninits.assign(uninitsWhenFalse); 2280 scanExpr(tree.detail); 2281 } 2282 assignToInits(tree, initsExit); 2283 uninits.assign(uninitsExit); 2284 } 2285 2286 public void visitAssign(JCAssign tree) { 2287 JCTree lhs = TreeInfo.skipParens(tree.lhs); 2288 if (!isIdentOrThisDotIdent(lhs)) 2289 scanExpr(lhs); 2290 scanExpr(tree.rhs); 2291 letInit(lhs); 2292 } 2293 private boolean isIdentOrThisDotIdent(JCTree lhs) { 2294 if (lhs.hasTag(IDENT)) 2295 return true; 2296 if (!lhs.hasTag(SELECT)) 2297 return false; 2298 2299 JCFieldAccess fa = (JCFieldAccess)lhs; 2300 return fa.selected.hasTag(IDENT) && 2301 ((JCIdent)fa.selected).name == names._this; 2302 } 2303 2304 // check fields accessed through this.<field> are definitely 2305 // assigned before reading their value 2306 public void visitSelect(JCFieldAccess tree) { 2307 super.visitSelect(tree); 2308 if (enforceThisDotInit && 2309 tree.selected.hasTag(IDENT) && 2310 ((JCIdent)tree.selected).name == names._this && 2311 tree.sym.kind == VAR) 2312 { 2313 checkInit(tree.pos(), (VarSymbol)tree.sym); 2314 } 2315 } 2316 2317 public void visitAssignop(JCAssignOp tree) { 2318 scanExpr(tree.lhs); 2319 scanExpr(tree.rhs); 2320 letInit(tree.lhs); 2321 } 2322 2323 public void visitUnary(JCUnary tree) { 2324 switch (tree.getTag()) { 2325 case NOT: 2326 scanCond(tree.arg); 2327 final Bits t = new Bits(initsWhenFalse); 2328 initsWhenFalse.assign(initsWhenTrue); 2329 initsWhenTrue.assign(t); 2330 t.assign(uninitsWhenFalse); 2331 uninitsWhenFalse.assign(uninitsWhenTrue); 2332 uninitsWhenTrue.assign(t); 2333 break; 2334 case PREINC: case POSTINC: 2335 case PREDEC: case POSTDEC: 2336 scanExpr(tree.arg); 2337 letInit(tree.arg); 2338 break; 2339 default: 2340 scanExpr(tree.arg); 2341 } 2342 } 2343 2344 public void visitBinary(JCBinary tree) { 2345 switch (tree.getTag()) { 2346 case AND: 2347 scanCond(tree.lhs); 2348 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); 2349 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); 2350 assignToInits(tree.lhs, initsWhenTrue); 2351 uninits.assign(uninitsWhenTrue); 2352 scanCond(tree.rhs); 2353 initsWhenFalse.andSet(initsWhenFalseLeft); 2354 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); 2355 break; 2356 case OR: 2357 scanCond(tree.lhs); 2358 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); 2359 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); 2360 assignToInits(tree.lhs, initsWhenFalse); 2361 uninits.assign(uninitsWhenFalse); 2362 scanCond(tree.rhs); 2363 initsWhenTrue.andSet(initsWhenTrueLeft); 2364 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); 2365 break; 2366 default: 2367 scanExpr(tree.lhs); 2368 scanExpr(tree.rhs); 2369 } 2370 } 2371 2372 public void visitIdent(JCIdent tree) { 2373 if (tree.sym.kind == VAR) { 2374 checkInit(tree.pos(), (VarSymbol)tree.sym); 2375 referenced(tree.sym); 2376 } 2377 } 2378 2379 void referenced(Symbol sym) { 2380 unrefdResources.remove(sym); 2381 } 2382 2383 public void visitAnnotatedType(JCAnnotatedType tree) { 2384 // annotations don't get scanned 2385 tree.underlyingType.accept(this); 2386 } 2387 2388 /************************************************************************** 2389 * main method 2390 *************************************************************************/ 2391 2392 /** Perform definite assignment/unassignment analysis on a tree. 2393 */ 2394 public void analyzeTree(Env<?> env) { 2395 analyzeTree(env, env.tree); 2396 } 2397 2398 public void analyzeTree(Env<?> env, JCTree tree) { 2399 try { 2400 startPos = tree.pos().getStartPosition(); 2401 2402 if (vardecls == null) 2403 vardecls = new JCVariableDecl[32]; 2404 else 2405 for (int i=0; i<vardecls.length; i++) 2406 vardecls[i] = null; 2407 firstadr = 0; 2408 nextadr = 0; 2409 pendingExits = new ListBuffer<>(); 2410 this.classDef = null; 2411 unrefdResources = WriteableScope.create(env.enclClass.sym); 2412 scan(tree); 2413 } finally { 2414 // note that recursive invocations of this method fail hard 2415 startPos = -1; 2416 resetBits(inits, uninits, uninitsTry, initsWhenTrue, 2417 initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse); 2418 if (vardecls != null) { 2419 for (int i=0; i<vardecls.length; i++) 2420 vardecls[i] = null; 2421 } 2422 firstadr = 0; 2423 nextadr = 0; 2424 pendingExits = null; 2425 this.classDef = null; 2426 unrefdResources = null; 2427 } 2428 } 2429 } 2430 2431 public class AssignAnalyzer extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> { 2432 2433 public class AssignPendingExit extends AbstractAssignAnalyzer<AssignPendingExit>.AbstractAssignPendingExit { 2434 2435 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { 2436 super(tree, inits, uninits); 2437 } 2438 } 2439 2440 @Override 2441 protected AssignPendingExit createNewPendingExit(JCTree tree, 2442 Bits inits, Bits uninits) { 2443 return new AssignPendingExit(tree, inits, uninits); 2444 } 2445 2446 /** Record an initialization of a trackable variable. 2447 */ 2448 @Override 2449 void letInit(DiagnosticPosition pos, VarSymbol sym) { 2450 if (sym.adr >= firstadr && trackable(sym)) { 2451 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) { 2452 if (!uninits.isMember(sym.adr)) { 2453 //assignment targeting an effectively final variable 2454 //makes the variable lose its status of effectively final 2455 //if the variable is _not_ definitively unassigned 2456 sym.flags_field &= ~EFFECTIVELY_FINAL; 2457 } else { 2458 uninit(sym); 2459 } 2460 } 2461 else if ((sym.flags() & FINAL) != 0) { 2462 if ((sym.flags() & PARAMETER) != 0) { 2463 if ((sym.flags() & UNION) != 0) { //multi-catch parameter 2464 log.error(pos, "multicatch.parameter.may.not.be.assigned", sym); 2465 } 2466 else { 2467 log.error(pos, "final.parameter.may.not.be.assigned", 2468 sym); 2469 } 2470 } else if (!uninits.isMember(sym.adr)) { 2471 log.error(pos, flowKind.errKey, sym); 2472 } else { 2473 uninit(sym); 2474 } 2475 } 2476 inits.incl(sym.adr); 2477 } else if ((sym.flags() & FINAL) != 0) { 2478 log.error(pos, "var.might.already.be.assigned", sym); 2479 } 2480 } 2481 2482 @Override 2483 void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) { 2484 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && 2485 trackable(sym) && 2486 !inits.isMember(sym.adr)) { 2487 log.error(pos, errkey, sym); 2488 inits.incl(sym.adr); 2489 } 2490 } 2491 2492 @Override 2493 void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, 2494 String key, Object ... args) { 2495 log.warning(lc, pos, key, args); 2496 } 2497 2498 @Override 2499 int getLogNumberOfErrors() { 2500 return log.nerrors; 2501 } 2502 2503 @Override 2504 boolean isEnabled(Lint.LintCategory lc) { 2505 return lint.isEnabled(lc); 2506 } 2507 2508 @Override 2509 public void visitClassDef(JCClassDecl tree) { 2510 if (tree.sym == null) { 2511 return; 2512 } 2513 2514 Lint lintPrev = lint; 2515 lint = lint.augment(tree.sym); 2516 try { 2517 super.visitClassDef(tree); 2518 } finally { 2519 lint = lintPrev; 2520 } 2521 } 2522 2523 @Override 2524 public void visitMethodDef(JCMethodDecl tree) { 2525 if (tree.body == null) { 2526 return; 2527 } 2528 2529 /* MemberEnter can generate synthetic methods ignore them 2530 */ 2531 if ((tree.sym.flags() & SYNTHETIC) != 0) { 2532 return; 2533 } 2534 2535 Lint lintPrev = lint; 2536 lint = lint.augment(tree.sym); 2537 try { 2538 super.visitMethodDef(tree); 2539 } finally { 2540 lint = lintPrev; 2541 } 2542 } 2543 2544 @Override 2545 public void visitVarDef(JCVariableDecl tree) { 2546 if (tree.init == null) { 2547 super.visitVarDef(tree); 2548 } else { 2549 Lint lintPrev = lint; 2550 lint = lint.augment(tree.sym); 2551 try{ 2552 super.visitVarDef(tree); 2553 } finally { 2554 lint = lintPrev; 2555 } 2556 } 2557 } 2558 2559 } 2560 2561 /** 2562 * This pass implements the last step of the dataflow analysis, namely 2563 * the effectively-final analysis check. This checks that every local variable 2564 * reference from a lambda body/local inner class is either final or effectively final. 2565 * As effectively final variables are marked as such during DA/DU, this pass must run after 2566 * AssignAnalyzer. 2567 */ 2568 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { 2569 2570 JCTree currentTree; //local class or lambda 2571 2572 @Override 2573 void markDead(JCTree tree) { 2574 //do nothing 2575 } 2576 2577 @SuppressWarnings("fallthrough") 2578 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { 2579 if (currentTree != null && 2580 sym.owner.kind == MTH && 2581 sym.pos < currentTree.getStartPosition()) { 2582 switch (currentTree.getTag()) { 2583 case CLASSDEF: 2584 if (!allowEffectivelyFinalInInnerClasses) { 2585 if ((sym.flags() & FINAL) == 0) { 2586 reportInnerClsNeedsFinalError(pos, sym); 2587 } 2588 break; 2589 } 2590 case LAMBDA: 2591 if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) { 2592 reportEffectivelyFinalError(pos, sym); 2593 } 2594 } 2595 } 2596 } 2597 2598 @SuppressWarnings("fallthrough") 2599 void letInit(JCTree tree) { 2600 tree = TreeInfo.skipParens(tree); 2601 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) { 2602 Symbol sym = TreeInfo.symbol(tree); 2603 if (currentTree != null && 2604 sym.kind == VAR && 2605 sym.owner.kind == MTH && 2606 ((VarSymbol)sym).pos < currentTree.getStartPosition()) { 2607 switch (currentTree.getTag()) { 2608 case CLASSDEF: 2609 if (!allowEffectivelyFinalInInnerClasses) { 2610 reportInnerClsNeedsFinalError(tree, sym); 2611 break; 2612 } 2613 case LAMBDA: 2614 reportEffectivelyFinalError(tree, sym); 2615 } 2616 } 2617 } 2618 } 2619 2620 void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { 2621 String subKey = currentTree.hasTag(LAMBDA) ? 2622 "lambda" : "inner.cls"; 2623 log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey)); 2624 } 2625 2626 void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) { 2627 log.error(pos, 2628 "local.var.accessed.from.icls.needs.final", 2629 sym); 2630 } 2631 2632 /************************************************************************* 2633 * Visitor methods for statements and definitions 2634 *************************************************************************/ 2635 2636 /* ------------ Visitor methods for various sorts of trees -------------*/ 2637 2638 public void visitClassDef(JCClassDecl tree) { 2639 JCTree prevTree = currentTree; 2640 try { 2641 currentTree = tree.sym.isLocal() ? tree : null; 2642 super.visitClassDef(tree); 2643 } finally { 2644 currentTree = prevTree; 2645 } 2646 } 2647 2648 @Override 2649 public void visitLambda(JCLambda tree) { 2650 JCTree prevTree = currentTree; 2651 try { 2652 currentTree = tree; 2653 super.visitLambda(tree); 2654 } finally { 2655 currentTree = prevTree; 2656 } 2657 } 2658 2659 @Override 2660 public void visitIdent(JCIdent tree) { 2661 if (tree.sym.kind == VAR) { 2662 checkEffectivelyFinal(tree, (VarSymbol)tree.sym); 2663 } 2664 } 2665 2666 public void visitAssign(JCAssign tree) { 2667 JCTree lhs = TreeInfo.skipParens(tree.lhs); 2668 if (!(lhs instanceof JCIdent)) { 2669 scan(lhs); 2670 } 2671 scan(tree.rhs); 2672 letInit(lhs); 2673 } 2674 2675 public void visitAssignop(JCAssignOp tree) { 2676 scan(tree.lhs); 2677 scan(tree.rhs); 2678 letInit(tree.lhs); 2679 } 2680 2681 public void visitUnary(JCUnary tree) { 2682 switch (tree.getTag()) { 2683 case PREINC: case POSTINC: 2684 case PREDEC: case POSTDEC: 2685 scan(tree.arg); 2686 letInit(tree.arg); 2687 break; 2688 default: 2689 scan(tree.arg); 2690 } 2691 } 2692 2693 /************************************************************************** 2694 * main method 2695 *************************************************************************/ 2696 2697 /** Perform definite assignment/unassignment analysis on a tree. 2698 */ 2699 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 2700 analyzeTree(env, env.tree, make); 2701 } 2702 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { 2703 try { 2704 attrEnv = env; 2705 Flow.this.make = make; 2706 pendingExits = new ListBuffer<>(); 2707 scan(tree); 2708 } finally { 2709 pendingExits = null; 2710 Flow.this.make = null; 2711 } 2712 } 2713 } 2714} 2715