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;
27 public TypeBinding genericCast;
29 public SingleNameReference(char[] source, long pos) {
32 sourceStart = (int) (pos >>> 32);
33 sourceEnd = (int) pos;
35 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
37 boolean isReachable = flowInfo.isReachable();
38 // compound assignment extra work
39 if (isCompound) { // check the variable part is initialized if blank final
40 switch (bits & RestrictiveFlagMASK) {
41 case Binding.FIELD : // reading a field
42 FieldBinding fieldBinding;
43 if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
44 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
45 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
46 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
49 manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
51 case Binding.LOCAL : // reading a local variable
52 // check if assigning a final blank field
53 LocalVariableBinding localBinding;
54 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
55 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
56 // we could improve error msg here telling "cannot use compound assignment on final local variable"
59 localBinding.useFlag = LocalVariableBinding.USED;
60 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
61 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
65 if (assignment.expression != null) {
66 flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
68 switch (bits & RestrictiveFlagMASK) {
69 case Binding.FIELD : // assigning to a field
70 manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);
72 // check if assigning a final field
73 FieldBinding fieldBinding;
74 if ((fieldBinding = (FieldBinding) binding).isFinal()) {
75 // inside a context where allowed
76 if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
77 if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
78 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
80 flowContext.recordSettingFinal(fieldBinding, this, flowInfo);
82 flowInfo.markAsDefinitelyAssigned(fieldBinding);
84 currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
88 case Binding.LOCAL : // assigning to a local variable
89 LocalVariableBinding localBinding = (LocalVariableBinding) binding;
90 if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes
91 bits |= FirstAssignmentToLocalMASK;
93 bits &= ~FirstAssignmentToLocalMASK;
95 if (localBinding.isFinal()) {
96 if ((bits & DepthMASK) == 0) {
97 // tolerate assignment to final local in unreachable code (45674)
98 if ((isReachable && isCompound) || !localBinding.isBlankFinal()){
99 currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this);
100 } else if (flowInfo.isPotentiallyAssigned(localBinding)) {
101 currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
103 flowContext.recordSettingFinal(localBinding, this, flowInfo);
106 currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
109 flowInfo.markAsDefinitelyAssigned(localBinding);
111 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
114 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
115 return analyseCode(currentScope, flowContext, flowInfo, true);
117 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
119 switch (bits & RestrictiveFlagMASK) {
120 case Binding.FIELD : // reading a field
122 manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
124 // check if reading a final blank field
125 FieldBinding fieldBinding;
126 if ((fieldBinding = (FieldBinding) binding).isBlankFinal()
127 && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
128 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
129 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
133 case Binding.LOCAL : // reading a local variable
134 LocalVariableBinding localBinding;
135 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
136 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
138 if (flowInfo.isReachable()) {
139 localBinding.useFlag = LocalVariableBinding.USED;
140 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
141 localBinding.useFlag = LocalVariableBinding.FAKE_USED;
145 manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
150 public TypeBinding checkFieldAccess(BlockScope scope) {
152 FieldBinding fieldBinding = (FieldBinding) binding;
154 bits &= ~RestrictiveFlagMASK; // clear bits
155 bits |= Binding.FIELD;
156 if (!((FieldBinding) binding).isStatic()) {
157 // must check for the static status....
158 if (scope.methodScope().isStatic) {
159 scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding);
160 constant = NotAConstant;
161 return fieldBinding.type;
164 constant = FieldReference.getConstantFor(fieldBinding, this, true, scope);
166 if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssignedMASK) !=0))
167 scope.problemReporter().deprecatedField(fieldBinding, this);
169 MethodScope ms = scope.methodScope();
170 if ((this.bits & IsStrictlyAssignedMASK) == 0
171 && ms.enclosingSourceType() == fieldBinding.declaringClass
172 && ms.lastVisibleFieldID >= 0
173 && fieldBinding.id >= ms.lastVisibleFieldID) {
174 //if the field is static and ms is not .... then it is valid
175 if (!fieldBinding.isStatic() || ms.isStatic)
176 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
178 //====================================================
180 return fieldBinding.type;
185 * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
187 public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
188 if (runtimeTimeType == null || compileTimeType == null)
190 if ((bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) {
191 // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
192 FieldBinding originalBinding = ((FieldBinding)this.binding).original();
193 if (originalBinding != this.binding) {
194 // extra cast needed if method return type has type variable
195 if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && runtimeTimeType.id != T_JavaLangObject) {
196 this.genericCast = originalBinding.type.genericCast(scope.boxing(runtimeTimeType)); // runtimeType could be base type in boxing case
200 super.computeConversion(scope, runtimeTimeType, compileTimeType);
203 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
205 // optimizing assignment like: i = i + 1 or i = 1 + i
206 if (assignment.expression.isCompactableOperation()) {
207 BinaryExpression operation = (BinaryExpression) assignment.expression;
208 SingleNameReference variableReference;
209 if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
210 // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
211 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);
214 int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
215 if ((operation.right instanceof SingleNameReference)
216 && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
217 && ((variableReference = (SingleNameReference) operation.right).binding == binding)
218 && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
219 && (((operation.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString) // exclude string concatenation which would occur backwards
220 && (((operation.right.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString)) { // exclude string concatenation which would occur backwards
221 // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
222 variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
226 switch (bits & RestrictiveFlagMASK) {
227 case Binding.FIELD : // assigning to a field
228 FieldBinding fieldBinding;
229 if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver?
230 if ((bits & DepthMASK) != 0) {
231 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
232 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
233 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
235 this.generateReceiver(codeStream);
238 assignment.expression.generateCode(currentScope, codeStream, true);
239 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
241 codeStream.generateImplicitConversion(assignment.implicitConversion);
243 // no need for generic cast as value got dupped
245 case Binding.LOCAL : // assigning to a local variable
246 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
247 if (localBinding.resolvedPosition != -1) {
248 assignment.expression.generateCode(currentScope, codeStream, true);
250 if (assignment.expression.constant != NotAConstant) {
251 // assigning an unused local to a constant value = no actual assignment is necessary
253 codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
256 assignment.expression.generateCode(currentScope, codeStream, true);
257 /* Even though the value may not be required, we force it to be produced, and discard it later
258 on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
260 codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
262 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
271 // 26903, need extra cast to store null in array local var
272 if (localBinding.type.isArrayType()
273 && (assignment.expression.resolvedType == NullBinding // arrayLoc = null
274 || ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null
275 && (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == NullBinding)))){
276 codeStream.checkcast(localBinding.type);
279 // normal local assignment (since cannot store in outer local which are final locations)
280 codeStream.store(localBinding, valueRequired);
281 if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes
282 localBinding.recordInitializationStartPC(codeStream.position);
284 // implicit conversion
286 codeStream.generateImplicitConversion(assignment.implicitConversion);
290 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
291 int pc = codeStream.position;
292 if (constant != NotAConstant) {
294 codeStream.generateConstant(constant, implicitConversion);
297 switch (bits & RestrictiveFlagMASK) {
298 case Binding.FIELD : // reading a field
299 FieldBinding fieldBinding;
301 if (!(fieldBinding = (FieldBinding) this.codegenBinding).isConstantValue()) { // directly use inlined value for constant fields
303 if (!(isStatic = fieldBinding.isStatic())) {
304 if ((bits & DepthMASK) != 0) {
305 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
306 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
307 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
309 generateReceiver(codeStream);
312 // managing private access
313 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
315 codeStream.getstatic(fieldBinding);
317 codeStream.getfield(fieldBinding);
320 codeStream.invokestatic(syntheticAccessors[READ]);
322 if (this.genericCast != null) codeStream.checkcast(this.genericCast);
323 codeStream.generateImplicitConversion(implicitConversion);
324 } else { // directly use the inlined value
325 codeStream.generateConstant(fieldBinding.constant(), implicitConversion);
329 case Binding.LOCAL : // reading a local
330 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
333 if ((bits & DepthMASK) != 0) {
334 // outer local can be reached either through a synthetic arg or a synthetic field
335 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
336 codeStream.generateOuterAccess(path, this, localBinding, currentScope);
338 // regular local variable read
339 codeStream.load(localBinding);
341 codeStream.generateImplicitConversion(implicitConversion);
345 codeStream.recordPositionsFrom(pc, this.sourceStart);
348 * Regular API for compound assignment, relies on the fact that there is only one reference to the
349 * variable, which carries both synthetic read/write accessors.
350 * The APIs with an extra argument is used whenever there are two references to the same variable which
351 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
353 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
355 this.generateCompoundAssignment(
358 syntheticAccessors == null ? null : syntheticAccessors[WRITE],
361 assignmentImplicitConversion,
365 * The APIs with an extra argument is used whenever there are two references to the same variable which
366 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
368 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
369 switch (bits & RestrictiveFlagMASK) {
370 case Binding.FIELD : // assigning to a field
371 FieldBinding fieldBinding;
372 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
373 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
374 codeStream.getstatic(fieldBinding);
376 codeStream.invokestatic(syntheticAccessors[READ]);
379 if ((bits & DepthMASK) != 0) {
380 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
381 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
382 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
384 codeStream.aload_0();
387 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
388 codeStream.getfield(fieldBinding);
390 codeStream.invokestatic(syntheticAccessors[READ]);
394 case Binding.LOCAL : // assigning to a local variable (cannot assign to outer local)
395 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
396 Constant assignConstant;
398 // using incr bytecode if possible
399 switch (localBinding.type.id) {
400 case T_JavaLangString :
401 codeStream.generateStringConcatenationAppend(currentScope, this, expression);
405 codeStream.store(localBinding, false);
408 if (((assignConstant = expression.constant) != NotAConstant)
409 && (assignConstant.typeID() != T_float) // only for integral types
410 && (assignConstant.typeID() != T_double)
411 && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value
414 codeStream.iinc(localBinding.resolvedPosition, increment);
416 codeStream.load(localBinding);
420 codeStream.iinc(localBinding.resolvedPosition, -increment);
422 codeStream.load(localBinding);
428 codeStream.load(localBinding);
431 // perform the actual compound operation
433 switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
434 case T_JavaLangString :
435 case T_JavaLangObject :
437 // we enter here if the single name reference is a field of type java.lang.String or if the type of the
438 // operation is java.lang.Object
439 // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
440 codeStream.generateStringConcatenationAppend(currentScope, null, expression);
441 // no need for generic cast on previous #getfield since using Object string buffer methods.
444 // promote the array reference to the suitable operation type
445 codeStream.generateImplicitConversion(implicitConversion);
446 // generate the increment value (will by itself be promoted to the operation value)
447 if (expression == IntLiteral.One){ // prefix operation
448 codeStream.generateConstant(expression.constant, implicitConversion);
450 expression.generateCode(currentScope, codeStream, true);
452 // perform the operation
453 codeStream.sendOperator(operator, operationTypeID);
454 // cast the value back to the array reference type
455 codeStream.generateImplicitConversion(assignmentImplicitConversion);
457 // store the result back into the variable
458 switch (bits & RestrictiveFlagMASK) {
459 case Binding.FIELD : // assigning to a field
460 fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired);
461 // no need for generic cast as value got dupped
463 case Binding.LOCAL : // assigning to a local variable
464 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
466 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
472 codeStream.store(localBinding, false);
476 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
477 switch (bits & RestrictiveFlagMASK) {
478 case Binding.FIELD : // assigning to a field
479 FieldBinding fieldBinding;
480 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
481 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
482 codeStream.getstatic(fieldBinding);
484 codeStream.invokestatic(syntheticAccessors[READ]);
487 if ((bits & DepthMASK) != 0) {
488 ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
489 Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
490 codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
492 codeStream.aload_0();
495 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
496 codeStream.getfield(fieldBinding);
498 codeStream.invokestatic(syntheticAccessors[READ]);
502 if (fieldBinding.isStatic()) {
503 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
508 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
509 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
510 codeStream.dup2_x1();
516 codeStream.generateImplicitConversion(implicitConversion);
517 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
518 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
519 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
520 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
521 // no need for generic cast
523 case Binding.LOCAL : // assigning to a local variable
524 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
525 // using incr bytecode if possible
526 if (localBinding.type == IntBinding) {
528 codeStream.load(localBinding);
530 if (postIncrement.operator == PLUS) {
531 codeStream.iinc(localBinding.resolvedPosition, 1);
533 codeStream.iinc(localBinding.resolvedPosition, -1);
536 codeStream.load(localBinding);
538 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
544 codeStream.generateImplicitConversion(implicitConversion);
545 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
546 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
547 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
549 codeStream.store(localBinding, false);
554 public void generateReceiver(CodeStream codeStream) {
556 codeStream.aload_0();
560 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
562 public TypeBinding[] genericTypeArguments() {
566 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
568 if (!flowInfo.isReachable()) return;
569 //If inlinable field, forget the access emulation, the code gen will directly target it
570 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return;
572 if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
573 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
576 public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
578 if (!flowInfo.isReachable()) return;
580 //If inlinable field, forget the access emulation, the code gen will directly target it
581 if (constant != NotAConstant)
584 if ((bits & Binding.FIELD) != 0) {
585 FieldBinding fieldBinding = (FieldBinding) binding;
586 FieldBinding codegenField = fieldBinding.original();
587 this.codegenBinding = codegenField;
588 if (((bits & DepthMASK) != 0)
589 && (codegenField.isPrivate() // private access
590 || (codegenField.isProtected() // implicit protected access
591 && codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) {
592 if (syntheticAccessors == null)
593 syntheticAccessors = new MethodBinding[2];
594 syntheticAccessors[isReadAccess ? READ : WRITE] =
595 ((SourceTypeBinding)currentScope.enclosingSourceType().
596 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess);
597 currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess);
600 // if the binding declaring class is not visible, need special action
601 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
602 // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
603 // and not from Object or implicit static field access.
604 if (fieldBinding.declaringClass != this.actualReceiverType
605 && !this.actualReceiverType.isArrayType()
606 && fieldBinding.declaringClass != null
607 && !fieldBinding.isConstantValue()
608 && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
609 && !fieldBinding.isStatic()
610 && fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields (if there was any)
611 || !codegenField.declaringClass.canBeSeenBy(currentScope))){
612 this.codegenBinding =
613 currentScope.enclosingSourceType().getUpdatedFieldBinding(
615 (ReferenceBinding)this.actualReceiverType.erasure());
619 public StringBuffer printExpression(int indent, StringBuffer output){
621 return output.append(token);
624 public TypeBinding reportError(BlockScope scope) {
626 //=====error cases=======
627 constant = Constant.NotAConstant;
628 if (binding instanceof ProblemFieldBinding) {
629 scope.problemReporter().invalidField(this, (FieldBinding) binding);
630 } else if (binding instanceof ProblemReferenceBinding) {
631 scope.problemReporter().invalidType(this, (TypeBinding) binding);
633 scope.problemReporter().unresolvableReference(this, binding);
637 public TypeBinding resolveType(BlockScope scope) {
638 // for code gen, harm the restrictiveFlag
640 if (this.actualReceiverType != null) {
641 this.binding = scope.getField(this.actualReceiverType, token, this);
643 this.actualReceiverType = scope.enclosingSourceType();
644 this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this, true /*resolve*/);
646 this.codegenBinding = this.binding;
647 if (this.binding.isValidBinding()) {
648 switch (bits & RestrictiveFlagMASK) {
649 case Binding.VARIABLE : // =========only variable============
650 case Binding.VARIABLE | Binding.TYPE : //====both variable and type============
651 if (binding instanceof VariableBinding) {
652 VariableBinding variable = (VariableBinding) binding;
653 if (binding instanceof LocalVariableBinding) {
654 bits &= ~RestrictiveFlagMASK; // clear bits
655 bits |= Binding.LOCAL;
656 if ((this.bits & IsStrictlyAssignedMASK) == 0) {
657 constant = variable.constant();
659 constant = NotAConstant;
661 if (!variable.isFinal() && (bits & DepthMASK) != 0) {
662 scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this);
664 return this.resolvedType = variable.type;
667 FieldBinding field = (FieldBinding) this.binding;
668 if (!field.isStatic() && scope.environment().options.getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
669 scope.problemReporter().unqualifiedFieldAccess(this, field);
671 return this.resolvedType = checkFieldAccess(scope);
674 // thus it was a type
675 bits &= ~RestrictiveFlagMASK; // clear bits
676 bits |= Binding.TYPE;
677 case Binding.TYPE : //========only type==============
678 constant = Constant.NotAConstant;
680 TypeBinding type = (TypeBinding)binding;
681 if (isTypeUseDeprecated(type, scope))
682 scope.problemReporter().deprecatedType(type, this);
683 return this.resolvedType = scope.convertToRawType(type);
688 return this.resolvedType = this.reportError(scope);
691 public void traverse(ASTVisitor visitor, BlockScope scope) {
693 visitor.visit(this, scope);
694 visitor.endVisit(this, scope);
697 public String unboundReferenceErrorName(){
699 return new String(token);
703 * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference)
704 * or thru a cast expression etc...
706 public LocalVariableBinding localVariableBinding() {
707 switch (bits & RestrictiveFlagMASK) {
708 case Binding.FIELD : // reading a field
710 case Binding.LOCAL : // reading a local variable
711 return (LocalVariableBinding) this.binding;