1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.codegen.*;
17 import org.eclipse.jdt.internal.compiler.flow.*;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19 import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
21 public class SingleNameReference extends NameReference implements OperatorIds {
24 public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
25 public static final int READ = 0;
26 public static final int WRITE = 1;
28 public SingleNameReference(char[] source, long pos) {
31 sourceStart = (int) (pos >>> 32);
32 sourceEnd = (int) pos;
34 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
36 boolean isReachable = flowInfo.isReachable();
37 // compound assignment extra work
38 if (isCompound) { // check the variable part is initialized if blank final
39 switch (bits & RestrictiveFlagMASK) {
40 case FIELD : // reading a field
41 FieldBinding fieldBinding;
42 if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
43 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
44 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
45 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
48 manageSyntheticReadAccessIfNecessary(currentScope, flowInfo);
50 case LOCAL : // reading a local variable
51 // check if assigning a final blank field
52 LocalVariableBinding localBinding;
53 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
54 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
55 // we could improve error msg here telling "cannot use compound assignment on final local variable"
58 localBinding.useFlag = LocalVariableBinding.USED;
59 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
60 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
64 if (assignment.expression != null) {
65 flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
67 switch (bits & RestrictiveFlagMASK) {
68 case FIELD : // assigning to a field
69 manageSyntheticWriteAccessIfNecessary(currentScope, flowInfo);
71 // check if assigning a final field
72 FieldBinding fieldBinding;
73 if ((fieldBinding = (FieldBinding) binding).isFinal()) {
74 // inside a context where allowed
75 if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
76 if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
77 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
79 flowContext.recordSettingFinal(fieldBinding, this, flowInfo);
81 flowInfo.markAsDefinitelyAssigned(fieldBinding);
83 currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
87 case LOCAL : // assigning to a local variable
88 LocalVariableBinding localBinding = (LocalVariableBinding) binding;
89 if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes
90 bits |= FirstAssignmentToLocalMASK;
92 bits &= ~FirstAssignmentToLocalMASK;
94 if (localBinding.isFinal()) {
95 if ((bits & DepthMASK) == 0) {
96 // tolerate assignment to final local in unreachable code (45674)
97 if ((isReachable && isCompound) || !localBinding.isBlankFinal()){
98 currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this);
99 } else if (flowInfo.isPotentiallyAssigned(localBinding)) {
100 currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
102 flowContext.recordSettingFinal(localBinding, this, flowInfo);
105 currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
108 flowInfo.markAsDefinitelyAssigned(localBinding);
110 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
113 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
114 return analyseCode(currentScope, flowContext, flowInfo, true);
116 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
118 switch (bits & RestrictiveFlagMASK) {
119 case FIELD : // reading a field
121 manageSyntheticReadAccessIfNecessary(currentScope, flowInfo);
123 // check if reading a final blank field
124 FieldBinding fieldBinding;
125 if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
126 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
127 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
128 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
132 case LOCAL : // reading a local variable
133 LocalVariableBinding localBinding;
134 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
135 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
137 if (flowInfo.isReachable()) {
138 localBinding.useFlag = LocalVariableBinding.USED;
139 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
140 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
144 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
148 public TypeBinding checkFieldAccess(BlockScope scope) {
150 FieldBinding fieldBinding = (FieldBinding) binding;
152 bits &= ~RestrictiveFlagMASK; // clear bits
154 if (!((FieldBinding) binding).isStatic()) {
155 // must check for the static status....
156 if (scope.methodScope().isStatic) {
157 scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding);
158 constant = NotAConstant;
159 return fieldBinding.type;
162 constant = FieldReference.getConstantFor(fieldBinding, this, true, scope);
164 if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssignedMASK) !=0))
165 scope.problemReporter().deprecatedField(fieldBinding, this);
167 MethodScope ms = scope.methodScope();
168 if ((this.bits & IsStrictlyAssignedMASK) == 0
169 && ms.enclosingSourceType() == fieldBinding.declaringClass
170 && ms.lastVisibleFieldID >= 0
171 && fieldBinding.id >= ms.lastVisibleFieldID) {
172 //if the field is static and ms is not .... then it is valid
173 if (!fieldBinding.isStatic() || ms.isStatic)
174 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
176 //====================================================
178 return fieldBinding.type;
181 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
183 // optimizing assignment like: i = i + 1 or i = 1 + i
184 if (assignment.expression.isCompactableOperation()) {
185 BinaryExpression operation = (BinaryExpression) assignment.expression;
186 SingleNameReference variableReference;
187 if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
188 // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
189 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);
192 int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
193 if ((operation.right instanceof SingleNameReference)
194 && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
195 && ((variableReference = (SingleNameReference) operation.right).binding == binding)
196 && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
197 && ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards
198 && ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards
199 // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
200 variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
204 switch (bits & RestrictiveFlagMASK) {
205 case FIELD : // assigning to a field
206 FieldBinding fieldBinding;
207 if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver?
208 if ((bits & DepthMASK) != 0) {
209 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
210 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
211 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
213 this.generateReceiver(codeStream);
216 assignment.expression.generateCode(currentScope, codeStream, true);
217 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
219 codeStream.generateImplicitConversion(assignment.implicitConversion);
222 case LOCAL : // assigning to a local variable
223 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
224 if (localBinding.resolvedPosition != -1) {
225 assignment.expression.generateCode(currentScope, codeStream, true);
227 if (assignment.expression.constant != NotAConstant) {
228 // assigning an unused local to a constant value = no actual assignment is necessary
230 codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
233 assignment.expression.generateCode(currentScope, codeStream, true);
234 /* Even though the value may not be required, we force it to be produced, and discard it later
235 on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
237 codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
239 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
248 // 26903, need extra cast to store null in array local var
249 if (localBinding.type.isArrayType()
250 && (assignment.expression.resolvedType == NullBinding // arrayLoc = null
251 || ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null
252 && (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == NullBinding)))){
253 codeStream.checkcast(localBinding.type);
256 // normal local assignment (since cannot store in outer local which are final locations)
257 codeStream.store(localBinding, valueRequired);
258 if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes
259 localBinding.recordInitializationStartPC(codeStream.position);
261 // implicit conversion
263 codeStream.generateImplicitConversion(assignment.implicitConversion);
267 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
268 int pc = codeStream.position;
269 if (constant != NotAConstant) {
271 codeStream.generateConstant(constant, implicitConversion);
274 switch (bits & RestrictiveFlagMASK) {
275 case FIELD : // reading a field
276 FieldBinding fieldBinding;
278 if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields
280 if (!(isStatic = fieldBinding.isStatic())) {
281 if ((bits & DepthMASK) != 0) {
282 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
283 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
284 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
286 generateReceiver(codeStream);
289 // managing private access
290 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
292 codeStream.getstatic(fieldBinding);
294 codeStream.getfield(fieldBinding);
297 codeStream.invokestatic(syntheticAccessors[READ]);
299 codeStream.generateImplicitConversion(implicitConversion);
300 } else { // directly use the inlined value
301 codeStream.generateConstant(fieldBinding.constant, implicitConversion);
305 case LOCAL : // reading a local
306 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
309 if ((bits & DepthMASK) != 0) {
310 // outer local can be reached either through a synthetic arg or a synthetic field
311 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
312 codeStream.generateOuterAccess(path, this, localBinding, currentScope);
314 // regular local variable read
315 codeStream.load(localBinding);
317 codeStream.generateImplicitConversion(implicitConversion);
321 codeStream.recordPositionsFrom(pc, this.sourceStart);
324 * Regular API for compound assignment, relies on the fact that there is only one reference to the
325 * variable, which carries both synthetic read/write accessors.
326 * The APIs with an extra argument is used whenever there are two references to the same variable which
327 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
329 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
331 this.generateCompoundAssignment(
334 syntheticAccessors == null ? null : syntheticAccessors[WRITE],
337 assignmentImplicitConversion,
341 * The APIs with an extra argument is used whenever there are two references to the same variable which
342 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
344 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
345 switch (bits & RestrictiveFlagMASK) {
346 case FIELD : // assigning to a field
347 FieldBinding fieldBinding;
348 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
349 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
350 codeStream.getstatic(fieldBinding);
352 codeStream.invokestatic(syntheticAccessors[READ]);
355 if ((bits & DepthMASK) != 0) {
356 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
357 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
358 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
360 codeStream.aload_0();
363 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
364 codeStream.getfield(fieldBinding);
366 codeStream.invokestatic(syntheticAccessors[READ]);
370 case LOCAL : // assigning to a local variable (cannot assign to outer local)
371 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
372 Constant assignConstant;
374 // using incr bytecode if possible
375 switch (localBinding.type.id) {
377 codeStream.generateStringAppend(currentScope, this, expression);
381 codeStream.store(localBinding, false);
384 if (((assignConstant = expression.constant) != NotAConstant)
385 && (assignConstant.typeID() != T_float) // only for integral types
386 && (assignConstant.typeID() != T_double)
387 && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value
390 codeStream.iinc(localBinding.resolvedPosition, increment);
392 codeStream.load(localBinding);
396 codeStream.iinc(localBinding.resolvedPosition, -increment);
398 codeStream.load(localBinding);
404 codeStream.load(localBinding);
407 // perform the actual compound operation
409 if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) {
410 // we enter here if the single name reference is a field of type java.lang.String or if the type of the
411 // operation is java.lang.Object
412 // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
413 codeStream.generateStringAppend(currentScope, null, expression);
415 // promote the array reference to the suitable operation type
416 codeStream.generateImplicitConversion(implicitConversion);
417 // generate the increment value (will by itself be promoted to the operation value)
418 if (expression == IntLiteral.One){ // prefix operation
419 codeStream.generateConstant(expression.constant, implicitConversion);
421 expression.generateCode(currentScope, codeStream, true);
423 // perform the operation
424 codeStream.sendOperator(operator, operationTypeID);
425 // cast the value back to the array reference type
426 codeStream.generateImplicitConversion(assignmentImplicitConversion);
428 // store the result back into the variable
429 switch (bits & RestrictiveFlagMASK) {
430 case FIELD : // assigning to a field
431 fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired);
433 case LOCAL : // assigning to a local variable
434 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
436 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
442 codeStream.store(localBinding, false);
446 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
447 switch (bits & RestrictiveFlagMASK) {
448 case FIELD : // assigning to a field
449 FieldBinding fieldBinding;
450 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
451 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
452 codeStream.getstatic(fieldBinding);
454 codeStream.invokestatic(syntheticAccessors[READ]);
457 if ((bits & DepthMASK) != 0) {
458 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
459 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
460 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
462 codeStream.aload_0();
465 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
466 codeStream.getfield(fieldBinding);
468 codeStream.invokestatic(syntheticAccessors[READ]);
472 if (fieldBinding.isStatic()) {
473 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
478 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
479 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
480 codeStream.dup2_x1();
486 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
487 codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
488 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
489 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
491 case LOCAL : // assigning to a local variable
492 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
493 // using incr bytecode if possible
494 if (localBinding.type == IntBinding) {
496 codeStream.load(localBinding);
498 if (postIncrement.operator == PLUS) {
499 codeStream.iinc(localBinding.resolvedPosition, 1);
501 codeStream.iinc(localBinding.resolvedPosition, -1);
504 codeStream.load(localBinding);
506 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
512 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
513 codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
514 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
516 codeStream.store(localBinding, false);
521 public void generateReceiver(CodeStream codeStream) {
523 codeStream.aload_0();
526 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
528 if (!flowInfo.isReachable()) return;
529 //If inlinable field, forget the access emulation, the code gen will directly target it
530 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return;
532 if ((bits & RestrictiveFlagMASK) == LOCAL) {
533 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
536 public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
538 if (!flowInfo.isReachable()) return;
540 //If inlinable field, forget the access emulation, the code gen will directly target it
541 if (constant != NotAConstant)
544 if ((bits & FIELD) != 0) {
545 FieldBinding fieldBinding = (FieldBinding) binding;
546 if (((bits & DepthMASK) != 0)
547 && (fieldBinding.isPrivate() // private access
548 || (fieldBinding.isProtected() // implicit protected access
549 && fieldBinding.declaringClass.getPackage()
550 != currentScope.enclosingSourceType().getPackage()))) {
551 if (syntheticAccessors == null)
552 syntheticAccessors = new MethodBinding[2];
553 syntheticAccessors[READ] =
554 ((SourceTypeBinding)currentScope.enclosingSourceType().
555 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
556 addSyntheticMethod(fieldBinding, true);
557 currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
560 // if the binding declaring class is not visible, need special action
561 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
562 // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
563 // and not from Object or implicit static field access.
564 if (fieldBinding.declaringClass != this.actualReceiverType
565 && !this.actualReceiverType.isArrayType()
566 && fieldBinding.declaringClass != null
567 && fieldBinding.constant == NotAConstant
568 && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
569 && !fieldBinding.isStatic()
570 && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
571 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
572 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
576 public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
578 if (!flowInfo.isReachable()) return;
579 if ((bits & FIELD) != 0) {
580 FieldBinding fieldBinding = (FieldBinding) binding;
581 if (((bits & DepthMASK) != 0)
582 && (fieldBinding.isPrivate() // private access
583 || (fieldBinding.isProtected() // implicit protected access
584 && fieldBinding.declaringClass.getPackage()
585 != currentScope.enclosingSourceType().getPackage()))) {
586 if (syntheticAccessors == null)
587 syntheticAccessors = new MethodBinding[2];
588 syntheticAccessors[WRITE] =
589 ((SourceTypeBinding)currentScope.enclosingSourceType().
590 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
591 addSyntheticMethod(fieldBinding, false);
592 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
595 // if the binding declaring class is not visible, need special action
596 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
597 // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
598 // and not from Object or implicit static field access.
599 if (fieldBinding.declaringClass != this.actualReceiverType
600 && !this.actualReceiverType.isArrayType()
601 && fieldBinding.declaringClass != null
602 && fieldBinding.constant == NotAConstant
603 && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
604 && !fieldBinding.isStatic()
605 && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
606 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
607 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
611 public StringBuffer printExpression(int indent, StringBuffer output){
613 return output.append(token);
616 public TypeBinding reportError(BlockScope scope) {
618 //=====error cases=======
619 constant = Constant.NotAConstant;
620 if (binding instanceof ProblemFieldBinding) {
621 scope.problemReporter().invalidField(this, (FieldBinding) binding);
622 } else if (binding instanceof ProblemReferenceBinding) {
623 scope.problemReporter().invalidType(this, (TypeBinding) binding);
625 scope.problemReporter().unresolvableReference(this, binding);
629 public TypeBinding resolveType(BlockScope scope) {
630 // for code gen, harm the restrictiveFlag
632 this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
634 if ((this.codegenBinding = this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) {
635 switch (bits & RestrictiveFlagMASK) {
636 case VARIABLE : // =========only variable============
637 case VARIABLE | TYPE : //====both variable and type============
638 if (binding instanceof VariableBinding) {
639 VariableBinding variable = (VariableBinding) binding;
640 if (binding instanceof LocalVariableBinding) {
641 bits &= ~RestrictiveFlagMASK; // clear bits
643 if ((this.bits & IsStrictlyAssignedMASK) == 0) {
644 constant = variable.constant;
646 constant = NotAConstant;
648 if (!variable.isFinal() && (bits & DepthMASK) != 0) {
649 scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this);
651 return this.resolvedType = variable.type;
654 FieldBinding field = (FieldBinding) this.binding;
655 if (!field.isStatic() && scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
656 scope.problemReporter().unqualifiedFieldAccess(this, field);
658 return this.resolvedType = checkFieldAccess(scope);
661 // thus it was a type
662 bits &= ~RestrictiveFlagMASK; // clear bits
664 case TYPE : //========only type==============
665 constant = Constant.NotAConstant;
667 if (isTypeUseDeprecated((TypeBinding) binding, scope))
668 scope.problemReporter().deprecatedType((TypeBinding) binding, this);
669 return this.resolvedType = (TypeBinding) binding;
674 return this.resolvedType = this.reportError(scope);
677 public void traverse(ASTVisitor visitor, BlockScope scope) {
679 visitor.visit(this, scope);
680 visitor.endVisit(this, scope);
683 public String unboundReferenceErrorName(){
685 return new String(token);