1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.internal.compiler.lookup.*;
19 public class QualifiedNameReference extends NameReference {
21 public char[][] tokens;
22 public FieldBinding[] otherBindings, otherCodegenBindings;
24 public int indexOfFirstFieldBinding;//points (into tokens) for the first token that corresponds to first FieldBinding
25 SyntheticAccessMethodBinding syntheticWriteAccessor;
26 SyntheticAccessMethodBinding[] syntheticReadAccessors;
27 protected FieldBinding lastFieldBinding;
28 public QualifiedNameReference(
34 this.sourceStart = sourceStart;
35 this.sourceEnd = sourceEnd;
37 public FlowInfo analyseAssignment(
38 BlockScope currentScope,
39 FlowContext flowContext,
41 Assignment assignment,
44 if (assignment.expression != null) {
48 .analyseCode(currentScope, flowContext, flowInfo)
49 .unconditionalInits();
51 // determine the rank until which we now we do not need any actual value for the field access
52 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
53 int indexOfFirstValueRequired = otherBindingsCount;
54 while (indexOfFirstValueRequired > 0) {
55 FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
56 if (otherBinding.isStatic())
57 break; // no longer need any value before this point
58 indexOfFirstValueRequired--;
60 FieldBinding lastFieldBinding = null;
61 if ((bits & FIELD) != 0) {
62 // reading from a field
63 // check if final blank field
64 if ((lastFieldBinding = (FieldBinding) binding).isFinal()
65 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
66 if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
67 currentScope.problemReporter().uninitializedBlankFinalField(
73 if ((bits & LOCAL) != 0) {
74 // first binding is a local variable
75 LocalVariableBinding localBinding;
77 .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
78 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
80 if (!flowInfo.isFakeReachable())
81 localBinding.used = true;
84 if (indexOfFirstValueRequired == 0) {
85 manageEnclosingInstanceAccessIfNecessary(currentScope);
86 // only for first binding
88 // all intermediate field accesses are read accesses
89 if (otherBindings != null) {
90 int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
91 for (int i = start; i < otherBindingsCount; i++) {
92 if (lastFieldBinding != null) { // could be null if first was a local variable
93 TypeBinding lastReceiverType;
96 lastReceiverType = this.actualReceiverType;
99 lastReceiverType = ((VariableBinding)binding).type;
102 lastReceiverType = otherBindings[i-1].type;
104 manageSyntheticReadAccessIfNecessary(
110 lastFieldBinding = otherBindings[i];
114 if (binding == lastFieldBinding
115 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)
116 && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
117 currentScope.problemReporter().uninitializedBlankFinalField(
121 TypeBinding lastReceiverType;
122 if (lastFieldBinding == binding){
123 lastReceiverType = this.actualReceiverType;
124 } else if (otherBindingsCount == 1){
125 lastReceiverType = ((VariableBinding)this.binding).type;
127 lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
129 manageSyntheticReadAccessIfNecessary(
133 lastFieldBinding == binding
135 : otherBindingsCount);
137 // the last field access is a write access
138 if (lastFieldBinding.isFinal()) {
139 // in a context where it can be assigned?
140 if (currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) {
141 if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
142 if (indexOfFirstFieldBinding == 1) {
143 // was an implicit reference to the first field binding
144 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(
148 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
149 // attempting to assign a non implicit reference
152 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
153 flowContext.recordSettingFinal(lastFieldBinding, this);
155 currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this);
158 // equivalent to valuesRequired[maxOtherBindings]
159 TypeBinding lastReceiverType;
160 if (lastFieldBinding == binding){
161 lastReceiverType = this.actualReceiverType;
162 } else if (otherBindingsCount == 1){
163 lastReceiverType = ((VariableBinding)this.binding).type;
165 lastReceiverType = this.otherBindings[otherBindingsCount-2].type;
167 manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding, lastReceiverType);
171 public FlowInfo analyseCode(
172 BlockScope currentScope,
173 FlowContext flowContext,
176 return analyseCode(currentScope, flowContext, flowInfo, true);
179 public FlowInfo analyseCode(
180 BlockScope currentScope,
181 FlowContext flowContext,
183 boolean valueRequired) {
185 // determine the rank until which we now we do not need any actual value for the field access
186 int otherBindingsCount = otherBindings == null ? 0 : otherBindings.length;
187 int indexOfFirstValueRequired;
189 indexOfFirstValueRequired = otherBindingsCount;
190 while (indexOfFirstValueRequired > 0) {
191 FieldBinding otherBinding = otherBindings[indexOfFirstValueRequired - 1];
192 if (otherBinding.isStatic())
193 break; // no longer need any value before this point
194 indexOfFirstValueRequired--;
197 indexOfFirstValueRequired = otherBindingsCount + 1;
199 switch (bits & RestrictiveFlagMASK) {
200 case FIELD : // reading a field
201 if (indexOfFirstValueRequired == 0) {
202 manageSyntheticReadAccessIfNecessary(currentScope, (FieldBinding) binding, this.actualReceiverType, 0);
204 // check if reading a final blank field
205 FieldBinding fieldBinding;
206 if ((fieldBinding = (FieldBinding) binding).isFinal()
207 && (indexOfFirstFieldBinding == 1)
208 // was an implicit reference to the first field binding
209 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)
210 && (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
211 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
214 case LOCAL : // reading a local variable
215 LocalVariableBinding localBinding;
217 .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
218 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
220 if (!flowInfo.isFakeReachable())
221 localBinding.used = true;
223 if (indexOfFirstValueRequired == 0) {
224 manageEnclosingInstanceAccessIfNecessary(currentScope);
225 // only for first binding
227 if (otherBindings != null) {
228 int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
229 for (int i = start; i < otherBindingsCount; i++) {
230 manageSyntheticReadAccessIfNecessary(
234 ? ((VariableBinding)binding).type
235 : otherBindings[i-1].type,
242 * Check and/or redirect the field access to the delegate receiver if any
244 public TypeBinding checkFieldAccess(BlockScope scope) {
245 // check for forward references
246 FieldBinding fieldBinding = (FieldBinding) binding;
247 MethodScope methodScope = scope.methodScope();
248 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
249 && methodScope.fieldDeclarationIndex != methodScope.NotInFieldDecl
250 && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
251 if ((!fieldBinding.isStatic() || methodScope.isStatic)
252 && this.indexOfFirstFieldBinding == 1)
253 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
255 bits &= ~RestrictiveFlagMASK; // clear bits
257 return getOtherFieldBindings(scope);
259 public void generateAssignment(
260 BlockScope currentScope,
261 CodeStream codeStream,
262 Assignment assignment,
263 boolean valueRequired) {
265 generateReadSequence(currentScope, codeStream, true);
266 assignment.expression.generateCode(currentScope, codeStream, true);
267 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
268 // equivalent to valuesRequired[maxOtherBindings]
270 codeStream.generateImplicitConversion(assignment.implicitConversion);
273 public void generateCode(
274 BlockScope currentScope,
275 CodeStream codeStream,
276 boolean valueRequired) {
277 int pc = codeStream.position;
278 if (constant != NotAConstant) {
280 codeStream.generateConstant(constant, implicitConversion);
283 generateReadSequence(currentScope, codeStream, valueRequired);
285 if (lastFieldBinding.declaringClass == null) { // array length
286 codeStream.arraylength();
287 codeStream.generateImplicitConversion(implicitConversion);
289 if (lastFieldBinding.constant != NotAConstant) {
290 // inline the last field constant
291 codeStream.generateConstant(lastFieldBinding.constant, implicitConversion);
293 SyntheticAccessMethodBinding accessor =
294 syntheticReadAccessors == null
296 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
297 if (accessor == null) {
298 if (lastFieldBinding.isStatic()) {
299 codeStream.getstatic(lastFieldBinding);
301 codeStream.getfield(lastFieldBinding);
304 codeStream.invokestatic(accessor);
306 codeStream.generateImplicitConversion(implicitConversion);
311 codeStream.recordPositionsFrom(pc, this.sourceStart);
313 public void generateCompoundAssignment(
314 BlockScope currentScope,
315 CodeStream codeStream,
316 Expression expression,
318 int assignmentImplicitConversion,
319 boolean valueRequired) {
321 generateReadSequence(currentScope, codeStream, true);
322 SyntheticAccessMethodBinding accessor =
323 syntheticReadAccessors == null
325 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
326 if (lastFieldBinding.isStatic()) {
327 if (accessor == null) {
328 codeStream.getstatic(lastFieldBinding);
330 codeStream.invokestatic(accessor);
334 if (accessor == null) {
335 codeStream.getfield(lastFieldBinding);
337 codeStream.invokestatic(accessor);
340 // the last field access is a write access
341 // perform the actual compound operation
343 if ((operationTypeID = implicitConversion >> 4) == T_String) {
344 codeStream.generateStringAppend(currentScope, null, expression);
346 // promote the array reference to the suitable operation type
347 codeStream.generateImplicitConversion(implicitConversion);
348 // generate the increment value (will by itself be promoted to the operation value)
349 if (expression == IntLiteral.One) { // prefix operation
350 codeStream.generateConstant(expression.constant, implicitConversion);
352 expression.generateCode(currentScope, codeStream, true);
354 // perform the operation
355 codeStream.sendOperator(operator, operationTypeID);
356 // cast the value back to the array reference type
357 codeStream.generateImplicitConversion(assignmentImplicitConversion);
360 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, valueRequired);
361 // equivalent to valuesRequired[maxOtherBindings]
363 public void generatePostIncrement(
364 BlockScope currentScope,
365 CodeStream codeStream,
366 CompoundAssignment postIncrement,
367 boolean valueRequired) {
368 generateReadSequence(currentScope, codeStream, true);
369 SyntheticAccessMethodBinding accessor =
370 syntheticReadAccessors == null
372 : syntheticReadAccessors[syntheticReadAccessors.length - 1];
373 if (lastFieldBinding.isStatic()) {
374 if (accessor == null) {
375 codeStream.getstatic(lastFieldBinding);
377 codeStream.invokestatic(accessor);
381 if (accessor == null) {
382 codeStream.getfield(lastFieldBinding);
384 codeStream.invokestatic(accessor);
387 // duplicate the old field value
389 if (lastFieldBinding.isStatic()) {
390 if ((lastFieldBinding.type == LongBinding)
391 || (lastFieldBinding.type == DoubleBinding)) {
396 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
397 if ((lastFieldBinding.type == LongBinding)
398 || (lastFieldBinding.type == DoubleBinding)) {
399 codeStream.dup2_x1();
405 codeStream.generateConstant(
406 postIncrement.expression.constant,
408 codeStream.sendOperator(postIncrement.operator, lastFieldBinding.type.id);
409 codeStream.generateImplicitConversion(
410 postIncrement.assignmentImplicitConversion);
411 fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor, false);
414 * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code
415 * for a read or write access.
417 public void generateReadSequence(
418 BlockScope currentScope,
419 CodeStream codeStream,
420 boolean valueRequired) {
421 // determine the rank until which we now we do not need any actual value for the field access
422 int otherBindingsCount = this.otherCodegenBindings == null ? 0 : otherCodegenBindings.length;
423 int indexOfFirstValueRequired;
425 indexOfFirstValueRequired = otherBindingsCount;
426 while (indexOfFirstValueRequired > 0) {
427 FieldBinding otherBinding = this.otherCodegenBindings[indexOfFirstValueRequired - 1];
428 if (otherBinding.isStatic() || otherBinding.constant != NotAConstant)
429 break; // no longer need any value before this point
430 indexOfFirstValueRequired--;
433 indexOfFirstValueRequired = otherBindingsCount + 1;
435 if (indexOfFirstValueRequired == 0) {
436 switch (bits & RestrictiveFlagMASK) {
438 lastFieldBinding = (FieldBinding) this.codegenBinding;
439 // if first field is actually constant, we can inline it
440 if (lastFieldBinding.constant != NotAConstant) {
441 codeStream.generateConstant(lastFieldBinding.constant, 0);
442 // no implicit conversion
443 lastFieldBinding = null; // will not generate it again
446 if (!lastFieldBinding.isStatic()) {
447 if ((bits & DepthMASK) != 0) {
448 Object[] emulationPath =
449 currentScope.getExactEmulationPath(
450 currentScope.enclosingSourceType().enclosingTypeAt(
451 (bits & DepthMASK) >> DepthSHIFT));
452 if (emulationPath == null) {
453 // internal error, per construction we should have found it
454 currentScope.problemReporter().needImplementation();
456 codeStream.generateOuterAccess(emulationPath, this, currentScope);
459 generateReceiver(codeStream);
463 case LOCAL : // reading the first local variable
464 lastFieldBinding = null;
465 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
466 // regular local variable read
467 if (localBinding.constant != NotAConstant) {
468 codeStream.generateConstant(localBinding.constant, 0);
469 // no implicit conversion
472 if ((bits & DepthMASK) != 0) {
473 // outer local can be reached either through a synthetic arg or a synthetic field
474 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
476 // emulation was not possible (should not happen per construction)
477 currentScope.problemReporter().needImplementation();
479 codeStream.generateOuterAccess(path, this, currentScope);
482 codeStream.load(localBinding);
487 lastFieldBinding = null;
489 // all intermediate field accesses are read accesses
490 // only the last field binding is a write access
491 if (this.otherCodegenBindings != null) {
492 int start = indexOfFirstValueRequired == 0 ? 0 : indexOfFirstValueRequired - 1;
493 for (int i = start; i < otherBindingsCount; i++) {
494 if (lastFieldBinding != null) {
495 MethodBinding accessor =
496 syntheticReadAccessors == null ? null : syntheticReadAccessors[i];
497 if (accessor == null)
498 if (lastFieldBinding.isStatic())
499 codeStream.getstatic(lastFieldBinding);
501 codeStream.getfield(lastFieldBinding);
503 codeStream.invokestatic(accessor);
505 lastFieldBinding = otherCodegenBindings[i];
509 public void generateReceiver(CodeStream codeStream) {
510 codeStream.aload_0();
512 public TypeBinding getOtherFieldBindings(BlockScope scope) {
513 // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid)
514 if ((bits & FIELD) != 0) {
515 if (!((FieldBinding) binding).isStatic()) {
516 //must check for the static status....
517 if (indexOfFirstFieldBinding == 1) {
518 //the field is the first token of the qualified reference....
519 if (scope.methodScope().isStatic) {
520 scope.problemReporter().staticFieldAccessToNonStaticVariable(
522 (FieldBinding) binding);
525 } else { //accessing to a field using a type as "receiver" is allowed only with static field
526 scope.problemReporter().staticFieldAccessToNonStaticVariable(
528 (FieldBinding) binding);
532 if (isFieldUseDeprecated((FieldBinding) binding, scope))
533 scope.problemReporter().deprecatedField((FieldBinding) binding, this);
535 TypeBinding type = ((VariableBinding) binding).type;
536 int index = indexOfFirstFieldBinding;
537 int length = tokens.length;
538 if (index == length) { // restrictiveFlag == FIELD
540 FieldReference.getConstantFor((FieldBinding) binding, false, this, scope, index - 1);
543 // allocation of the fieldBindings array and its respective constants
544 int otherBindingsLength = length - index;
545 otherCodegenBindings = otherBindings = new FieldBinding[otherBindingsLength];
546 otherDepths = new int[otherBindingsLength];
548 // fill the first constant (the one of the binding)
550 ((bits & FIELD) != 0)
551 ? FieldReference.getConstantFor((FieldBinding) binding, false, this, scope, index - 1)
552 : ((VariableBinding) binding).constant;
553 // save first depth, since will be updated by visibility checks of other bindings
554 int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
555 // iteration on each field
556 while (index < length) {
557 char[] token = tokens[index];
559 return null; // could not resolve type prior to this point
561 bits &= ~DepthMASK; // flush previous depth if any
562 FieldBinding field = scope.getField(type, token, this);
563 int place = index - indexOfFirstFieldBinding;
564 otherBindings[place] = field;
565 otherDepths[place] = (bits & DepthMASK) >> DepthSHIFT;
566 if (field.isValidBinding()) {
567 if (isFieldUseDeprecated(field, scope))
568 scope.problemReporter().deprecatedField(field, this);
569 Constant someConstant =
570 FieldReference.getConstantFor(field, false, this, scope, place);
571 // constant propagation can only be performed as long as the previous one is a constant too.
572 if (constant != NotAConstant) {
573 constant = someConstant;
578 constant = NotAConstant; //don't fill other constants slots...
579 scope.problemReporter().invalidField(this, field, index, type);
580 setDepth(firstDepth);
584 setDepth(firstDepth);
585 return (otherBindings[otherBindingsLength - 1]).type;
587 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
588 //If inlinable field, forget the access emulation, the code gen will directly target it
589 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) {
592 switch (bits & RestrictiveFlagMASK) {
594 FieldBinding fieldBinding;
595 if ((fieldBinding = (FieldBinding) binding).isStatic()
596 || (fieldBinding.constant != NotAConstant))
598 ReferenceBinding compatibleType = currentScope.enclosingSourceType();
599 // the declaringClass of the target binding must be compatible with the enclosing
600 // type at <depth> levels outside
601 for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
602 compatibleType = compatibleType.enclosingType();
604 currentScope.emulateOuterAccess(compatibleType, false);
605 // request cascade of accesses
608 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
611 public void manageSyntheticReadAccessIfNecessary(
612 BlockScope currentScope,
613 FieldBinding fieldBinding,
614 TypeBinding lastReceiverType,
616 // index == 0 denotes the first fieldBinding, index > 0 denotes one of the 'otherBindings'
617 if (fieldBinding.constant != NotAConstant)
619 if (fieldBinding.isPrivate()) { // private access
620 if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
621 if (syntheticReadAccessors == null) {
622 if (otherBindings == null)
623 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
625 syntheticReadAccessors =
626 new SyntheticAccessMethodBinding[otherBindings.length + 1];
628 syntheticReadAccessors[index] = ((SourceTypeBinding) fieldBinding.declaringClass).addSyntheticMethod(fieldBinding, true);
629 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
632 } else if (fieldBinding.isProtected()){
633 int depth = index == 0 ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[index-1];
634 // implicit protected access (only for first one)
635 if (depth > 0 && (fieldBinding.declaringClass.getPackage()
636 != currentScope.enclosingSourceType().getPackage())) {
637 if (syntheticReadAccessors == null) {
638 if (otherBindings == null)
639 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
641 syntheticReadAccessors =
642 new SyntheticAccessMethodBinding[otherBindings.length + 1];
644 syntheticReadAccessors[index] =
645 ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth))
646 .addSyntheticMethod(fieldBinding, true);
647 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
651 // if the binding declaring class is not visible, need special action
652 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
653 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
654 if (fieldBinding.declaringClass != lastReceiverType
655 && !lastReceiverType.isArrayType()
656 && fieldBinding.declaringClass != null
657 && fieldBinding.constant == NotAConstant
658 && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
659 && (index > 0 || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
660 && fieldBinding.declaringClass.id != T_Object)
661 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
663 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
665 if (this.otherCodegenBindings == this.otherBindings){
666 int l = this.otherBindings.length;
667 System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l);
669 this.otherCodegenBindings[index-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
674 * No need to emulate access to protected fields since not implicitly accessed
676 public void manageSyntheticWriteAccessIfNecessary(
677 BlockScope currentScope,
678 FieldBinding fieldBinding,
679 TypeBinding lastReceiverType) {
680 if (fieldBinding.isPrivate()) {
681 if (fieldBinding.declaringClass != currentScope.enclosingSourceType()) {
682 syntheticWriteAccessor = ((SourceTypeBinding) fieldBinding.declaringClass)
683 .addSyntheticMethod(fieldBinding, false);
684 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
687 } else if (fieldBinding.isProtected()){
688 int depth = fieldBinding == binding ? (bits & DepthMASK) >> DepthSHIFT : otherDepths[otherDepths.length-1];
689 if (depth > 0 && (fieldBinding.declaringClass.getPackage()
690 != currentScope.enclosingSourceType().getPackage())) {
691 syntheticWriteAccessor = ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth))
692 .addSyntheticMethod(fieldBinding, false);
693 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
697 // if the binding declaring class is not visible, need special action
698 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
699 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
700 if (fieldBinding.declaringClass != lastReceiverType
701 && !lastReceiverType.isArrayType()
702 && fieldBinding.declaringClass != null
703 && fieldBinding.constant == NotAConstant
704 && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
705 && (fieldBinding != binding || indexOfFirstFieldBinding > 1 || !fieldBinding.isStatic())
706 && fieldBinding.declaringClass.id != T_Object)
707 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
708 if (fieldBinding == binding){
709 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
711 if (this.otherCodegenBindings == this.otherBindings){
712 int l = this.otherBindings.length;
713 System.arraycopy(this.otherBindings, 0, this.otherCodegenBindings = new FieldBinding[l], 0, l);
715 this.otherCodegenBindings[this.otherCodegenBindings.length-1] = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)lastReceiverType);
721 * Normal field binding did not work, try to bind to a field of the delegate receiver.
723 public TypeBinding reportError(BlockScope scope) {
724 if (binding instanceof ProblemFieldBinding) {
725 scope.problemReporter().invalidField(this, (FieldBinding) binding);
726 } else if (binding instanceof ProblemReferenceBinding) {
727 scope.problemReporter().invalidType(this, (TypeBinding) binding);
729 scope.problemReporter().unresolvableReference(this, binding);
733 public TypeBinding resolveType(BlockScope scope) {
734 // field and/or local are done before type lookups
735 // the only available value for the restrictiveFlag BEFORE
736 // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField
737 this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
738 constant = Constant.NotAConstant;
739 if ((this.codegenBinding = this.binding = scope.getBinding(tokens, bits & RestrictiveFlagMASK, this))
741 switch (bits & RestrictiveFlagMASK) {
742 case VARIABLE : //============only variable===========
743 case TYPE | VARIABLE :
744 if (binding instanceof LocalVariableBinding) {
745 if (!((LocalVariableBinding) binding).isFinal() && ((bits & DepthMASK) != 0))
746 scope.problemReporter().cannotReferToNonFinalOuterLocal(
747 (LocalVariableBinding) binding,
749 bits &= ~RestrictiveFlagMASK; // clear bits
751 return getOtherFieldBindings(scope);
753 if (binding instanceof FieldBinding) {
754 // check for forward references
755 FieldBinding fieldBinding = (FieldBinding) binding;
756 MethodScope methodScope = scope.methodScope();
757 if (methodScope.enclosingSourceType() == fieldBinding.declaringClass
758 && methodScope.fieldDeclarationIndex != methodScope.NotInFieldDecl
759 && fieldBinding.id >= methodScope.fieldDeclarationIndex) {
760 if ((!fieldBinding.isStatic() || methodScope.isStatic)
761 && this.indexOfFirstFieldBinding == 1)
762 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
764 bits &= ~RestrictiveFlagMASK; // clear bits
766 return getOtherFieldBindings(scope);
768 // thus it was a type
769 bits &= ~RestrictiveFlagMASK; // clear bits
771 case TYPE : //=============only type ==============
773 if (isTypeUseDeprecated((TypeBinding) binding, scope))
774 scope.problemReporter().deprecatedType((TypeBinding) binding, this);
775 return (TypeBinding) binding;
778 //========error cases===============
779 return this.reportError(scope);
781 public void setFieldIndex(int index) {
782 this.indexOfFirstFieldBinding = index;
784 public String toStringExpression() {
785 StringBuffer buffer = new StringBuffer();
786 for (int i = 0; i < tokens.length; i++) {
787 buffer.append(tokens[i]);
788 if (i < (tokens.length - 1)) {
789 buffer.append("."); //$NON-NLS-1$
792 return buffer.toString();
794 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
795 visitor.visit(this, scope);
796 visitor.endVisit(this, scope);
798 public String unboundReferenceErrorName() {
799 return new String(tokens[0]);