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