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
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.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;
28 public class QualifiedNameReference extends NameReference {
30 public char[][] tokens;
32 public FieldBinding[] otherBindings, otherCodegenBindings;
36 public int indexOfFirstFieldBinding;// points (into tokens) for the first
37 // token that corresponds to first
40 SyntheticAccessMethodBinding syntheticWriteAccessor;
42 SyntheticAccessMethodBinding[] syntheticReadAccessors;
44 protected FieldBinding lastFieldBinding;
46 public QualifiedNameReference(char[][] sources, int sourceStart,
50 this.sourceStart = sourceStart;
51 this.sourceEnd = sourceEnd;
54 public FlowInfo analyseAssignment(BlockScope currentScope,
55 FlowContext flowContext, FlowInfo flowInfo, Assignment assignment,
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;
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
75 .allowBlankFinalFieldAssignment(lastFieldBinding)) {
76 if (!flowInfo.isDefinitelyAssigned(lastFieldBinding)) {
77 currentScope.problemReporter()
78 .uninitializedBlankFinalField(lastFieldBinding,
84 // // first binding is a local variable
85 // LocalVariableBinding localBinding;
87 // .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding))
89 // currentScope.problemReporter().uninitializedLocalVariable(localBinding,
92 // if (flowInfo.isReachable()) {
93 // localBinding.useFlag = LocalVariableBinding.USED;
94 // } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
95 // localBinding.useFlag = LocalVariableBinding.FAKE_USED;
100 manageEnclosingInstanceAccessIfNecessary(currentScope);
101 // only for first binding
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();
109 manageSyntheticReadAccessIfNecessary(currentScope,
111 i == 0 ? ((VariableBinding) binding).type
112 : otherBindings[i - 1].type, i + 1);
115 lastFieldBinding = otherBindings[otherBindingsCount - 1];
119 if (binding == lastFieldBinding
120 && lastFieldBinding.isBlankFinal()
122 .allowBlankFinalFieldAssignment(lastFieldBinding)
123 && (!flowInfo.isDefinitelyAssigned(lastFieldBinding))) {
124 currentScope.problemReporter().uninitializedBlankFinalField(
125 lastFieldBinding, this);
127 TypeBinding lastReceiverType;
128 if (lastFieldBinding == binding) {
129 lastReceiverType = this.actualReceiverType;
130 } else if (otherBindingsCount == 1) {
131 lastReceiverType = ((VariableBinding) this.binding).type;
133 lastReceiverType = this.otherBindings[otherBindingsCount - 2].type;
135 manageSyntheticReadAccessIfNecessary(currentScope,
136 lastFieldBinding, lastReceiverType,
137 lastFieldBinding == binding ? 0 : otherBindingsCount);
140 if (assignment.expression != null) {
141 flowInfo = assignment.expression.analyseCode(currentScope,
142 flowContext, flowInfo).unconditionalInits();
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()
151 .allowBlankFinalFieldAssignment(lastFieldBinding)
152 && indexOfFirstFieldBinding == 1) {
153 if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) {
154 currentScope.problemReporter()
155 .duplicateInitializationOfBlankFinalField(
156 lastFieldBinding, this);
158 flowContext.recordSettingFinal(lastFieldBinding, this);
160 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
162 currentScope.problemReporter().cannotAssignToFinalField(
163 lastFieldBinding, this);
165 .allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend
169 flowInfo.markAsDefinitelyAssigned(lastFieldBinding);
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;
180 lastReceiverType = this.otherBindings[otherBindingsCount - 2].type;
182 manageSyntheticWriteAccessIfNecessary(currentScope, lastFieldBinding,
188 public FlowInfo analyseCode(BlockScope currentScope,
189 FlowContext flowContext, FlowInfo flowInfo) {
191 return analyseCode(currentScope, flowContext, flowInfo, true);
194 public FlowInfo analyseCode(BlockScope currentScope,
195 FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
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;
202 boolean needValue = otherBindingsCount == 0 ? valueRequired
203 : !this.otherBindings[0].isStatic();
204 switch (bits & RestrictiveFlagMASK) {
205 case FIELD: // reading a field
207 manageSyntheticReadAccessIfNecessary(currentScope,
208 (FieldBinding) binding, this.actualReceiverType, 0);
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
216 .allowBlankFinalFieldAssignment(fieldBinding)
217 && (!flowInfo.isDefinitelyAssigned(fieldBinding))) {
218 currentScope.problemReporter().uninitializedBlankFinalField(
222 // case LOCAL : // reading a local variable
223 // LocalVariableBinding localBinding;
225 // .isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding))
227 // currentScope.problemReporter().uninitializedLocalVariable(localBinding,
230 // if (flowInfo.isReachable()) {
231 // localBinding.useFlag = LocalVariableBinding.USED;
232 // } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
233 // localBinding.useFlag = LocalVariableBinding.FAKE_USED;
237 manageEnclosingInstanceAccessIfNecessary(currentScope);
238 // only for first binding
240 if (otherBindings != null) {
241 for (int i = 0; i < otherBindingsCount; i++) {
242 needValue = i < otherBindingsCount - 1 ? !otherBindings[i + 1]
243 .isStatic() : valueRequired;
245 manageSyntheticReadAccessIfNecessary(currentScope,
247 i == 0 ? ((VariableBinding) binding).type
248 : otherBindings[i - 1].type, i + 1);
256 * Check and/or redirect the field access to the delegate receiver if any
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());
270 bits &= ~RestrictiveFlagMASK; // clear bits
272 return getOtherFieldBindings(scope);
275 // public void generateAssignment(
276 // BlockScope currentScope,
277 // CodeStream codeStream,
278 // Assignment assignment,
279 // boolean valueRequired) {
281 // generateReadSequence(currentScope, codeStream);
282 // assignment.expression.generateCode(currentScope, codeStream, true);
283 // fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor,
285 // // equivalent to valuesRequired[maxOtherBindings]
286 // if (valueRequired) {
287 // codeStream.generateImplicitConversion(assignment.implicitConversion);
290 // public void generateCode(
291 // BlockScope currentScope,
292 // CodeStream codeStream,
293 // boolean valueRequired) {
295 // int pc = codeStream.position;
296 // if (constant != NotAConstant) {
297 // if (valueRequired) {
298 // codeStream.generateConstant(constant, implicitConversion);
301 // generateReadSequence(currentScope, codeStream);
302 // if (valueRequired) {
303 // if (lastFieldBinding.declaringClass == null) { // array length
304 // codeStream.arraylength();
305 // codeStream.generateImplicitConversion(implicitConversion);
307 // if (lastFieldBinding.constant != NotAConstant) {
308 // if (!lastFieldBinding.isStatic()){
309 // codeStream.invokeObjectGetClass();
312 // // inline the last field constant
313 // codeStream.generateConstant(lastFieldBinding.constant,
314 // implicitConversion);
316 // SyntheticAccessMethodBinding accessor =
317 // syntheticReadAccessors == null
319 // : syntheticReadAccessors[syntheticReadAccessors.length - 1];
320 // if (accessor == null) {
321 // if (lastFieldBinding.isStatic()) {
322 // codeStream.getstatic(lastFieldBinding);
324 // codeStream.getfield(lastFieldBinding);
327 // codeStream.invokestatic(accessor);
329 // codeStream.generateImplicitConversion(implicitConversion);
333 // if (lastFieldBinding != null && !lastFieldBinding.isStatic()){
334 // codeStream.invokeObjectGetClass(); // perform null check
340 // codeStream.recordPositionsFrom(pc, this.sourceStart);
342 // public void generateCompoundAssignment(
343 // BlockScope currentScope,
344 // CodeStream codeStream,
345 // Expression expression,
347 // int assignmentImplicitConversion,
348 // boolean valueRequired) {
350 // generateReadSequence(currentScope, codeStream);
351 // SyntheticAccessMethodBinding accessor =
352 // syntheticReadAccessors == null
354 // : syntheticReadAccessors[syntheticReadAccessors.length - 1];
355 // if (lastFieldBinding.isStatic()) {
356 // if (accessor == null) {
357 // codeStream.getstatic(lastFieldBinding);
359 // codeStream.invokestatic(accessor);
363 // if (accessor == null) {
364 // codeStream.getfield(lastFieldBinding);
366 // codeStream.invokestatic(accessor);
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);
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
379 // if (expression == IntLiteral.One) { // prefix operation
380 // codeStream.generateConstant(expression.constant, implicitConversion);
382 // expression.generateCode(currentScope, codeStream, true);
384 // // perform the operation
385 // codeStream.sendOperator(operator, operationTypeID);
386 // // cast the value back to the array reference type
387 // codeStream.generateImplicitConversion(assignmentImplicitConversion);
389 // // actual assignment
390 // fieldStore(codeStream, lastFieldBinding, syntheticWriteAccessor,
392 // // equivalent to valuesRequired[maxOtherBindings]
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
403 // : syntheticReadAccessors[syntheticReadAccessors.length - 1];
404 // if (lastFieldBinding.isStatic()) {
405 // if (accessor == null) {
406 // codeStream.getstatic(lastFieldBinding);
408 // codeStream.invokestatic(accessor);
412 // if (accessor == null) {
413 // codeStream.getfield(lastFieldBinding);
415 // codeStream.invokestatic(accessor);
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();
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();
433 // codeStream.dup_x1();
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);
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.
451 // public void generateReadSequence(
452 // BlockScope currentScope,
453 // CodeStream codeStream) {
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;
460 // boolean needValue = otherBindingsCount == 0 ||
461 // !this.otherBindings[0].isStatic();
462 // switch (bits & RestrictiveFlagMASK) {
464 // lastFieldBinding = (FieldBinding) this.codegenBinding;
465 // // if first field is actually constant, we can inline it
466 // if (lastFieldBinding.constant != NotAConstant) {
469 // if (needValue && !lastFieldBinding.isStatic()) {
470 // if ((bits & DepthMASK) != 0) {
471 // ReferenceBinding targetType =
472 // currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >>
474 // Object[] emulationPath = currentScope.getEmulationPath(targetType, true
475 // /*only exact match*/, false/*consider enclosing arg*/);
476 // codeStream.generateOuterAccess(emulationPath, this, targetType,
479 // generateReceiver(codeStream);
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
494 // if ((bits & DepthMASK) != 0) {
495 // // outer local can be reached either through a synthetic arg or a
497 // VariableBinding[] path = currentScope.getEmulationPath(localBinding);
498 // codeStream.generateOuterAccess(path, this, localBinding, currentScope);
500 // codeStream.load(localBinding);
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();
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
522 // codeStream.generateConstant(lastFieldBinding.constant, 0);
523 // } else if (lastFieldBinding.isStatic()) {
524 // codeStream.getstatic(lastFieldBinding);
526 // codeStream.getfield(lastFieldBinding);
529 // codeStream.invokestatic(accessor);
532 // if (this.codegenBinding != this.lastFieldBinding &&
533 // !this.lastFieldBinding.isStatic()){
534 // codeStream.invokeObjectGetClass(); // perform null check
539 // this.lastFieldBinding = nextField;
543 // public void generateReceiver(CodeStream codeStream) {
544 // codeStream.aload_0();
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
555 if (scope.methodScope().isStatic) {
556 scope.problemReporter()
557 .staticFieldAccessToNonStaticVariable(this,
558 (FieldBinding) binding);
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);
569 if (isFieldUseDeprecated((FieldBinding) binding, scope))
570 scope.problemReporter().deprecatedField((FieldBinding) binding,
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);
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];
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
592 int firstDepth = (bits & DepthMASK) >> DepthSHIFT;
593 // iteration on each field
594 while (index < length) {
595 char[] token = tokens[index];
597 return null; // could not resolve type prior to this point
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,
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;
618 if (field.isStatic()) {
619 // static field accessed through receiver? legal but
620 // unoptimal (optional warning)
621 scope.problemReporter().unnecessaryReceiverForStaticField(
626 constant = NotAConstant; // don't fill other constants
628 scope.problemReporter().invalidField(this, field, index, type);
629 setDepth(firstDepth);
633 setDepth(firstDepth);
634 return (otherBindings[otherBindingsLength - 1]).type;
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)) {
643 if ((bits & RestrictiveFlagMASK) == LOCAL) {
644 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
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)
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];
661 syntheticReadAccessors = new SyntheticAccessMethodBinding[otherBindings.length + 1];
663 syntheticReadAccessors[index] = ((SourceTypeBinding) fieldBinding.declaringClass)
664 .addSyntheticMethod(fieldBinding, true);
665 currentScope.problemReporter().needToEmulateFieldReadAccess(
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)
674 && (fieldBinding.declaringClass.getPackage() != currentScope
675 .enclosingSourceType().getPackage())) {
676 if (syntheticReadAccessors == null) {
677 if (otherBindings == null)
678 syntheticReadAccessors = new SyntheticAccessMethodBinding[1];
680 syntheticReadAccessors = new SyntheticAccessMethodBinding[otherBindings.length + 1];
682 syntheticReadAccessors[index] = ((SourceTypeBinding) currentScope
683 .enclosingSourceType().enclosingTypeAt(depth))
684 .addSyntheticMethod(fieldBinding, true);
685 currentScope.problemReporter().needToEmulateFieldReadAccess(
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
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))){
706 // this.codegenBinding =
707 // currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding,
708 // (ReferenceBinding)lastReceiverType);
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);
715 // this.otherCodegenBindings[index-1] =
716 // currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding,
717 // (ReferenceBinding)lastReceiverType);
723 * No need to emulate access to protected fields since not implicitly
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(
737 } else if (fieldBinding.isProtected()) {
738 int depth = fieldBinding == binding ? (bits & DepthMASK) >> DepthSHIFT
739 : otherDepths[otherDepths.length - 1];
741 && (fieldBinding.declaringClass.getPackage() != currentScope
742 .enclosingSourceType().getPackage())) {
743 syntheticWriteAccessor = ((SourceTypeBinding) currentScope
744 .enclosingSourceType().enclosingTypeAt(depth))
745 .addSyntheticMethod(fieldBinding, false);
746 currentScope.problemReporter().needToEmulateFieldWriteAccess(
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
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);
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);
776 // this.otherCodegenBindings[this.otherCodegenBindings.length-1] =
777 // currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding,
778 // (ReferenceBinding)lastReceiverType);
785 * Normal field binding did not work, try to bind to a field of the delegate
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);
794 scope.problemReporter().unresolvableReference(this, binding);
799 public StringBuffer printExpression(int indent, StringBuffer output) {
801 for (int i = 0; i < tokens.length; i++) {
804 output.append(tokens[i]);
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
829 return this.resolvedType = getOtherFieldBindings(scope);
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());
843 bits &= ~RestrictiveFlagMASK; // clear bits
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);
854 return this.resolvedType = getOtherFieldBindings(scope);
856 // thus it was a type
857 bits &= ~RestrictiveFlagMASK; // clear bits
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;
866 // ========error cases===============
867 return this.resolvedType = this.reportError(scope);
870 public void setFieldIndex(int index) {
871 this.indexOfFirstFieldBinding = index;
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$
882 return buffer.toString();
885 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
886 visitor.visit(this, scope);
887 visitor.endVisit(this, scope);
890 public String unboundReferenceErrorName() {
891 return new String(tokens[0]);