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