c654dfc48811edec2ff67aac8590f1a93abb4cc7
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / FieldDeclaration.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.FieldBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
23 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
24 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
26
27 public class FieldDeclaration extends AbstractVariableDeclaration {
28         public FieldBinding binding;
29         boolean hasBeenResolved = false;
30
31         //allows to retrieve both the "type" part of the declaration (part1)
32         //and also the part that decribe the name and the init and optionally
33         //some other dimension ! .... 
34         //public int[] a, b[] = X, c ;
35         //for b that would give for 
36         // - part1 : public int[]
37         // - part2 : b[] = X,
38
39         public int endPart1Position;
40         public int endPart2Position;
41
42         public FieldDeclaration() {
43         }
44
45         public FieldDeclaration(
46                 Expression initialization,
47                 char[] name,
48                 int sourceStart,
49                 int sourceEnd) {
50
51                 this.initialization = initialization;
52                 this.name = name;
53
54                 //due to some declaration like 
55                 // int x, y = 3, z , x ;
56                 //the sourceStart and the sourceEnd is ONLY on  the name
57                 this.sourceStart = sourceStart;
58                 this.sourceEnd = sourceEnd;
59         }
60
61         public FlowInfo analyseCode(
62                 MethodScope initializationScope,
63                 FlowContext flowContext,
64                 FlowInfo flowInfo) {
65
66                 // cannot define static non-constant field inside nested class
67                 if (binding != null
68                         && binding.isValidBinding()
69                         && binding.isStatic()
70                         && binding.constant == NotAConstant
71                         && binding.declaringClass.isNestedType()
72                         && binding.declaringClass.isClass()
73                         && !binding.declaringClass.isStatic()) {
74                         initializationScope.problemReporter().unexpectedStaticModifierForField(
75                                 (SourceTypeBinding) binding.declaringClass,
76                                 this);
77                 }
78
79                 if (initialization != null) {
80                         flowInfo =
81                                 initialization
82                                         .analyseCode(initializationScope, flowContext, flowInfo)
83                                         .unconditionalInits();
84                         flowInfo.markAsDefinitelyAssigned(binding);
85                 } else {
86                         flowInfo.markAsDefinitelyNotAssigned(binding);
87                         // clear the bit in case it was already set (from enclosing info)
88                 }
89                 return flowInfo;
90         }
91
92         /**
93          * Code generation for a field declaration:
94          *      i.e. normal assignment to a field 
95          *
96          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
97          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
98          */
99         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
100
101                 if ((bits & IsReachableMASK) == 0) {
102                         return;
103                 }
104                 // do not generate initialization code if final and static (constant is then
105                 // recorded inside the field itself).
106                 int pc = codeStream.position;
107                 boolean isStatic;
108                 if (initialization != null
109                         && !((isStatic = binding.isStatic()) && binding.constant != NotAConstant)) {
110                         // non-static field, need receiver
111                         if (!isStatic)
112                                 codeStream.aload_0();
113                         // generate initialization value
114                         initialization.generateCode(currentScope, codeStream, true);
115                         // store into field
116                         if (isStatic) {
117                                 codeStream.putstatic(binding);
118                         } else {
119                                 codeStream.putfield(binding);
120                         }
121                 }
122                 codeStream.recordPositionsFrom(pc, this.sourceStart);
123         }
124
125         public TypeBinding getTypeBinding(Scope scope) {
126
127                 return type.getTypeBinding(scope);
128         }
129
130         public boolean isField() {
131
132                 return true;
133         }
134
135         public boolean isStatic() {
136
137                 if (binding != null)
138                         return binding.isStatic();
139                 return (modifiers & AccStatic) != 0;
140         }
141
142         public String name() {
143
144                 return String.valueOf(name);
145         }
146
147         public void resolve(MethodScope initializationScope) {
148
149                 // the two <constant = Constant.NotAConstant> could be regrouped into
150                 // a single line but it is clearer to have two lines while the reason of their
151                 // existence is not at all the same. See comment for the second one.
152
153                 //--------------------------------------------------------
154                 if (!this.hasBeenResolved && binding != null && this.binding.isValidBinding()) {
155
156                         this.hasBeenResolved = true;
157
158                         if (isTypeUseDeprecated(this.binding.type, initializationScope))
159                                 initializationScope.problemReporter().deprecatedType(this.binding.type, this.type);
160
161                         this.type.binding = this.binding.type; // update binding for type reference
162
163                         // the resolution of the initialization hasn't been done
164                         if (this.initialization == null) {
165                                 this.binding.constant = Constant.NotAConstant;
166                         } else {
167                                 int previous = initializationScope.fieldDeclarationIndex;
168                                 try {
169                                         initializationScope.fieldDeclarationIndex = this.binding.id;
170
171                                         // break dead-lock cycles by forcing constant to NotAConstant
172                                         this.binding.constant = Constant.NotAConstant;
173                                         
174                                         TypeBinding typeBinding = this.binding.type;
175                                         TypeBinding initializationTypeBinding;
176                                         
177                                         if (initialization instanceof ArrayInitializer) {
178
179                                                 if ((initializationTypeBinding = this.initialization.resolveTypeExpecting(initializationScope, typeBinding))    != null) {
180                                                         ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationTypeBinding;
181                                                         this.initialization.implicitWidening(typeBinding, initializationTypeBinding);
182                                                 }
183                                         } else if ((initializationTypeBinding = initialization.resolveType(initializationScope)) != null) {
184
185                                                 if (this.initialization.isConstantValueOfTypeAssignableToType(initializationTypeBinding, typeBinding)
186                                                         || (typeBinding.isBaseType() && BaseTypeBinding.isWidening(typeBinding.id, initializationTypeBinding.id))) {
187
188                                                         this.initialization.implicitWidening(typeBinding, initializationTypeBinding);
189
190                                                 }       else if (MethodScope.areTypesCompatible(initializationTypeBinding, typeBinding)) {
191                                                         this.initialization.implicitWidening(typeBinding, initializationTypeBinding);
192
193                                                 } else {
194                                                         initializationScope.problemReporter().typeMismatchError(initializationTypeBinding, typeBinding, this);
195                                                 }
196                                                 if (this.binding.isFinal()){ // cast from constant actual type to variable type
197                                                         this.binding.constant =
198                                                                 this.initialization.constant.castTo(
199                                                                         (this.binding.type.id << 4) + this.initialization.constant.typeID());
200                                                 }
201                                         } else {
202                                                 this.binding.constant = NotAConstant;
203                                         }
204                                 } finally {
205                                         initializationScope.fieldDeclarationIndex = previous;
206                                         if (this.binding.constant == null)
207                                                 this.binding.constant = Constant.NotAConstant;
208                                 }
209                         }
210                 }
211         }
212
213         public void traverse(IAbstractSyntaxTreeVisitor visitor, MethodScope scope) {
214
215                 if (visitor.visit(this, scope)) {
216                         type.traverse(visitor, scope);
217                         if (initialization != null)
218                                 initialization.traverse(visitor, scope);
219                 }
220                 visitor.endVisit(this, scope);
221         }
222 }