eff7863ae3a866327ce61a9cf4f8e9a747e362a3
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / QualifiedNameReference.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
18 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
24 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemFieldBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReferenceBinding;
26 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
27 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
28 import net.sourceforge.phpdt.internal.compiler.lookup.SyntheticAccessMethodBinding;
29 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
30 import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
31
32 public class QualifiedNameReference extends NameReference {
33         
34         public char[][] tokens;
35         public FieldBinding[] otherBindings, otherCodegenBindings;
36         int[] otherDepths;
37         public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding
38         SyntheticAccessMethodBinding syntheticWriteAccessor;
39         SyntheticAccessMethodBinding[] syntheticReadAccessors;
40         protected FieldBinding lastFieldBinding;
41         public QualifiedNameReference(
42                 char[][] sources,
43                 int sourceStart,
44                 int sourceEnd) {
45                 super();
46                 tokens = sources;
47                 this.sourceStart = sourceStart;
48                 this.sourceEnd = sourceEnd;
49         }
50         public FlowInfo analyseAssignment(
51                 BlockScope currentScope,
52                 FlowContext flowContext,
53                 FlowInfo flowInfo,
54                 Assignment assignment,
55                 boolean isCompound) {
56
57                 if (assignment.expression != null) {
58                         flowInfo =
59                                 assignment
60                                         .expression
61                                         .analyseCode(currentScope, flowContext, flowInfo)
62                                         .unconditionalInits();
63                 }
64                 // determine the rank until which we now we do not need any actual value for the field access
65                 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
66                 int indexOfFirstValueRequired = otherBindingsCount;
67                 while (indexOfFirstValueRequired > 0) {
68                         FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
69                         if (otherBinding.isStatic())
70                                 break; // no longer need any value before this point
71                         indexOfFirstValueRequired--;
72                 }
73                 FieldBinding lastFieldBinding = null;
74                 if ((bits & FIELD) != 0) {
75                         // reading from a field
76                         // check if final blank field
77                         if ((lastFieldBinding = (FieldBinding) binding).isFinal()
78                                 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
79                                 if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
80                                         currentScope.problemReporter().uninitializedBlankFinalField(
81                                                 lastFieldBinding,
82                                                 this);
83                                 }
84                         }
85                 } else {
86                         if ((bits & LOCAL) != 0) {
87                                 // first binding is a local variable
88                                 LocalVariableBinding localBinding;
89                                 if (!flowInfo
90                                         .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
91                                         currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
92                                 }
93                                 if (!flowInfo.isFakeReachable())
94                                         localBinding.used = true;
95                         }
96                 }
97                 if (indexOfFirstValueRequired == 0) {
98                         manageEnclosingInstanceAccessIfNecessary(currentScope);
99                         // only for first binding
100                 }
101                 // all intermediate field accesses are read accesses
102                 if (otherBindings != null) {
103                         int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
104                         for (int i = start; i < otherBindingsCount; i++) {
105                                 if (lastFieldBinding != null) { // could be null if first was a local variable
106                                         TypeBinding lastReceiverType;
107                                         switch(i){
108                                                 case 0 :
109                                                         lastReceiverType = this.actualReceiverType;
110                                                         break;
111                                                 case 1 :
112                                                         lastReceiverType = ((VariableBinding)binding).type;
113                                                         break;
114                                                 default :
115                                                         lastReceiverType = otherBindings[i-1].type;
116                                         }
117                                         manageSyntheticReadAccessIfNecessary(
118                                                 currentScope, 
119                                                 lastFieldBinding, 
120                                                 lastReceiverType,
121                                                 i);
122                                 }
123                                 lastFieldBinding = otherBindings[i];
124                         }
125                 }
126                 if (isCompound) {
127                         if (binding == lastFieldBinding
128                                 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
129                                 && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
130                                 currentScope.problemReporter().uninitializedBlankFinalField(
131                                         lastFieldBinding,
132                                         this);
133                         }
134                         TypeBinding lastReceiverType;
135                         if (lastFieldBinding == binding){
136                                 lastReceiverType = this.actualReceiverType;
137                         } else if (otherBindingsCount == 1){
138                                 lastReceiverType = ((VariableBinding)this.binding).type;
139                         } else {
140                                 lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
141                         }
142                         manageSyntheticReadAccessIfNecessary(
143                                 currentScope,
144                                 lastFieldBinding,
145                                 lastReceiverType,
146                                 lastFieldBinding == binding
147                                         ? 0 
148                                         : otherBindingsCount);
149                 }
150                 // the last field access is a write access
151                 if (lastFieldBinding.isFinal()) {
152                         // in a context where it can be assigned?
153                         if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
154                                 if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
155                                         if (indexOfFirstFieldBinding == 1) {
156                                                 // was an implicit reference to the first field binding
157                                                 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
158                                                         lastFieldBinding,
159                                                         this);
160                                         } else {
161                                                 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
162                                                 // attempting to assign a non implicit reference
163                                         }
164                                 }
165                                 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
166                                 flowContext.recordSettingFinal(lastFieldBinding, this);
167                         } else {
168                                 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
169                         }
170                 }
171                 // equivalent to valuesRequired[maxOtherBindings]
172                 TypeBinding lastReceiverType;
173                 if (lastFieldBinding == binding){
174                         lastReceiverType = this.actualReceiverType;
175                 } else if (otherBindingsCount == 1){
176                         lastReceiverType = ((VariableBinding)this.binding).type;
177                 } else {
178                         lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
179                 }
180                 manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType);
181
182                 return flowInfo;
183         }
184         public FlowInfo analyseCode(
185                 BlockScope currentScope,
186                 FlowContext flowContext,
187                 FlowInfo flowInfo) {
188
189                 return analyseCode(currentScope, flowContext, flowInfo, true);
190         }
191         
192         public FlowInfo analyseCode(
193                 BlockScope currentScope,
194                 FlowContext flowContext,
195                 FlowInfo flowInfo,
196                 boolean valueRequired) {
197                         
198                 // determine the rank until which we now we do not need any actual value for the field access
199                 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
200                 int indexOfFirstValueRequired;
201                 if (valueRequired) {
202                         indexOfFirstValueRequired = otherBindingsCount;
203                         while (indexOfFirstValueRequired > 0) {
204                                 FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
205                                 if (otherBinding.isStatic())
206                                         break; // no longer need any value before this point
207                                 indexOfFirstValueRequired--;
208                         }
209                 } else {
210                         indexOfFirstValueRequired = otherBindingsCount + 1;
211                 }
212                 switch (bits & RestrictiveFlagMASK) {
213                         case FIELD : // reading a field
214                                 if (indexOfFirstValueRequired == 0) {
215                                         manageSyntheticReadAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0);
216                                 }
217                                 // check if reading a final blank field
218                                 FieldBinding fieldBinding;
219                                         if ((fieldBinding = (FieldBinding) binding).isFinal()
220                                                 && (indexOfFirstFieldBinding == 1)
221                                         // was an implicit reference to the first field binding
222                                                 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)
223                                                 && (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
224                                         currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
225                                 }
226                                 break;
227                         case LOCAL : // reading a local variable
228                                 LocalVariableBinding localBinding;
229                                 if (!flowInfo
230                                         .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
231                                         currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
232                                 }
233                                 if (!flowInfo.isFakeReachable())
234                                         localBinding.used = true;
235                 }
236                 if (indexOfFirstValueRequired == 0) {
237                         manageEnclosingInstanceAccessIfNecessary(currentScope);
238                         // only for first binding
239                 }
240                 if (otherBindings != null) {
241                         int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
242                         for (int i = start; i < otherBindingsCount; i++) {
243                                 manageSyntheticReadAccessIfNecessary(
244                                         currentScope, 
245                                         otherBindings[i], 
246                                         i == 0 
247                                                 ? ((VariableBinding)binding).type
248                                                 : otherBindings[i-1].type,
249                                         i + 1);
250                         }
251                 }
252                 return flowInfo;
253         }
254         /**
255          * Check and/or redirect the field access to the delegate receiver if any
256          */
257         public TypeBinding checkFieldAccess(BlockScope scope) {
258                 // check for forward references
259                 FieldBinding fieldBinding = (FieldBinding) binding;
260                 MethodScope methodScope = scope.methodScope();
261                 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
262                         && methodScope.fieldDeclarationIndex != MethodScope.NotInFieldDecl
263                         && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
264                         if ((!fieldBinding.isStatic() || methodScope.isStatic)
265                                 && this.indexOfFirstFieldBinding == 1)
266                                 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
267                 }
268                 bits &= ~RestrictiveFlagMASK; // clear bits
269                 bits |= FIELD;
270                 return getOtherFieldBindings(scope);
271         }
272         public void generateAssignment(
273                 BlockScope currentScope,
274                 CodeStream codeStream,
275                 Assignment assignment,
276                 boolean valueRequired) {
277                         
278                 generateReadSequence(currentScope, codeStream, true);
279                 assignment.expression.generateCode(currentScope, codeStream, true);
280                 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
281                 // equivalent to valuesRequired[maxOtherBindings]
282                 if (valueRequired) {
283                         codeStream.generateImplicitConversion(assignment.implicitConversion);
284                 }
285         }
286         public void generateCode(
287                 BlockScope currentScope,
288                 CodeStream codeStream,
289                 boolean valueRequired) {
290                 int pc = codeStream.position;
291                 if (constant != NotAConstant) {
292                         if (valueRequired) {
293                                 codeStream.generateConstant(constant, implicitConversion);
294                         }
295                 } else {
296                         generateReadSequence(currentScope, codeStream, valueRequired);
297                         if (valueRequired) {
298                                 if (lastFieldBinding.declaringClass == null) { // array length
299                                         codeStream.arraylength();
300                                         codeStream.generateImplicitConversion(implicitConversion);
301                                 } else {
302                                         if (lastFieldBinding.constant != NotAConstant) {
303                                                 // inline the last field constant
304                                                 codeStream.generateConstant(lastFieldBinding.constant, implicitConversion);
305                                         } else {
306                                                 SyntheticAccessMethodBinding accessor =
307                                                         syntheticReadAccessors == null
308                                                                 ? null
309                                                                 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
310                                                 if (accessor == null) {
311                                                         if (lastFieldBinding.isStatic()) {
312                                                                 codeStream.getstatic(lastFieldBinding);
313                                                         } else {
314                                                                 codeStream.getfield(lastFieldBinding);
315                                                         }
316                                                 } else {
317                                                         codeStream.invokestatic(accessor);
318                                                 }
319                                                 codeStream.generateImplicitConversion(implicitConversion);
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, true);
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, true);
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                 boolean valueRequired) {
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                 int indexOfFirstValueRequired;
437                 if (valueRequired) {
438                         indexOfFirstValueRequired = otherBindingsCount;
439                         while (indexOfFirstValueRequired > 0) {
440                                 FieldBinding otherBinding = this.otherCodegenBindings[indexOfFirstValueRequired - 1];
441                                 if (otherBinding.isStatic() || otherBinding.constant != NotAConstant)
442                                         break; // no longer need any value before this point
443                                 indexOfFirstValueRequired--;
444                         }
445                 } else {
446                         indexOfFirstValueRequired = otherBindingsCount + 1;
447                 }
448                 if (indexOfFirstValueRequired == 0) {
449                         switch (bits & RestrictiveFlagMASK) {
450                                 case FIELD :
451                                         lastFieldBinding = (FieldBinding) this.codegenBinding;
452                                         // if first field is actually constant, we can inline it
453                                         if (lastFieldBinding.constant != NotAConstant) {
454                                                 codeStream.generateConstant(lastFieldBinding.constant, 0);
455                                                 // no implicit conversion
456                                                 lastFieldBinding = null; // will not generate it again
457                                                 break;
458                                         }
459                                         if (!lastFieldBinding.isStatic()) {
460                                                 if ((bits & DepthMASK) != 0) {
461                                                         Object[] emulationPath =
462                                                                 currentScope.getExactEmulationPath(
463                                                                         currentScope.enclosingSourceType().enclosingTypeAt(
464                                                                                 (bits & DepthMASK) >> DepthSHIFT));
465                                                         if (emulationPath == null) {
466                                                                 // internal error, per construction we should have found it
467                                                                 currentScope.problemReporter().needImplementation();
468                                                         } else {
469                                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
470                                                         }
471                                                 } else {
472                                                         generateReceiver(codeStream);
473                                                 }
474                                         }
475                                         break;
476                                 case LOCAL : // reading the first local variable
477                                         lastFieldBinding = null;
478                                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
479                                         // regular local variable read
480                                         if (localBinding.constant != NotAConstant) {
481                                                 codeStream.generateConstant(localBinding.constant, 0);
482                                                 // no implicit conversion
483                                         } else {
484                                                 // outer local?
485                                                 if ((bits & DepthMASK) != 0) {
486                                                         // outer local can be reached either through a synthetic arg or a synthetic field
487                                                         VariableBinding[] path = currentScope.getEmulationPath(localBinding);
488                                                         if (path == null) {
489                                                                 // emulation was not possible (should not happen per construction)
490                                                                 currentScope.problemReporter().needImplementation();
491                                                         } else {
492                                                                 codeStream.generateOuterAccess(path, this, currentScope);
493                                                         }
494                                                 } else {
495                                                         codeStream.load(localBinding);
496                                                 }
497                                         }
498                         }
499                 } else {
500                         lastFieldBinding = null;
501                 }
502                 // all intermediate field accesses are read accesses
503                 // only the last field binding is a write access
504                 if (this.otherCodegenBindings != null) {
505                         int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
506                         for (int i = start; i < otherBindingsCount; i++) {
507                                 if (lastFieldBinding != null) {
508                                         MethodBinding accessor =
509                                                 syntheticReadAccessors == null ? null : syntheticReadAccessors[i];
510                                         if (accessor == null)
511                                                 if (lastFieldBinding.isStatic())
512                                                         codeStream.getstatic(lastFieldBinding);
513                                                 else
514                                                         codeStream.getfield(lastFieldBinding);
515                                         else
516                                                 codeStream.invokestatic(accessor);
517                                 }
518                                 lastFieldBinding = otherCodegenBindings[i];
519                         }
520                 }
521         }
522         public void generateReceiver(CodeStream codeStream) {
523                 codeStream.aload_0();
524         }
525         public TypeBinding getOtherFieldBindings(BlockScope scope) {
526                 // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
527                 if ((bits & FIELD) != 0) {
528                         if (!((FieldBinding) binding).isStatic()) {
529                                 //must check for the static status....
530                                 if (indexOfFirstFieldBinding == 1) {
531                                         //the field is the first token of the qualified reference....
532                                         if (scope.methodScope().isStatic) {
533                                                 scope.problemReporter().staticFieldAccessToNonStaticVariable(
534                                                         this,
535                                                         (FieldBinding) binding);
536                                                 return null;
537                                         }
538                                 } else { //accessing to a field using a type as "receiver" is allowed only with static field    
539                                         scope.problemReporter().staticFieldAccessToNonStaticVariable(
540                                                 this,
541                                                 (FieldBinding) binding);
542                                         return null;
543                                 }
544                         }
545                         if (isFieldUseDeprecated((FieldBinding) binding, scope))
546                                 scope.problemReporter().deprecatedField((FieldBinding) binding, this);
547                 }
548                 TypeBinding type = ((VariableBinding) binding).type;
549                 int index = indexOfFirstFieldBinding;
550                 int length = tokens.length;
551                 if (index == length) { //       restrictiveFlag == FIELD
552                         constant =
553                                 FieldReference.getConstantFor((FieldBinding) binding, false, this, scope, index - 1);
554                         return type;
555                 }
556                 // allocation of the fieldBindings array        and its respective constants
557                 int otherBindingsLength = length - index;
558                 otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength];
559                 otherDepths = new int[otherBindingsLength];
560                 
561                 // fill the first constant (the one of the binding)
562                 constant =
563                         ((bits & FIELD) != 0)
564                                 ? FieldReference.getConstantFor((FieldBinding) binding, false, this, scope, index - 1)
565                                 : ((VariableBinding) binding).constant;
566                 // save first depth, since will be updated by visibility checks of other bindings
567                 int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
568                 // iteration on each field      
569                 while (index < length) {
570                         char[] token = tokens[index];
571                         if (type == null)
572                                 return null; // could not resolve type prior to this point
573
574                         bits &= ~DepthMASK; // flush previous depth if any                      
575                         FieldBinding field = scope.getField(type, token, this);
576                         int place = index - indexOfFirstFieldBinding;
577                         otherBindings[place] = field;
578                         otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
579                         if (field.isValidBinding()) {
580                                 if (isFieldUseDeprecated(field, scope))
581                                         scope.problemReporter().deprecatedField(field, this);
582                                 Constant someConstant =
583                                         FieldReference.getConstantFor(field, false, this, scope, place);
584                                 // constant propagation can only be performed as long as the previous one is a constant too.
585                                 if (constant != NotAConstant) {
586                                         constant = someConstant;
587                                 }
588                                 type = field.type;
589                                 index++;
590                         } else {
591                                 constant = NotAConstant; //don't fill other constants slots...
592                                 scope.problemReporter().invalidField(this, field, index, type);
593                                 setDepth(firstDepth);
594                                 return null;
595                         }
596                 }
597                 setDepth(firstDepth);
598                 return (otherBindings[otherBindingsLength - 1]).type;
599         }
600         public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
601                 //If inlinable field, forget the access emulation, the code gen will directly target it
602                 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) {
603                         return;
604                 }
605                 switch (bits & RestrictiveFlagMASK) {
606                         case FIELD :
607                                 FieldBinding fieldBinding;
608                                 if ((fieldBinding = (FieldBinding) binding).isStatic()
609                                         || (fieldBinding.constant != NotAConstant))
610                                         return;
611                                 ReferenceBinding compatibleType = currentScope.enclosingSourceType();
612                                 // the declaringClass of the target binding must be compatible with the enclosing
613                                 // type at <depth> levels outside
614                                 for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
615                                         compatibleType = compatibleType.enclosingType();
616                                 }
617                                 currentScope.emulateOuterAccess(compatibleType, false);
618                                 // request cascade of accesses
619                                 break;
620                         case LOCAL :
621                                 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
622                 }
623         }
624         public void manageSyntheticReadAccessIfNecessary(
625                 BlockScope currentScope,
626                 FieldBinding fieldBinding,
627                 TypeBinding lastReceiverType,
628                 int index) {
629                 // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings'
630                 if (fieldBinding.constant != NotAConstant)
631                         return;
632                 if (fieldBinding.isPrivate()) { // private access
633                         if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
634                                 if (syntheticReadAccessors == null) {
635                                         if (otherBindings == null)
636                                                 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
637                                         else
638                                                 syntheticReadAccessors =
639                                                         new SyntheticAccessMethodBinding[otherBindings.length + 1];
640                                 }
641                                 syntheticReadAccessors[index] = ((SourceTypeBinding) fieldBinding.declaringClass).addSyntheticMethod(fieldBinding, true);
642                                 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
643                                 return;
644                         }
645                 } else if (fieldBinding.isProtected()){
646                         int depth = index == 0 ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[index-1];
647                         // implicit protected access (only for first one)
648                         if (depth > 0 && (fieldBinding.declaringClass.getPackage()
649                                                                 != currentScope.enclosingSourceType().getPackage())) {
650                                 if (syntheticReadAccessors == null) {
651                                         if (otherBindings == null)
652                                                 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
653                                         else
654                                                 syntheticReadAccessors =
655                                                         new SyntheticAccessMethodBinding[otherBindings.length + 1];
656                                 }
657                                 syntheticReadAccessors[index] =
658                                         ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth))
659                                                                                         .addSyntheticMethod(fieldBinding, true);
660                                 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
661                                 return;
662                         }
663                 }
664                 // if the binding declaring class is not visible, need special action
665                 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
666                 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
667                 if (fieldBinding.declaringClass != lastReceiverType
668                         && !lastReceiverType.isArrayType()                      
669                         && fieldBinding.declaringClass != null
670                         && fieldBinding.constant == NotAConstant
671                         && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
672                                         && (index > 0 || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
673                                         && fieldBinding.declaringClass.id != T_Object)
674                                 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
675                         if (index == 0){
676                                 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
677                         } else {
678                                 if (this.otherCodegenBindings == this.otherBindings){
679                                         int l = this.otherBindings.length;
680                                         System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l);
681                                 }
682                                 this.otherCodegenBindings[index-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
683                         }
684                 }
685         }
686         /*
687          * No need to emulate access to protected fields since not implicitly accessed
688          */
689         public void manageSyntheticWriteAccessIfNecessary(
690                 BlockScope currentScope,
691                 FieldBinding fieldBinding,
692                 TypeBinding lastReceiverType) {
693                 if (fieldBinding.isPrivate()) {
694                         if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
695                                 syntheticWriteAccessor = ((SourceTypeBinding) fieldBinding.declaringClass)
696                                                                                         .addSyntheticMethod(fieldBinding, false);
697                                 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
698                                 return;
699                         }
700                 } else if (fieldBinding.isProtected()){
701                         int depth = fieldBinding == binding ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[otherDepths.length-1];
702                         if (depth > 0 && (fieldBinding.declaringClass.getPackage()
703                                                                 != currentScope.enclosingSourceType().getPackage())) {
704                                 syntheticWriteAccessor = ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth))
705                                                                                         .addSyntheticMethod(fieldBinding, false);
706                                 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
707                                 return;
708                         }
709                 }
710                 // if the binding declaring class is not visible, need special action
711                 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
712                 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
713                 if (fieldBinding.declaringClass != lastReceiverType
714                         && !lastReceiverType.isArrayType()                      
715                         && fieldBinding.declaringClass != null
716                         && fieldBinding.constant == NotAConstant
717                         && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
718                                         && (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
719                                         && fieldBinding.declaringClass.id != T_Object)
720                                 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
721                         if (fieldBinding == binding){
722                                 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
723                         } else {
724                                 if (this.otherCodegenBindings == this.otherBindings){
725                                         int l = this.otherBindings.length;
726                                         System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l);
727                                 }
728                                 this.otherCodegenBindings[this.otherCodegenBindings.length-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
729                         }
730                 }
731                 
732         }
733         /**
734          * Normal field binding did not work, try to bind to a field of the delegate receiver.
735          */
736         public TypeBinding reportError(BlockScope scope) {
737                 if (binding instanceof ProblemFieldBinding) {
738                         scope.problemReporter().invalidField(this, (FieldBinding) binding);
739                 } else if (binding instanceof ProblemReferenceBinding) {
740                         scope.problemReporter().invalidType(this, (TypeBinding) binding);
741                 } else {
742                         scope.problemReporter().unresolvableReference(this, binding);
743                 }
744                 return null;
745         }
746         public TypeBinding resolveType(BlockScope scope) {
747                 // field and/or local are done before type lookups
748                 // the only available value for the restrictiveFlag BEFORE
749                 // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField 
750                 this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
751                 constant = Constant.NotAConstant;
752                 if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this))
753                         .isValidBinding()) {
754                         switch (bits & RestrictiveFlagMASK) {
755                                 case VARIABLE : //============only variable===========
756                                 case TYPE | VARIABLE :
757                                         if (binding instanceof LocalVariableBinding) {
758                                                 if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
759                                                         scope.problemReporter().cannotReferToNonFinalOuterLocal(
760                                                                 (LocalVariableBinding) binding,
761                                                                 this);
762                                                 bits &= ~RestrictiveFlagMASK; // clear bits
763                                                 bits |= LOCAL;
764                                                 return getOtherFieldBindings(scope);
765                                         }
766                                         if (binding instanceof FieldBinding) {
767                                                 // check for forward references
768                                                 FieldBinding fieldBinding = (FieldBinding) binding;
769                                                 MethodScope methodScope = scope.methodScope();
770                                                 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
771                                                         && methodScope.fieldDeclarationIndex != MethodScope.NotInFieldDecl
772                                                         && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
773                                                         if ((!fieldBinding.isStatic() || methodScope.isStatic)
774                                                                 && this.indexOfFirstFieldBinding == 1)
775                                                                 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
776                                                 }
777                                                 bits &= ~RestrictiveFlagMASK; // clear bits
778                                                 bits |= FIELD;
779                                                 return getOtherFieldBindings(scope);
780                                         }
781                                         // thus it was a type
782                                         bits &= ~RestrictiveFlagMASK; // clear bits
783                                         bits |= TYPE;
784                                 case TYPE : //=============only type ==============
785                                         //deprecated test
786                                         if (isTypeUseDeprecated((TypeBinding) binding, scope))
787                                                 scope.problemReporter().deprecatedType((TypeBinding) binding, this);
788                                         return (TypeBinding) binding;
789                         }
790                 }
791                 //========error cases===============
792                 return this.reportError(scope);
793         }
794         public void setFieldIndex(int index) {
795                 this.indexOfFirstFieldBinding = index;
796         }
797         public String toStringExpression() {
798                 StringBuffer buffer = new StringBuffer();
799                 for (int i = 0; i < tokens.length; i++) {
800                         buffer.append(tokens[i]);
801                         if (i < (tokens.length - 1)) {
802                                 buffer.append("."); //$NON-NLS-1$
803                         }
804                 }
805                 return buffer.toString();
806         }
807         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
808                 visitor.visit(this, scope);
809                 visitor.endVisit(this, scope);
810         }
811         public String unboundReferenceErrorName() {
812                 return new String(tokens[0]);
813         }
814 }