1) Need to syncronize also the type of variable values not only the values (makes...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / FieldDeclaration.java
1 /***********************************************************************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made
3  * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  * 
6  * Contributors: IBM Corporation - initial API and implementation
7  **********************************************************************************************************************************/
8 package net.sourceforge.phpdt.internal.compiler.ast;
9
10 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
11 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
12 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
13 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
14 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
15 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypeBinding;
16 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
17 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21
22 public class FieldDeclaration extends AbstractVariableDeclaration {
23         public FieldBinding binding;
24
25         boolean hasBeenResolved = false;
26
27         // allows to retrieve both the "type" part of the declaration (part1)
28         // and also the part that decribe the name and the init and optionally
29         // some other dimension ! ....
30         // public int[] a, b[] = X, c ;
31         // for b that would give for
32         // - part1 : public int[]
33         // - part2 : b[] = X,
34
35         public int endPart1Position;
36
37         public int endPart2Position;
38
39         public FieldDeclaration() {
40         }
41
42         public FieldDeclaration(char[] name, int sourceStart, int sourceEnd) {
43
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 FieldDeclaration(Expression initialization, char[] name,
54                         int sourceStart, int sourceEnd) {
55
56                 this.initialization = initialization;
57                 this.name = name;
58
59                 // due to some declaration like
60                 // int x, y = 3, z , x ;
61                 // the sourceStart and the sourceEnd is ONLY on the name
62                 this.sourceStart = sourceStart;
63                 this.sourceEnd = sourceEnd;
64         }
65
66         public FlowInfo analyseCode(MethodScope initializationScope,
67                         FlowContext flowContext, FlowInfo flowInfo) {
68
69                 if (this.binding != null && this.binding.isPrivate()
70                                 && !this.binding.isPrivateUsed()) {
71                         if (!initializationScope.referenceCompilationUnit().compilationResult
72                                         .hasSyntaxError()) {
73                                 initializationScope.problemReporter().unusedPrivateField(this);
74                         }
75                 }
76                 // cannot define static non-constant field inside nested class
77                 if (binding != null && binding.isValidBinding() && binding.isStatic()
78                                 && binding.constant == NotAConstant
79                                 && binding.declaringClass.isNestedType()
80                                 && binding.declaringClass.isClass()
81                                 && !binding.declaringClass.isStatic()) {
82                         initializationScope.problemReporter()
83                                         .unexpectedStaticModifierForField(
84                                                         (SourceTypeBinding) binding.declaringClass, this);
85                 }
86
87                 if (initialization != null) {
88                         flowInfo = initialization.analyseCode(initializationScope,
89                                         flowContext, flowInfo).unconditionalInits();
90                         flowInfo.markAsDefinitelyAssigned(binding);
91                 }
92                 return flowInfo;
93         }
94
95         /**
96          * Code generation for a field declaration: standard assignment to a field
97          * 
98          * @param currentScope
99          *            net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
100          * @param codeStream
101          *            net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
102          */
103         // public void generateCode(BlockScope currentScope, CodeStream codeStream)
104         // {
105         //
106         // if ((bits & IsReachableMASK) == 0) {
107         // return;
108         // }
109         // // do not generate initialization code if final and static (constant is
110         // then
111         // // recorded inside the field itself).
112         // int pc = codeStream.position;
113         // boolean isStatic;
114         // if (initialization != null
115         // && !((isStatic = binding.isStatic()) && binding.constant !=
116         // NotAConstant)) {
117         // // non-static field, need receiver
118         // if (!isStatic)
119         // codeStream.aload_0();
120         // // generate initialization value
121         // initialization.generateCode(currentScope, codeStream, true);
122         // // store into field
123         // if (isStatic) {
124         // codeStream.putstatic(binding);
125         // } else {
126         // codeStream.putfield(binding);
127         // }
128         // }
129         // codeStream.recordPositionsFrom(pc, this.sourceStart);
130         // }
131         public TypeBinding getTypeBinding(Scope scope) {
132
133                 return type.getTypeBinding(scope);
134         }
135
136         public boolean isField() {
137
138                 return true;
139         }
140
141         public boolean isStatic() {
142
143                 if (binding != null)
144                         return binding.isStatic();
145                 return (modifiers & AccStatic) != 0;
146         }
147
148         public String name() {
149
150                 return String.valueOf(name);
151         }
152
153         public void resolve(MethodScope initializationScope) {
154
155                 // the two <constant = Constant.NotAConstant> could be regrouped into
156                 // a single line but it is clearer to have two lines while the reason of
157                 // their
158                 // existence is not at all the same. See comment for the second one.
159
160                 // --------------------------------------------------------
161                 if (!this.hasBeenResolved && binding != null
162                                 && this.binding.isValidBinding()) {
163
164                         this.hasBeenResolved = true;
165
166                         if (isTypeUseDeprecated(this.binding.type, initializationScope))
167                                 initializationScope.problemReporter().deprecatedType(
168                                                 this.binding.type, this.type);
169
170                         this.type.resolvedType = this.binding.type; // update binding for
171                                                                                                                 // type reference
172
173                         // the resolution of the initialization hasn't been done
174                         if (this.initialization == null) {
175                                 this.binding.constant = Constant.NotAConstant;
176                         } else {
177                                 int previous = initializationScope.fieldDeclarationIndex;
178                                 try {
179                                         initializationScope.fieldDeclarationIndex = this.binding.id;
180
181                                         // break dead-lock cycles by forcing constant to
182                                         // NotAConstant
183                                         this.binding.constant = Constant.NotAConstant;
184
185                                         TypeBinding typeBinding = this.binding.type;
186                                         TypeBinding initializationTypeBinding;
187
188                                         if (initialization instanceof ArrayInitializer) {
189
190                                                 if ((initializationTypeBinding = this.initialization
191                                                                 .resolveTypeExpecting(initializationScope,
192                                                                                 typeBinding)) != null) {
193                                                         ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationTypeBinding;
194                                                         this.initialization.implicitWidening(typeBinding,
195                                                                         initializationTypeBinding);
196                                                 }
197                                         } else if ((initializationTypeBinding = initialization
198                                                         .resolveType(initializationScope)) != null) {
199
200                                                 if (this.initialization
201                                                                 .isConstantValueOfTypeAssignableToType(
202                                                                                 initializationTypeBinding, typeBinding)
203                                                                 || (typeBinding.isBaseType() && BaseTypeBinding
204                                                                                 .isWidening(typeBinding.id,
205                                                                                                 initializationTypeBinding.id))) {
206
207                                                         this.initialization.implicitWidening(typeBinding,
208                                                                         initializationTypeBinding);
209
210                                                 } else if (initializationTypeBinding
211                                                                 .isCompatibleWith(typeBinding)) {
212                                                         this.initialization.implicitWidening(typeBinding,
213                                                                         initializationTypeBinding);
214
215                                                 } else {
216                                                         initializationScope.problemReporter()
217                                                                         .typeMismatchError(
218                                                                                         initializationTypeBinding,
219                                                                                         typeBinding, this);
220                                                 }
221                                                 if (this.binding.isFinal()) { // cast from constant
222                                                                                                                 // actual type to
223                                                                                                                 // variable type
224                                                         this.binding.constant = this.initialization.constant
225                                                                         .castTo((this.binding.type.id << 4)
226                                                                                         + this.initialization.constant
227                                                                                                         .typeID());
228                                                 }
229                                         } else {
230                                                 this.binding.constant = NotAConstant;
231                                         }
232                                 } finally {
233                                         initializationScope.fieldDeclarationIndex = previous;
234                                         if (this.binding.constant == null)
235                                                 this.binding.constant = Constant.NotAConstant;
236                                 }
237                         }
238                 }
239         }
240
241         public void traverse(ASTVisitor visitor, MethodScope scope) {
242
243                 if (visitor.visit(this, scope)) {
244                         type.traverse(visitor, scope);
245                         if (initialization != null)
246                                 initialization.traverse(visitor, scope);
247                 }
248                 visitor.endVisit(this, scope);
249         }
250
251         /*
252          * (non-Javadoc)
253          * 
254          * @see java.lang.Object#equals(java.lang.Object)
255          */
256         public boolean equals(Object obj) {
257                 if (obj instanceof FieldDeclaration) {
258                         char[] objName = ((FieldDeclaration) obj).name;
259                         if (name.length != objName.length) {
260                                 return false;
261                         }
262                         for (int i = 0; i < objName.length; i++) {
263                                 if (name[i] != objName[i]) {
264                                         return false;
265                                 }
266                         }
267                         return true;
268                 }
269                 return super.equals(obj);
270         }
271 }