da5359a4560bd6333b25f3bd712a2703c05f988c
[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.BlockScope;
18 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
20 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
21 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemFieldBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReferenceBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
24 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticAccessMethodBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
26 import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
27
28
29 public class QualifiedNameReference extends NameReference {
30         
31         public char[][] tokens;
32         public FieldBinding[] otherBindings, otherCodegenBindings;
33         int[] otherDepths;
34         public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding
35         SyntheticAccessMethodBinding syntheticWriteAccessor;
36         SyntheticAccessMethodBinding[] syntheticReadAccessors;
37         protected FieldBinding lastFieldBinding;
38         public QualifiedNameReference(
39                 char[][] sources,
40                 int sourceStart,
41                 int sourceEnd) {
42                 super();
43                 tokens = sources;
44                 this.sourceStart = sourceStart;
45                 this.sourceEnd = sourceEnd;
46         }
47         public FlowInfo analyseAssignment(
48                 BlockScope currentScope,
49                 FlowContext flowContext,
50                 FlowInfo flowInfo,
51                 Assignment assignment,
52                 boolean isCompound) {
53
54                 // determine the rank until which we now we do not need any actual value for the field access
55                 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
56                 boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
57                 switch (bits & RestrictiveFlagMASK) {
58                         case FIELD : // reading a field
59                                 lastFieldBinding = (FieldBinding) binding;
60                                 if (needValue) {
61                                         manageSyntheticReadAccessIfNecessary(currentScope, lastFieldBinding, this.actualReceiverType, 0);
62                                 }                               // check if final blank field
63                                 if (lastFieldBinding.isBlankFinal()
64                                     && this.otherBindings != null // the last field binding is only assigned
65                                         && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
66                                         if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
67                                                 currentScope.problemReporter().uninitializedBlankFinalField(
68                                                         lastFieldBinding,
69                                                         this);
70                                         }
71                                 }
72                                 break;
73 //                      case LOCAL :
74 //                              // first binding is a local variable
75 //                              LocalVariableBinding localBinding;
76 //                              if (!flowInfo
77 //                                      .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
78 //                                      currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
79 //                              }
80 //                              if (flowInfo.isReachable()) {
81 //                                      localBinding.useFlag = LocalVariableBinding.USED;
82 //                              } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
83 //                                      localBinding.useFlag = LocalVariableBinding.FAKE_USED;
84 //                              }
85                 }
86                 
87                 if (needValue) {
88                         manageEnclosingInstanceAccessIfNecessary(currentScope);
89                         // only for first binding
90                 }
91                 // all intermediate field accesses are read accesses
92                 if (otherBindings != null) {
93                         for (int i = 0; i < otherBindingsCount-1; i++) {
94                                 lastFieldBinding = otherBindings[i];
95                                 needValue = !otherBindings[i+1].isStatic();
96                                 if (needValue) {
97                                         manageSyntheticReadAccessIfNecessary(
98                                                 currentScope, 
99                                                 lastFieldBinding, 
100                                                 i == 0 
101                                                         ? ((VariableBinding)binding).type
102                                                         : otherBindings[i-1].type,
103                                                 i + 1);
104                                 }
105                         }
106                         lastFieldBinding = otherBindings[otherBindingsCount-1];
107                 }
108
109                 if (isCompound) {
110                         if (binding == lastFieldBinding
111                                 && lastFieldBinding.isBlankFinal()
112                                 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
113                                 && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
114                                 currentScope.problemReporter().uninitializedBlankFinalField(
115                                         lastFieldBinding,
116                                         this);
117                         }
118                         TypeBinding lastReceiverType;
119                         if (lastFieldBinding == binding){
120                                 lastReceiverType = this.actualReceiverType;
121                         } else if (otherBindingsCount == 1){
122                                 lastReceiverType = ((VariableBinding)this.binding).type;
123                         } else {
124                                 lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
125                         }
126                         manageSyntheticReadAccessIfNecessary(
127                                 currentScope,
128                                 lastFieldBinding,
129                                 lastReceiverType,
130                                 lastFieldBinding == binding
131                                         ? 0 
132                                         : otherBindingsCount);
133                 }
134                 
135                 if (assignment.expression != null) {
136                         flowInfo =
137                                 assignment
138                                         .expression
139                                         .analyseCode(currentScope, flowContext, flowInfo)
140                                         .unconditionalInits();
141                 }
142                 
143                 // the last field access is a write access
144                 if (lastFieldBinding.isFinal()) {
145                         // in a context where it can be assigned?
146                         if (lastFieldBinding.isBlankFinal()
147                                         && !isCompound
148                                         && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding) 
149                                         && indexOfFirstFieldBinding == 1) {
150                                 if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
151                                         currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this);
152                                 } else {
153                                         flowContext.recordSettingFinal(lastFieldBinding, this);
154                                 }
155                                 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
156                         } else {
157                                 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
158                                 if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned
159                                         flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
160                                 }
161                         }
162                 }
163                 // equivalent to valuesRequired[maxOtherBindings]
164                 TypeBinding lastReceiverType;
165                 if (lastFieldBinding == binding){
166                         lastReceiverType = this.actualReceiverType;
167                 } else if (otherBindingsCount == 1){
168                         lastReceiverType = ((VariableBinding)this.binding).type;
169                 } else {
170                         lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
171                 }
172                 manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType);
173
174                 return flowInfo;
175         }
176         
177         public FlowInfo analyseCode(
178                 BlockScope currentScope,
179                 FlowContext flowContext,
180                 FlowInfo flowInfo) {
181
182                 return analyseCode(currentScope, flowContext, flowInfo, true);
183         }
184         
185         public FlowInfo analyseCode(
186                 BlockScope currentScope,
187                 FlowContext flowContext,
188                 FlowInfo flowInfo,
189                 boolean valueRequired) {
190                         
191                 // determine the rank until which we now we do not need any actual value for the field access
192                 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
193
194                 boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic();
195                 switch (bits & RestrictiveFlagMASK) {
196                         case FIELD : // reading a field
197                                 if (needValue) {
198                                         manageSyntheticReadAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0);
199                                 }
200                                 // check if reading a final blank field
201                                 FieldBinding fieldBinding;
202                                         if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
203                                                 && (indexOfFirstFieldBinding == 1)
204                                         // was an implicit reference to the first field binding
205                                                 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)
206                                                 && (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
207                                         currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
208                                 }
209                                 break;
210 //                      case LOCAL : // reading a local variable
211 //                              LocalVariableBinding localBinding;
212 //                              if (!flowInfo
213 //                                      .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
214 //                                      currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
215 //                              }
216 //                              if (flowInfo.isReachable()) {
217 //                                      localBinding.useFlag = LocalVariableBinding.USED;
218 //                              } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
219 //                                      localBinding.useFlag = LocalVariableBinding.FAKE_USED;
220 //                              }
221                 }
222                 if (needValue) {
223                         manageEnclosingInstanceAccessIfNecessary(currentScope);
224                         // only for first binding
225                 }
226                 if (otherBindings != null) {
227                         for (int i = 0; i < otherBindingsCount; i++) {
228                                 needValue = i < otherBindingsCount-1 ? !otherBindings[i+1].isStatic() : valueRequired;
229                                 if (needValue) {
230                                         manageSyntheticReadAccessIfNecessary(
231                                                 currentScope, 
232                                                 otherBindings[i], 
233                                                 i == 0 
234                                                         ? ((VariableBinding)binding).type
235                                                         : otherBindings[i-1].type,
236                                                 i + 1);
237                                 }
238                         }
239                 }
240                 return flowInfo;
241         }
242         /**
243          * Check and/or redirect the field access to the delegate receiver if any
244          */
245         public TypeBinding checkFieldAccess(BlockScope scope) {
246                 // check for forward references
247                 FieldBinding fieldBinding = (FieldBinding) binding;
248                 MethodScope methodScope = scope.methodScope();
249                 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
250                         && methodScope.fieldDeclarationIndex != MethodScope.NotInFieldDecl
251                         && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
252                         if ((!fieldBinding.isStatic() || methodScope.isStatic)
253                                 && this.indexOfFirstFieldBinding == 1)
254                                 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
255                 }
256                 bits &= ~RestrictiveFlagMASK; // clear bits
257                 bits |= FIELD;
258                 return getOtherFieldBindings(scope);
259         }
260 //      public void generateAssignment(
261 //              BlockScope currentScope,
262 //              CodeStream codeStream,
263 //              Assignment assignment,
264 //              boolean valueRequired) {
265 //                      
266 //              generateReadSequence(currentScope, codeStream);
267 //              assignment.expression.generateCode(currentScope, codeStream, true);
268 //              fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
269 //              // equivalent to valuesRequired[maxOtherBindings]
270 //              if (valueRequired) {
271 //                      codeStream.generateImplicitConversion(assignment.implicitConversion);
272 //              }
273 //      }
274 //      public void generateCode(
275 //              BlockScope currentScope,
276 //              CodeStream codeStream,
277 //              boolean valueRequired) {
278 //                      
279 //              int pc = codeStream.position;
280 //              if (constant != NotAConstant) {
281 //                      if (valueRequired) {
282 //                              codeStream.generateConstant(constant, implicitConversion);
283 //                      }
284 //              } else {
285 //                      generateReadSequence(currentScope, codeStream); 
286 //                      if (valueRequired) {
287 //                              if (lastFieldBinding.declaringClass == null) { // array length
288 //                                      codeStream.arraylength();
289 //                                      codeStream.generateImplicitConversion(implicitConversion);
290 //                              } else {
291 //                                      if (lastFieldBinding.constant != NotAConstant) {
292 //                                              if (!lastFieldBinding.isStatic()){
293 //                                                      codeStream.invokeObjectGetClass();
294 //                                                      codeStream.pop();
295 //                                              }
296 //                                              // inline the last field constant
297 //                                              codeStream.generateConstant(lastFieldBinding.constant, implicitConversion);
298 //                                      } else {
299 //                                              SyntheticAccessMethodBinding accessor =
300 //                                                      syntheticReadAccessors == null
301 //                                                              ? null
302 //                                                              : syntheticReadAccessors[syntheticReadAccessors.length - 1];
303 //                                              if (accessor == null) {
304 //                                                      if (lastFieldBinding.isStatic()) {
305 //                                                              codeStream.getstatic(lastFieldBinding);
306 //                                                      } else {
307 //                                                              codeStream.getfield(lastFieldBinding);
308 //                                                      }
309 //                                              } else {
310 //                                                      codeStream.invokestatic(accessor);
311 //                                              }
312 //                                              codeStream.generateImplicitConversion(implicitConversion);
313 //                                      }
314 //                              }
315 //                      } else {
316 //                              if (lastFieldBinding != null && !lastFieldBinding.isStatic()){
317 //                                      codeStream.invokeObjectGetClass(); // perform null check
318 //                                      codeStream.pop();
319 //                              }
320 //                                                      
321 //                      }
322 //              }
323 //              codeStream.recordPositionsFrom(pc, this.sourceStart);
324 //      }
325 //      public void generateCompoundAssignment(
326 //              BlockScope currentScope,
327 //              CodeStream codeStream,
328 //              Expression expression,
329 //              int operator,
330 //              int assignmentImplicitConversion,
331 //              boolean valueRequired) {
332 //                      
333 //              generateReadSequence(currentScope, codeStream);
334 //              SyntheticAccessMethodBinding accessor =
335 //                      syntheticReadAccessors == null
336 //                              ? null
337 //                              : syntheticReadAccessors[syntheticReadAccessors.length - 1];
338 //              if (lastFieldBinding.isStatic()) {
339 //                      if (accessor == null) {
340 //                              codeStream.getstatic(lastFieldBinding);
341 //                      } else {
342 //                              codeStream.invokestatic(accessor);
343 //                      }
344 //              } else {
345 //                      codeStream.dup();
346 //                      if (accessor == null) {
347 //                              codeStream.getfield(lastFieldBinding);
348 //                      } else {
349 //                              codeStream.invokestatic(accessor);
350 //                      }
351 //              }
352 //              // the last field access is a write access
353 //              // perform the actual compound operation
354 //              int operationTypeID;
355 //              if ((operationTypeID = implicitConversion >> 4) == T_String) {
356 //                      codeStream.generateStringAppend(currentScope, null, expression);
357 //              } else {
358 //                      // promote the array reference to the suitable operation type
359 //                      codeStream.generateImplicitConversion(implicitConversion);
360 //                      // generate the increment value (will by itself  be promoted to the operation value)
361 //                      if (expression == IntLiteral.One) { // prefix operation
362 //                              codeStream.generateConstant(expression.constant, implicitConversion);
363 //                      } else {
364 //                              expression.generateCode(currentScope, codeStream, true);
365 //                      }
366 //                      // perform the operation
367 //                      codeStream.sendOperator(operator, operationTypeID);
368 //                      // cast the value back to the array reference type
369 //                      codeStream.generateImplicitConversion(assignmentImplicitConversion);
370 //              }
371 //              // actual assignment
372 //              fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
373 //              // equivalent to valuesRequired[maxOtherBindings]
374 //      }
375 //      public void generatePostIncrement(
376 //              BlockScope currentScope,
377 //              CodeStream codeStream,
378 //              CompoundAssignment postIncrement,
379 //              boolean valueRequired) {
380 //              generateReadSequence(currentScope, codeStream);
381 //              SyntheticAccessMethodBinding accessor =
382 //                      syntheticReadAccessors == null
383 //                              ? null
384 //                              : syntheticReadAccessors[syntheticReadAccessors.length - 1];
385 //              if (lastFieldBinding.isStatic()) {
386 //                      if (accessor == null) {
387 //                              codeStream.getstatic(lastFieldBinding);
388 //                      } else {
389 //                              codeStream.invokestatic(accessor);
390 //                      }
391 //              } else {
392 //                      codeStream.dup();
393 //                      if (accessor == null) {
394 //                              codeStream.getfield(lastFieldBinding);
395 //                      } else {
396 //                              codeStream.invokestatic(accessor);
397 //                      }
398 //              }
399 //              // duplicate the old field value
400 //              if (valueRequired) {
401 //                      if (lastFieldBinding.isStatic()) {
402 //                              if ((lastFieldBinding.type == LongBinding)
403 //                                      || (lastFieldBinding.type == DoubleBinding)) {
404 //                                      codeStream.dup2();
405 //                              } else {
406 //                                      codeStream.dup();
407 //                              }
408 //                      } else { // Stack:  [owner][old field value]  ---> [old field value][owner][old field value]
409 //                              if ((lastFieldBinding.type == LongBinding)
410 //                                      || (lastFieldBinding.type == DoubleBinding)) {
411 //                                      codeStream.dup2_x1();
412 //                              } else {
413 //                                      codeStream.dup_x1();
414 //                              }
415 //                      }
416 //              }
417 //              codeStream.generateConstant(
418 //                      postIncrement.expression.constant,
419 //                      implicitConversion);
420 //              codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
421 //              codeStream.generateImplicitConversion(
422 //                      postIncrement.assignmentImplicitConversion);
423 //              fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
424 //      }
425 //      /*
426 //       * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
427 //       * for a read or write access.
428 //       */
429 //      public void generateReadSequence(
430 //              BlockScope currentScope,
431 //              CodeStream codeStream) {
432 //                      
433 //              // determine the rank until which we now we do not need any actual value for the field access
434 //              int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length;
435 //
436 //              boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic();
437 //              switch (bits & RestrictiveFlagMASK) {
438 //                      case FIELD :
439 //                              lastFieldBinding = (FieldBinding) this.codegenBinding;
440 //                              // if first field is actually constant, we can inline it
441 //                              if (lastFieldBinding.constant != NotAConstant) {
442 //                                      break;
443 //                              }
444 //                              if (needValue && !lastFieldBinding.isStatic()) {
445 //                                      if ((bits & DepthMASK) != 0) {
446 //                                              ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
447 //                                              Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
448 //                                              codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
449 //                                      } else {
450 //                                              generateReceiver(codeStream);
451 //                                      }
452 //                              }
453 //                              break;
454 //                      case LOCAL : // reading the first local variable
455 //                              if (!needValue) break; // no value needed
456 //                              lastFieldBinding = null;
457 //                              LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
458 //                              // regular local variable read
459 //                              if (localBinding.constant != NotAConstant) {
460 //                                      codeStream.generateConstant(localBinding.constant, 0);
461 //                                      // no implicit conversion
462 //                              } else {
463 //                                      // outer local?
464 //                                      if ((bits & DepthMASK) != 0) {
465 //                                              // outer local can be reached either through a synthetic arg or a synthetic field
466 //                                              VariableBinding[] path = currentScope.getEmulationPath(localBinding);
467 //                                              codeStream.generateOuterAccess(path, this, localBinding, currentScope);
468 //                                      } else {
469 //                                              codeStream.load(localBinding);
470 //                                      }
471 //                              }
472 //              }
473 //
474 //              // all intermediate field accesses are read accesses
475 //              // only the last field binding is a write access
476 //              if (this.otherCodegenBindings != null) {
477 //                      for (int i = 0; i < otherBindingsCount; i++) {
478 //                              FieldBinding nextField = this.otherCodegenBindings[i];
479 //                              if (lastFieldBinding != null) {
480 //                                      needValue = !nextField.isStatic();
481 //                                      if (needValue) {
482 //                                              MethodBinding accessor =
483 //                                                      syntheticReadAccessors == null ? null : syntheticReadAccessors[i]; 
484 //                                              if (accessor == null) {
485 //                                                      if (lastFieldBinding.constant != NotAConstant) {
486 //                                                              if (this.lastFieldBinding != this.codegenBinding && !this.lastFieldBinding.isStatic()) {
487 //                                                                      codeStream.invokeObjectGetClass(); // perform null check
488 //                                                                      codeStream.pop();
489 //                                                              }
490 //                                                              codeStream.generateConstant(lastFieldBinding.constant, 0);
491 //                                                      } else if (lastFieldBinding.isStatic()) {
492 //                                                              codeStream.getstatic(lastFieldBinding);
493 //                                                      } else {
494 //                                                              codeStream.getfield(lastFieldBinding);
495 //                                                      }
496 //                                              } else {
497 //                                                      codeStream.invokestatic(accessor);
498 //                                              }
499 //                                      } else {
500 //                                              if (this.codegenBinding != this.lastFieldBinding && !this.lastFieldBinding.isStatic()){
501 //                                                      codeStream.invokeObjectGetClass(); // perform null check
502 //                                                      codeStream.pop();
503 //                                              }                                               
504 //                                      }
505 //                              }
506 //                              this.lastFieldBinding = nextField;
507 //                      }
508 //              }
509 //      }
510 //      public void generateReceiver(CodeStream codeStream) {
511 //              codeStream.aload_0();
512 //      }
513         public TypeBinding getOtherFieldBindings(BlockScope scope) {
514                 // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
515                 if ((bits & FIELD) != 0) {
516                         if (!((FieldBinding) binding).isStatic()) {
517                                 //must check for the static status....
518                                 if (indexOfFirstFieldBinding == 1) {
519                                         //the field is the first token of the qualified reference....
520                                         if (scope.methodScope().isStatic) {
521                                                 scope.problemReporter().staticFieldAccessToNonStaticVariable(
522                                                         this,
523                                                         (FieldBinding) binding);
524                                                 return null;
525                                         }
526                                 } else { //accessing to a field using a type as "receiver" is allowed only with static field    
527                                         scope.problemReporter().staticFieldAccessToNonStaticVariable(
528                                                 this,
529                                                 (FieldBinding) binding);
530                                         return null;
531                                 }
532                         }
533                         if (isFieldUseDeprecated((FieldBinding) binding, scope))
534                                 scope.problemReporter().deprecatedField((FieldBinding) binding, this);
535                 }
536                 TypeBinding type = ((VariableBinding) binding).type;
537                 int index = indexOfFirstFieldBinding;
538                 int length = tokens.length;
539                 if (index == length) { //       restrictiveFlag == FIELD
540                         this.constant = FieldReference.getConstantFor((FieldBinding) binding, this, false, scope);
541                         return type;
542                 }
543                 // allocation of the fieldBindings array        and its respective constants
544                 int otherBindingsLength = length - index;
545                 otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength];
546                 otherDepths = new int[otherBindingsLength];
547                 
548                 // fill the first constant (the one of the binding)
549                 this.constant =
550                         ((bits & FIELD) != 0)
551                                 ? FieldReference.getConstantFor((FieldBinding) binding, this, false, scope)
552                                 : ((VariableBinding) binding).constant;
553                 // save first depth, since will be updated by visibility checks of other bindings
554                 int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
555                 // iteration on each field      
556                 while (index < length) {
557                         char[] token = tokens[index];
558                         if (type == null)
559                                 return null; // could not resolve type prior to this point
560
561                         bits &= ~DepthMASK; // flush previous depth if any                      
562                         FieldBinding field = scope.getField(type, token, this);
563                         int place = index - indexOfFirstFieldBinding;
564                         otherBindings[place] = field;
565                         otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
566                         if (field.isValidBinding()) {
567                                 if (isFieldUseDeprecated(field, scope))
568                                         scope.problemReporter().deprecatedField(field, this);
569                                 Constant someConstant = FieldReference.getConstantFor(field, this, false, scope);
570                                 // constant propagation can only be performed as long as the previous one is a constant too.
571                                 if (this.constant != NotAConstant) {
572                                         this.constant = someConstant;                                   
573                                 }
574
575                                 type = field.type;
576                                 index++;
577                                 
578                                 if (field.isStatic()) {
579                                         // static field accessed through receiver? legal but unoptimal (optional warning)
580                                         scope.problemReporter().unnecessaryReceiverForStaticField(this, field);
581                                 }
582                                 
583                         } else {
584                                 constant = NotAConstant; //don't fill other constants slots...
585                                 scope.problemReporter().invalidField(this, field, index, type);
586                                 setDepth(firstDepth);
587                                 return null;
588                         }
589                 }
590                 setDepth(firstDepth);
591                 return (otherBindings[otherBindingsLength - 1]).type;
592         }
593         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
594                 //If inlinable field, forget the access emulation, the code gen will directly target it
595                 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) {
596                         return;
597                 }
598                 if ((bits & RestrictiveFlagMASK) == LOCAL) {
599                         currentScope.emulateOuterAccess((LocalVariableBinding) binding);
600                 }
601         }
602         public void manageSyntheticReadAccessIfNecessary(
603                 BlockScope currentScope,
604                 FieldBinding fieldBinding,
605                 TypeBinding lastReceiverType,
606                 int index) {
607                 // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings'
608                 if (fieldBinding.constant != NotAConstant)
609                         return;
610                 if (fieldBinding.isPrivate()) { // private access
611                         if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
612                                 if (syntheticReadAccessors == null) {
613                                         if (otherBindings == null)
614                                                 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
615                                         else
616                                                 syntheticReadAccessors =
617                                                         new SyntheticAccessMethodBinding[otherBindings.length + 1];
618                                 }
619                                 syntheticReadAccessors[index] = ((SourceTypeBinding) fieldBinding.declaringClass).addSyntheticMethod(fieldBinding, true);
620                                 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
621                                 return;
622                         }
623                 } else if (fieldBinding.isProtected()){
624                         int depth = index == 0 ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[index-1];
625                         // implicit protected access (only for first one)
626                         if (depth > 0 && (fieldBinding.declaringClass.getPackage()
627                                                                 != currentScope.enclosingSourceType().getPackage())) {
628                                 if (syntheticReadAccessors == null) {
629                                         if (otherBindings == null)
630                                                 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
631                                         else
632                                                 syntheticReadAccessors =
633                                                         new SyntheticAccessMethodBinding[otherBindings.length + 1];
634                                 }
635                                 syntheticReadAccessors[index] =
636                                         ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth))
637                                                                                         .addSyntheticMethod(fieldBinding, true);
638                                 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
639                                 return;
640                         }
641                 }
642                 // if the binding declaring class is not visible, need special action
643                 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
644                 // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
645 //              if (fieldBinding.declaringClass != lastReceiverType
646 //                      && !lastReceiverType.isArrayType()                      
647 //                      && fieldBinding.declaringClass != null
648 //                      && fieldBinding.constant == NotAConstant
649 //                      && ((currentScope.environment().options.targetJDK >= CompilerOptions.JDK1_2
650 //                                      && (index > 0 || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
651 //                                      && fieldBinding.declaringClass.id != T_Object)
652 //                              || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
653 //                      if (index == 0){
654 //                              this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
655 //                      } else {
656 //                              if (this.otherCodegenBindings == this.otherBindings){
657 //                                      int l = this.otherBindings.length;
658 //                                      System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l);
659 //                              }
660 //                              this.otherCodegenBindings[index-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
661 //                      }
662 //              }
663         }
664         /*
665          * No need to emulate access to protected fields since not implicitly accessed
666          */
667         public void manageSyntheticWriteAccessIfNecessary(
668                 BlockScope currentScope,
669                 FieldBinding fieldBinding,
670                 TypeBinding lastReceiverType) {
671                 if (fieldBinding.isPrivate()) {
672                         if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
673                                 syntheticWriteAccessor = ((SourceTypeBinding) fieldBinding.declaringClass)
674                                                                                         .addSyntheticMethod(fieldBinding, false);
675                                 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
676                                 return;
677                         }
678                 } else if (fieldBinding.isProtected()){
679                         int depth = fieldBinding == binding ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[otherDepths.length-1];
680                         if (depth > 0 && (fieldBinding.declaringClass.getPackage()
681                                                                 != currentScope.enclosingSourceType().getPackage())) {
682                                 syntheticWriteAccessor = ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth))
683                                                                                         .addSyntheticMethod(fieldBinding, false);
684                                 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
685                                 return;
686                         }
687                 }
688                 // if the binding declaring class is not visible, need special action
689                 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
690                 // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
691 //              if (fieldBinding.declaringClass != lastReceiverType
692 //                      && !lastReceiverType.isArrayType()                      
693 //                      && fieldBinding.declaringClass != null
694 //                      && fieldBinding.constant == NotAConstant
695 //                      && ((currentScope.environment().options.targetJDK >= CompilerOptions.JDK1_2
696 //                                      && (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
697 //                                      && fieldBinding.declaringClass.id != T_Object)
698 //                              || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
699 //                      if (fieldBinding == binding){
700 //                              this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
701 //                      } else {
702 //                              if (this.otherCodegenBindings == this.otherBindings){
703 //                                      int l = this.otherBindings.length;
704 //                                      System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l);
705 //                              }
706 //                              this.otherCodegenBindings[this.otherCodegenBindings.length-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
707 //                      }
708 //              }
709                 
710         }
711         /**
712          * Normal field binding did not work, try to bind to a field of the delegate receiver.
713          */
714         public TypeBinding reportError(BlockScope scope) {
715                 if (binding instanceof ProblemFieldBinding) {
716                         scope.problemReporter().invalidField(this, (FieldBinding) binding);
717                 } else if (binding instanceof ProblemReferenceBinding) {
718                         scope.problemReporter().invalidType(this, (TypeBinding) binding);
719                 } else {
720                         scope.problemReporter().unresolvableReference(this, binding);
721                 }
722                 return null;
723         }
724         public StringBuffer printExpression(int indent, StringBuffer output) {
725                 
726                 for (int i = 0; i < tokens.length; i++) {
727                         if (i > 0) output.append('.');
728                         output.append(tokens[i]);
729                 }
730                 return output;
731         }
732         public TypeBinding resolveType(BlockScope scope) {
733                 // field and/or local are done before type lookups
734                 // the only available value for the restrictiveFlag BEFORE
735                 // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField 
736                 this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
737                 constant = Constant.NotAConstant;
738                 if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this))
739                         .isValidBinding()) {
740                         switch (bits & RestrictiveFlagMASK) {
741                                 case VARIABLE : //============only variable===========
742                                 case TYPE | VARIABLE :
743                                         if (binding instanceof LocalVariableBinding) {
744                                                 if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
745                                                         scope.problemReporter().cannotReferToNonFinalOuterLocal(
746                                                                 (LocalVariableBinding) binding,
747                                                                 this);
748                                                 bits &= ~RestrictiveFlagMASK; // clear bits
749                                                 bits |= LOCAL;
750                                                 return this.resolvedType = getOtherFieldBindings(scope);
751                                         }
752                                         if (binding instanceof FieldBinding) {
753                                                 // check for forward references
754                                                 FieldBinding fieldBinding = (FieldBinding) binding;
755                                                 MethodScope methodScope = scope.methodScope();
756                                                 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
757                                                         && methodScope.fieldDeclarationIndex != MethodScope.NotInFieldDecl
758                                                         && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
759                                                         if ((!fieldBinding.isStatic() || methodScope.isStatic)
760                                                                 && this.indexOfFirstFieldBinding == 1)
761                                                                 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
762                                                 }
763                                                 bits &= ~RestrictiveFlagMASK; // clear bits
764                                                 bits |= FIELD;
765                                                 
766                                                 // check for deprecated receiver type
767                                                 // deprecation check for receiver type if not first token
768                                                 if (indexOfFirstFieldBinding > 1) {
769                                                         if (isTypeUseDeprecated(this.actualReceiverType, scope))
770                                                                 scope.problemReporter().deprecatedType(this.actualReceiverType, this);
771                                                 }
772                                                 
773                                                 return this.resolvedType = getOtherFieldBindings(scope);
774                                         }
775                                         // thus it was a type
776                                         bits &= ~RestrictiveFlagMASK; // clear bits
777                                         bits |= TYPE;
778                                 case TYPE : //=============only type ==============
779                                         if (isTypeUseDeprecated((TypeBinding) binding, scope))
780                                                 scope.problemReporter().deprecatedType((TypeBinding) binding, this);
781                                         return this.resolvedType = (TypeBinding) binding;
782                         }
783                 }
784                 //========error cases===============
785                 return this.resolvedType = this.reportError(scope);
786         }
787         public void setFieldIndex(int index) {
788                 this.indexOfFirstFieldBinding = index;
789         }
790         public String toStringExpression() {
791                 StringBuffer buffer = new StringBuffer();
792                 for (int i = 0; i < tokens.length; i++) {
793                         buffer.append(tokens[i]);
794                         if (i < (tokens.length - 1)) {
795                                 buffer.append("."); //$NON-NLS-1$
796                         }
797                 }
798                 return buffer.toString();
799         }
800         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
801                 visitor.visit(this, scope);
802                 visitor.endVisit(this, scope);
803         }
804         public String unboundReferenceErrorName() {
805                 return new String(tokens[0]);
806         }
807 }