KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > flow > LoopingFlowContext


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11 package org.eclipse.jdt.internal.compiler.flow;
12
13 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
14 import org.eclipse.jdt.internal.compiler.ast.Expression;
15 import org.eclipse.jdt.internal.compiler.ast.Reference;
16 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
17 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
18 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
19 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
20 import org.eclipse.jdt.internal.compiler.lookup.Scope;
21 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
22
23 /**
24  * Reflects the context of code analysis, keeping track of enclosing
25  * try statements, exception handlers, etc...
26  */

27 public class LoopingFlowContext extends SwitchFlowContext {
28     
29     public BranchLabel continueLabel;
30     public UnconditionalFlowInfo initsOnContinue = FlowInfo.DEAD_END;
31     private UnconditionalFlowInfo upstreamNullFlowInfo;
32     private LoopingFlowContext innerFlowContexts[] = null;
33     private UnconditionalFlowInfo innerFlowInfos[] = null;
34     private int innerFlowContextsCount = 0;
35     private LabelFlowContext breakTargetContexts[] = null;
36     private int breakTargetsCount = 0;
37     
38     Reference finalAssignments[];
39     VariableBinding finalVariables[];
40     int assignCount = 0;
41     
42     LocalVariableBinding[] nullLocals;
43     Expression[] nullReferences;
44     int[] nullCheckTypes;
45     int nullCount;
46     
47     Scope associatedScope;
48     
49     public LoopingFlowContext(
50         FlowContext parent,
51         FlowInfo upstreamNullFlowInfo,
52         ASTNode associatedNode,
53         BranchLabel breakLabel,
54         BranchLabel continueLabel,
55         Scope associatedScope) {
56         super(parent, associatedNode, breakLabel);
57         preemptNullDiagnostic = true;
58             // children will defer to this, which may defer to its own parent
59
this.continueLabel = continueLabel;
60         this.associatedScope = associatedScope;
61         this.upstreamNullFlowInfo = upstreamNullFlowInfo.unconditionalCopy();
62     }
63
64 /**
65  * Perform deferred checks relative to final variables duplicate initialization
66  * of lack of initialization.
67  * @param scope the scope to which this context is associated
68  * @param flowInfo the flow info against which checks must be performed
69  */

70 public void complainOnDeferredFinalChecks(BlockScope scope, FlowInfo flowInfo) {
71     // complain on final assignments in loops
72
for (int i = 0; i < assignCount; i++) {
73         VariableBinding variable = finalVariables[i];
74         if (variable == null) continue;
75         boolean complained = false; // remember if have complained on this final assignment
76
if (variable instanceof FieldBinding) {
77             if (flowInfo.isPotentiallyAssigned((FieldBinding) variable)) {
78                 complained = true;
79                 scope.problemReporter().duplicateInitializationOfBlankFinalField(
80                     (FieldBinding) variable,
81                     finalAssignments[i]);
82             }
83         } else {
84             if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
85                 complained = true;
86                 scope.problemReporter().duplicateInitializationOfFinalLocal(
87                     (LocalVariableBinding) variable,
88                     finalAssignments[i]);
89             }
90         }
91         // any reference reported at this level is removed from the parent context where it
92
// could also be reported again
93
if (complained) {
94             FlowContext context = parent;
95             while (context != null) {
96                 context.removeFinalAssignmentIfAny(finalAssignments[i]);
97                 context = context.parent;
98             }
99         }
100     }
101 }
102
103 /**
104  * Perform deferred checks relative to the null status of local variables.
105  * @param scope the scope to which this context is associated
106  * @param callerFlowInfo the flow info against which checks must be performed
107  */

108 public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowInfo) {
109     for (int i = 0 ; i < this.innerFlowContextsCount ; i++) {
110         this.upstreamNullFlowInfo.
111             addPotentialNullInfoFrom(
112                 this.innerFlowContexts[i].upstreamNullFlowInfo).
113             addPotentialNullInfoFrom(this.innerFlowInfos[i]);
114     }
115     this.innerFlowContextsCount = 0;
116     UnconditionalFlowInfo flowInfo = this.upstreamNullFlowInfo.
117         addPotentialNullInfoFrom(callerFlowInfo.unconditionalInitsWithoutSideEffect());
118     if (this.deferNullDiagnostic) {
119         // check only immutable null checks on innermost looping context
120
for (int i = 0; i < this.nullCount; i++) {
121             LocalVariableBinding local = this.nullLocals[i];
122             Expression expression = this.nullReferences[i];
123             // final local variable
124
switch (this.nullCheckTypes[i]) {
125                 case CAN_ONLY_NON_NULL | IN_COMPARISON_NULL:
126                 case CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL:
127                     if (flowInfo.isDefinitelyNonNull(local)) {
128                         this.nullReferences[i] = null;
129                         if (this.nullCheckTypes[i] == (CAN_ONLY_NON_NULL | IN_COMPARISON_NON_NULL)) {
130                             scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
131                         } else {
132                             scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
133                         }
134                         continue;
135                     }
136                     break;
137                 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
138                 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
139                     if (flowInfo.isDefinitelyNonNull(local)) {
140                         this.nullReferences[i] = null;
141                         if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
142                             scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
143                         } else {
144                             scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
145                         }
146                         continue;
147                     }
148                     if (flowInfo.isDefinitelyNull(local)) {
149                         this.nullReferences[i] = null;
150                         if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
151                             scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
152                         } else {
153                             scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
154                         }
155                         continue;
156                     }
157                     break;
158                 case CAN_ONLY_NULL | IN_COMPARISON_NULL:
159                 case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
160                 case CAN_ONLY_NULL | IN_ASSIGNMENT:
161                 case CAN_ONLY_NULL | IN_INSTANCEOF:
162                     if (flowInfo.isDefinitelyNull(local)) {
163                         this.nullReferences[i] = null;
164                         switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
165                             case FlowContext.IN_COMPARISON_NULL:
166                                 scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
167                                 continue;
168                             case FlowContext.IN_COMPARISON_NON_NULL:
169                                 scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
170                                 continue;
171                             case FlowContext.IN_ASSIGNMENT:
172                                 scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
173                                 continue;
174                             case FlowContext.IN_INSTANCEOF:
175                                 scope.problemReporter().localVariableNullInstanceof(local, expression);
176                                 continue;
177                         }
178                     }
179                     break;
180                 case MAY_NULL:
181                     if (flowInfo.isDefinitelyNull(local)) {
182                         this.nullReferences[i] = null;
183                         scope.problemReporter().localVariableNullReference(local, expression);
184                         continue;
185                     }
186                     break;
187                 default:
188                     // never happens
189
}
190             this.parent.recordUsingNullReference(scope, local, expression,
191                     this.nullCheckTypes[i], flowInfo);
192         }
193     }
194     else {
195         // check inconsistent null checks on outermost looping context
196
for (int i = 0; i < this.nullCount; i++) {
197             Expression expression = this.nullReferences[i];
198             // final local variable
199
LocalVariableBinding local = this.nullLocals[i];
200             switch (this.nullCheckTypes[i]) {
201                 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
202                 case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
203                     if (flowInfo.isDefinitelyNonNull(local)) {
204                         this.nullReferences[i] = null;
205                         if (this.nullCheckTypes[i] == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
206                             scope.problemReporter().localVariableRedundantCheckOnNonNull(local, expression);
207                         } else {
208                             scope.problemReporter().localVariableNonNullComparedToNull(local, expression);
209                         }
210                         continue;
211                     }
212                 case CAN_ONLY_NULL | IN_COMPARISON_NULL:
213                 case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
214                 case CAN_ONLY_NULL | IN_ASSIGNMENT:
215                 case CAN_ONLY_NULL | IN_INSTANCEOF:
216                     if (flowInfo.isDefinitelyNull(local)) {
217                         this.nullReferences[i] = null;
218                         switch(this.nullCheckTypes[i] & CONTEXT_MASK) {
219                             case FlowContext.IN_COMPARISON_NULL:
220                                 scope.problemReporter().localVariableRedundantCheckOnNull(local, expression);
221                                 continue;
222                             case FlowContext.IN_COMPARISON_NON_NULL:
223                                 scope.problemReporter().localVariableNullComparedToNonNull(local, expression);
224                                 continue;
225                             case FlowContext.IN_ASSIGNMENT:
226                                 scope.problemReporter().localVariableRedundantNullAssignment(local, expression);
227                                 continue;
228                             case FlowContext.IN_INSTANCEOF:
229                                 scope.problemReporter().localVariableNullInstanceof(local, expression);
230                                 continue;
231                         }
232                     }
233                     break;
234                 case MAY_NULL:
235                     if (flowInfo.isDefinitelyNull(local)) {
236                         this.nullReferences[i] = null;
237                         scope.problemReporter().localVariableNullReference(local, expression);
238                         continue;
239                     }
240                     if (flowInfo.isPotentiallyNull(local)) {
241                         this.nullReferences[i] = null;
242                         scope.problemReporter().localVariablePotentialNullReference(local, expression);
243                         continue;
244                     }
245                     break;
246                 default:
247                     // never happens
248
}
249         }
250     }
251     // propagate breaks
252
for (int i = 0; i < this.breakTargetsCount; i++) {
253         this.breakTargetContexts[i].initsOnBreak.addPotentialNullInfoFrom(flowInfo);
254     }
255 }
256     
257     public BranchLabel continueLabel() {
258         return continueLabel;
259     }
260
261     public String JavaDoc individualToString() {
262         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("Looping flow context"); //$NON-NLS-1$
263
buffer.append("[initsOnBreak - ").append(initsOnBreak.toString()).append(']'); //$NON-NLS-1$
264
buffer.append("[initsOnContinue - ").append(initsOnContinue.toString()).append(']'); //$NON-NLS-1$
265
buffer.append("[finalAssignments count - ").append(assignCount).append(']'); //$NON-NLS-1$
266
buffer.append("[nullReferences count - ").append(nullCount).append(']'); //$NON-NLS-1$
267
return buffer.toString();
268     }
269
270     public boolean isContinuable() {
271         return true;
272     }
273
274     public boolean isContinuedTo() {
275         return initsOnContinue != FlowInfo.DEAD_END;
276     }
277
278 public void recordBreakTo(FlowContext targetContext) {
279     if (targetContext instanceof LabelFlowContext) {
280         int current;
281         if ((current = this.breakTargetsCount++) == 0) {
282             this.breakTargetContexts = new LabelFlowContext[2];
283         } else if (current == this.breakTargetContexts.length) {
284             System.arraycopy(this.breakTargetContexts, 0, this.breakTargetContexts = new LabelFlowContext[current + 2], 0, current);
285         }
286         this.breakTargetContexts[current] = (LabelFlowContext) targetContext;
287     }
288 }
289
290 public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) {
291     if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
292     if ((initsOnContinue.tagBits & FlowInfo.UNREACHABLE) == 0) {
293         initsOnContinue = initsOnContinue.
294             mergedWith(flowInfo.unconditionalInitsWithoutSideEffect());
295     }
296     else {
297         initsOnContinue = flowInfo.unconditionalCopy();
298     }
299     FlowContext inner = innerFlowContext;
300     while (inner != this && !(inner instanceof LoopingFlowContext)) {
301         inner = inner.parent;
302     }
303     if (inner == this) {
304         this.upstreamNullFlowInfo.
305             addPotentialNullInfoFrom(
306                 flowInfo.unconditionalInitsWithoutSideEffect());
307     }
308     else {
309         int length = 0;
310         if (this.innerFlowContexts == null) {
311             this.innerFlowContexts = new LoopingFlowContext[5];
312             this.innerFlowInfos = new UnconditionalFlowInfo[5];
313         }
314         else if (this.innerFlowContextsCount ==
315                 (length = this.innerFlowContexts.length) - 1) {
316             System.arraycopy(this.innerFlowContexts, 0,
317                 (this.innerFlowContexts = new LoopingFlowContext[length + 5]),
318                 0, length);
319             System.arraycopy(this.innerFlowInfos, 0,
320                 (this.innerFlowInfos= new UnconditionalFlowInfo[length + 5]),
321                 0, length);
322         }
323         this.innerFlowContexts[this.innerFlowContextsCount] = (LoopingFlowContext) inner;
324         this.innerFlowInfos[this.innerFlowContextsCount++] =
325             flowInfo.unconditionalInitsWithoutSideEffect();
326     }
327     }
328 }
329
330     protected boolean recordFinalAssignment(
331         VariableBinding binding,
332         Reference finalAssignment) {
333
334         // do not consider variables which are defined inside this loop
335
if (binding instanceof LocalVariableBinding) {
336             Scope scope = ((LocalVariableBinding) binding).declaringScope;
337             while ((scope = scope.parent) != null) {
338                 if (scope == associatedScope)
339                     return false;
340             }
341         }
342         if (assignCount == 0) {
343             finalAssignments = new Reference[5];
344             finalVariables = new VariableBinding[5];
345         } else {
346             if (assignCount == finalAssignments.length)
347                 System.arraycopy(
348                     finalAssignments,
349                     0,
350                     (finalAssignments = new Reference[assignCount * 2]),
351                     0,
352                     assignCount);
353             System.arraycopy(
354                 finalVariables,
355                 0,
356                 (finalVariables = new VariableBinding[assignCount * 2]),
357                 0,
358                 assignCount);
359         }
360         finalAssignments[assignCount] = finalAssignment;
361         finalVariables[assignCount++] = binding;
362         return true;
363     }
364
365 protected void recordNullReference(LocalVariableBinding local,
366     Expression expression, int status) {
367     if (nullCount == 0) {
368         nullLocals = new LocalVariableBinding[5];
369         nullReferences = new Expression[5];
370         nullCheckTypes = new int[5];
371     }
372     else if (nullCount == nullLocals.length) {
373         System.arraycopy(nullLocals, 0,
374             nullLocals = new LocalVariableBinding[nullCount * 2], 0, nullCount);
375         System.arraycopy(nullReferences, 0,
376             nullReferences = new Expression[nullCount * 2], 0, nullCount);
377         System.arraycopy(nullCheckTypes, 0,
378             nullCheckTypes = new int[nullCount * 2], 0, nullCount);
379     }
380     nullLocals[nullCount] = local;
381     nullReferences[nullCount] = expression;
382     nullCheckTypes[nullCount++] = status;
383 }
384     
385 public void recordUsingNullReference(Scope scope, LocalVariableBinding local,
386         Expression reference, int checkType, FlowInfo flowInfo) {
387     if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0 ||
388             flowInfo.isDefinitelyUnknown(local)) {
389         return;
390     }
391     switch (checkType) {
392         case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL:
393         case CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL:
394             if (flowInfo.isDefinitelyNonNull(local)) {
395                 if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NON_NULL)) {
396                     scope.problemReporter().localVariableRedundantCheckOnNonNull(local, reference);
397                 } else {
398                     scope.problemReporter().localVariableNonNullComparedToNull(local, reference);
399                 }
400             } else if (flowInfo.isDefinitelyNull(local)) {
401                 if (checkType == (CAN_ONLY_NULL_NON_NULL | IN_COMPARISON_NULL)) {
402                     scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
403                 } else {
404                     scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
405                 }
406             } else if (! flowInfo.cannotBeDefinitelyNullOrNonNull(local)) {
407                 if (flowInfo.isPotentiallyNonNull(local)) {
408                     recordNullReference(local, reference, CAN_ONLY_NON_NULL | checkType & CONTEXT_MASK);
409                 } else {
410                     recordNullReference(local, reference, checkType);
411                 }
412             }
413             return;
414         case CAN_ONLY_NULL | IN_COMPARISON_NULL:
415         case CAN_ONLY_NULL | IN_COMPARISON_NON_NULL:
416         case CAN_ONLY_NULL | IN_ASSIGNMENT:
417         case CAN_ONLY_NULL | IN_INSTANCEOF:
418             if (flowInfo.isPotentiallyNonNull(local)
419                     || flowInfo.isPotentiallyUnknown(local)) {
420                 return;
421             }
422             if (flowInfo.isDefinitelyNull(local)) {
423                 switch(checkType & CONTEXT_MASK) {
424                     case FlowContext.IN_COMPARISON_NULL:
425                         scope.problemReporter().localVariableRedundantCheckOnNull(local, reference);
426                         return;
427                     case FlowContext.IN_COMPARISON_NON_NULL:
428                         scope.problemReporter().localVariableNullComparedToNonNull(local, reference);
429                         return;
430                     case FlowContext.IN_ASSIGNMENT:
431                         scope.problemReporter().localVariableRedundantNullAssignment(local, reference);
432                         return;
433                     case FlowContext.IN_INSTANCEOF:
434                         scope.problemReporter().localVariableNullInstanceof(local, reference);
435                         return;
436                 }
437             }
438             recordNullReference(local, reference, checkType);
439             return;
440         case MAY_NULL :
441             if (flowInfo.isDefinitelyNonNull(local)) {
442                 return;
443             }
444             if (flowInfo.isDefinitelyNull(local)) {
445                 scope.problemReporter().localVariableNullReference(local, reference);
446                 return;
447             }
448             if (flowInfo.isPotentiallyNull(local)) {
449                 scope.problemReporter().localVariablePotentialNullReference(local, reference);
450                 return;
451             }
452             recordNullReference(local, reference, checkType);
453             return;
454         default:
455             // never happens
456
}
457 }
458     
459     void removeFinalAssignmentIfAny(Reference reference) {
460         for (int i = 0; i < assignCount; i++) {
461             if (finalAssignments[i] == reference) {
462                 finalAssignments[i] = null;
463                 finalVariables[i] = null;
464                 return;
465             }
466         }
467     }
468 }
469
Popular Tags