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