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