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