001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.flow;
011:
012: import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
013: import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
014:
015: public abstract class FlowInfo {
016:
017: public int tagBits; // REACHABLE by default
018: public final static int REACHABLE = 0;
019: public final static int UNREACHABLE = 1;
020: public final static int NULL_FLAG_MASK = 2;
021:
022: public final static int UNKNOWN = 0;
023: public final static int NULL = 1;
024: public final static int NON_NULL = -1;
025:
026: public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
027: static {
028: DEAD_END = new UnconditionalFlowInfo();
029: DEAD_END.tagBits = UNREACHABLE;
030: }
031:
032: /**
033: * Add other inits to this flow info, then return this. The operation semantics
034: * are to match as closely as possible the application to this flow info of all
035: * the operations that resulted into otherInits.
036: * @param otherInits other inits to add to this
037: * @return this, modified according to otherInits information
038: */
039: abstract public FlowInfo addInitializationsFrom(FlowInfo otherInits);
040:
041: /**
042: * Compose other inits over this flow info, then return this. The operation
043: * semantics are to wave into this flow info the consequences of a possible
044: * path into the operations that resulted into otherInits. The fact that this
045: * path may be left unexecuted under peculiar conditions results into less
046: * specific results than {@link #addInitializationsFrom(FlowInfo)
047: * addInitializationsFrom}.
048: * @param otherInits other inits to compose over this
049: * @return this, modified according to otherInits information
050: */
051: abstract public FlowInfo addPotentialInitializationsFrom(
052: FlowInfo otherInits);
053:
054: public FlowInfo asNegatedCondition() {
055:
056: return this ;
057: }
058:
059: public static FlowInfo conditional(FlowInfo initsWhenTrue,
060: FlowInfo initsWhenFalse) {
061:
062: // if (initsWhenTrue.equals(initsWhenFalse)) return initsWhenTrue; -- could optimize if #equals is defined
063: return new ConditionalFlowInfo(initsWhenTrue, initsWhenFalse);
064: }
065:
066: /**
067: * Check whether a given local variable is known to be unable to gain a definite
068: * non null or definite null status by the use of an enclosing flow info. The
069: * semantics are that if the current flow info marks the variable as potentially
070: * unknown or else as being both potentially null and potentially non null,
071: * then it won't ever be promoted as definitely null or definitely non null. (It
072: * could still get promoted to definite unknown).
073: * @param local the variable to ckeck
074: * @return true iff this flow info prevents local from being promoted to
075: * definite non null or definite null against an enclosing flow info
076: */
077: public boolean cannotBeDefinitelyNullOrNonNull(
078: LocalVariableBinding local) {
079: return isPotentiallyUnknown(local)
080: || isPotentiallyNonNull(local)
081: && isPotentiallyNull(local);
082: }
083:
084: /**
085: * Check whether a given local variable is known to be non null, either because
086: * it is definitely non null, or because is has been tested against non null.
087: * @param local the variable to ckeck
088: * @return true iff local cannot be null for this flow info
089: */
090: public boolean cannotBeNull(LocalVariableBinding local) {
091: return isDefinitelyNonNull(local) || isProtectedNonNull(local);
092: }
093:
094: /**
095: * Check whether a given local variable is known to be null, either because it
096: * is definitely null, or because is has been tested against null.
097: * @param local the variable to ckeck
098: * @return true iff local can only be null for this flow info
099: */
100: public boolean canOnlyBeNull(LocalVariableBinding local) {
101: return isDefinitelyNull(local) || isProtectedNull(local);
102: }
103:
104: /**
105: * Return a deep copy of the current instance.
106: * @return a deep copy of this flow info
107: */
108: abstract public FlowInfo copy();
109:
110: public static UnconditionalFlowInfo initial(int maxFieldCount) {
111: UnconditionalFlowInfo info = new UnconditionalFlowInfo();
112: info.maxFieldCount = maxFieldCount;
113: return info;
114: }
115:
116: /**
117: * Return the flow info that would result from the path associated to the
118: * value false for the condition expression that generated this flow info.
119: * May be this flow info if it is not an instance of {@link
120: * ConditionalFlowInfo}. May have a side effect on subparts of this flow
121: * info (subtrees get merged).
122: * @return the flow info associated to the false branch of the condition
123: * that generated this flow info
124: */
125: abstract public FlowInfo initsWhenFalse();
126:
127: /**
128: * Return the flow info that would result from the path associated to the
129: * value true for the condition expression that generated this flow info.
130: * May be this flow info if it is not an instance of {@link
131: * ConditionalFlowInfo}. May have a side effect on subparts of this flow
132: * info (subtrees get merged).
133: * @return the flow info associated to the true branch of the condition
134: * that generated this flow info
135: */
136: abstract public FlowInfo initsWhenTrue();
137:
138: /**
139: * Check status of definite assignment for a field.
140: */
141: abstract public boolean isDefinitelyAssigned(FieldBinding field);
142:
143: /**
144: * Check status of definite assignment for a local.
145: */
146: public abstract boolean isDefinitelyAssigned(
147: LocalVariableBinding local);
148:
149: /**
150: * Check status of definite non-null value for a given local variable.
151: * @param local the variable to ckeck
152: * @return true iff local is definitely non null for this flow info
153: */
154: public abstract boolean isDefinitelyNonNull(
155: LocalVariableBinding local);
156:
157: /**
158: * Check status of definite null value for a given local variable.
159: * @param local the variable to ckeck
160: * @return true iff local is definitely null for this flow info
161: */
162: public abstract boolean isDefinitelyNull(LocalVariableBinding local);
163:
164: /**
165: * Check status of definite unknown value for a given local variable.
166: * @param local the variable to ckeck
167: * @return true iff local is definitely unknown for this flow info
168: */
169: public abstract boolean isDefinitelyUnknown(
170: LocalVariableBinding local);
171:
172: /**
173: * Check status of potential assignment for a field.
174: */
175: abstract public boolean isPotentiallyAssigned(FieldBinding field);
176:
177: /**
178: * Check status of potential assignment for a local variable.
179: */
180:
181: abstract public boolean isPotentiallyAssigned(
182: LocalVariableBinding field);
183:
184: /**
185: * Check status of potential null assignment for a local. Return true if there
186: * is a reasonable expectation that the variable be non null at this point.
187: * @param local LocalVariableBinding - the binding for the checked local
188: * @return true if there is a reasonable expectation that local be non null at
189: * this point
190: */
191: public abstract boolean isPotentiallyNonNull(
192: LocalVariableBinding local);
193:
194: /**
195: * Check status of potential null assignment for a local. Return true if there
196: * is a reasonable expectation that the variable be null at this point. This
197: * includes the protected null case, so as to augment diagnostics, but does not
198: * really check that someone deliberately assigned to null on any specific
199: * path
200: * @param local LocalVariableBinding - the binding for the checked local
201: * @return true if there is a reasonable expectation that local be null at
202: * this point
203: */
204: public abstract boolean isPotentiallyNull(LocalVariableBinding local);
205:
206: /**
207: * Return true if the given local may have been assigned to an unknown value.
208: * @param local the local to check
209: * @return true if the given local may have been assigned to an unknown value
210: */
211: public abstract boolean isPotentiallyUnknown(
212: LocalVariableBinding local);
213:
214: /**
215: * Return true if the given local is protected by a test against a non null
216: * value.
217: * @param local the local to check
218: * @return true if the given local is protected by a test against a non null
219: */
220: public abstract boolean isProtectedNonNull(
221: LocalVariableBinding local);
222:
223: /**
224: * Return true if the given local is protected by a test against null.
225: * @param local the local to check
226: * @return true if the given local is protected by a test against null
227: */
228: public abstract boolean isProtectedNull(LocalVariableBinding local);
229:
230: /**
231: * Record that a local variable got checked to be non null.
232: * @param local the checked local variable
233: */
234: abstract public void markAsComparedEqualToNonNull(
235: LocalVariableBinding local);
236:
237: /**
238: * Record that a local variable got checked to be null.
239: * @param local the checked local variable
240: */
241: abstract public void markAsComparedEqualToNull(
242: LocalVariableBinding local);
243:
244: /**
245: * Record a field got definitely assigned.
246: */
247: abstract public void markAsDefinitelyAssigned(FieldBinding field);
248:
249: /**
250: * Record a local got definitely assigned to a non-null value.
251: */
252: abstract public void markAsDefinitelyNonNull(
253: LocalVariableBinding local);
254:
255: /**
256: * Record a local got definitely assigned to null.
257: */
258: abstract public void markAsDefinitelyNull(LocalVariableBinding local);
259:
260: /**
261: * Record a local got definitely assigned.
262: */
263: abstract public void markAsDefinitelyAssigned(
264: LocalVariableBinding local);
265:
266: /**
267: * Record a local got definitely assigned to an unknown value.
268: */
269: abstract public void markAsDefinitelyUnknown(
270: LocalVariableBinding local);
271:
272: /**
273: * Merge branches using optimized boolean conditions
274: */
275: public static UnconditionalFlowInfo mergedOptimizedBranches(
276: FlowInfo initsWhenTrue, boolean isOptimizedTrue,
277: FlowInfo initsWhenFalse, boolean isOptimizedFalse,
278: boolean allowFakeDeadBranch) {
279: UnconditionalFlowInfo mergedInfo;
280: if (isOptimizedTrue) {
281: if (initsWhenTrue == FlowInfo.DEAD_END
282: && allowFakeDeadBranch) {
283: mergedInfo = initsWhenFalse.setReachMode(
284: FlowInfo.UNREACHABLE).unconditionalInits();
285: } else {
286: mergedInfo = initsWhenTrue
287: .addPotentialInitializationsFrom(
288: initsWhenFalse
289: .nullInfoLessUnconditionalCopy())
290: .unconditionalInits();
291: }
292: } else if (isOptimizedFalse) {
293: if (initsWhenFalse == FlowInfo.DEAD_END
294: && allowFakeDeadBranch) {
295: mergedInfo = initsWhenTrue.setReachMode(
296: FlowInfo.UNREACHABLE).unconditionalInits();
297: } else {
298: mergedInfo = initsWhenFalse
299: .addPotentialInitializationsFrom(
300: initsWhenTrue
301: .nullInfoLessUnconditionalCopy())
302: .unconditionalInits();
303: }
304: } else {
305: mergedInfo = initsWhenTrue.mergedWith(initsWhenFalse
306: .unconditionalInits());
307: }
308: return mergedInfo;
309: }
310:
311: /**
312: * Return REACHABLE if this flow info is reachable, UNREACHABLE
313: * else.
314: * @return REACHABLE if this flow info is reachable, UNREACHABLE
315: * else
316: */
317: public int reachMode() {
318: return this .tagBits & UNREACHABLE;
319: }
320:
321: /**
322: * Return a flow info that carries the same information as the result of
323: * {@link #initsWhenTrue() initsWhenTrue}, but warrantied to be different
324: * from this.<br>
325: * Caveat: side effects on the result may affect components of this.
326: * @return the result of initsWhenTrue or a copy of it
327: */
328: abstract public FlowInfo safeInitsWhenTrue();
329:
330: /**
331: * Set this flow info reach mode and return this.
332: * @param reachMode one of {@link #REACHABLE REACHABLE} or {@link #UNREACHABLE UNREACHABLE}
333: * @return this, with the reach mode set to reachMode
334: */
335: abstract public FlowInfo setReachMode(int reachMode);
336:
337: /**
338: * Return the intersection of this and otherInits, that is
339: * one of:<ul>
340: * <li>the receiver updated in the following way:<ul>
341: * <li>intersection of definitely assigned variables,
342: * <li>union of potentially assigned variables,
343: * <li>similar operations for null,</ul>
344: * <li>or the receiver or otherInits if the other one is non
345: * reachable.</ul>
346: * otherInits is not affected, and is not returned either (no
347: * need to protect the result).
348: * @param otherInits the flow info to merge with this
349: * @return the intersection of this and otherInits.
350: */
351: abstract public UnconditionalFlowInfo mergedWith(
352: UnconditionalFlowInfo otherInits);
353:
354: /**
355: * Return a copy of this unconditional flow info, deprived from its null
356: * info. {@link #DEAD_END DEAD_END} is returned unmodified.
357: * @return a copy of this unconditional flow info deprived from its null info
358: */
359: abstract public UnconditionalFlowInfo nullInfoLessUnconditionalCopy();
360:
361: public String toString() {
362:
363: if (this == DEAD_END) {
364: return "FlowInfo.DEAD_END"; //$NON-NLS-1$
365: }
366: return super .toString();
367: }
368:
369: /**
370: * Return a new flow info that holds the same information as this would after
371: * a call to unconditionalInits, but leaving this info unaffected. Moreover,
372: * the result can be modified without affecting this.
373: * @return a new flow info carrying this unconditional flow info
374: */
375: abstract public UnconditionalFlowInfo unconditionalCopy();
376:
377: /**
378: * Return a new flow info that holds the same information as this would after
379: * a call to {@link #unconditionalInits() unconditionalInits} followed by the
380: * erasure of fields specific information, but leaving this flow info unaffected.
381: * @return a new flow info carrying the unconditional flow info for local variables
382: */
383: abstract public UnconditionalFlowInfo unconditionalFieldLessCopy();
384:
385: /**
386: * Return a flow info that merges the possible paths of execution described by
387: * this flow info. In case of an unconditional flow info, return this. In case
388: * of a conditional flow info, merge branches recursively. Caveat: this may
389: * be affected, and modifying the result may affect this.
390: * @return a flow info that merges the possible paths of execution described by
391: * this
392: */
393: abstract public UnconditionalFlowInfo unconditionalInits();
394:
395: /**
396: * Return a new flow info that holds the same information as this would after
397: * a call to {@link #unconditionalInits() unconditionalInits}, but leaving
398: * this info unaffected. Side effects on the result might affect this though
399: * (consider it as read only).
400: * @return a flow info carrying this unconditional flow info
401: */
402: abstract public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect();
403: }
|