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