6ecbaa393ba30443133bfe6e286e7544a0fcd33b
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / SingleNameReference.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
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;
30
31 public class SingleNameReference extends NameReference implements OperatorIds {
32         public char[] token;
33
34         public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
35         public static final int READ = 0;
36         public static final int WRITE = 1;
37         
38 public SingleNameReference(char[] source, long pos) {
39         super();
40         token = source;
41         sourceStart = (int) (pos >>> 32);
42         sourceEnd = (int) pos;
43 }
44 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
45
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"
55                                         }
56                                 }
57                                 manageSyntheticReadAccessIfNecessary(currentScope);
58                                 break;
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"
65                                 }
66                                 if (!flowInfo.isFakeReachable()) localBinding.used = true;
67                 }
68         }
69         if (assignment.expression != null) {
70                 flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
71         }
72         switch (bits & RestrictiveFlagMASK) {
73                 case FIELD : // assigning to a field
74                         manageSyntheticWriteAccessIfNecessary(currentScope);
75
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);
83                                         }
84                                         flowInfo.markAsDefinitelyAssigned(fieldBinding);
85                                         flowContext.recordSettingFinal(fieldBinding, this);                                             
86                                 } else {
87                                         currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
88                                 }
89                         }
90                         break;
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;
95                         } else {
96                                 bits &= ~FirstAssignmentToLocalMASK;
97                         }
98                         if (localBinding.isFinal()) {
99                                 if ((bits & DepthMASK) == 0) {
100                                         if (flowInfo.isPotentiallyAssigned(localBinding)) {
101                                                 currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
102                                         }
103                                         flowContext.recordSettingFinal(localBinding, this);                                                             
104                                 } else {
105                                         currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
106                                 }
107                         }
108                         flowInfo.markAsDefinitelyAssigned(localBinding);
109         }
110         manageEnclosingInstanceAccessIfNecessary(currentScope);
111         return flowInfo;
112 }
113 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
114         return analyseCode(currentScope, flowContext, flowInfo, true);
115 }
116 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
117
118         switch (bits & RestrictiveFlagMASK) {
119                 case FIELD : // reading a field
120                         if (valueRequired) {
121                                 manageSyntheticReadAccessIfNecessary(currentScope);
122                         }
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);
128                                 }
129                         }
130                         break;
131                 case LOCAL : // reading a local variable
132                         LocalVariableBinding localBinding;
133                         if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
134                                 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
135                         }
136                         if (!flowInfo.isFakeReachable()) localBinding.used = true;                      
137         }
138         if (valueRequired) {
139                 manageEnclosingInstanceAccessIfNecessary(currentScope);
140         }
141         return flowInfo;
142 }
143 public TypeBinding checkFieldAccess(BlockScope scope) {
144
145         FieldBinding fieldBinding = (FieldBinding) binding;
146         
147         bits &= ~RestrictiveFlagMASK; // clear bits
148         bits |= FIELD;
149         if (!((FieldBinding) binding).isStatic()) {
150                 // must check for the static status....
151                 if (scope.methodScope().isStatic) {
152                         scope.problemReporter().staticFieldAccessToNonStaticVariable(
153                                 this,
154                                 fieldBinding);
155                         constant = NotAConstant;
156                         return null;
157                 }
158         }
159         constant = FieldReference.getConstantFor(fieldBinding, true, this, scope, 0);
160         if (isFieldUseDeprecated(fieldBinding, scope))
161                 scope.problemReporter().deprecatedField(fieldBinding, this);
162
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.
169
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;}
174
175         //notice that the next one is also valid ?!?!
176         //class A {     static int k = foo().k+1 ; static A foo(){return new A();}}
177
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.....
180
181         //instance field may refer to forward static field, like in
182         //int i = staticI;
183         //static int staticI = 2 ;
184
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());
192         }
193         //====================================================
194
195         return fieldBinding.type;
196
197 }
198 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
199
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);
207                         return;
208                 }
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);
218                         return;
219                 }
220         }
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();
230                                         } else {
231                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
232                                         }
233                                 } else {
234                                         this.generateReceiver(codeStream);
235                                 }
236                         }
237                         assignment.expression.generateCode(currentScope, codeStream, true);
238                         fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
239                         if (valueRequired) {
240                                 codeStream.generateImplicitConversion(assignment.implicitConversion);
241                         }
242                         return;
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);
247                         } else {
248                                 if (assignment.expression.constant != NotAConstant) {
249                                         // assigning an unused local to a constant value = no actual assignment is necessary
250                                         if (valueRequired) {
251                                                 codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
252                                         }
253                                 } else {
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. */
257                                         if (valueRequired) {
258                                                 codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
259                                         } else {
260                                                 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
261                                                         codeStream.pop2();
262                                                 } else {
263                                                         codeStream.pop();
264                                                 }
265                                         }
266                                 }
267                                 return;
268                         }
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);
273                         }
274                         // implicit conversion
275                         if (valueRequired) {
276                                 codeStream.generateImplicitConversion(assignment.implicitConversion);
277                         }
278         }
279 }
280 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
281         int pc = codeStream.position;
282         if (constant != NotAConstant) {
283                 if (valueRequired) {
284                         codeStream.generateConstant(constant, implicitConversion);
285                 }
286         } else {
287                 switch (bits & RestrictiveFlagMASK) {
288                         case FIELD : // reading a field
289                                 FieldBinding fieldBinding;
290                                 if (valueRequired) {
291                                         if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields
292                                                 boolean isStatic;
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();
299                                                                 } else {
300                                                                         codeStream.generateOuterAccess(emulationPath, this, currentScope);
301                                                                 }
302                                                         } else {
303                                                                 generateReceiver(codeStream);
304                                                         }
305                                                 }
306                                                 // managing private access                                                      
307                                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
308                                                         if (isStatic) {
309                                                                 codeStream.getstatic(fieldBinding);
310                                                         } else {
311                                                                 codeStream.getfield(fieldBinding);
312                                                         }
313                                                 } else {
314                                                         codeStream.invokestatic(syntheticAccessors[READ]);
315                                                 }
316                                                 codeStream.generateImplicitConversion(implicitConversion);
317                                         } else { // directly use the inlined value
318                                                 codeStream.generateConstant(fieldBinding.constant, implicitConversion);
319                                         }
320                                 }
321                                 break;
322                         case LOCAL : // reading a local
323                                 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
324                                 if (valueRequired) {
325                                         // outer local?
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);
329                                                 if (path == null) {
330                                                         // emulation was not possible (should not happen per construction)
331                                                         currentScope.problemReporter().needImplementation();
332                                                 } else {
333                                                         codeStream.generateOuterAccess(path, this, currentScope);
334                                                 }
335                                         } else {
336                                                 // regular local variable read
337                                                 codeStream.load(localBinding);
338                                         }
339                                         codeStream.generateImplicitConversion(implicitConversion);
340                                 }
341                 }
342         }
343         codeStream.recordPositionsFrom(pc, this.sourceStart);
344 }
345 /*
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++".
350  */
351 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
352
353         this.generateCompoundAssignment(
354                 currentScope, 
355                 codeStream, 
356                 syntheticAccessors == null ? null : syntheticAccessors[WRITE],
357                 expression,
358                 operator, 
359                 assignmentImplicitConversion, 
360                 valueRequired);
361 }
362 /*
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++".
365  */
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);
373                                 } else {
374                                         codeStream.invokestatic(syntheticAccessors[READ]);
375                                 }
376                         } else {
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();
382                                         } else {
383                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
384                                         }
385                                 } else {
386                                         codeStream.aload_0();
387                                 }
388                                 codeStream.dup();
389                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
390                                         codeStream.getfield(fieldBinding);
391                                 } else {
392                                         codeStream.invokestatic(syntheticAccessors[READ]);
393                                 }
394                         }
395                         break;
396                 case LOCAL : // assigning to a local variable (cannot assign to outer local)
397                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
398                         Constant assignConstant;
399                         int increment;
400                         // using incr bytecode if possible
401                         switch (localBinding.type.id) {
402                                 case T_String :
403                                         codeStream.generateStringAppend(currentScope, this, expression);
404                                         if (valueRequired) {
405                                                 codeStream.dup();
406                                         }
407                                         codeStream.store(localBinding, false);
408                                         return;
409                                 case T_int :
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
414                                                 switch (operator) {
415                                                         case PLUS :
416                                                                 codeStream.iinc(localBinding.resolvedPosition, increment);
417                                                                 if (valueRequired) {
418                                                                         codeStream.load(localBinding);
419                                                                 }
420                                                                 return;
421                                                         case MINUS :
422                                                                 codeStream.iinc(localBinding.resolvedPosition, -increment);
423                                                                 if (valueRequired) {
424                                                                         codeStream.load(localBinding);
425                                                                 }
426                                                                 return;
427                                                 }
428                                         }
429                                 default :
430                                         codeStream.load(localBinding);
431                         }
432         }
433         // perform the actual compound operation
434         int operationTypeID;
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);
440         } else {
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);                   
446                 } else {
447                         expression.generateCode(currentScope, codeStream, true);
448                 }               
449                 // perform the operation
450                 codeStream.sendOperator(operator, operationTypeID);
451                 // cast the value back to the array reference type
452                 codeStream.generateImplicitConversion(assignmentImplicitConversion);
453         }
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);
458                         return;
459                 case LOCAL : // assigning to a local variable
460                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
461                         if (valueRequired) {
462                                 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
463                                         codeStream.dup2();
464                                 } else {
465                                         codeStream.dup();
466                                 }
467                         }
468                         codeStream.store(localBinding, false);
469         }
470 }
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);
478                                 } else {
479                                         codeStream.invokestatic(syntheticAccessors[READ]);
480                                 }
481                         } else {
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();
487                                         } else {
488                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
489                                         }
490                                 } else {
491                                         codeStream.aload_0();
492                                 }
493                                 codeStream.dup();
494                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
495                                         codeStream.getfield(fieldBinding);
496                                 } else {
497                                         codeStream.invokestatic(syntheticAccessors[READ]);
498                                 }
499                         }
500                         if (valueRequired) {
501                                 if (fieldBinding.isStatic()) {
502                                         if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
503                                                 codeStream.dup2();
504                                         } else {
505                                                 codeStream.dup();
506                                         }
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();
510                                         } else {
511                                                 codeStream.dup_x1();
512                                         }
513                                 }
514                         }
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);
519                         return;
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) {
524                                 if (valueRequired) {
525                                         codeStream.load(localBinding);
526                                 }
527                                 if (postIncrement.operator == PLUS) {
528                                         codeStream.iinc(localBinding.resolvedPosition, 1);
529                                 } else {
530                                         codeStream.iinc(localBinding.resolvedPosition, -1);
531                                 }
532                         } else {
533                                 codeStream.load(localBinding);
534                                 if (valueRequired){
535                                         if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
536                                                 codeStream.dup2();
537                                         } else {
538                                                 codeStream.dup();
539                                         }
540                                 }
541                                 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
542                                 codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
543                                 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
544
545                                 codeStream.store(localBinding, false);
546                         }
547         }
548 }
549 public void generateReceiver(CodeStream codeStream) {
550         codeStream.aload_0();
551 }
552 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
553
554         //If inlinable field, forget the access emulation, the code gen will directly target it
555         if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return;
556
557         switch (bits & RestrictiveFlagMASK) {
558                 case FIELD :
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();
566                         }
567                         currentScope.emulateOuterAccess(compatibleType, false); // request cascade of accesses
568                         break;
569                 case LOCAL :
570                         currentScope.emulateOuterAccess((LocalVariableBinding) binding);
571         }
572 }
573 public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
574
575         //If inlinable field, forget the access emulation, the code gen will directly target it
576         if (constant != NotAConstant)
577                 return;
578
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);
593                         return;
594                 }
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);
608                 }
609         }
610 }
611 public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
612
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);
627                         return;
628                 }
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);
642                 }
643         }
644 }
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);
652         } else {
653                 scope.problemReporter().unresolvableReference(this, binding);
654         }
655         return null;
656 }
657 public TypeBinding resolveType(BlockScope scope) {
658         // for code gen, harm the restrictiveFlag       
659
660         this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
661         
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
670                                                 bits |= LOCAL;
671                                                 constant = vb.constant;
672                                                 if ((!vb.isFinal()) && ((bits & DepthMASK) != 0))
673                                                         scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)vb, this);
674                                                 return vb.type;
675                                         }
676                                         // a field
677                                         return checkFieldAccess(scope);
678                                 }
679
680                                 // thus it was a type
681                                 bits &= ~RestrictiveFlagMASK;  // clear bits
682                                 bits |= TYPE;
683                         case TYPE : //========only type==============
684                                 constant = Constant.NotAConstant;
685                                 //deprecated test
686                                 if (isTypeUseDeprecated((TypeBinding) binding, scope))
687                                         scope.problemReporter().deprecatedType((TypeBinding) binding, this);
688                                 return (TypeBinding) binding;
689                 }
690         }
691
692         // error scenarii
693         return this.reportError(scope);
694 }
695 public String toStringExpression(){
696
697         return new String(token);}
698 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
699         visitor.visit(this, scope);
700         visitor.endVisit(this, scope);
701 }
702 public String unboundReferenceErrorName(){
703
704         return new String(token);}
705 }