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