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