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 SingleNameReference extends NameReference implements OperatorIds {
22 public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
23 public static final int READ = 0;
24 public static final int WRITE = 1;
26 public SingleNameReference(char[] source, long pos) {
29 sourceStart = (int) (pos >>> 32);
30 sourceEnd = (int) pos;
32 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
34 // compound assignment extra work
35 if (isCompound) { // check the variable part is initialized if blank final
36 switch (bits & RestrictiveFlagMASK) {
37 case FIELD : // reading a field
38 FieldBinding fieldBinding;
39 if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
40 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
41 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
42 // we could improve error msg here telling "cannot use compound assignment on final blank field"
45 manageSyntheticReadAccessIfNecessary(currentScope);
47 case LOCAL : // reading a local variable
48 // check if assigning a final blank field
49 LocalVariableBinding localBinding;
50 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
51 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
52 // we could improve error msg here telling "cannot use compound assignment on final local variable"
54 if (!flowInfo.isFakeReachable()) localBinding.used = true;
57 if (assignment.expression != null) {
58 flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
60 switch (bits & RestrictiveFlagMASK) {
61 case FIELD : // assigning to a field
62 manageSyntheticWriteAccessIfNecessary(currentScope);
64 // check if assigning a final field
65 FieldBinding fieldBinding;
66 if ((fieldBinding = (FieldBinding) binding).isFinal()) {
67 // inside a context where allowed
68 if (currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
69 if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
70 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
72 flowInfo.markAsDefinitelyAssigned(fieldBinding);
73 flowContext.recordSettingFinal(fieldBinding, this);
75 currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
79 case LOCAL : // assigning to a local variable
80 LocalVariableBinding localBinding = (LocalVariableBinding) binding;
81 if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes
82 bits |= FirstAssignmentToLocalMASK;
84 bits &= ~FirstAssignmentToLocalMASK;
86 if (localBinding.isFinal()) {
87 if ((bits & DepthMASK) == 0) {
88 if (flowInfo.isPotentiallyAssigned(localBinding)) {
89 currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
91 flowContext.recordSettingFinal(localBinding, this);
93 currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
96 flowInfo.markAsDefinitelyAssigned(localBinding);
98 manageEnclosingInstanceAccessIfNecessary(currentScope);
101 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
102 return analyseCode(currentScope, flowContext, flowInfo, true);
104 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
106 switch (bits & RestrictiveFlagMASK) {
107 case FIELD : // reading a field
109 manageSyntheticReadAccessIfNecessary(currentScope);
111 // check if reading a final blank field
112 FieldBinding fieldBinding;
113 if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
114 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
115 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
119 case LOCAL : // reading a local variable
120 LocalVariableBinding localBinding;
121 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
122 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
124 if (!flowInfo.isFakeReachable()) localBinding.used = true;
127 manageEnclosingInstanceAccessIfNecessary(currentScope);
131 public TypeBinding checkFieldAccess(BlockScope scope) {
133 FieldBinding fieldBinding = (FieldBinding) binding;
135 bits &= ~RestrictiveFlagMASK; // clear bits
137 if (!((FieldBinding) binding).isStatic()) {
138 // must check for the static status....
139 if (scope.methodScope().isStatic) {
140 scope.problemReporter().staticFieldAccessToNonStaticVariable(
143 constant = NotAConstant;
147 constant = FieldReference.getConstantFor(fieldBinding, true, this, scope, 0);
148 if (isFieldUseDeprecated(fieldBinding, scope))
149 scope.problemReporter().deprecatedField(fieldBinding, this);
151 //===============================================
152 //cycle are forbidden ONLY within the same class...why ?????? (poor javac....)
153 //Cycle can be done using cross class ref but not direct into a same class reference ????
154 //class A { static int k = B.k+1;}
155 //class B { static int k = A.k+2;}
156 //The k-cycle in this example is valid.
158 //class C { static int k = k + 1 ;}
159 //here it is forbidden ! ????
160 //but the next one is valid !!!
161 //class C { static int k = C.k + 1;}
163 //notice that the next one is also valid ?!?!
164 //class A { static int k = foo().k+1 ; static A foo(){return new A();}}
166 //for all these reasons, the next piece of code is only here and not
167 //commun for all FieldRef and QualifiedNameRef....(i.e. in the getField(..) API.....
169 //instance field may refer to forward static field, like in
171 //static int staticI = 2 ;
173 MethodScope ms = scope.methodScope();
174 if (ms.enclosingSourceType() == fieldBinding.declaringClass
175 && ms.fieldDeclarationIndex != ms.NotInFieldDecl
176 && fieldBinding.id >= ms.fieldDeclarationIndex) {
177 //if the field is static and ms is not .... then it is valid
178 if (!fieldBinding.isStatic() || ms.isStatic)
179 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
181 //====================================================
183 return fieldBinding.type;
186 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
188 // optimizing assignment like: i = i + 1 or i = 1 + i
189 if (assignment.expression.isCompactableOperation()) {
190 BinaryExpression operation = (BinaryExpression) assignment.expression;
191 SingleNameReference variableReference;
192 if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
193 // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
194 variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
197 int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
198 if ((operation.right instanceof SingleNameReference)
199 && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
200 && ((variableReference = (SingleNameReference) operation.right).binding == binding)
201 && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
202 && ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards
203 && ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards
204 // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
205 variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
209 switch (bits & RestrictiveFlagMASK) {
210 case FIELD : // assigning to a field
211 FieldBinding fieldBinding;
212 if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver?
213 if ((bits & DepthMASK) != 0) {
214 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
215 if (emulationPath == null) {
216 // internal error, per construction we should have found it
217 currentScope.problemReporter().needImplementation();
219 codeStream.generateOuterAccess(emulationPath, this, currentScope);
222 this.generateReceiver(codeStream);
225 assignment.expression.generateCode(currentScope, codeStream, true);
226 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
228 codeStream.generateImplicitConversion(assignment.implicitConversion);
231 case LOCAL : // assigning to a local variable
232 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
233 if (localBinding.resolvedPosition != -1) {
234 assignment.expression.generateCode(currentScope, codeStream, true);
236 if (assignment.expression.constant != NotAConstant) {
237 // assigning an unused local to a constant value = no actual assignment is necessary
239 codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
242 assignment.expression.generateCode(currentScope, codeStream, true);
243 /* Even though the value may not be required, we force it to be produced, and discard it later
244 on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
246 codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
248 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
257 // normal local assignment (since cannot store in outer local which are final locations)
258 codeStream.store(localBinding, valueRequired);
259 if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes
260 localBinding.recordInitializationStartPC(codeStream.position);
262 // implicit conversion
264 codeStream.generateImplicitConversion(assignment.implicitConversion);
268 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
269 int pc = codeStream.position;
270 if (constant != NotAConstant) {
272 codeStream.generateConstant(constant, implicitConversion);
275 switch (bits & RestrictiveFlagMASK) {
276 case FIELD : // reading a field
277 FieldBinding fieldBinding;
279 if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields
281 if (!(isStatic = fieldBinding.isStatic())) {
282 if ((bits & DepthMASK) != 0) {
283 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
284 if (emulationPath == null) {
285 // internal error, per construction we should have found it
286 currentScope.problemReporter().needImplementation();
288 codeStream.generateOuterAccess(emulationPath, this, currentScope);
291 generateReceiver(codeStream);
294 // managing private access
295 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
297 codeStream.getstatic(fieldBinding);
299 codeStream.getfield(fieldBinding);
302 codeStream.invokestatic(syntheticAccessors[READ]);
304 codeStream.generateImplicitConversion(implicitConversion);
305 } else { // directly use the inlined value
306 codeStream.generateConstant(fieldBinding.constant, implicitConversion);
310 case LOCAL : // reading a local
311 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
314 if ((bits & DepthMASK) != 0) {
315 // outer local can be reached either through a synthetic arg or a synthetic field
316 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
318 // emulation was not possible (should not happen per construction)
319 currentScope.problemReporter().needImplementation();
321 codeStream.generateOuterAccess(path, this, currentScope);
324 // regular local variable read
325 codeStream.load(localBinding);
327 codeStream.generateImplicitConversion(implicitConversion);
331 codeStream.recordPositionsFrom(pc, this.sourceStart);
334 * Regular API for compound assignment, relies on the fact that there is only one reference to the
335 * variable, which carries both synthetic read/write accessors.
336 * The APIs with an extra argument is used whenever there are two references to the same variable which
337 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
339 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
341 this.generateCompoundAssignment(
344 syntheticAccessors == null ? null : syntheticAccessors[WRITE],
347 assignmentImplicitConversion,
351 * The APIs with an extra argument is used whenever there are two references to the same variable which
352 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
354 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
355 switch (bits & RestrictiveFlagMASK) {
356 case FIELD : // assigning to a field
357 FieldBinding fieldBinding;
358 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
359 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
360 codeStream.getstatic(fieldBinding);
362 codeStream.invokestatic(syntheticAccessors[READ]);
365 if ((bits & DepthMASK) != 0) {
366 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
367 if (emulationPath == null) {
368 // internal error, per construction we should have found it
369 currentScope.problemReporter().needImplementation();
371 codeStream.generateOuterAccess(emulationPath, this, currentScope);
374 codeStream.aload_0();
377 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
378 codeStream.getfield(fieldBinding);
380 codeStream.invokestatic(syntheticAccessors[READ]);
384 case LOCAL : // assigning to a local variable (cannot assign to outer local)
385 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
386 Constant assignConstant;
388 // using incr bytecode if possible
389 switch (localBinding.type.id) {
391 codeStream.generateStringAppend(currentScope, this, expression);
395 codeStream.store(localBinding, false);
398 if (((assignConstant = expression.constant) != NotAConstant)
399 && (assignConstant.typeID() != T_float) // only for integral types
400 && (assignConstant.typeID() != T_double)
401 && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value
404 codeStream.iinc(localBinding.resolvedPosition, increment);
406 codeStream.load(localBinding);
410 codeStream.iinc(localBinding.resolvedPosition, -increment);
412 codeStream.load(localBinding);
418 codeStream.load(localBinding);
421 // perform the actual compound operation
423 if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) {
424 // we enter here if the single name reference is a field of type java.lang.String or if the type of the
425 // operation is java.lang.Object
426 // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
427 codeStream.generateStringAppend(currentScope, null, expression);
429 // promote the array reference to the suitable operation type
430 codeStream.generateImplicitConversion(implicitConversion);
431 // generate the increment value (will by itself be promoted to the operation value)
432 if (expression == IntLiteral.One){ // prefix operation
433 codeStream.generateConstant(expression.constant, implicitConversion);
435 expression.generateCode(currentScope, codeStream, true);
437 // perform the operation
438 codeStream.sendOperator(operator, operationTypeID);
439 // cast the value back to the array reference type
440 codeStream.generateImplicitConversion(assignmentImplicitConversion);
442 // store the result back into the variable
443 switch (bits & RestrictiveFlagMASK) {
444 case FIELD : // assigning to a field
445 fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired);
447 case LOCAL : // assigning to a local variable
448 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
450 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
456 codeStream.store(localBinding, false);
459 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
460 switch (bits & RestrictiveFlagMASK) {
461 case FIELD : // assigning to a field
462 FieldBinding fieldBinding;
463 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
464 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
465 codeStream.getstatic(fieldBinding);
467 codeStream.invokestatic(syntheticAccessors[READ]);
470 if ((bits & DepthMASK) != 0) {
471 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
472 if (emulationPath == null) {
473 // internal error, per construction we should have found it
474 currentScope.problemReporter().needImplementation();
476 codeStream.generateOuterAccess(emulationPath, this, currentScope);
479 codeStream.aload_0();
482 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
483 codeStream.getfield(fieldBinding);
485 codeStream.invokestatic(syntheticAccessors[READ]);
489 if (fieldBinding.isStatic()) {
490 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
495 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
496 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
497 codeStream.dup2_x1();
503 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
504 codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
505 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
506 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
508 case LOCAL : // assigning to a local variable
509 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
510 // using incr bytecode if possible
511 if (localBinding.type == IntBinding) {
513 codeStream.load(localBinding);
515 if (postIncrement.operator == PLUS) {
516 codeStream.iinc(localBinding.resolvedPosition, 1);
518 codeStream.iinc(localBinding.resolvedPosition, -1);
521 codeStream.load(localBinding);
523 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
529 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
530 codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
531 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
533 codeStream.store(localBinding, false);
537 public void generateReceiver(CodeStream codeStream) {
538 codeStream.aload_0();
540 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
542 //If inlinable field, forget the access emulation, the code gen will directly target it
543 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return;
545 switch (bits & RestrictiveFlagMASK) {
547 FieldBinding fieldBinding;
548 if ((fieldBinding = (FieldBinding)binding).isStatic() || (fieldBinding.constant != NotAConstant)) return;
549 ReferenceBinding compatibleType = currentScope.enclosingSourceType();
550 // the declaringClass of the target binding must be compatible with the enclosing
551 // type at <depth> levels outside
552 for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
553 compatibleType = compatibleType.enclosingType();
555 currentScope.emulateOuterAccess(compatibleType, false); // request cascade of accesses
558 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
561 public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
563 //If inlinable field, forget the access emulation, the code gen will directly target it
564 if (constant != NotAConstant)
567 if ((bits & FIELD) != 0) {
568 FieldBinding fieldBinding = (FieldBinding) binding;
569 if (((bits & DepthMASK) != 0)
570 && (fieldBinding.isPrivate() // private access
571 || (fieldBinding.isProtected() // implicit protected access
572 && fieldBinding.declaringClass.getPackage()
573 != currentScope.enclosingSourceType().getPackage()))) {
574 if (syntheticAccessors == null)
575 syntheticAccessors = new MethodBinding[2];
576 syntheticAccessors[READ] =
577 ((SourceTypeBinding)currentScope.enclosingSourceType().
578 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
579 addSyntheticMethod(fieldBinding, true);
580 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
583 // if the binding declaring class is not visible, need special action
584 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
585 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
586 // and not from Object or implicit static field access.
587 if (fieldBinding.declaringClass != this.actualReceiverType
588 && !this.actualReceiverType.isArrayType()
589 && fieldBinding.declaringClass != null
590 && fieldBinding.constant == NotAConstant
591 && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
592 && !fieldBinding.isStatic()
593 && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
594 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
595 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
599 public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
601 if ((bits & FIELD) != 0) {
602 FieldBinding fieldBinding = (FieldBinding) binding;
603 if (((bits & DepthMASK) != 0)
604 && (fieldBinding.isPrivate() // private access
605 || (fieldBinding.isProtected() // implicit protected access
606 && fieldBinding.declaringClass.getPackage()
607 != currentScope.enclosingSourceType().getPackage()))) {
608 if (syntheticAccessors == null)
609 syntheticAccessors = new MethodBinding[2];
610 syntheticAccessors[WRITE] =
611 ((SourceTypeBinding)currentScope.enclosingSourceType().
612 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
613 addSyntheticMethod(fieldBinding, false);
614 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
617 // if the binding declaring class is not visible, need special action
618 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
619 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
620 // and not from Object or implicit static field access.
621 if (fieldBinding.declaringClass != this.actualReceiverType
622 && !this.actualReceiverType.isArrayType()
623 && fieldBinding.declaringClass != null
624 && fieldBinding.constant == NotAConstant
625 && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
626 && !fieldBinding.isStatic()
627 && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
628 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
629 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
633 public TypeBinding reportError(BlockScope scope) {
634 //=====error cases=======
635 constant = Constant.NotAConstant;
636 if (binding instanceof ProblemFieldBinding) {
637 scope.problemReporter().invalidField(this, (FieldBinding) binding);
638 } else if (binding instanceof ProblemReferenceBinding) {
639 scope.problemReporter().invalidType(this, (TypeBinding) binding);
641 scope.problemReporter().unresolvableReference(this, binding);
645 public TypeBinding resolveType(BlockScope scope) {
646 // for code gen, harm the restrictiveFlag
648 this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
650 if ((this.codegenBinding = this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this)).isValidBinding()) {
651 switch (bits & RestrictiveFlagMASK) {
652 case VARIABLE : // =========only variable============
653 case VARIABLE | TYPE : //====both variable and type============
654 if (binding instanceof VariableBinding) {
655 VariableBinding vb = (VariableBinding) binding;
656 if (binding instanceof LocalVariableBinding) {
657 bits &= ~RestrictiveFlagMASK; // clear bits
659 constant = vb.constant;
660 if ((!vb.isFinal()) && ((bits & DepthMASK) != 0))
661 scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)vb, this);
665 return checkFieldAccess(scope);
668 // thus it was a type
669 bits &= ~RestrictiveFlagMASK; // clear bits
671 case TYPE : //========only type==============
672 constant = Constant.NotAConstant;
674 if (isTypeUseDeprecated((TypeBinding) binding, scope))
675 scope.problemReporter().deprecatedType((TypeBinding) binding, this);
676 return (TypeBinding) binding;
681 return this.reportError(scope);
683 public String toStringExpression(){
685 return new String(token);}
686 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
687 visitor.visit(this, scope);
688 visitor.endVisit(this, scope);
690 public String unboundReferenceErrorName(){
692 return new String(token);}