*** empty log message ***
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / LocalDeclaration.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.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.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
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                 } else {
41                         this.declarationSourceEnd = sourceEnd;
42                 }
43                 this.declarationEnd = this.declarationSourceEnd;
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.isDeadEnd() && !flowInfo.isFakeReachable()) {
53                         bits |= IsLocalDeclarationReachableMASK; // only set if actually reached
54                 }
55                 if (initialization == null)
56                         return flowInfo;
57                 flowInfo =
58                         initialization
59                                 .analyseCode(currentScope, flowContext, flowInfo)
60                                 .unconditionalInits();
61                 flowInfo.markAsDefinitelyAssigned(binding);
62                 return flowInfo;
63         }
64
65         public void checkModifiers() {
66                 //only potential valid modifier is <<final>>
67
68                 if (((modifiers & AccJustFlag) | AccFinal) != AccFinal)
69                         //AccModifierProblem -> other (non-visibility problem)
70                         //AccAlternateModifierProblem -> duplicate modifier
71                         //AccModifierProblem | AccAlternateModifierProblem -> visibility problem"
72                         // -x-1 returns the bitInvert 
73
74                         modifiers =
75                                 (modifiers & (-AccAlternateModifierProblem - 1)) | AccModifierProblem;
76         }
77
78         /**
79          * Code generation for a local declaration:
80          *      i.e.&nbsp;normal assignment to a local variable + unused variable handling 
81          */
82         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
83
84                 if ((bits & IsReachableMASK) == 0) {
85                         return;
86                 }
87                 int pc = codeStream.position;
88                 Constant inlinedValue;
89                 // something to initialize?
90                 if (binding.resolvedPosition != -1) {
91                         codeStream.addVisibleLocalVariable(binding);
92                 }
93                 if (initialization != null) {
94                         // initialize to constant value?
95                         if ((inlinedValue = initialization.constant) != NotAConstant) {
96                                 // forget initializing unused or final locals set to constant value (final ones are inlined)
97                                 if (binding.resolvedPosition != -1) { // may need to preserve variable
98                                         int initPC = codeStream.position;
99                                         codeStream.generateConstant(inlinedValue, initialization.implicitConversion);
100                                         codeStream.recordPositionsFrom(initPC, initialization.sourceStart);
101                                         codeStream.store(binding, false);
102                                         binding.recordInitializationStartPC(codeStream.position);
103                                         //                              codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index 
104                                         //                              codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index            
105                                 }
106                         } else { // initializing to non-constant value
107                                 initialization.generateCode(currentScope, codeStream, true);
108                                 // if binding unused generate then discard the value
109                                 if (binding.resolvedPosition != -1) {
110                                         codeStream.store(binding, false);
111                                         if (binding.initializationCount == 0) {
112                                                 /* Variable may have been initialized during the code initializing it
113                                                         e.g. int i = (i = 1);
114                                                 */
115                                                 binding.recordInitializationStartPC(codeStream.position);
116                                                 //                                      codeStream.lastInitStateIndexWhenRemovingInits = -2; // reinitialize remove index 
117                                                 //                                      codeStream.lastInitStateIndexWhenAddingInits = -2; // reinitialize add index 
118                                         }
119                                 } else {
120                                         if ((binding.type == LongBinding) || (binding.type == DoubleBinding)) {
121                                                 codeStream.pop2();
122                                         } else {
123                                                 codeStream.pop();
124                                         }
125                                 }
126                         }
127                 }
128                 codeStream.recordPositionsFrom(pc, this.sourceStart);
129         }
130
131         public String name() {
132
133                 return String.valueOf(name);
134         }
135
136         public void resolve(BlockScope scope) {
137
138                 // create a binding and add it to the scope
139                 TypeBinding tb = type.resolveType(scope);
140
141                 checkModifiers();
142
143                 if (tb != null) {
144                         if (tb == VoidBinding) {
145                                 scope.problemReporter().variableTypeCannotBeVoid(this);
146                                 return;
147                         }
148                         if (tb.isArrayType() && ((ArrayBinding) tb).leafComponentType == VoidBinding) {
149                                 scope.problemReporter().variableTypeCannotBeVoidArray(this);
150                                 return;
151                         }
152                 }
153
154                 // duplicate checks
155                 if ((binding = scope.duplicateName(name)) != null) {
156                         // the name already exists... may carry on with the first binding...
157                         scope.problemReporter().redefineLocal(this);
158                 } else {
159                         binding = new LocalVariableBinding(this, tb, modifiers, false);
160                         scope.addLocalVariable(binding);
161                         binding.constant = NotAConstant;
162                         // allow to recursivelly target the binding....
163                         // the correct constant is harmed if correctly computed at the end of this method
164                 }
165
166                 if (tb == null) {
167                         if (initialization != null)
168                                 initialization.resolveType(scope); // want to report all possible errors
169                         return;
170                 }
171
172                 // store the constant for final locals  
173                 if (initialization != null) {
174                         if (initialization instanceof ArrayInitializer) {
175                                 TypeBinding initTb = initialization.resolveTypeExpecting(scope, tb);
176                                 if (initTb != null) {
177                                         ((ArrayInitializer) initialization).binding = (ArrayBinding) initTb;
178                                         initialization.implicitWidening(tb, initTb);
179                                 }
180                         } else {
181                                 TypeBinding initTb = initialization.resolveType(scope);
182                                 if (initTb != null) {
183                                         if (initialization.isConstantValueOfTypeAssignableToType(initTb, tb)
184                                                 || (tb.isBaseType() && BaseTypeBinding.isWidening(tb.id, initTb.id))
185                                                 || BlockScope.areTypesCompatible(initTb, tb))
186                                                 initialization.implicitWidening(tb, initTb);
187                                         else
188                                                 scope.problemReporter().typeMismatchError(initTb, tb, this);
189                                 }
190                         }
191
192                         // change the constant in the binding when it is final
193                         // (the optimization of the constant propagation will be done later on)
194                         // cast from constant actual type to variable type
195                         binding.constant =
196                                 binding.isFinal()
197                                         ? initialization.constant.castTo((tb.id << 4) + initialization.constant.typeID())
198                                         : NotAConstant;
199                 }
200         }
201
202         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
203
204                 if (visitor.visit(this, scope)) {
205                         type.traverse(visitor, scope);
206                         if (initialization != null)
207                                 initialization.traverse(visitor, scope);
208                 }
209                 visitor.endVisit(this, scope);
210         }
211 }