added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / flow / LoopingFlowContext.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-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.Label;
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 Label continueLabel;
30         public UnconditionalFlowInfo initsOnContinue = FlowInfo.DEAD_END;
31         Reference finalAssignments[];
32         VariableBinding finalVariables[];
33         int assignCount = 0;
34         
35         Expression[] nullReferences;
36         int[] nullStatus;
37         int nullCount;
38         
39         Scope associatedScope;
40         
41         public LoopingFlowContext(
42                 FlowContext parent,
43                 ASTNode associatedNode,
44                 Label breakLabel,
45                 Label continueLabel,
46                 Scope associatedScope) {
47                 super(parent, associatedNode, breakLabel);
48                 this.continueLabel = continueLabel;
49                 this.associatedScope = associatedScope;
50         }
51         
52         public void complainOnDeferredChecks(BlockScope scope, FlowInfo flowInfo) {
53                 
54                 // complain on final assignments in loops
55                 for (int i = 0; i < assignCount; i++) {
56                         VariableBinding variable = finalVariables[i];
57                         if (variable == null) continue;
58                         boolean complained = false; // remember if have complained on this final assignment
59                         if (variable instanceof FieldBinding) {
60                                 if (flowInfo.isPotentiallyAssigned((FieldBinding) variable)) {
61                                         complained = true;
62                                         scope.problemReporter().duplicateInitializationOfBlankFinalField(
63                                                 (FieldBinding) variable,
64                                                 finalAssignments[i]);
65                                 }
66                         } else {
67                                 if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
68                                         complained = true;
69                                         scope.problemReporter().duplicateInitializationOfFinalLocal(
70                                                 (LocalVariableBinding) variable,
71                                                 finalAssignments[i]);
72                                 }
73                         }
74                         // any reference reported at this level is removed from the parent context where it 
75                         // could also be reported again
76                         if (complained) {
77                                 FlowContext context = parent;
78                                 while (context != null) {
79                                         context.removeFinalAssignmentIfAny(finalAssignments[i]);
80                                         context = context.parent;
81                                 }
82                         }
83                 }
84                 // check inconsistent null checks
85                 for (int i = 0; i < nullCount; i++) {
86                         Expression expression = nullReferences[i];
87                         if (expression == null) continue;
88                         // final local variable
89                         LocalVariableBinding local = expression.localVariableBinding();
90                         switch (nullStatus[i]) {
91                                 case FlowInfo.NULL :
92                                         if (flowInfo.isDefinitelyNull(local)) {
93                                                 nullReferences[i] = null;
94                                                 this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
95                                         }
96                                         break;
97                                 case FlowInfo.NON_NULL :
98                                         if (flowInfo.isDefinitelyNonNull(local)) {
99                                                 nullReferences[i] = null;
100                                                 this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
101                                         }
102                                         break;
103                         }
104                 }               
105         }
106
107         public Label continueLabel() {
108                 return continueLabel;
109         }
110
111         public String individualToString() {
112                 StringBuffer buffer = new StringBuffer("Looping flow context"); //$NON-NLS-1$
113                 buffer.append("[initsOnBreak - ").append(initsOnBreak.toString()).append(']'); //$NON-NLS-1$
114                 buffer.append("[initsOnContinue - ").append(initsOnContinue.toString()).append(']'); //$NON-NLS-1$
115                 buffer.append("[finalAssignments count - ").append(assignCount).append(']'); //$NON-NLS-1$
116                 buffer.append("[nullReferences count - ").append(nullCount).append(']'); //$NON-NLS-1$
117                 return buffer.toString();
118         }
119
120         public boolean isContinuable() {
121                 return true;
122         }
123
124         public boolean isContinuedTo() {
125                 return initsOnContinue != FlowInfo.DEAD_END;
126         }
127
128         public void recordContinueFrom(FlowInfo flowInfo) {
129
130                 if (!flowInfo.isReachable()) return;
131                 if (initsOnContinue == FlowInfo.DEAD_END) {
132                         initsOnContinue = flowInfo.copy().unconditionalInits();
133                 } else {
134                         initsOnContinue = initsOnContinue.mergedWith(flowInfo.copy().unconditionalInits());
135                 }
136         }
137
138         protected boolean recordFinalAssignment(
139                 VariableBinding binding,
140                 Reference finalAssignment) {
141
142                 // do not consider variables which are defined inside this loop
143                 if (binding instanceof LocalVariableBinding) {
144                         Scope scope = ((LocalVariableBinding) binding).declaringScope;
145                         while ((scope = scope.parent) != null) {
146                                 if (scope == associatedScope)
147                                         return false;
148                         }
149                 }
150                 if (assignCount == 0) {
151                         finalAssignments = new Reference[5];
152                         finalVariables = new VariableBinding[5];
153                 } else {
154                         if (assignCount == finalAssignments.length)
155                                 System.arraycopy(
156                                         finalAssignments,
157                                         0,
158                                         (finalAssignments = new Reference[assignCount * 2]),
159                                         0,
160                                         assignCount);
161                         System.arraycopy(
162                                 finalVariables,
163                                 0,
164                                 (finalVariables = new VariableBinding[assignCount * 2]),
165                                 0,
166                                 assignCount);
167                 }
168                 finalAssignments[assignCount] = finalAssignment;
169                 finalVariables[assignCount++] = binding;
170                 return true;
171         }
172
173         protected boolean recordNullReference(Expression expression, int status) {
174                 if (nullCount == 0) {
175                         nullReferences = new Expression[5];
176                         nullStatus = new int[5];
177                 } else {
178                         if (nullCount == nullReferences.length) {
179                                 System.arraycopy(nullReferences, 0, nullReferences = new Expression[nullCount * 2], 0, nullCount);
180                                 System.arraycopy(nullStatus, 0, nullStatus = new int[nullCount * 2], 0, nullCount);
181                         }
182                 }
183                 nullReferences[nullCount] = expression;
184                 nullStatus[nullCount++] = status;
185                 return true;
186         }       
187         
188         void removeFinalAssignmentIfAny(Reference reference) {
189                 for (int i = 0; i < assignCount; i++) {
190                         if (finalAssignments[i] == reference) {
191                                 finalAssignments[i] = null;
192                                 finalVariables[i] = null;
193                                 return;
194                         }
195                 }
196         }
197 }