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.codegen.CodeStream;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
18 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
21 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
22 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
23 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
24 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemFieldBinding;
25 import net.sourceforge.phpdt.internal.compiler.lookup.ProblemReferenceBinding;
26 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
27 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
28 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
29 import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
31 public class SingleNameReference extends NameReference implements OperatorIds {
34 public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
35 public static final int READ = 0;
36 public static final int WRITE = 1;
38 public SingleNameReference(char[] source, long pos) {
41 sourceStart = (int) (pos >>> 32);
42 sourceEnd = (int) pos;
44 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
46 // compound assignment extra work
47 if (isCompound) { // check the variable part is initialized if blank final
48 switch (bits & RestrictiveFlagMASK) {
49 case FIELD : // reading a field
50 FieldBinding fieldBinding;
51 if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
52 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
53 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
54 // we could improve error msg here telling "cannot use compound assignment on final blank field"
57 manageSyntheticReadAccessIfNecessary(currentScope);
59 case LOCAL : // reading a local variable
60 // check if assigning a final blank field
61 LocalVariableBinding localBinding;
62 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
63 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
64 // we could improve error msg here telling "cannot use compound assignment on final local variable"
66 if (!flowInfo.isFakeReachable()) localBinding.used = true;
69 if (assignment.expression != null) {
70 flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
72 switch (bits & RestrictiveFlagMASK) {
73 case FIELD : // assigning to a field
74 manageSyntheticWriteAccessIfNecessary(currentScope);
76 // check if assigning a final field
77 FieldBinding fieldBinding;
78 if ((fieldBinding = (FieldBinding) binding).isFinal()) {
79 // inside a context where allowed
80 if (currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
81 if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
82 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
84 flowInfo.markAsDefinitelyAssigned(fieldBinding);
85 flowContext.recordSettingFinal(fieldBinding, this);
87 currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
91 case LOCAL : // assigning to a local variable
92 LocalVariableBinding localBinding = (LocalVariableBinding) binding;
93 if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes
94 bits |= FirstAssignmentToLocalMASK;
96 bits &= ~FirstAssignmentToLocalMASK;
98 if (localBinding.isFinal()) {
99 if ((bits & DepthMASK) == 0) {
100 if (flowInfo.isPotentiallyAssigned(localBinding)) {
101 currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
103 flowContext.recordSettingFinal(localBinding, this);
105 currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
108 flowInfo.markAsDefinitelyAssigned(localBinding);
110 manageEnclosingInstanceAccessIfNecessary(currentScope);
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);
123 // check if reading a final blank field
124 FieldBinding fieldBinding;
125 if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
126 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
127 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
131 case LOCAL : // reading a local variable
132 LocalVariableBinding localBinding;
133 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
134 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
136 if (!flowInfo.isFakeReachable()) localBinding.used = true;
139 manageEnclosingInstanceAccessIfNecessary(currentScope);
143 public TypeBinding checkFieldAccess(BlockScope scope) {
145 FieldBinding fieldBinding = (FieldBinding) binding;
147 bits &= ~RestrictiveFlagMASK; // clear bits
149 if (!((FieldBinding) binding).isStatic()) {
150 // must check for the static status....
151 if (scope.methodScope().isStatic) {
152 scope.problemReporter().staticFieldAccessToNonStaticVariable(
155 constant = NotAConstant;
159 constant = FieldReference.getConstantFor(fieldBinding, true, this, scope, 0);
160 if (isFieldUseDeprecated(fieldBinding, scope))
161 scope.problemReporter().deprecatedField(fieldBinding, this);
163 //===============================================
164 //cycle are forbidden ONLY within the same class...why ?????? (poor javac....)
165 //Cycle can be done using cross class ref but not direct into a same class reference ????
166 //class A { static int k = B.k+1;}
167 //class B { static int k = A.k+2;}
168 //The k-cycle in this example is valid.
170 //class C { static int k = k + 1 ;}
171 //here it is forbidden ! ????
172 //but the next one is valid !!!
173 //class C { static int k = C.k + 1;}
175 //notice that the next one is also valid ?!?!
176 //class A { static int k = foo().k+1 ; static A foo(){return new A();}}
178 //for all these reasons, the next piece of code is only here and not
179 //commun for all FieldRef and QualifiedNameRef....(i.e. in the getField(..) API.....
181 //instance field may refer to forward static field, like in
183 //static int staticI = 2 ;
185 MethodScope ms = scope.methodScope();
186 if (ms.enclosingSourceType() == fieldBinding.declaringClass
187 && ms.fieldDeclarationIndex != MethodScope.NotInFieldDecl
188 && fieldBinding.id >= ms.fieldDeclarationIndex) {
189 //if the field is static and ms is not .... then it is valid
190 if (!fieldBinding.isStatic() || ms.isStatic)
191 scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
193 //====================================================
195 return fieldBinding.type;
198 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
200 // optimizing assignment like: i = i + 1 or i = 1 + i
201 if (assignment.expression.isCompactableOperation()) {
202 BinaryExpression operation = (BinaryExpression) assignment.expression;
203 SingleNameReference variableReference;
204 if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
205 // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
206 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);
209 int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
210 if ((operation.right instanceof SingleNameReference)
211 && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
212 && ((variableReference = (SingleNameReference) operation.right).binding == binding)
213 && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
214 && ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards
215 && ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards
216 // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
217 variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
221 switch (bits & RestrictiveFlagMASK) {
222 case FIELD : // assigning to a field
223 FieldBinding fieldBinding;
224 if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver?
225 if ((bits & DepthMASK) != 0) {
226 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
227 if (emulationPath == null) {
228 // internal error, per construction we should have found it
229 currentScope.problemReporter().needImplementation();
231 codeStream.generateOuterAccess(emulationPath, this, currentScope);
234 this.generateReceiver(codeStream);
237 assignment.expression.generateCode(currentScope, codeStream, true);
238 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
240 codeStream.generateImplicitConversion(assignment.implicitConversion);
243 case LOCAL : // assigning to a local variable
244 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
245 if (localBinding.resolvedPosition != -1) {
246 assignment.expression.generateCode(currentScope, codeStream, true);
248 if (assignment.expression.constant != NotAConstant) {
249 // assigning an unused local to a constant value = no actual assignment is necessary
251 codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
254 assignment.expression.generateCode(currentScope, codeStream, true);
255 /* Even though the value may not be required, we force it to be produced, and discard it later
256 on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
258 codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
260 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
269 // normal local assignment (since cannot store in outer local which are final locations)
270 codeStream.store(localBinding, valueRequired);
271 if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes
272 localBinding.recordInitializationStartPC(codeStream.position);
274 // implicit conversion
276 codeStream.generateImplicitConversion(assignment.implicitConversion);
280 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
281 int pc = codeStream.position;
282 if (constant != NotAConstant) {
284 codeStream.generateConstant(constant, implicitConversion);
287 switch (bits & RestrictiveFlagMASK) {
288 case FIELD : // reading a field
289 FieldBinding fieldBinding;
291 if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields
293 if (!(isStatic = fieldBinding.isStatic())) {
294 if ((bits & DepthMASK) != 0) {
295 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
296 if (emulationPath == null) {
297 // internal error, per construction we should have found it
298 currentScope.problemReporter().needImplementation();
300 codeStream.generateOuterAccess(emulationPath, this, currentScope);
303 generateReceiver(codeStream);
306 // managing private access
307 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
309 codeStream.getstatic(fieldBinding);
311 codeStream.getfield(fieldBinding);
314 codeStream.invokestatic(syntheticAccessors[READ]);
316 codeStream.generateImplicitConversion(implicitConversion);
317 } else { // directly use the inlined value
318 codeStream.generateConstant(fieldBinding.constant, implicitConversion);
322 case LOCAL : // reading a local
323 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
326 if ((bits & DepthMASK) != 0) {
327 // outer local can be reached either through a synthetic arg or a synthetic field
328 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
330 // emulation was not possible (should not happen per construction)
331 currentScope.problemReporter().needImplementation();
333 codeStream.generateOuterAccess(path, this, currentScope);
336 // regular local variable read
337 codeStream.load(localBinding);
339 codeStream.generateImplicitConversion(implicitConversion);
343 codeStream.recordPositionsFrom(pc, this.sourceStart);
346 * Regular API for compound assignment, relies on the fact that there is only one reference to the
347 * variable, which carries both synthetic read/write accessors.
348 * The APIs with an extra argument is used whenever there are two references to the same variable which
349 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
351 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
353 this.generateCompoundAssignment(
356 syntheticAccessors == null ? null : syntheticAccessors[WRITE],
359 assignmentImplicitConversion,
363 * The APIs with an extra argument is used whenever there are two references to the same variable which
364 * are optimized in one access: e.g "a = a + 1" optimized into "a++".
366 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
367 switch (bits & RestrictiveFlagMASK) {
368 case FIELD : // assigning to a field
369 FieldBinding fieldBinding;
370 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
371 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
372 codeStream.getstatic(fieldBinding);
374 codeStream.invokestatic(syntheticAccessors[READ]);
377 if ((bits & DepthMASK) != 0) {
378 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
379 if (emulationPath == null) {
380 // internal error, per construction we should have found it
381 currentScope.problemReporter().needImplementation();
383 codeStream.generateOuterAccess(emulationPath, this, currentScope);
386 codeStream.aload_0();
389 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
390 codeStream.getfield(fieldBinding);
392 codeStream.invokestatic(syntheticAccessors[READ]);
396 case LOCAL : // assigning to a local variable (cannot assign to outer local)
397 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
398 Constant assignConstant;
400 // using incr bytecode if possible
401 switch (localBinding.type.id) {
403 codeStream.generateStringAppend(currentScope, this, expression);
407 codeStream.store(localBinding, false);
410 if (((assignConstant = expression.constant) != NotAConstant)
411 && (assignConstant.typeID() != T_float) // only for integral types
412 && (assignConstant.typeID() != T_double)
413 && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value
416 codeStream.iinc(localBinding.resolvedPosition, increment);
418 codeStream.load(localBinding);
422 codeStream.iinc(localBinding.resolvedPosition, -increment);
424 codeStream.load(localBinding);
430 codeStream.load(localBinding);
433 // perform the actual compound operation
435 if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) {
436 // we enter here if the single name reference is a field of type java.lang.String or if the type of the
437 // operation is java.lang.Object
438 // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
439 codeStream.generateStringAppend(currentScope, null, expression);
441 // promote the array reference to the suitable operation type
442 codeStream.generateImplicitConversion(implicitConversion);
443 // generate the increment value (will by itself be promoted to the operation value)
444 if (expression == IntLiteral.One){ // prefix operation
445 codeStream.generateConstant(expression.constant, implicitConversion);
447 expression.generateCode(currentScope, codeStream, true);
449 // perform the operation
450 codeStream.sendOperator(operator, operationTypeID);
451 // cast the value back to the array reference type
452 codeStream.generateImplicitConversion(assignmentImplicitConversion);
454 // store the result back into the variable
455 switch (bits & RestrictiveFlagMASK) {
456 case FIELD : // assigning to a field
457 fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired);
459 case LOCAL : // assigning to a local variable
460 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
462 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
468 codeStream.store(localBinding, false);
471 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
472 switch (bits & RestrictiveFlagMASK) {
473 case FIELD : // assigning to a field
474 FieldBinding fieldBinding;
475 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
476 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
477 codeStream.getstatic(fieldBinding);
479 codeStream.invokestatic(syntheticAccessors[READ]);
482 if ((bits & DepthMASK) != 0) {
483 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
484 if (emulationPath == null) {
485 // internal error, per construction we should have found it
486 currentScope.problemReporter().needImplementation();
488 codeStream.generateOuterAccess(emulationPath, this, currentScope);
491 codeStream.aload_0();
494 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
495 codeStream.getfield(fieldBinding);
497 codeStream.invokestatic(syntheticAccessors[READ]);
501 if (fieldBinding.isStatic()) {
502 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
507 } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
508 if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
509 codeStream.dup2_x1();
515 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
516 codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
517 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
518 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
520 case LOCAL : // assigning to a local variable
521 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
522 // using incr bytecode if possible
523 if (localBinding.type == IntBinding) {
525 codeStream.load(localBinding);
527 if (postIncrement.operator == PLUS) {
528 codeStream.iinc(localBinding.resolvedPosition, 1);
530 codeStream.iinc(localBinding.resolvedPosition, -1);
533 codeStream.load(localBinding);
535 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
541 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
542 codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
543 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
545 codeStream.store(localBinding, false);
549 public void generateReceiver(CodeStream codeStream) {
550 codeStream.aload_0();
552 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
554 //If inlinable field, forget the access emulation, the code gen will directly target it
555 if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return;
557 switch (bits & RestrictiveFlagMASK) {
559 FieldBinding fieldBinding;
560 if ((fieldBinding = (FieldBinding)binding).isStatic() || (fieldBinding.constant != NotAConstant)) return;
561 ReferenceBinding compatibleType = currentScope.enclosingSourceType();
562 // the declaringClass of the target binding must be compatible with the enclosing
563 // type at <depth> levels outside
564 for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
565 compatibleType = compatibleType.enclosingType();
567 currentScope.emulateOuterAccess(compatibleType, false); // request cascade of accesses
570 currentScope.emulateOuterAccess((LocalVariableBinding) binding);
573 public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
575 //If inlinable field, forget the access emulation, the code gen will directly target it
576 if (constant != NotAConstant)
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[READ] =
589 ((SourceTypeBinding)currentScope.enclosingSourceType().
590 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
591 addSyntheticMethod(fieldBinding, true);
592 currentScope.problemReporter().needToEmulateFieldReadAccess(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 1.4 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.complianceLevel >= CompilerOptions.JDK1_4
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 void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
613 if ((bits & FIELD) != 0) {
614 FieldBinding fieldBinding = (FieldBinding) binding;
615 if (((bits & DepthMASK) != 0)
616 && (fieldBinding.isPrivate() // private access
617 || (fieldBinding.isProtected() // implicit protected access
618 && fieldBinding.declaringClass.getPackage()
619 != currentScope.enclosingSourceType().getPackage()))) {
620 if (syntheticAccessors == null)
621 syntheticAccessors = new MethodBinding[2];
622 syntheticAccessors[WRITE] =
623 ((SourceTypeBinding)currentScope.enclosingSourceType().
624 enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
625 addSyntheticMethod(fieldBinding, false);
626 currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
629 // if the binding declaring class is not visible, need special action
630 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
631 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
632 // and not from Object or implicit static field access.
633 if (fieldBinding.declaringClass != this.actualReceiverType
634 && !this.actualReceiverType.isArrayType()
635 && fieldBinding.declaringClass != null
636 && fieldBinding.constant == NotAConstant
637 && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4
638 && !fieldBinding.isStatic()
639 && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
640 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
641 this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
645 public TypeBinding reportError(BlockScope scope) {
646 //=====error cases=======
647 constant = Constant.NotAConstant;
648 if (binding instanceof ProblemFieldBinding) {
649 scope.problemReporter().invalidField(this, (FieldBinding) binding);
650 } else if (binding instanceof ProblemReferenceBinding) {
651 scope.problemReporter().invalidType(this, (TypeBinding) binding);
653 scope.problemReporter().unresolvableReference(this, binding);
657 public TypeBinding resolveType(BlockScope scope) {
658 // for code gen, harm the restrictiveFlag
660 this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
662 if ((this.codegenBinding = this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this)).isValidBinding()) {
663 switch (bits & RestrictiveFlagMASK) {
664 case VARIABLE : // =========only variable============
665 case VARIABLE | TYPE : //====both variable and type============
666 if (binding instanceof VariableBinding) {
667 VariableBinding vb = (VariableBinding) binding;
668 if (binding instanceof LocalVariableBinding) {
669 bits &= ~RestrictiveFlagMASK; // clear bits
671 constant = vb.constant;
672 if ((!vb.isFinal()) && ((bits & DepthMASK) != 0))
673 scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)vb, this);
677 return checkFieldAccess(scope);
680 // thus it was a type
681 bits &= ~RestrictiveFlagMASK; // clear bits
683 case TYPE : //========only type==============
684 constant = Constant.NotAConstant;
686 if (isTypeUseDeprecated((TypeBinding) binding, scope))
687 scope.problemReporter().deprecatedType((TypeBinding) binding, this);
688 return (TypeBinding) binding;
693 return this.reportError(scope);
695 public String toStringExpression(){
697 return new String(token);}
698 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
699 visitor.visit(this, scope);
700 visitor.endVisit(this, scope);
702 public String unboundReferenceErrorName(){
704 return new String(token);}