195 private Env<AttrContext> attrEnv; |
195 private Env<AttrContext> attrEnv; |
196 private Lint lint; |
196 private Lint lint; |
197 private final boolean allowImprovedRethrowAnalysis; |
197 private final boolean allowImprovedRethrowAnalysis; |
198 private final boolean allowImprovedCatchAnalysis; |
198 private final boolean allowImprovedCatchAnalysis; |
199 private final boolean allowEffectivelyFinalInInnerClasses; |
199 private final boolean allowEffectivelyFinalInInnerClasses; |
|
200 private final boolean enforceThisDotInit; |
200 |
201 |
201 public static Flow instance(Context context) { |
202 public static Flow instance(Context context) { |
202 Flow instance = context.get(flowKey); |
203 Flow instance = context.get(flowKey); |
203 if (instance == null) |
204 if (instance == null) |
204 instance = new Flow(context); |
205 instance = new Flow(context); |
205 return instance; |
206 return instance; |
206 } |
207 } |
207 |
208 |
208 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { |
209 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { |
209 new AliveAnalyzer().analyzeTree(env, make); |
210 new AliveAnalyzer().analyzeTree(env, make); |
210 new AssignAnalyzer(log, syms, lint, names).analyzeTree(env); |
211 new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env); |
211 new FlowAnalyzer().analyzeTree(env, make); |
212 new FlowAnalyzer().analyzeTree(env, make); |
212 new CaptureAnalyzer().analyzeTree(env, make); |
213 new CaptureAnalyzer().analyzeTree(env, make); |
213 } |
214 } |
214 |
215 |
215 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) { |
216 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) { |
237 //message will be reported and will cause compilation to skip the flow analyis |
238 //message will be reported and will cause compilation to skip the flow analyis |
238 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis |
239 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis |
239 //related errors, which will allow for more errors to be detected |
240 //related errors, which will allow for more errors to be detected |
240 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); |
241 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); |
241 try { |
242 try { |
242 new AssignAnalyzer(log, syms, lint, names).analyzeTree(env); |
243 new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env); |
243 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); |
244 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); |
244 flowAnalyzer.analyzeTree(env, that, make); |
245 flowAnalyzer.analyzeTree(env, that, make); |
245 return flowAnalyzer.inferredThrownTypes; |
246 return flowAnalyzer.inferredThrownTypes; |
246 } finally { |
247 } finally { |
247 log.popDiagnosticHandler(diagHandler); |
248 log.popDiagnosticHandler(diagHandler); |
287 diags = JCDiagnostic.Factory.instance(context); |
288 diags = JCDiagnostic.Factory.instance(context); |
288 Source source = Source.instance(context); |
289 Source source = Source.instance(context); |
289 allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis(); |
290 allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis(); |
290 allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); |
291 allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis(); |
291 allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); |
292 allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses(); |
|
293 enforceThisDotInit = source.enforceThisDotInit(); |
292 } |
294 } |
293 |
295 |
294 /** |
296 /** |
295 * Base visitor class for all visitors implementing dataflow analysis logic. |
297 * Base visitor class for all visitors implementing dataflow analysis logic. |
296 * This class define the shared logic for handling jumps (break/continue statements). |
298 * This class define the shared logic for handling jumps (break/continue statements). |
1447 inits.andSet(exit_inits); |
1451 inits.andSet(exit_inits); |
1448 uninits.andSet(exit_uninits); |
1452 uninits.andSet(exit_uninits); |
1449 } |
1453 } |
1450 } |
1454 } |
1451 |
1455 |
1452 public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) { |
1456 public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names, boolean enforceThisDotInit) { |
1453 this.inits = inits; |
1457 this.inits = inits; |
1454 uninits = new Bits(); |
1458 uninits = new Bits(); |
1455 uninitsTry = new Bits(); |
1459 uninitsTry = new Bits(); |
1456 initsWhenTrue = new Bits(true); |
1460 initsWhenTrue = new Bits(true); |
1457 initsWhenFalse = new Bits(true); |
1461 initsWhenFalse = new Bits(true); |
1458 uninitsWhenTrue = new Bits(true); |
1462 uninitsWhenTrue = new Bits(true); |
1459 uninitsWhenFalse = new Bits(true); |
1463 uninitsWhenFalse = new Bits(true); |
1460 this.syms = syms; |
1464 this.syms = syms; |
1461 this.names = names; |
1465 this.names = names; |
|
1466 this.enforceThisDotInit = enforceThisDotInit; |
1462 } |
1467 } |
1463 |
1468 |
1464 private boolean isInitialConstructor = false; |
1469 private boolean isInitialConstructor = false; |
1465 |
1470 |
1466 @Override |
1471 @Override |
2278 uninits.assign(uninitsExit); |
2283 uninits.assign(uninitsExit); |
2279 } |
2284 } |
2280 |
2285 |
2281 public void visitAssign(JCAssign tree) { |
2286 public void visitAssign(JCAssign tree) { |
2282 JCTree lhs = TreeInfo.skipParens(tree.lhs); |
2287 JCTree lhs = TreeInfo.skipParens(tree.lhs); |
2283 if (!(lhs instanceof JCIdent)) { |
2288 if (!isIdentOrThisDotIdent(lhs)) |
2284 scanExpr(lhs); |
2289 scanExpr(lhs); |
2285 } |
|
2286 scanExpr(tree.rhs); |
2290 scanExpr(tree.rhs); |
2287 letInit(lhs); |
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 } |
2288 } |
2315 } |
2289 |
2316 |
2290 public void visitAssignop(JCAssignOp tree) { |
2317 public void visitAssignop(JCAssignOp tree) { |
2291 scanExpr(tree.lhs); |
2318 scanExpr(tree.lhs); |
2292 scanExpr(tree.rhs); |
2319 scanExpr(tree.rhs); |
2417 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { |
2444 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { |
2418 super(tree, inits, uninits); |
2445 super(tree, inits, uninits); |
2419 } |
2446 } |
2420 } |
2447 } |
2421 |
2448 |
2422 public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) { |
2449 public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names, boolean enforceThisDotInit) { |
2423 super(new Bits(), syms, names); |
2450 super(new Bits(), syms, names, enforceThisDotInit); |
2424 this.log = log; |
2451 this.log = log; |
2425 this.lint = lint; |
2452 this.lint = lint; |
2426 } |
2453 } |
2427 |
2454 |
2428 @Override |
2455 @Override |