first scanner /parser copied from the jdt java version
[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.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18
19 public class SingleNameReference extends NameReference implements OperatorIds {
20         public char[] token;
21
22         public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
23         public static final int READ = 0;
24         public static final int WRITE = 1;
25         
26 public SingleNameReference(char[] source, long pos) {
27         super();
28         token = source;
29         sourceStart = (int) (pos >>> 32);
30         sourceEnd = (int) pos;
31 }
32 public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) {
33
34         // compound assignment extra work
35         if (isCompound) { // check the variable part is initialized if blank final
36                 switch (bits & RestrictiveFlagMASK) {
37                         case FIELD : // reading a field
38                                 FieldBinding fieldBinding;
39                                 if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
40                                         if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
41                                                 currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
42                                                 // we could improve error msg here telling "cannot use compound assignment on final blank field"
43                                         }
44                                 }
45                                 manageSyntheticReadAccessIfNecessary(currentScope);
46                                 break;
47                         case LOCAL : // reading a local variable
48                                 // check if assigning a final blank field
49                                 LocalVariableBinding localBinding;
50                                 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
51                                         currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
52                                         // we could improve error msg here telling "cannot use compound assignment on final local variable"
53                                 }
54                                 if (!flowInfo.isFakeReachable()) localBinding.used = true;
55                 }
56         }
57         if (assignment.expression != null) {
58                 flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
59         }
60         switch (bits & RestrictiveFlagMASK) {
61                 case FIELD : // assigning to a field
62                         manageSyntheticWriteAccessIfNecessary(currentScope);
63
64                         // check if assigning a final field
65                         FieldBinding fieldBinding;
66                         if ((fieldBinding = (FieldBinding) binding).isFinal()) {
67                                 // inside a context where allowed
68                                 if (currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
69                                         if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
70                                                 currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
71                                         }
72                                         flowInfo.markAsDefinitelyAssigned(fieldBinding);
73                                         flowContext.recordSettingFinal(fieldBinding, this);                                             
74                                 } else {
75                                         currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
76                                 }
77                         }
78                         break;
79                 case LOCAL : // assigning to a local variable 
80                         LocalVariableBinding localBinding = (LocalVariableBinding) binding;
81                         if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes
82                                 bits |= FirstAssignmentToLocalMASK;
83                         } else {
84                                 bits &= ~FirstAssignmentToLocalMASK;
85                         }
86                         if (localBinding.isFinal()) {
87                                 if ((bits & DepthMASK) == 0) {
88                                         if (flowInfo.isPotentiallyAssigned(localBinding)) {
89                                                 currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
90                                         }
91                                         flowContext.recordSettingFinal(localBinding, this);                                                             
92                                 } else {
93                                         currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
94                                 }
95                         }
96                         flowInfo.markAsDefinitelyAssigned(localBinding);
97         }
98         manageEnclosingInstanceAccessIfNecessary(currentScope);
99         return flowInfo;
100 }
101 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
102         return analyseCode(currentScope, flowContext, flowInfo, true);
103 }
104 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
105
106         switch (bits & RestrictiveFlagMASK) {
107                 case FIELD : // reading a field
108                         if (valueRequired) {
109                                 manageSyntheticReadAccessIfNecessary(currentScope);
110                         }
111                         // check if reading a final blank field
112                         FieldBinding fieldBinding;
113                         if ((fieldBinding = (FieldBinding) binding).isFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
114                                 if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
115                                         currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
116                                 }
117                         }
118                         break;
119                 case LOCAL : // reading a local variable
120                         LocalVariableBinding localBinding;
121                         if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
122                                 currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
123                         }
124                         if (!flowInfo.isFakeReachable()) localBinding.used = true;                      
125         }
126         if (valueRequired) {
127                 manageEnclosingInstanceAccessIfNecessary(currentScope);
128         }
129         return flowInfo;
130 }
131 public TypeBinding checkFieldAccess(BlockScope scope) {
132
133         FieldBinding fieldBinding = (FieldBinding) binding;
134         
135         bits &= ~RestrictiveFlagMASK; // clear bits
136         bits |= FIELD;
137         if (!((FieldBinding) binding).isStatic()) {
138                 // must check for the static status....
139                 if (scope.methodScope().isStatic) {
140                         scope.problemReporter().staticFieldAccessToNonStaticVariable(
141                                 this,
142                                 fieldBinding);
143                         constant = NotAConstant;
144                         return null;
145                 }
146         }
147         constant = FieldReference.getConstantFor(fieldBinding, true, this, scope, 0);
148         if (isFieldUseDeprecated(fieldBinding, scope))
149                 scope.problemReporter().deprecatedField(fieldBinding, this);
150
151         //===============================================
152         //cycle are forbidden ONLY within the same class...why ?????? (poor javac....)
153         //Cycle can be done using cross class ref but not direct into a same class reference ????
154         //class A {     static int k = B.k+1;}
155         //class B {     static int k = A.k+2;}
156         //The k-cycle in this example is valid.
157
158         //class C { static int k = k + 1 ;}
159         //here it is forbidden ! ????
160         //but the next one is valid !!!
161         //class C { static int k = C.k + 1;}
162
163         //notice that the next one is also valid ?!?!
164         //class A {     static int k = foo().k+1 ; static A foo(){return new A();}}
165
166         //for all these reasons, the next piece of code is only here and not
167         //commun for all FieldRef and QualifiedNameRef....(i.e. in the getField(..) API.....
168
169         //instance field may refer to forward static field, like in
170         //int i = staticI;
171         //static int staticI = 2 ;
172
173         MethodScope ms = scope.methodScope();
174         if (ms.enclosingSourceType() == fieldBinding.declaringClass
175                 && ms.fieldDeclarationIndex != ms.NotInFieldDecl
176                 && fieldBinding.id >= ms.fieldDeclarationIndex) {
177                 //if the field is static and ms is not .... then it is valid
178                 if (!fieldBinding.isStatic() || ms.isStatic)
179                         scope.problemReporter().forwardReference(this, 0, scope.enclosingSourceType());
180         }
181         //====================================================
182
183         return fieldBinding.type;
184
185 }
186 public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
187
188         // optimizing assignment like: i = i + 1 or i = 1 + i
189         if (assignment.expression.isCompactableOperation()) {
190                 BinaryExpression operation = (BinaryExpression) assignment.expression;
191                 SingleNameReference variableReference;
192                 if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
193                         // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
194                         variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, (operation.bits & OperatorMASK) >> OperatorSHIFT, operation.left.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
195                         return;
196                 }
197                 int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
198                 if ((operation.right instanceof SingleNameReference)
199                         && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
200                         && ((variableReference = (SingleNameReference) operation.right).binding == binding)
201                         && (operation.left.constant != NotAConstant) // exclude non constant expressions, since could have side-effect
202                         && ((operation.left.implicitConversion >> 4) != T_String) // exclude string concatenation which would occur backwards
203                         && ((operation.right.implicitConversion >> 4) != T_String)) { // exclude string concatenation which would occur backwards
204                         // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
205                         variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.right.implicitConversion /*should be equivalent to no conversion*/, valueRequired);
206                         return;
207                 }
208         }
209         switch (bits & RestrictiveFlagMASK) {
210                 case FIELD : // assigning to a field
211                         FieldBinding fieldBinding;
212                         if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver?
213                                 if ((bits & DepthMASK) != 0) {
214                                         Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
215                                         if (emulationPath == null) {
216                                                 // internal error, per construction we should have found it
217                                                 currentScope.problemReporter().needImplementation();
218                                         } else {
219                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
220                                         }
221                                 } else {
222                                         this.generateReceiver(codeStream);
223                                 }
224                         }
225                         assignment.expression.generateCode(currentScope, codeStream, true);
226                         fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
227                         if (valueRequired) {
228                                 codeStream.generateImplicitConversion(assignment.implicitConversion);
229                         }
230                         return;
231                 case LOCAL : // assigning to a local variable
232                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
233                         if (localBinding.resolvedPosition != -1) {
234                                 assignment.expression.generateCode(currentScope, codeStream, true);
235                         } else {
236                                 if (assignment.expression.constant != NotAConstant) {
237                                         // assigning an unused local to a constant value = no actual assignment is necessary
238                                         if (valueRequired) {
239                                                 codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
240                                         }
241                                 } else {
242                                         assignment.expression.generateCode(currentScope, codeStream, true);
243                                         /* Even though the value may not be required, we force it to be produced, and discard it later
244                                         on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */
245                                         if (valueRequired) {
246                                                 codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
247                                         } else {
248                                                 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
249                                                         codeStream.pop2();
250                                                 } else {
251                                                         codeStream.pop();
252                                                 }
253                                         }
254                                 }
255                                 return;
256                         }
257                         // normal local assignment (since cannot store in outer local which are final locations)
258                         codeStream.store(localBinding, valueRequired);
259                         if ((bits & FirstAssignmentToLocalMASK) != 0) { // for local variable debug attributes
260                                 localBinding.recordInitializationStartPC(codeStream.position);
261                         }
262                         // implicit conversion
263                         if (valueRequired) {
264                                 codeStream.generateImplicitConversion(assignment.implicitConversion);
265                         }
266         }
267 }
268 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
269         int pc = codeStream.position;
270         if (constant != NotAConstant) {
271                 if (valueRequired) {
272                         codeStream.generateConstant(constant, implicitConversion);
273                 }
274         } else {
275                 switch (bits & RestrictiveFlagMASK) {
276                         case FIELD : // reading a field
277                                 FieldBinding fieldBinding;
278                                 if (valueRequired) {
279                                         if ((fieldBinding = (FieldBinding) this.codegenBinding).constant == NotAConstant) { // directly use inlined value for constant fields
280                                                 boolean isStatic;
281                                                 if (!(isStatic = fieldBinding.isStatic())) {
282                                                         if ((bits & DepthMASK) != 0) {
283                                                                 Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
284                                                                 if (emulationPath == null) {
285                                                                         // internal error, per construction we should have found it
286                                                                         currentScope.problemReporter().needImplementation();
287                                                                 } else {
288                                                                         codeStream.generateOuterAccess(emulationPath, this, currentScope);
289                                                                 }
290                                                         } else {
291                                                                 generateReceiver(codeStream);
292                                                         }
293                                                 }
294                                                 // managing private access                                                      
295                                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
296                                                         if (isStatic) {
297                                                                 codeStream.getstatic(fieldBinding);
298                                                         } else {
299                                                                 codeStream.getfield(fieldBinding);
300                                                         }
301                                                 } else {
302                                                         codeStream.invokestatic(syntheticAccessors[READ]);
303                                                 }
304                                                 codeStream.generateImplicitConversion(implicitConversion);
305                                         } else { // directly use the inlined value
306                                                 codeStream.generateConstant(fieldBinding.constant, implicitConversion);
307                                         }
308                                 }
309                                 break;
310                         case LOCAL : // reading a local
311                                 LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
312                                 if (valueRequired) {
313                                         // outer local?
314                                         if ((bits & DepthMASK) != 0) {
315                                                 // outer local can be reached either through a synthetic arg or a synthetic field
316                                                 VariableBinding[] path = currentScope.getEmulationPath(localBinding);
317                                                 if (path == null) {
318                                                         // emulation was not possible (should not happen per construction)
319                                                         currentScope.problemReporter().needImplementation();
320                                                 } else {
321                                                         codeStream.generateOuterAccess(path, this, currentScope);
322                                                 }
323                                         } else {
324                                                 // regular local variable read
325                                                 codeStream.load(localBinding);
326                                         }
327                                         codeStream.generateImplicitConversion(implicitConversion);
328                                 }
329                 }
330         }
331         codeStream.recordPositionsFrom(pc, this.sourceStart);
332 }
333 /*
334  * Regular API for compound assignment, relies on the fact that there is only one reference to the
335  * variable, which carries both synthetic read/write accessors.
336  * The APIs with an extra argument is used whenever there are two references to the same variable which
337  * are optimized in one access: e.g "a = a + 1" optimized into "a++".
338  */
339 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
340
341         this.generateCompoundAssignment(
342                 currentScope, 
343                 codeStream, 
344                 syntheticAccessors == null ? null : syntheticAccessors[WRITE],
345                 expression,
346                 operator, 
347                 assignmentImplicitConversion, 
348                 valueRequired);
349 }
350 /*
351  * The APIs with an extra argument is used whenever there are two references to the same variable which
352  * are optimized in one access: e.g "a = a + 1" optimized into "a++".
353  */
354 public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
355         switch (bits & RestrictiveFlagMASK) {
356                 case FIELD : // assigning to a field
357                         FieldBinding fieldBinding;
358                         if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
359                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
360                                         codeStream.getstatic(fieldBinding);
361                                 } else {
362                                         codeStream.invokestatic(syntheticAccessors[READ]);
363                                 }
364                         } else {
365                                 if ((bits & DepthMASK) != 0) {
366                                         Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
367                                         if (emulationPath == null) {
368                                                 // internal error, per construction we should have found it
369                                                 currentScope.problemReporter().needImplementation();
370                                         } else {
371                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
372                                         }
373                                 } else {
374                                         codeStream.aload_0();
375                                 }
376                                 codeStream.dup();
377                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
378                                         codeStream.getfield(fieldBinding);
379                                 } else {
380                                         codeStream.invokestatic(syntheticAccessors[READ]);
381                                 }
382                         }
383                         break;
384                 case LOCAL : // assigning to a local variable (cannot assign to outer local)
385                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
386                         Constant assignConstant;
387                         int increment;
388                         // using incr bytecode if possible
389                         switch (localBinding.type.id) {
390                                 case T_String :
391                                         codeStream.generateStringAppend(currentScope, this, expression);
392                                         if (valueRequired) {
393                                                 codeStream.dup();
394                                         }
395                                         codeStream.store(localBinding, false);
396                                         return;
397                                 case T_int :
398                                         if (((assignConstant = expression.constant) != NotAConstant) 
399                                                 && (assignConstant.typeID() != T_float) // only for integral types
400                                                 && (assignConstant.typeID() != T_double)
401                                                 && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value
402                                                 switch (operator) {
403                                                         case PLUS :
404                                                                 codeStream.iinc(localBinding.resolvedPosition, increment);
405                                                                 if (valueRequired) {
406                                                                         codeStream.load(localBinding);
407                                                                 }
408                                                                 return;
409                                                         case MINUS :
410                                                                 codeStream.iinc(localBinding.resolvedPosition, -increment);
411                                                                 if (valueRequired) {
412                                                                         codeStream.load(localBinding);
413                                                                 }
414                                                                 return;
415                                                 }
416                                         }
417                                 default :
418                                         codeStream.load(localBinding);
419                         }
420         }
421         // perform the actual compound operation
422         int operationTypeID;
423         if ((operationTypeID = implicitConversion >> 4) == T_String || operationTypeID == T_Object) {
424                 // we enter here if the single name reference is a field of type java.lang.String or if the type of the 
425                 // operation is java.lang.Object
426                 // For example: o = o + ""; // where the compiled type of o is java.lang.Object.
427                 codeStream.generateStringAppend(currentScope, null, expression);
428         } else {
429                 // promote the array reference to the suitable operation type
430                 codeStream.generateImplicitConversion(implicitConversion);
431                 // generate the increment value (will by itself  be promoted to the operation value)
432                 if (expression == IntLiteral.One){ // prefix operation
433                         codeStream.generateConstant(expression.constant, implicitConversion);                   
434                 } else {
435                         expression.generateCode(currentScope, codeStream, true);
436                 }               
437                 // perform the operation
438                 codeStream.sendOperator(operator, operationTypeID);
439                 // cast the value back to the array reference type
440                 codeStream.generateImplicitConversion(assignmentImplicitConversion);
441         }
442         // store the result back into the variable
443         switch (bits & RestrictiveFlagMASK) {
444                 case FIELD : // assigning to a field
445                         fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired);
446                         return;
447                 case LOCAL : // assigning to a local variable
448                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
449                         if (valueRequired) {
450                                 if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
451                                         codeStream.dup2();
452                                 } else {
453                                         codeStream.dup();
454                                 }
455                         }
456                         codeStream.store(localBinding, false);
457         }
458 }
459 public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
460         switch (bits & RestrictiveFlagMASK) {
461                 case FIELD : // assigning to a field
462                         FieldBinding fieldBinding;
463                         if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
464                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
465                                         codeStream.getstatic(fieldBinding);
466                                 } else {
467                                         codeStream.invokestatic(syntheticAccessors[READ]);
468                                 }
469                         } else {
470                                 if ((bits & DepthMASK) != 0) {
471                                         Object[] emulationPath = currentScope.getExactEmulationPath(currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT));
472                                         if (emulationPath == null) {
473                                                 // internal error, per construction we should have found it
474                                                 currentScope.problemReporter().needImplementation();
475                                         } else {
476                                                 codeStream.generateOuterAccess(emulationPath, this, currentScope);
477                                         }
478                                 } else {
479                                         codeStream.aload_0();
480                                 }
481                                 codeStream.dup();
482                                 if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
483                                         codeStream.getfield(fieldBinding);
484                                 } else {
485                                         codeStream.invokestatic(syntheticAccessors[READ]);
486                                 }
487                         }
488                         if (valueRequired) {
489                                 if (fieldBinding.isStatic()) {
490                                         if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
491                                                 codeStream.dup2();
492                                         } else {
493                                                 codeStream.dup();
494                                         }
495                                 } else { // Stack:  [owner][old field value]  ---> [old field value][owner][old field value]
496                                         if ((fieldBinding.type == LongBinding) || (fieldBinding.type == DoubleBinding)) {
497                                                 codeStream.dup2_x1();
498                                         } else {
499                                                 codeStream.dup_x1();
500                                         }
501                                 }
502                         }
503                         codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
504                         codeStream.sendOperator(postIncrement.operator, fieldBinding.type.id);
505                         codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
506                         fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
507                         return;
508                 case LOCAL : // assigning to a local variable
509                         LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
510                         // using incr bytecode if possible
511                         if (localBinding.type == IntBinding) {
512                                 if (valueRequired) {
513                                         codeStream.load(localBinding);
514                                 }
515                                 if (postIncrement.operator == PLUS) {
516                                         codeStream.iinc(localBinding.resolvedPosition, 1);
517                                 } else {
518                                         codeStream.iinc(localBinding.resolvedPosition, -1);
519                                 }
520                         } else {
521                                 codeStream.load(localBinding);
522                                 if (valueRequired){
523                                         if ((localBinding.type == LongBinding) || (localBinding.type == DoubleBinding)) {
524                                                 codeStream.dup2();
525                                         } else {
526                                                 codeStream.dup();
527                                         }
528                                 }
529                                 codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
530                                 codeStream.sendOperator(postIncrement.operator, localBinding.type.id);
531                                 codeStream.generateImplicitConversion(postIncrement.assignmentImplicitConversion);
532
533                                 codeStream.store(localBinding, false);
534                         }
535         }
536 }
537 public void generateReceiver(CodeStream codeStream) {
538         codeStream.aload_0();
539 }
540 public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope) {
541
542         //If inlinable field, forget the access emulation, the code gen will directly target it
543         if (((bits & DepthMASK) == 0) || (constant != NotAConstant)) return;
544
545         switch (bits & RestrictiveFlagMASK) {
546                 case FIELD :
547                         FieldBinding fieldBinding;
548                         if ((fieldBinding = (FieldBinding)binding).isStatic() || (fieldBinding.constant != NotAConstant)) return;
549                         ReferenceBinding compatibleType = currentScope.enclosingSourceType();
550                         // the declaringClass of the target binding must be compatible with the enclosing
551                         // type at <depth> levels outside
552                         for (int i = 0, depth = (bits & DepthMASK) >> DepthSHIFT; i < depth; i++) {
553                                 compatibleType = compatibleType.enclosingType();
554                         }
555                         currentScope.emulateOuterAccess(compatibleType, false); // request cascade of accesses
556                         break;
557                 case LOCAL :
558                         currentScope.emulateOuterAccess((LocalVariableBinding) binding);
559         }
560 }
561 public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope) {
562
563         //If inlinable field, forget the access emulation, the code gen will directly target it
564         if (constant != NotAConstant)
565                 return;
566
567         if ((bits & FIELD) != 0) {
568                 FieldBinding fieldBinding = (FieldBinding) binding;
569                 if (((bits & DepthMASK) != 0)
570                         && (fieldBinding.isPrivate() // private access
571                                 || (fieldBinding.isProtected() // implicit protected access
572                                                 && fieldBinding.declaringClass.getPackage() 
573                                                         != currentScope.enclosingSourceType().getPackage()))) {
574                         if (syntheticAccessors == null)
575                                 syntheticAccessors = new MethodBinding[2];
576                         syntheticAccessors[READ] = 
577                                 ((SourceTypeBinding)currentScope.enclosingSourceType().
578                                         enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
579                                                 addSyntheticMethod(fieldBinding, true);
580                         currentScope.problemReporter().needToEmulateFieldReadAccess(fieldBinding, this);
581                         return;
582                 }
583                 // if the binding declaring class is not visible, need special action
584                 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
585                 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
586                 // and not from Object or implicit static field access. 
587                 if (fieldBinding.declaringClass != this.actualReceiverType
588                         && !this.actualReceiverType.isArrayType()       
589                         && fieldBinding.declaringClass != null
590                         && fieldBinding.constant == NotAConstant
591                         && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 
592                                         && !fieldBinding.isStatic()
593                                         && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
594                                 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
595                         this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
596                 }
597         }
598 }
599 public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope) {
600
601         if ((bits & FIELD) != 0) {
602                 FieldBinding fieldBinding = (FieldBinding) binding;
603                 if (((bits & DepthMASK) != 0) 
604                         && (fieldBinding.isPrivate() // private access
605                                 || (fieldBinding.isProtected() // implicit protected access
606                                                 && fieldBinding.declaringClass.getPackage() 
607                                                         != currentScope.enclosingSourceType().getPackage()))) {
608                         if (syntheticAccessors == null)
609                                 syntheticAccessors = new MethodBinding[2];
610                         syntheticAccessors[WRITE] = 
611                                 ((SourceTypeBinding)currentScope.enclosingSourceType().
612                                         enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).
613                                                 addSyntheticMethod(fieldBinding, false);
614                         currentScope.problemReporter().needToEmulateFieldWriteAccess(fieldBinding, this);
615                         return;
616                 }
617                 // if the binding declaring class is not visible, need special action
618                 // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
619                 // NOTE: from 1.4 on, field's declaring class is touched if any different from receiver type
620                 // and not from Object or implicit static field access. 
621                 if (fieldBinding.declaringClass != this.actualReceiverType
622                         && !this.actualReceiverType.isArrayType()       
623                         && fieldBinding.declaringClass != null
624                         && fieldBinding.constant == NotAConstant
625                         && ((currentScope.environment().options.complianceLevel >= CompilerOptions.JDK1_4 
626                                         && !fieldBinding.isStatic()
627                                         && fieldBinding.declaringClass.id != T_Object) // no change for Object fields (if there was any)
628                                 || !fieldBinding.declaringClass.canBeSeenBy(currentScope))){
629                         this.codegenBinding = currentScope.enclosingSourceType().getUpdatedFieldBinding(fieldBinding, (ReferenceBinding)this.actualReceiverType);
630                 }
631         }
632 }
633 public TypeBinding reportError(BlockScope scope) {
634         //=====error cases=======
635         constant = Constant.NotAConstant;
636         if (binding instanceof ProblemFieldBinding) {
637                 scope.problemReporter().invalidField(this, (FieldBinding) binding);
638         } else if (binding instanceof ProblemReferenceBinding) {
639                 scope.problemReporter().invalidType(this, (TypeBinding) binding);
640         } else {
641                 scope.problemReporter().unresolvableReference(this, binding);
642         }
643         return null;
644 }
645 public TypeBinding resolveType(BlockScope scope) {
646         // for code gen, harm the restrictiveFlag       
647
648         this.actualReceiverType = this.receiverType = scope.enclosingSourceType();
649         
650         if ((this.codegenBinding = this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this)).isValidBinding()) {
651                 switch (bits & RestrictiveFlagMASK) {
652                         case VARIABLE : // =========only variable============
653                         case VARIABLE | TYPE : //====both variable and type============
654                                 if (binding instanceof VariableBinding) {
655                                         VariableBinding vb = (VariableBinding) binding;
656                                         if (binding instanceof LocalVariableBinding) {
657                                                 bits &= ~RestrictiveFlagMASK;  // clear bits
658                                                 bits |= LOCAL;
659                                                 constant = vb.constant;
660                                                 if ((!vb.isFinal()) && ((bits & DepthMASK) != 0))
661                                                         scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)vb, this);
662                                                 return vb.type;
663                                         }
664                                         // a field
665                                         return checkFieldAccess(scope);
666                                 }
667
668                                 // thus it was a type
669                                 bits &= ~RestrictiveFlagMASK;  // clear bits
670                                 bits |= TYPE;
671                         case TYPE : //========only type==============
672                                 constant = Constant.NotAConstant;
673                                 //deprecated test
674                                 if (isTypeUseDeprecated((TypeBinding) binding, scope))
675                                         scope.problemReporter().deprecatedType((TypeBinding) binding, this);
676                                 return (TypeBinding) binding;
677                 }
678         }
679
680         // error scenarii
681         return this.reportError(scope);
682 }
683 public String toStringExpression(){
684
685         return new String(token);}
686 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
687         visitor.visit(this, scope);
688         visitor.endVisit(this, scope);
689 }
690 public String unboundReferenceErrorName(){
691
692         return new String(token);}
693 }