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