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