Applying pteague's patch (re #685)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / LocalDeclaration.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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 net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
17 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21
22 public class LocalDeclaration extends AbstractVariableDeclaration {
23
24         public LocalVariableBinding binding;
25
26         public LocalDeclaration(Expression expr, char[] name, int sourceStart,
27                         int sourceEnd) {
28
29                 initialization = expr;
30                 this.name = name;
31                 this.sourceStart = sourceStart;
32                 this.sourceEnd = sourceEnd;
33                 if (initialization != null) {
34                         this.declarationSourceEnd = initialization.sourceEnd;
35                         this.declarationEnd = initialization.sourceEnd;
36                 } else {
37                         this.declarationEnd = sourceEnd;
38                 }
39         }
40
41         public FlowInfo analyseCode(BlockScope currentScope,
42                         FlowContext flowContext, FlowInfo flowInfo) {
43
44                 // record variable initialization if any
45                 if (flowInfo.isReachable()) {
46                         bits |= IsLocalDeclarationReachableMASK; // only set if actually
47                                                                                                                 // reached
48                 }
49                 if (initialization == null)
50                         return flowInfo;
51
52                 flowInfo = initialization.analyseCode(currentScope, flowContext,
53                                 flowInfo).unconditionalInits();
54
55                 // final int i = (i = 0);
56                 // no need to complain since (i = 0) part will get the blame
57                 // if (binding.isFinal() && flowInfo.isPotentiallyAssigned(binding)) {
58                 // currentScope.problemReporter().duplicateInitializationOfFinalLocal(binding,
59                 // this);
60                 // }
61
62                 flowInfo.markAsDefinitelyAssigned(binding);
63                 return flowInfo;
64         }
65
66         public void checkModifiers() {
67
68                 // only potential valid modifier is <<final>>
69                 if (((modifiers & AccJustFlag) & ~AccFinal) != 0)
70                         // AccModifierProblem -> other (non-visibility problem)
71                         // AccAlternateModifierProblem -> duplicate modifier
72                         // AccModifierProblem | AccAlternateModifierProblem -> visibility
73                         // problem"
74
75                         modifiers = (modifiers & ~AccAlternateModifierProblem)
76                                         | AccModifierProblem;
77         }
78
79         /**
80          * Code generation for a local declaration: normal assignment to a local
81          * variable + unused variable handling
82          */
83         // public void generateCode(BlockScope currentScope, CodeStream codeStream)
84         // {
85         //
86         // // even if not reachable, variable must be added to visible if allocated
87         // (28298)
88         // if (binding.resolvedPosition != -1) {
89         // codeStream.addVisibleLocalVariable(binding);
90         // }
91         // if ((bits & IsReachableMASK) == 0) {
92         // return;
93         // }
94         // int pc = codeStream.position;
95         // Constant inlinedValue;
96         //
97         // // something to initialize?
98         // if (initialization != null) {
99         // // initialize to constant value?
100         // if ((inlinedValue = initialization.constant) != NotAConstant) {
101         // // forget initializing unused or final locals set to constant value
102         // (final ones are inlined)
103         // if (binding.resolvedPosition != -1) { // may need to preserve variable
104         // int initPC = codeStream.position;
105         // codeStream.generateConstant(inlinedValue,
106         // initialization.implicitConversion);
107         // codeStream.recordPositionsFrom(initPC, initialization.sourceStart);
108         // codeStream.store(binding, false);
109         // binding.recordInitializationStartPC(codeStream.position);
110         // // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize
111         // remove index
112         // // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add
113         // index
114         // }
115         // } else { // initializing to non-constant value
116         // initialization.generateCode(currentScope, codeStream, true);
117         // // if binding unused generate then discard the value
118         // if (binding.resolvedPosition != -1) {
119         // // 26903, need extra cast to store null in array local var
120         // if (binding.type.isArrayType()
121         // && (initialization.resolvedType == NullBinding // arrayLoc = null
122         // || ((initialization instanceof CastExpression) // arrayLoc = (type[])null
123         // &&
124         // (((CastExpression)initialization).innermostCastedExpression().resolvedType
125         // == NullBinding)))){
126         // codeStream.checkcast(binding.type);
127         // }
128         // codeStream.store(binding, false);
129         // if (binding.initializationCount == 0) {
130         // /* Variable may have been initialized during the code initializing it
131         // e.g. int i = (i = 1);
132         // */
133         // binding.recordInitializationStartPC(codeStream.position);
134         // // codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize
135         // remove index
136         // // codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add
137         // index
138         // }
139         // } else {
140         // if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
141         // codeStream.pop2();
142         // } else {
143         // codeStream.pop();
144         // }
145         // }
146         // }
147         // }
148         // codeStream.recordPositionsFrom(pc, this.sourceStart);
149         // }
150         public String name() {
151
152                 return String.valueOf(name);
153         }
154
155         public void resolve(BlockScope scope) {
156
157                 // create a binding and add it to the scope
158                 TypeBinding tb = type.resolveType(scope);
159
160                 checkModifiers();
161
162                 if (tb != null) {
163                         if (tb == VoidBinding) {
164                                 scope.problemReporter().variableTypeCannotBeVoid(this);
165                                 return;
166                         }
167                         if (tb.isArrayType()
168                                         && ((ArrayBinding) tb).leafComponentType == VoidBinding) {
169                                 scope.problemReporter().variableTypeCannotBeVoidArray(this);
170                                 return;
171                         }
172                 }
173
174                 // duplicate checks
175                 if ((binding = scope.duplicateName(name)) != null) {
176                         // the name already exists... may carry on with the first binding...
177                         scope.problemReporter().redefineLocal(this);
178                 } else {
179                         if ((modifiers & AccFinal) != 0 && this.initialization == null) {
180                                 modifiers |= AccBlankFinal;
181                         }
182                         binding = new LocalVariableBinding(this, tb, modifiers, false);
183                         scope.addLocalVariable(binding);
184                         binding.constant = NotAConstant;
185                         // allow to recursivelly target the binding....
186                         // the correct constant is harmed if correctly computed at the end
187                         // of this method
188                 }
189
190                 if (tb == null) {
191                         if (initialization != null)
192                                 initialization.resolveType(scope); // want to report all
193                                                                                                         // possible errors
194                         return;
195                 }
196
197                 // store the constant for final locals
198                 if (initialization != null) {
199                         if (initialization instanceof ArrayInitializer) {
200                                 TypeBinding initTb = initialization.resolveTypeExpecting(scope,
201                                                 tb);
202                                 if (initTb != null) {
203                                         ((ArrayInitializer) initialization).binding = (ArrayBinding) initTb;
204                                         initialization.implicitWidening(tb, initTb);
205                                 }
206                         } else {
207                                 TypeBinding initTb = initialization.resolveType(scope);
208                                 if (initTb != null) {
209                                         if (initialization.isConstantValueOfTypeAssignableToType(
210                                                         initTb, tb)
211                                                         || (tb.isBaseType() && BaseTypeBinding.isWidening(
212                                                                         tb.id, initTb.id))
213                                                         || initTb.isCompatibleWith(tb))
214                                                 initialization.implicitWidening(tb, initTb);
215                                         else
216                                                 scope.problemReporter().typeMismatchError(initTb, tb,
217                                                                 this);
218                                 }
219                         }
220
221                         // change the constant in the binding when it is final
222                         // (the optimization of the constant propagation will be done later
223                         // on)
224                         // cast from constant actual type to variable type
225                         binding.constant = binding.isFinal() ? initialization.constant
226                                         .castTo((tb.id << 4) + initialization.constant.typeID())
227                                         : NotAConstant;
228                 }
229         }
230
231         public void traverse(ASTVisitor visitor, BlockScope scope) {
232
233                 if (visitor.visit(this, scope)) {
234                         type.traverse(visitor, scope);
235                         if (initialization != null)
236                                 initialization.traverse(visitor, scope);
237                 }
238                 visitor.endVisit(this, scope);
239         }
240 }