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