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