added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / flow / FinallyFlowContext.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.lookup.BlockScope;
17 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
18 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
19 import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
20
21 /**
22  * Reflects the context of code analysis, keeping track of enclosing
23  *      try statements, exception handlers, etc...
24  */
25 public class FinallyFlowContext extends FlowContext {
26         
27         Reference[] finalAssignments;
28         VariableBinding[] finalVariables;
29         int assignCount;
30
31         Expression[] nullReferences;
32         int[] nullStatus;
33         int nullCount;
34         
35         public FinallyFlowContext(FlowContext parent, ASTNode associatedNode) {
36                 super(parent, associatedNode);
37         }
38
39         /**
40          * Given some contextual initialization info (derived from a try block or a catch block), this 
41          * code will check that the subroutine context does not also initialize a final variable potentially set
42          * redundantly.
43          */
44         public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) {
45                 
46                 // check redundant final assignments
47                 for (int i = 0; i < assignCount; i++) {
48                         VariableBinding variable = finalVariables[i];
49                         if (variable == null) continue;
50                         
51                         boolean complained = false; // remember if have complained on this final assignment
52                         if (variable instanceof FieldBinding) {
53                                 // final field
54                                 if (flowInfo.isPotentiallyAssigned((FieldBinding)variable)) {
55                                         complained = true;
56                                         scope.problemReporter().duplicateInitializationOfBlankFinalField((FieldBinding)variable, finalAssignments[i]);
57                                 }
58                         } else {
59                                 // final local variable
60                                 if (flowInfo.isPotentiallyAssigned((LocalVariableBinding) variable)) {
61                                         complained = true;
62                                         scope.problemReporter().duplicateInitializationOfFinalLocal(
63                                                 (LocalVariableBinding) variable,
64                                                 finalAssignments[i]);
65                                 }
66                         }
67                         // any reference reported at this level is removed from the parent context 
68                         // where it could also be reported again
69                         if (complained) {
70                                 FlowContext currentContext = parent;
71                                 while (currentContext != null) {
72                                         //if (currentContext.isSubRoutine()) {
73                                         currentContext.removeFinalAssignmentIfAny(finalAssignments[i]);
74                                         //}
75                                         currentContext = currentContext.parent;
76                                 }
77                         }
78                 }
79                 
80                 // check inconsistent null checks
81                 for (int i = 0; i < nullCount; i++) {
82                         Expression expression = nullReferences[i];
83                         if (expression == null) continue;
84                         // final local variable
85                         LocalVariableBinding local = expression.localVariableBinding();
86                         switch (nullStatus[i]) {
87                                 case FlowInfo.NULL :
88                                         if (flowInfo.isDefinitelyNull(local)) {
89                                                 nullReferences[i] = null;
90                                                 this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
91                                         }
92                                         break;
93                                 case FlowInfo.NON_NULL :
94                                         if (flowInfo.isDefinitelyNonNull(local)) {
95                                                 nullReferences[i] = null;
96                                                 this.parent.recordUsingNullReference(scope, local, expression, nullStatus[i], flowInfo);
97                                         }
98                                         break;
99                         }
100                 }
101         }
102         
103         public String individualToString() {
104                 
105                 StringBuffer buffer = new StringBuffer("Finally flow context"); //$NON-NLS-1$
106                 buffer.append("[finalAssignments count - ").append(assignCount).append(']'); //$NON-NLS-1$
107                 buffer.append("[nullReferences count - ").append(nullCount).append(']'); //$NON-NLS-1$
108                 return buffer.toString();
109         }
110         
111         public boolean isSubRoutine() {
112                 return true;
113         }
114         
115         protected boolean recordFinalAssignment(
116                 VariableBinding binding,
117                 Reference finalAssignment) {
118                 if (assignCount == 0) {
119                         finalAssignments = new Reference[5];
120                         finalVariables = new VariableBinding[5];
121                 } else {
122                         if (assignCount == finalAssignments.length)
123                                 System.arraycopy(
124                                         finalAssignments,
125                                         0,
126                                         (finalAssignments = new Reference[assignCount * 2]),
127                                         0,
128                                         assignCount);
129                         System.arraycopy(
130                                 finalVariables,
131                                 0,
132                                 (finalVariables = new VariableBinding[assignCount * 2]),
133                                 0,
134                                 assignCount);
135                 }
136                 finalAssignments[assignCount] = finalAssignment;
137                 finalVariables[assignCount++] = binding;
138                 return true;
139         }
140
141         void removeFinalAssignmentIfAny(Reference reference) {
142                 for (int i = 0; i < assignCount; i++) {
143                         if (finalAssignments[i] == reference) {
144                                 finalAssignments[i] = null;
145                                 finalVariables[i] = null;
146                                 return;
147                         }
148                 }
149         }
150
151         protected boolean recordNullReference(Expression expression, int status) {
152                 if (nullCount == 0) {
153                         nullReferences = new Expression[5];
154                         nullStatus = new int[5];
155                 } else {
156                         if (nullCount == nullReferences.length) {
157                                 System.arraycopy(nullReferences, 0, nullReferences = new Expression[nullCount * 2], 0, nullCount);
158                                 System.arraycopy(nullStatus, 0, nullStatus = new int[nullCount * 2], 0, nullCount);
159                         }
160                 }
161                 nullReferences[nullCount] = expression;
162                 nullStatus[nullCount++] = status;
163                 return true;
164         }
165 }