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