1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
11  *			     				bug 292478 - Report potentially null across variable assignment
12  *     							bug 332637 - Dead Code detection removing code that isn't dead
13  *								bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional
14  *								Bug 411964 - [1.8][null] leverage null type annotation in foreach statement
15  *******************************************************************************/
16 package org.eclipse.jdt.internal.compiler.flow;
17 
18 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
19 import org.eclipse.jdt.internal.compiler.ast.IfStatement;
20 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
21 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
22 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
23 
24 public abstract class FlowInfo {
25 
26 	public int tagBits; // REACHABLE by default
27 	public final static int REACHABLE = 0;
28 	/* unreachable code
29 	 * eg. while (true);
30 	 *     i++;  --> unreachable code
31 	 */
32 	public final static int UNREACHABLE_OR_DEAD = 1;
33 	/* unreachable code as inferred by null analysis
34 	 * eg. str = null;
35 	 *     if (str != null) {
36 	 *        // dead code
37 	 *     }
38 	 */
39 	public final static int UNREACHABLE_BY_NULLANALYSIS = 2;
40 	/*
41 	 * code unreachable in any fashion
42 	 */
43 	public final static int UNREACHABLE = UNREACHABLE_OR_DEAD | UNREACHABLE_BY_NULLANALYSIS;
44 	public final static int NULL_FLAG_MASK = 4;
45 
46 	public final static int UNKNOWN = 1;
47 	public final static int NULL = 2;
48 	public final static int NON_NULL = 4;
49 	public final static int POTENTIALLY_UNKNOWN = 8;
50 	public final static int POTENTIALLY_NULL = 16;
51 	public final static int POTENTIALLY_NON_NULL = 32;
52 
53 	public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
54 	static {
55 		DEAD_END = new UnconditionalFlowInfo();
56 		DEAD_END.tagBits = UNREACHABLE;
57 	}
58 
59 /**
60  * Add other inits to this flow info, then return this. The operation semantics
61  * are to match as closely as possible the application to this flow info of all
62  * the operations that resulted into otherInits.
63  * @param otherInits other inits to add to this
64  * @return this, modified according to otherInits information
65  */
addInitializationsFrom(FlowInfo otherInits)66 abstract public FlowInfo addInitializationsFrom(FlowInfo otherInits);
67 
68 /**
69  * Add all null information from otherInits to this flow info and return this.
70  * The operation models the effect of an unconditional sequence of this flow info
71  * and otherInits.
72  */
addNullInfoFrom(FlowInfo otherInits)73 abstract public FlowInfo addNullInfoFrom(FlowInfo otherInits);
74 
75 
76 /**
77  * Compose other inits over this flow info, then return this. The operation
78  * semantics are to wave into this flow info the consequences of a possible
79  * path into the operations that resulted into otherInits. The fact that this
80  * path may be left unexecuted under peculiar conditions results into less
81  * specific results than {@link #addInitializationsFrom(FlowInfo)
82  * addInitializationsFrom}.
83  * @param otherInits other inits to compose over this
84  * @return this, modified according to otherInits information
85  */
addPotentialInitializationsFrom(FlowInfo otherInits)86 abstract public FlowInfo addPotentialInitializationsFrom(FlowInfo otherInits);
87 
asNegatedCondition()88 	public FlowInfo asNegatedCondition() {
89 
90 		return this;
91 	}
92 
conditional(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse)93 	public static FlowInfo conditional(FlowInfo initsWhenTrue, FlowInfo initsWhenFalse){
94 		if (initsWhenTrue == initsWhenFalse) return initsWhenTrue;
95 		// if (initsWhenTrue.equals(initsWhenFalse)) return initsWhenTrue; -- could optimize if #equals is defined
96 		return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse);
97 	}
98 
99 /**
100  * Check whether a given local variable is known to be unable to gain a definite
101  * non null or definite null status by the use of an enclosing flow info. The
102  * semantics are that if the current flow info marks the variable as potentially
103  * unknown or else as being both potentially null and potentially non null,
104  * then it won't ever be promoted as definitely null or definitely non null. (It
105  * could still get promoted to definite unknown).
106  * @param local the variable to check
107  * @return true iff this flow info prevents local from being promoted to
108  *         definite non null or definite null against an enclosing flow info
109  */
cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local)110 public boolean cannotBeDefinitelyNullOrNonNull(LocalVariableBinding local) {
111 	return isPotentiallyUnknown(local) ||
112 		isPotentiallyNonNull(local) && isPotentiallyNull(local);
113 }
114 
115 /**
116  * Check whether a given local variable is known to be non null, either because
117  * it is definitely non null, or because is has been tested against non null.
118  * @param local the variable to ckeck
119  * @return true iff local cannot be null for this flow info
120  */
cannotBeNull(LocalVariableBinding local)121 public boolean cannotBeNull(LocalVariableBinding local) {
122 	return isDefinitelyNonNull(local) || isProtectedNonNull(local);
123 }
124 
125 /**
126  * Check whether a given local variable is known to be null, either because it
127  * is definitely null, or because is has been tested against null.
128  * @param local the variable to ckeck
129  * @return true iff local can only be null for this flow info
130  */
canOnlyBeNull(LocalVariableBinding local)131 public boolean canOnlyBeNull(LocalVariableBinding local) {
132 	return isDefinitelyNull(local) || isProtectedNull(local);
133 }
134 
135 /**
136  * Return a deep copy of the current instance.
137  * @return a deep copy of this flow info
138  */
copy()139 	abstract public FlowInfo copy();
140 
initial(int maxFieldCount)141 	public static UnconditionalFlowInfo initial(int maxFieldCount) {
142 		UnconditionalFlowInfo info = new UnconditionalFlowInfo();
143 		info.maxFieldCount = maxFieldCount;
144 		return info;
145 	}
146 
147 /**
148  * Return the flow info that would result from the path associated to the
149  * value false for the condition expression that generated this flow info.
150  * May be this flow info if it is not an instance of {@link
151  * ConditionalFlowInfo}. May have a side effect on subparts of this flow
152  * info (subtrees get merged).
153  * @return the flow info associated to the false branch of the condition
154  * 			that generated this flow info
155  */
initsWhenFalse()156 abstract public FlowInfo initsWhenFalse();
157 
158 /**
159  * Return the flow info that would result from the path associated to the
160  * value true for the condition expression that generated this flow info.
161  * May be this flow info if it is not an instance of {@link
162  * ConditionalFlowInfo}. May have a side effect on subparts of this flow
163  * info (subtrees get merged).
164  * @return the flow info associated to the true branch of the condition
165  * 			that generated this flow info
166  */
initsWhenTrue()167 	abstract public FlowInfo initsWhenTrue();
168 
169 	/**
170 	 * Check status of definite assignment for a field.
171 	 */
isDefinitelyAssigned(FieldBinding field)172 	 abstract public boolean isDefinitelyAssigned(FieldBinding field);
173 
174 	/**
175 	 * Check status of definite assignment for a local.
176 	 */
isDefinitelyAssigned(LocalVariableBinding local)177 	public abstract boolean isDefinitelyAssigned(LocalVariableBinding local);
178 
179 /**
180  * Check status of definite non-null value for a given local variable.
181  * @param local the variable to ckeck
182  * @return true iff local is definitely non null for this flow info
183  */
isDefinitelyNonNull(LocalVariableBinding local)184 	public abstract boolean isDefinitelyNonNull(LocalVariableBinding local);
185 
186 /**
187  * Check status of definite null value for a given local variable.
188  * @param local the variable to ckeck
189  * @return true iff local is definitely null for this flow info
190  */
isDefinitelyNull(LocalVariableBinding local)191 public abstract boolean isDefinitelyNull(LocalVariableBinding local);
192 
193 /**
194  * Check status of definite unknown value for a given local variable.
195  * @param local the variable to ckeck
196  * @return true iff local is definitely unknown for this flow info
197  */
isDefinitelyUnknown(LocalVariableBinding local)198 public abstract boolean isDefinitelyUnknown(LocalVariableBinding local);
199 
200 /**
201  * Check if any null info has been recorded for a given local variable.
202  * Here even recording of 'UNKNOWN' is considered as null info.
203  */
hasNullInfoFor(LocalVariableBinding local)204 public abstract boolean hasNullInfoFor(LocalVariableBinding local);
205 
206 	/**
207 	 * Check status of potential assignment for a field.
208 	 */
isPotentiallyAssigned(FieldBinding field)209 	 abstract public boolean isPotentiallyAssigned(FieldBinding field);
210 
211 	/**
212 	 * Check status of potential assignment for a local variable.
213 	 */
214 
isPotentiallyAssigned(LocalVariableBinding field)215 	 abstract public boolean isPotentiallyAssigned(LocalVariableBinding field);
216 
217 /**
218  * Check status of potential null assignment for a local. Return true if there
219  * is a reasonable expectation that the variable be non null at this point.
220  * @param local LocalVariableBinding - the binding for the checked local
221  * @return true if there is a reasonable expectation that local be non null at
222  * this point
223  */
isPotentiallyNonNull(LocalVariableBinding local)224 public abstract boolean isPotentiallyNonNull(LocalVariableBinding local);
225 
226 /**
227  * Check status of potential null assignment for a local. Return true if there
228  * is a reasonable expectation that the variable be null at this point. This
229  * includes the protected null case, so as to augment diagnostics, but does not
230  * really check that someone deliberately assigned to null on any specific
231  * path
232  * @param local LocalVariableBinding - the binding for the checked local
233  * @return true if there is a reasonable expectation that local be null at
234  * this point
235  */
isPotentiallyNull(LocalVariableBinding local)236 public abstract boolean isPotentiallyNull(LocalVariableBinding local);
237 
238 /**
239  * Return true if the given local may have been assigned to an unknown value.
240  * @param local the local to check
241  * @return true if the given local may have been assigned to an unknown value
242  */
isPotentiallyUnknown(LocalVariableBinding local)243 public abstract boolean isPotentiallyUnknown(LocalVariableBinding local);
244 
245 /**
246  * Return true if the given local is protected by a test against a non null
247  * value.
248  * @param local the local to check
249  * @return true if the given local is protected by a test against a non null
250  */
isProtectedNonNull(LocalVariableBinding local)251 public abstract boolean isProtectedNonNull(LocalVariableBinding local);
252 
253 /**
254  * Return true if the given local is protected by a test against null.
255  * @param local the local to check
256  * @return true if the given local is protected by a test against null
257  */
isProtectedNull(LocalVariableBinding local)258 public abstract boolean isProtectedNull(LocalVariableBinding local);
259 
260 /**
261  * Record that a local variable got checked to be non null.
262  * @param local the checked local variable
263  */
markAsComparedEqualToNonNull(LocalVariableBinding local)264 abstract public void markAsComparedEqualToNonNull(LocalVariableBinding local);
265 
266 /**
267  * Record that a local variable got checked to be null.
268  * @param local the checked local variable
269  */
markAsComparedEqualToNull(LocalVariableBinding local)270 abstract public void markAsComparedEqualToNull(LocalVariableBinding local);
271 
272 	/**
273 	 * Record a field got definitely assigned.
274 	 */
markAsDefinitelyAssigned(FieldBinding field)275 	abstract public void markAsDefinitelyAssigned(FieldBinding field);
276 
277 	/**
278 	 * Record a local got definitely assigned to a non-null value.
279 	 */
markAsDefinitelyNonNull(LocalVariableBinding local)280 	abstract public void markAsDefinitelyNonNull(LocalVariableBinding local);
281 
282 	/**
283 	 * Record a local got definitely assigned to null.
284 	 */
markAsDefinitelyNull(LocalVariableBinding local)285 	abstract public void markAsDefinitelyNull(LocalVariableBinding local);
286 
287 	/**
288 	 * Reset all null-information about a given local.
289 	 */
resetNullInfo(LocalVariableBinding local)290 	abstract public void resetNullInfo(LocalVariableBinding local);
291 
292 	/**
293 	 * Record a local may have got assigned to unknown (set the bit on existing info).
294 	 */
markPotentiallyUnknownBit(LocalVariableBinding local)295 	abstract public void markPotentiallyUnknownBit(LocalVariableBinding local);
296 
297 	/**
298 	 * Record a local may have got assigned to null (set the bit on existing info).
299 	 */
markPotentiallyNullBit(LocalVariableBinding local)300 	abstract public void markPotentiallyNullBit(LocalVariableBinding local);
301 
302 	/**
303 	 * Record a local may have got assigned to non-null (set the bit on existing info).
304 	 */
markPotentiallyNonNullBit(LocalVariableBinding local)305 	abstract public void markPotentiallyNonNullBit(LocalVariableBinding local);
306 
307 	/**
308 	 * Record a local got definitely assigned.
309 	 */
markAsDefinitelyAssigned(LocalVariableBinding local)310 	abstract public void markAsDefinitelyAssigned(LocalVariableBinding local);
311 
312 /**
313  * Record a local got definitely assigned to an unknown value.
314  */
markAsDefinitelyUnknown(LocalVariableBinding local)315 abstract public void markAsDefinitelyUnknown(LocalVariableBinding local);
316 
317 /**
318  * Mark the null status of the given local according to the given status
319  * @param local
320  * @param nullStatus bitset of FLowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
321  */
markNullStatus(LocalVariableBinding local, int nullStatus)322 public void markNullStatus(LocalVariableBinding local, int nullStatus) {
323 	switch(nullStatus) {
324 		// definite status?
325 		case FlowInfo.UNKNOWN :
326 			markAsDefinitelyUnknown(local);
327 			break;
328 		case FlowInfo.NULL :
329 			markAsDefinitelyNull(local);
330 			break;
331 		case FlowInfo.NON_NULL :
332 			markAsDefinitelyNonNull(local);
333 			break;
334 		default:
335 			// collect potential status:
336 			resetNullInfo(local);
337 			if ((nullStatus & FlowInfo.POTENTIALLY_UNKNOWN) != 0)
338 				markPotentiallyUnknownBit(local);
339 			if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0)
340 				markPotentiallyNullBit(local);
341 			if ((nullStatus & FlowInfo.POTENTIALLY_NON_NULL) != 0)
342 				markPotentiallyNonNullBit(local);
343 			if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL|FlowInfo.POTENTIALLY_UNKNOWN)) == 0)
344 				markAsDefinitelyUnknown(local);
345 	}
346 }
347 
348 /**
349  * Answer the null status of the given local
350  * @param local
351  * @return bitset of FlowInfo.UNKNOWN ... FlowInfo.POTENTIALLY_NON_NULL
352  */
nullStatus(LocalVariableBinding local)353 public int nullStatus(LocalVariableBinding local) {
354 	if (isDefinitelyUnknown(local))
355 		return FlowInfo.UNKNOWN;
356 	if (isDefinitelyNull(local))
357 		return FlowInfo.NULL;
358 	if (isDefinitelyNonNull(local))
359 		return FlowInfo.NON_NULL;
360 	int status = 0;
361 	if (isPotentiallyUnknown(local))
362 		status |= FlowInfo.POTENTIALLY_UNKNOWN;
363 	if (isPotentiallyNull(local))
364 		status |= FlowInfo.POTENTIALLY_NULL;
365 	if (isPotentiallyNonNull(local))
366 		status |= FlowInfo.POTENTIALLY_NON_NULL;
367 	if (status > 0)
368 		return status;
369 	return FlowInfo.UNKNOWN;
370 }
371 
372 /**
373  * Merge two single bits (NULL, NON_NULL, POTENTIALLY*..) into one.
374  * This method implements a simpler logic than the 4-bit encoding used in FlowInfo instances.
375  */
mergeNullStatus(int nullStatus1, int nullStatus2)376 public static int mergeNullStatus(int nullStatus1, int nullStatus2) {
377 	boolean canBeNull = false;
378 	boolean canBeNonNull = false;
379 	switch (nullStatus1) {
380 		case POTENTIALLY_NULL:
381 			canBeNonNull = true;
382 			//$FALL-THROUGH$
383 		case NULL:
384 			canBeNull = true;
385 			break;
386 		case POTENTIALLY_NON_NULL:
387 			canBeNull = true;
388 			//$FALL-THROUGH$
389 		case NON_NULL:
390 			canBeNonNull = true;
391 			break;
392 	}
393 	switch (nullStatus2) {
394 		case POTENTIALLY_NULL:
395 			canBeNonNull = true;
396 			//$FALL-THROUGH$
397 		case NULL:
398 			canBeNull = true;
399 			break;
400 		case POTENTIALLY_NON_NULL:
401 			canBeNull = true;
402 			//$FALL-THROUGH$
403 		case NON_NULL:
404 			canBeNonNull = true;
405 			break;
406 	}
407 	if (canBeNull) {
408 		if (canBeNonNull)
409 			return POTENTIALLY_NULL;
410 		else
411 			return NULL;
412 	} else {
413 		if (canBeNonNull)
414 			return NON_NULL;
415 		else
416 			return UNKNOWN;
417 	}
418 }
419 
420 /**
421  * Merge branches using optimized boolean conditions
422  */
mergedOptimizedBranches( FlowInfo initsWhenTrue, boolean isOptimizedTrue, FlowInfo initsWhenFalse, boolean isOptimizedFalse, boolean allowFakeDeadBranch)423 public static UnconditionalFlowInfo mergedOptimizedBranches(
424 		FlowInfo initsWhenTrue, boolean isOptimizedTrue,
425 		FlowInfo initsWhenFalse, boolean isOptimizedFalse,
426 		boolean allowFakeDeadBranch) {
427 	UnconditionalFlowInfo mergedInfo;
428 	if (isOptimizedTrue){
429 		if (initsWhenTrue == FlowInfo.DEAD_END && allowFakeDeadBranch) {
430 			mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD).
431 				unconditionalInits();
432 		}
433 		else {
434 			mergedInfo =
435 				initsWhenTrue.addPotentialInitializationsFrom(initsWhenFalse.
436 					nullInfoLessUnconditionalCopy()).
437 				unconditionalInits();
438 		}
439 	}
440 	else if (isOptimizedFalse) {
441 		if (initsWhenFalse == FlowInfo.DEAD_END && allowFakeDeadBranch) {
442 			mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD).
443 				unconditionalInits();
444 		}
445 		else {
446 			mergedInfo =
447 				initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue.
448 					nullInfoLessUnconditionalCopy()).
449 				unconditionalInits();
450 		}
451 	}
452 	else {
453 		mergedInfo = initsWhenTrue.
454 			mergedWith(initsWhenFalse.unconditionalInits());
455 	}
456 	return mergedInfo;
457 }
458 
459 /**
460  * Merge if-else branches using optimized boolean conditions
461  */
mergedOptimizedBranchesIfElse( FlowInfo initsWhenTrue, boolean isOptimizedTrue, FlowInfo initsWhenFalse, boolean isOptimizedFalse, boolean allowFakeDeadBranch, FlowInfo flowInfo, IfStatement ifStatement, boolean reportDeadCodeInKnownPattern)462 public static UnconditionalFlowInfo mergedOptimizedBranchesIfElse(
463 		FlowInfo initsWhenTrue, boolean isOptimizedTrue,
464 		FlowInfo initsWhenFalse, boolean isOptimizedFalse,
465 		boolean allowFakeDeadBranch, FlowInfo flowInfo, IfStatement ifStatement,
466 		boolean reportDeadCodeInKnownPattern) {
467 	UnconditionalFlowInfo mergedInfo;
468 	if (isOptimizedTrue){
469 		if (initsWhenTrue == FlowInfo.DEAD_END && allowFakeDeadBranch) {
470 			if (!reportDeadCodeInKnownPattern) {
471 				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=256796
472 				// do not report code even after if-else as dead as a consequence of analysis done in known dead code pattern
473 				// when the CompilerOptions$reportDeadCodeInTrivialIfStatement option is disabled
474 				if (ifStatement.elseStatement == null) {
475 					mergedInfo = flowInfo.unconditionalInits();
476 				} else {
477 					mergedInfo = initsWhenFalse.unconditionalInits();
478 					if (initsWhenFalse != FlowInfo.DEAD_END) {
479 						// let the definitely true status of known dead code pattern not affect the reachability
480 						mergedInfo.setReachMode(flowInfo.reachMode());
481 					}
482 				}
483 			} else {
484 				mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD).
485 					unconditionalInits();
486 			}
487 		}
488 		else {
489 			mergedInfo =
490 				initsWhenTrue.addPotentialInitializationsFrom(initsWhenFalse.
491 					nullInfoLessUnconditionalCopy()).
492 				unconditionalInits();
493 		}
494 	}
495 	else if (isOptimizedFalse) {
496 		if (initsWhenFalse == FlowInfo.DEAD_END && allowFakeDeadBranch) {
497 			if (!reportDeadCodeInKnownPattern) {
498 				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=256796
499 				// do not report code even after if-else as dead as a consequence of analysis done in known dead code pattern
500 				// when the CompilerOptions$reportDeadCodeInTrivialIfStatement option is disabled
501 				if (ifStatement.thenStatement == null) {
502 					mergedInfo = flowInfo.unconditionalInits();
503 				} else {
504 					mergedInfo = initsWhenTrue.unconditionalInits();
505 					if (initsWhenTrue != FlowInfo.DEAD_END) {
506 						// let the definitely false status of known dead code pattern not affect the reachability
507 						mergedInfo.setReachMode(flowInfo.reachMode());
508 					}
509 				}
510 			} else {
511 				mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD).
512 					unconditionalInits();
513 			}
514 		}
515 		else {
516 			mergedInfo =
517 				initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue.
518 					nullInfoLessUnconditionalCopy()).
519 				unconditionalInits();
520 		}
521 	}
522 	else if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 &&
523 				(ifStatement.bits & ASTNode.IsElseStatementUnreachable) != 0 &&
524 				initsWhenTrue != FlowInfo.DEAD_END &&
525 				initsWhenFalse != FlowInfo.DEAD_END) {
526 		// Done when the then branch will always be executed but the condition does not have a boolean
527 		// true or false (i.e if(true), etc) for sure
528 		// We don't do this if both if and else branches themselves are in an unreachable code
529 		// or if any of them is a DEAD_END (e.g. contains 'return' or 'throws')
530 		mergedInfo =
531 			initsWhenTrue.addPotentialInitializationsFrom(initsWhenFalse.
532 				nullInfoLessUnconditionalCopy()).
533 			unconditionalInits();
534 		// if a variable is only initialized in one branch and not initialized in the other,
535 		// then we need to cast a doubt on its initialization in the merged info
536 		mergedInfo.definiteInits &= initsWhenFalse.unconditionalCopy().definiteInits;
537 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsElseStatementUnreachable could be due to null analysis
538 		if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenFalse.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
539 			mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
540 			mergedInfo.tagBits |= UNREACHABLE_BY_NULLANALYSIS;
541 		}
542 	}
543 	else if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0 &&
544 			(ifStatement.bits & ASTNode.IsThenStatementUnreachable) != 0 && initsWhenTrue != FlowInfo.DEAD_END
545 			&& initsWhenFalse != FlowInfo.DEAD_END) {
546 		// Done when the else branch will always be executed but the condition does not have a boolean
547 		// true or false (i.e if(true), etc) for sure
548 		// We don't do this if both if and else branches themselves are in an unreachable code
549 		// or if any of them is a DEAD_END (e.g. contains 'return' or 'throws')
550 		mergedInfo =
551 			initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue.
552 				nullInfoLessUnconditionalCopy()).
553 			unconditionalInits();
554 		// if a variable is only initialized in one branch and not initialized in the other,
555 		// then we need to cast a doubt on its initialization in the merged info
556 		mergedInfo.definiteInits &= initsWhenTrue.unconditionalCopy().definiteInits;
557 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsThenStatementUnreachable could be due to null analysis
558 		if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenTrue.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
559 			mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
560 			mergedInfo.tagBits |= UNREACHABLE_BY_NULLANALYSIS;
561 		}
562 	}
563 	else {
564 		mergedInfo = initsWhenTrue.
565 			mergedWith(initsWhenFalse.unconditionalInits());
566 	}
567 	return mergedInfo;
568 }
569 
570 /**
571  * Find out the reachability mode of this flowInfo.
572  * @return REACHABLE if this flow info is reachable, otherwise
573  *         either UNREACHABLE_OR_DEAD or UNREACHABLE_BY_NULLANALYSIS.
574  */
reachMode()575 public int reachMode() {
576 	return this.tagBits & UNREACHABLE;
577 }
578 
579 /**
580  * Return a flow info that carries the same information as the result of
581  * {@link #initsWhenTrue() initsWhenTrue}, but warrantied to be different
582  * from this.<br>
583  * Caveat: side effects on the result may affect components of this.
584  * @return the result of initsWhenTrue or a copy of it
585  */
safeInitsWhenTrue()586 abstract public FlowInfo safeInitsWhenTrue();
587 
588 /**
589  * Set this flow info reach mode and return this.
590  * @param reachMode one of {@link #REACHABLE REACHABLE}, {@link #UNREACHABLE_OR_DEAD UNREACHABLE_OR_DEAD},
591  * {@link #UNREACHABLE_BY_NULLANALYSIS UNREACHABLE_BY_NULLANALYSIS} or {@link #UNREACHABLE UNREACHABLE}
592  * @return this, with the reach mode set to reachMode
593  */
setReachMode(int reachMode)594 abstract public FlowInfo setReachMode(int reachMode);
595 
596 /**
597  * Return the intersection of this and otherInits, that is
598  * one of:<ul>
599  *   <li>the receiver updated in the following way:<ul>
600  *     <li>intersection of definitely assigned variables,
601  *     <li>union of potentially assigned variables,
602  *     <li>similar operations for null,</ul>
603  *   <li>or the receiver or otherInits if the other one is non
604  *       reachable.</ul>
605  * otherInits is not affected, and is not returned either (no
606  * need to protect the result).
607  * @param otherInits the flow info to merge with this
608  * @return the intersection of this and otherInits.
609  */
mergedWith( UnconditionalFlowInfo otherInits)610 abstract public UnconditionalFlowInfo mergedWith(
611 		UnconditionalFlowInfo otherInits);
612 
613 /**
614  * Return a copy of this unconditional flow info, deprived from its null
615  * info. {@link #DEAD_END DEAD_END} is returned unmodified.
616  * @return a copy of this unconditional flow info deprived from its null info
617  */
nullInfoLessUnconditionalCopy()618 abstract public UnconditionalFlowInfo nullInfoLessUnconditionalCopy();
619 
toString()620 	public String toString(){
621 
622 		if (this == DEAD_END){
623 			return "FlowInfo.DEAD_END"; //$NON-NLS-1$
624 		}
625 		return super.toString();
626 	}
627 
628 /**
629  * Return a new flow info that holds the same information as this would after
630  * a call to unconditionalInits, but leaving this info unaffected. Moreover,
631  * the result can be modified without affecting this.
632  * @return a new flow info carrying this unconditional flow info
633  */
unconditionalCopy()634 abstract public UnconditionalFlowInfo unconditionalCopy();
635 
636 /**
637  * Return a new flow info that holds the same information as this would after
638  * a call to {@link #unconditionalInits() unconditionalInits} followed by the
639  * erasure of fields specific information, but leaving this flow info unaffected.
640  * @return a new flow info carrying the unconditional flow info for local variables
641  */
unconditionalFieldLessCopy()642 abstract public UnconditionalFlowInfo unconditionalFieldLessCopy();
643 
644 /**
645  * Return a flow info that merges the possible paths of execution described by
646  * this flow info. In case of an unconditional flow info, return this. In case
647  * of a conditional flow info, merge branches recursively. Caveat: this may
648  * be affected, and modifying the result may affect this.
649  * @return a flow info that merges the possible paths of execution described by
650  * 			this
651  */
unconditionalInits()652 abstract public UnconditionalFlowInfo unconditionalInits();
653 
654 /**
655  * Return a new flow info that holds the same information as this would after
656  * a call to {@link #unconditionalInits() unconditionalInits}, but leaving
657  * this info unaffected. Side effects on the result might affect this though
658  * (consider it as read only).
659  * @return a flow info carrying this unconditional flow info
660  */
unconditionalInitsWithoutSideEffect()661 abstract public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect();
662 
663 /**
664  * Resets the definite and potential initialization info for the given local variable
665  * @param local
666  */
resetAssignmentInfo(LocalVariableBinding local)667 abstract public void resetAssignmentInfo(LocalVariableBinding local);
668 
669 /**
670  * Check whether 'tagBits' contains either {@link TagBits#AnnotationNonNull} or {@link TagBits#AnnotationNullable},
671  * and answer the corresponding null status ({@link #NON_NULL} etc.).
672  */
tagBitsToNullStatus(long tagBits)673 public static int tagBitsToNullStatus(long tagBits) {
674 	if ((tagBits & TagBits.AnnotationNonNull) != 0)
675 		return NON_NULL;
676 	if ((tagBits & TagBits.AnnotationNullable) != 0)
677 		return POTENTIALLY_NULL | POTENTIALLY_NON_NULL;
678 	return UNKNOWN;
679 }
680 }
681