KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > SingleNameReference


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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 static final int READ = 0;
24     public static final int WRITE = 1;
25     public char[] token;
26     public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
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.tagBits & FlowInfo.UNREACHABLE) == 0;
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                 FieldBinding fieldBinding = (FieldBinding) binding;
73                 ReferenceBinding declaringClass = fieldBinding.declaringClass;
74                 // check if accessing enum static field in initializer
75
if (declaringClass.isEnum()) {
76                     MethodScope methodScope = currentScope.methodScope();
77                     SourceTypeBinding sourceType = currentScope.enclosingSourceType();
78                     if (fieldBinding.isStatic()
79                             && this.constant == Constant.NotAConstant
80                             && !methodScope.isStatic
81                             && (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
82
&& methodScope.isInsideInitializerOrConstructor()) {
83                         currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
84                     }
85                 }
86                 // check if assigning a final field
87
if (fieldBinding.isFinal()) {
88                     // inside a context where allowed
89
if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
90                         if (flowInfo.isPotentiallyAssigned(fieldBinding)) {
91                             currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this);
92                         } else {
93                             flowContext.recordSettingFinal(fieldBinding, this, flowInfo);
94                         }
95                         flowInfo.markAsDefinitelyAssigned(fieldBinding);
96                     } else {
97                         currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this);
98                     }
99                 }
100                 break;
101             case Binding.LOCAL : // assigning to a local variable
102
LocalVariableBinding localBinding = (LocalVariableBinding) binding;
103                 if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes
104
bits |= FirstAssignmentToLocal;
105                 } else {
106                     bits &= ~FirstAssignmentToLocal;
107                 }
108                 if (localBinding.isFinal()) {
109                     if ((bits & DepthMASK) == 0) {
110                         // tolerate assignment to final local in unreachable code (45674)
111
if ((isReachable && isCompound) || !localBinding.isBlankFinal()){
112                             currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this);
113                         } else if (flowInfo.isPotentiallyAssigned(localBinding)) {
114                             currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this);
115                         } else {
116                             flowContext.recordSettingFinal(localBinding, this, flowInfo);
117                         }
118                     } else {
119                         currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this);
120                     }
121                 }
122                 else /* avoid double diagnostic */ if ((localBinding.tagBits & TagBits.IsArgument) != 0) {
123                     currentScope.problemReporter().parameterAssignment(localBinding, this);
124                 }
125                 flowInfo.markAsDefinitelyAssigned(localBinding);
126         }
127         manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
128         return flowInfo;
129     }
130     public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
131         return analyseCode(currentScope, flowContext, flowInfo, true);
132     }
133     public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
134     
135         switch (bits & RestrictiveFlagMASK) {
136             case Binding.FIELD : // reading a field
137
if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
138                     manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
139                 }
140                 FieldBinding fieldBinding = (FieldBinding) binding;
141                 ReferenceBinding declaringClass = fieldBinding.declaringClass;
142                 // check if accessing enum static field in initializer
143
if (declaringClass.isEnum()) {
144                     MethodScope methodScope = currentScope.methodScope();
145                     SourceTypeBinding sourceType = currentScope.enclosingSourceType();
146                     if (fieldBinding.isStatic()
147                             && this.constant == Constant.NotAConstant
148                             && !methodScope.isStatic
149                             && (sourceType == declaringClass || sourceType.superclass == declaringClass) // enum constant body
150
&& methodScope.isInsideInitializerOrConstructor()) {
151                         currentScope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this);
152                     }
153                 }
154                 // check if reading a final blank field
155
if (fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) {
156                     if (!flowInfo.isDefinitelyAssigned(fieldBinding)) {
157                         currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this);
158                     }
159                 }
160                 break;
161             case Binding.LOCAL : // reading a local variable
162
LocalVariableBinding localBinding;
163                 if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) binding)) {
164                     currentScope.problemReporter().uninitializedLocalVariable(localBinding, this);
165                 }
166                 if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
167                     localBinding.useFlag = LocalVariableBinding.USED;
168                 } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) {
169                     localBinding.useFlag = LocalVariableBinding.FAKE_USED;
170                 }
171         }
172         if (valueRequired) {
173             manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo);
174         }
175         return flowInfo;
176     }
177     
178     public TypeBinding checkFieldAccess(BlockScope scope) {
179     
180         FieldBinding fieldBinding = (FieldBinding) binding;
181         
182         bits &= ~RestrictiveFlagMASK; // clear bits
183
bits |= Binding.FIELD;
184         MethodScope methodScope = scope.methodScope();
185         boolean isStatic = fieldBinding.isStatic();
186         if (!isStatic) {
187             // must check for the static status....
188
if (methodScope.isStatic) {
189                 scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding);
190                 this.constant = Constant.NotAConstant;
191                 return fieldBinding.type;
192             }
193         }
194         this.constant = fieldBinding.constant();
195     
196         if (isFieldUseDeprecated(fieldBinding, scope, (this.bits & IsStrictlyAssigned) !=0))
197             scope.problemReporter().deprecatedField(fieldBinding, this);
198     
199         if ((this.bits & IsStrictlyAssigned) == 0
200                 && methodScope.enclosingSourceType() == fieldBinding.original().declaringClass
201                 && methodScope.lastVisibleFieldID >= 0
202                 && fieldBinding.id >= methodScope.lastVisibleFieldID
203                 && (!fieldBinding.isStatic() || methodScope.isStatic)) {
204             scope.problemReporter().forwardReference(this, 0, methodScope.enclosingSourceType());
205             this.bits |= ASTNode.IgnoreNoEffectAssignCheck;
206         }
207         return fieldBinding.type;
208     
209     }
210     
211     /**
212      * @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)
213      */

214     public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
215         if (runtimeTimeType == null || compileTimeType == null)
216             return;
217         if ((bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) {
218             // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
219
FieldBinding field = (FieldBinding) this.binding;
220             FieldBinding originalBinding = field.original();
221             TypeBinding originalType = originalBinding.type;
222             // extra cast needed if method return type is type variable
223
if (originalBinding != field
224                     && originalType != field.type
225                     && runtimeTimeType.id != T_JavaLangObject
226                     && (originalType.tagBits & TagBits.HasTypeVariable) != 0) {
227                 TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType())
228                     ? compileTimeType // unboxing: checkcast before conversion
229
: runtimeTimeType;
230                 this.genericCast = originalType.genericCast(scope.boxing(targetType));
231             }
232         }
233         super.computeConversion(scope, runtimeTimeType, compileTimeType);
234     }
235
236     public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
237     
238         // optimizing assignment like: i = i + 1 or i = 1 + i
239
if (assignment.expression.isCompactableOperation()) {
240             BinaryExpression operation = (BinaryExpression) assignment.expression;
241             int operator = (operation.bits & OperatorMASK) >> OperatorSHIFT;
242             SingleNameReference variableReference;
243             if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == binding)) {
244                 // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion
245
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.right, operator, operation.implicitConversion, valueRequired);
246                 if (valueRequired) {
247                     codeStream.generateImplicitConversion(assignment.implicitConversion);
248                 }
249                 return;
250             }
251             if ((operation.right instanceof SingleNameReference)
252                     && ((operator == PLUS) || (operator == MULTIPLY)) // only commutative operations
253
&& ((variableReference = (SingleNameReference) operation.right).binding == binding)
254                     && (operation.left.constant != Constant.NotAConstant) // exclude non constant expressions, since could have side-effect
255
&& (((operation.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString) // exclude string concatenation which would occur backwards
256
&& (((operation.right.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_JavaLangString)) { // exclude string concatenation which would occur backwards
257
// i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion
258
variableReference.generateCompoundAssignment(currentScope, codeStream, syntheticAccessors == null ? null : syntheticAccessors[WRITE], operation.left, operator, operation.implicitConversion, valueRequired);
259                 if (valueRequired) {
260                     codeStream.generateImplicitConversion(assignment.implicitConversion);
261                 }
262                 return;
263             }
264         }
265         switch (bits & RestrictiveFlagMASK) {
266             case Binding.FIELD : // assigning to a field
267
FieldBinding fieldBinding;
268                 int pc = codeStream.position;
269                 if (!(fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) { // need a receiver?
270
if ((bits & DepthMASK) != 0) {
271                         ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
272                         Object JavaDoc[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
273                         codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
274                     } else {
275                         this.generateReceiver(codeStream);
276                     }
277                 }
278                 codeStream.recordPositionsFrom(pc, this.sourceStart);
279                 assignment.expression.generateCode(currentScope, codeStream, true);
280                 fieldStore(codeStream, fieldBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], valueRequired);
281                 if (valueRequired) {
282                     codeStream.generateImplicitConversion(assignment.implicitConversion);
283                 }
284                 // no need for generic cast as value got dupped
285
return;
286             case Binding.LOCAL : // assigning to a local variable
287
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
288                 if (localBinding.resolvedPosition != -1) {
289                     assignment.expression.generateCode(currentScope, codeStream, true);
290                 } else {
291                     if (assignment.expression.constant != Constant.NotAConstant) {
292                         // assigning an unused local to a constant value = no actual assignment is necessary
293
if (valueRequired) {
294                             codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion);
295                         }
296                     } else {
297                         assignment.expression.generateCode(currentScope, codeStream, true);
298                         /* Even though the value may not be required, we force it to be produced, and discard it later
299                         on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */

300                         if (valueRequired) {
301                             codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion
302
} else {
303                             if ((localBinding.type == TypeBinding.LONG) || (localBinding.type == TypeBinding.DOUBLE)) {
304                                 codeStream.pop2();
305                             } else {
306                                 codeStream.pop();
307                             }
308                         }
309                     }
310                     return;
311                 }
312                 // 26903, need extra cast to store null in array local var
313
if (localBinding.type.isArrayType()
314                     && (assignment.expression.resolvedType == TypeBinding.NULL // arrayLoc = null
315
|| ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null
316
&& (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == TypeBinding.NULL)))){
317                     codeStream.checkcast(localBinding.type);
318                 }
319                 
320                 // normal local assignment (since cannot store in outer local which are final locations)
321
codeStream.store(localBinding, valueRequired);
322                 if ((bits & FirstAssignmentToLocal) != 0) { // for local variable debug attributes
323
localBinding.recordInitializationStartPC(codeStream.position);
324                 }
325                 // implicit conversion
326
if (valueRequired) {
327                     codeStream.generateImplicitConversion(assignment.implicitConversion);
328                 }
329         }
330     }
331     public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
332         int pc = codeStream.position;
333         if (constant != Constant.NotAConstant) {
334             if (valueRequired) {
335                 codeStream.generateConstant(constant, implicitConversion);
336             }
337             codeStream.recordPositionsFrom(pc, this.sourceStart);
338             return;
339         } else {
340             switch (bits & RestrictiveFlagMASK) {
341                 case Binding.FIELD : // reading a field
342
FieldBinding fieldBinding = (FieldBinding) this.codegenBinding;
343                     Constant fieldConstant = fieldBinding.constant();
344                     if (fieldConstant != Constant.NotAConstant) {
345                         // directly use inlined value for constant fields
346
if (valueRequired) {
347                             codeStream.generateConstant(fieldConstant, implicitConversion);
348                         }
349                         codeStream.recordPositionsFrom(pc, this.sourceStart);
350                         return;
351                     }
352                     if (fieldBinding.isStatic()) {
353                         if (!valueRequired
354                                 // if no valueRequired, still need possible side-effects of <clinit> invocation, if field belongs to different class
355
&& ((FieldBinding)binding).original().declaringClass == this.actualReceiverType.erasure()
356                                 && ((implicitConversion & TypeIds.UNBOXING) == 0)
357                                 && this.genericCast == null) {
358                             // if no valueRequired, optimize out entire gen
359
codeStream.recordPositionsFrom(pc, this.sourceStart);
360                             return;
361                         }
362                         // managing private access
363
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
364                             codeStream.getstatic(fieldBinding);
365                         } else {
366                             codeStream.invokestatic(syntheticAccessors[READ]);
367                         }
368                     } else {
369                         if (!valueRequired
370                                 && (implicitConversion & TypeIds.UNBOXING) == 0
371                                 && this.genericCast == null) {
372                             // if no valueRequired, optimize out entire gen
373
codeStream.recordPositionsFrom(pc, this.sourceStart);
374                             return;
375                         }
376                         // managing enclosing instance access
377
if ((bits & DepthMASK) != 0) {
378                             ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
379                             Object JavaDoc[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
380                             codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
381                         } else {
382                             generateReceiver(codeStream);
383                         }
384                         // managing private access
385
if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
386                             codeStream.getfield(fieldBinding);
387                         } else {
388                             codeStream.invokestatic(syntheticAccessors[READ]);
389                         }
390                     }
391                     break;
392                 case Binding.LOCAL : // reading a local
393
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
394                     if (!valueRequired && (implicitConversion & TypeIds.UNBOXING) == 0) {
395                         // if no valueRequired, optimize out entire gen
396
codeStream.recordPositionsFrom(pc, this.sourceStart);
397                         return;
398                     }
399                     // outer local?
400
if ((bits & DepthMASK) != 0) {
401                         // outer local can be reached either through a synthetic arg or a synthetic field
402
VariableBinding[] path = currentScope.getEmulationPath(localBinding);
403                         codeStream.generateOuterAccess(path, this, localBinding, currentScope);
404                     } else {
405                         // regular local variable read
406
codeStream.load(localBinding);
407                     }
408                     break;
409                 default: // type
410
codeStream.recordPositionsFrom(pc, this.sourceStart);
411                     return;
412             }
413         }
414         // required cast must occur even if no value is required
415
if (this.genericCast != null) codeStream.checkcast(this.genericCast);
416         if (valueRequired) {
417             codeStream.generateImplicitConversion(implicitConversion);
418         } else {
419             boolean isUnboxing = (implicitConversion & TypeIds.UNBOXING) != 0;
420             // conversion only generated if unboxing
421
if (isUnboxing) codeStream.generateImplicitConversion(implicitConversion);
422             switch (isUnboxing ? postConversionType(currentScope).id : this.resolvedType.id) {
423                 case T_long :
424                 case T_double :
425                     codeStream.pop2();
426                     break;
427                 default :
428                     codeStream.pop();
429             }
430         }
431         codeStream.recordPositionsFrom(pc, this.sourceStart);
432     }
433     /*
434      * Regular API for compound assignment, relies on the fact that there is only one reference to the
435      * variable, which carries both synthetic read/write accessors.
436      * The APIs with an extra argument is used whenever there are two references to the same variable which
437      * are optimized in one access: e.g "a = a + 1" optimized into "a++".
438      */

439     public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
440     
441         this.generateCompoundAssignment(
442             currentScope,
443             codeStream,
444             syntheticAccessors == null ? null : syntheticAccessors[WRITE],
445             expression,
446             operator,
447             assignmentImplicitConversion,
448             valueRequired);
449     }
450     /*
451      * The APIs with an extra argument is used whenever there are two references to the same variable which
452      * are optimized in one access: e.g "a = a + 1" optimized into "a++".
453      */

454     public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) {
455         switch (bits & RestrictiveFlagMASK) {
456             case Binding.FIELD : // assigning to a field
457
FieldBinding fieldBinding;
458                 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
459                     if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
460                         codeStream.getstatic(fieldBinding);
461                     } else {
462                         codeStream.invokestatic(syntheticAccessors[READ]);
463                     }
464                 } else {
465                     if ((bits & DepthMASK) != 0) {
466                         ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
467                         Object JavaDoc[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
468                         codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
469                     } else {
470                         codeStream.aload_0();
471                     }
472                     codeStream.dup();
473                     if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
474                         codeStream.getfield(fieldBinding);
475                     } else {
476                         codeStream.invokestatic(syntheticAccessors[READ]);
477                     }
478                 }
479                 break;
480             case Binding.LOCAL : // assigning to a local variable (cannot assign to outer local)
481
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
482                 Constant assignConstant;
483                 int increment;
484                 // using incr bytecode if possible
485
switch (localBinding.type.id) {
486                     case T_JavaLangString :
487                         codeStream.generateStringConcatenationAppend(currentScope, this, expression);
488                         if (valueRequired) {
489                             codeStream.dup();
490                         }
491                         codeStream.store(localBinding, false);
492                         return;
493                     case T_int :
494                         if (((assignConstant = expression.constant) != Constant.NotAConstant)
495                             && (assignConstant.typeID() != T_float) // only for integral types
496
&& (assignConstant.typeID() != T_double)
497                             && ((increment = assignConstant.intValue()) == (short) increment)) { // 16 bits value
498
switch (operator) {
499                                 case PLUS :
500                                     codeStream.iinc(localBinding.resolvedPosition, increment);
501                                     if (valueRequired) {
502                                         codeStream.load(localBinding);
503                                     }
504                                     return;
505                                 case MINUS :
506                                     codeStream.iinc(localBinding.resolvedPosition, -increment);
507                                     if (valueRequired) {
508                                         codeStream.load(localBinding);
509                                     }
510                                     return;
511                             }
512                         }
513                     default :
514                         codeStream.load(localBinding);
515                 }
516         }
517         // perform the actual compound operation
518
int operationTypeID;
519         switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
520             case T_JavaLangString :
521             case T_JavaLangObject :
522             case T_undefined :
523                 // we enter here if the single name reference is a field of type java.lang.String or if the type of the
524
// operation is java.lang.Object
525
// For example: o = o + ""; // where the compiled type of o is java.lang.Object.
526
codeStream.generateStringConcatenationAppend(currentScope, null, expression);
527                 // no need for generic cast on previous #getfield since using Object string buffer methods.
528
break;
529             default :
530                 // promote the array reference to the suitable operation type
531
if (this.genericCast != null)
532                     codeStream.checkcast(this.genericCast);
533                 codeStream.generateImplicitConversion(this.implicitConversion);
534                 // generate the increment value (will by itself be promoted to the operation value)
535
if (expression == IntLiteral.One){ // prefix operation
536
codeStream.generateConstant(expression.constant, this.implicitConversion);
537                 } else {
538                     expression.generateCode(currentScope, codeStream, true);
539                 }
540                 // perform the operation
541
codeStream.sendOperator(operator, operationTypeID);
542                 // cast the value back to the array reference type
543
codeStream.generateImplicitConversion(assignmentImplicitConversion);
544         }
545         // store the result back into the variable
546
switch (bits & RestrictiveFlagMASK) {
547             case Binding.FIELD : // assigning to a field
548
fieldStore(codeStream, (FieldBinding) this.codegenBinding, writeAccessor, valueRequired);
549                 // no need for generic cast as value got dupped
550
return;
551             case Binding.LOCAL : // assigning to a local variable
552
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
553                 if (valueRequired) {
554                     if ((localBinding.type == TypeBinding.LONG) || (localBinding.type == TypeBinding.DOUBLE)) {
555                         codeStream.dup2();
556                     } else {
557                         codeStream.dup();
558                     }
559                 }
560                 codeStream.store(localBinding, false);
561         }
562     }
563     
564     public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) {
565         switch (bits & RestrictiveFlagMASK) {
566             case Binding.FIELD : // assigning to a field
567
FieldBinding fieldBinding;
568                 if ((fieldBinding = (FieldBinding) this.codegenBinding).isStatic()) {
569                     if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
570                         codeStream.getstatic(fieldBinding);
571                     } else {
572                         codeStream.invokestatic(syntheticAccessors[READ]);
573                     }
574                 } else {
575                     if ((bits & DepthMASK) != 0) {
576                         ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT);
577                         Object JavaDoc[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/);
578                         codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope);
579                     } else {
580                         codeStream.aload_0();
581                     }
582                     codeStream.dup();
583                     if ((syntheticAccessors == null) || (syntheticAccessors[READ] == null)) {
584                         codeStream.getfield(fieldBinding);
585                     } else {
586                         codeStream.invokestatic(syntheticAccessors[READ]);
587                     }
588                 }
589                 if (valueRequired) {
590                     if (fieldBinding.isStatic()) {
591                         if ((fieldBinding.type == TypeBinding.LONG) || (fieldBinding.type == TypeBinding.DOUBLE)) {
592                             codeStream.dup2();
593                         } else {
594                             codeStream.dup();
595                         }
596                     } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value]
597
if ((fieldBinding.type == TypeBinding.LONG) || (fieldBinding.type == TypeBinding.DOUBLE)) {
598                             codeStream.dup2_x1();
599                         } else {
600                             codeStream.dup_x1();
601                         }
602                     }
603                 }
604                 if (this.genericCast != null)
605                     codeStream.checkcast(this.genericCast);
606                 codeStream.generateImplicitConversion(this.implicitConversion);
607                 codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion);
608                 codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
609                 codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
610                 fieldStore(codeStream, fieldBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[WRITE], false);
611                 // no need for generic cast
612
return;
613             case Binding.LOCAL : // assigning to a local variable
614
LocalVariableBinding localBinding = (LocalVariableBinding) this.codegenBinding;
615                 // using incr bytecode if possible
616
if (localBinding.type == TypeBinding.INT) {
617                     if (valueRequired) {
618                         codeStream.load(localBinding);
619                     }
620                     if (postIncrement.operator == PLUS) {
621                         codeStream.iinc(localBinding.resolvedPosition, 1);
622                     } else {
623                         codeStream.iinc(localBinding.resolvedPosition, -1);
624                     }
625                 } else {
626                     codeStream.load(localBinding);
627                     if (valueRequired){
628                         if ((localBinding.type == TypeBinding.LONG) || (localBinding.type == TypeBinding.DOUBLE)) {
629                             codeStream.dup2();
630                         } else {
631                             codeStream.dup();
632                         }
633                     }
634                     codeStream.generateImplicitConversion(implicitConversion);
635                     codeStream.generateConstant(postIncrement.expression.constant, implicitConversion);
636                     codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
637                     codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion);
638     
639                     codeStream.store(localBinding, false);
640                 }
641         }
642     }
643     
644     public void generateReceiver(CodeStream codeStream) {
645         codeStream.aload_0();
646     }
647     
648     /**
649      * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
650      */

651     public TypeBinding[] genericTypeArguments() {
652         return null;
653     }
654
655     /**
656      * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference)
657      * or thru a cast expression etc...
658      */

659     public LocalVariableBinding localVariableBinding() {
660         switch (bits & RestrictiveFlagMASK) {
661             case Binding.FIELD : // reading a field
662
break;
663             case Binding.LOCAL : // reading a local variable
664
return (LocalVariableBinding) this.binding;
665         }
666         return null;
667     }
668     
669     public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
670     
671         if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) {
672         //If inlinable field, forget the access emulation, the code gen will directly target it
673
if (((bits & DepthMASK) == 0) || (constant != Constant.NotAConstant)) return;
674     
675         if ((bits & RestrictiveFlagMASK) == Binding.LOCAL) {
676             currentScope.emulateOuterAccess((LocalVariableBinding) binding);
677         }
678         }
679     }
680     public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
681     
682         if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) != 0) return;
683     
684         //If inlinable field, forget the access emulation, the code gen will directly target it
685
if (constant != Constant.NotAConstant)
686             return;
687     
688         if ((bits & Binding.FIELD) != 0) {
689             FieldBinding fieldBinding = (FieldBinding) binding;
690             FieldBinding codegenField = fieldBinding.original();
691             this.codegenBinding = codegenField;
692             if (((bits & DepthMASK) != 0)
693                 && (codegenField.isPrivate() // private access
694
|| (codegenField.isProtected() // implicit protected access
695
&& codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) {
696                 if (syntheticAccessors == null)
697                     syntheticAccessors = new MethodBinding[2];
698                 syntheticAccessors[isReadAccess ? READ : WRITE] =
699                     ((SourceTypeBinding)currentScope.enclosingSourceType().
700                         enclosingTypeAt((bits & DepthMASK) >> DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess);
701                 currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess);
702                 return;
703             }
704             // if the binding declaring class is not visible, need special action
705
// for runtime compatibility on 1.2 VMs : change the declaring class of the binding
706
// NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
707
// and not from Object or implicit static field access.
708
if (fieldBinding.declaringClass != this.actualReceiverType
709                     && !this.actualReceiverType.isArrayType()
710                     && fieldBinding.declaringClass != null // array.length
711
&& fieldBinding.constant() == Constant.NotAConstant) {
712                 CompilerOptions options = currentScope.compilerOptions();
713                 if ((options.targetJDK >= ClassFileConstants.JDK1_2
714                         && (options.complianceLevel >= ClassFileConstants.JDK1_4 || !fieldBinding.isStatic())
715                         && fieldBinding.declaringClass.id != T_JavaLangObject) // no change for Object fields
716
|| !fieldBinding.declaringClass.canBeSeenBy(currentScope)) {
717         
718                     this.codegenBinding =
719                         currentScope.enclosingSourceType().getUpdatedFieldBinding(
720                                codegenField,
721                                 (ReferenceBinding)this.actualReceiverType.erasure());
722                 }
723             }
724         }
725     }
726
727 public int nullStatus(FlowInfo flowInfo) {
728     if (this.constant != null && this.constant != Constant.NotAConstant) {
729         return FlowInfo.NON_NULL; // constant expression cannot be null
730
}
731     switch (bits & RestrictiveFlagMASK) {
732         case Binding.FIELD : // reading a field
733
return FlowInfo.UNKNOWN;
734         case Binding.LOCAL : // reading a local variable
735
LocalVariableBinding local = (LocalVariableBinding) this.binding;
736             if (local != null) {
737                 if (flowInfo.isDefinitelyNull(local))
738                     return FlowInfo.NULL;
739                 if (flowInfo.isDefinitelyNonNull(local))
740                     return FlowInfo.NON_NULL;
741                 return FlowInfo.UNKNOWN;
742             }
743     }
744     return FlowInfo.NON_NULL; // never get there
745
}
746
747     /**
748      * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope)
749      */

750     public TypeBinding postConversionType(Scope scope) {
751         TypeBinding convertedType = this.resolvedType;
752         if (this.genericCast != null)
753             convertedType = this.genericCast;
754         int runtimeType = (this.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4;
755         switch (runtimeType) {
756             case T_boolean :
757                 convertedType = TypeBinding.BOOLEAN;
758                 break;
759             case T_byte :
760                 convertedType = TypeBinding.BYTE;
761                 break;
762             case T_short :
763                 convertedType = TypeBinding.SHORT;
764                 break;
765             case T_char :
766                 convertedType = TypeBinding.CHAR;
767                 break;
768             case T_int :
769                 convertedType = TypeBinding.INT;
770                 break;
771             case T_float :
772                 convertedType = TypeBinding.FLOAT;
773                 break;
774             case T_long :
775                 convertedType = TypeBinding.LONG;
776                 break;
777             case T_double :
778                 convertedType = TypeBinding.DOUBLE;
779                 break;
780             default :
781         }
782         if ((this.implicitConversion & BOXING) != 0) {
783             convertedType = scope.environment().computeBoxingType(convertedType);
784         }
785         return convertedType;
786     }
787     
788     public StringBuffer JavaDoc printExpression(int indent, StringBuffer JavaDoc output){
789     
790         return output.append(token);
791     }
792     public TypeBinding reportError(BlockScope scope) {
793         
794         //=====error cases=======
795
constant = Constant.NotAConstant;
796         if (binding instanceof ProblemFieldBinding) {
797             scope.problemReporter().invalidField(this, (FieldBinding) binding);
798         } else if (binding instanceof ProblemReferenceBinding) {
799             scope.problemReporter().invalidType(this, (TypeBinding) binding);
800         } else {
801             scope.problemReporter().unresolvableReference(this, binding);
802         }
803         return null;
804     }
805         
806     public TypeBinding resolveType(BlockScope scope) {
807         // for code gen, harm the restrictiveFlag
808

809         if (this.actualReceiverType != null) {
810             this.binding = scope.getField(this.actualReceiverType, token, this);
811         } else {
812             this.actualReceiverType = scope.enclosingSourceType();
813             this.binding = scope.getBinding(token, bits & RestrictiveFlagMASK, this, true /*resolve*/);
814         }
815         this.codegenBinding = this.binding;
816         if (this.binding.isValidBinding()) {
817             switch (bits & RestrictiveFlagMASK) {
818                 case Binding.VARIABLE : // =========only variable============
819
case Binding.VARIABLE | Binding.TYPE : //====both variable and type============
820
if (binding instanceof VariableBinding) {
821                         VariableBinding variable = (VariableBinding) binding;
822                         if (binding instanceof LocalVariableBinding) {
823                             bits &= ~RestrictiveFlagMASK; // clear bits
824
bits |= Binding.LOCAL;
825                             if (!variable.isFinal() && (bits & DepthMASK) != 0) {
826                                 scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this);
827                             }
828                             TypeBinding fieldType = variable.type;
829                             if ((this.bits & IsStrictlyAssigned) == 0) {
830                                 constant = variable.constant();
831                                 if (fieldType != null)
832                                     fieldType = fieldType.capture(scope, this.sourceEnd); // perform capture conversion if read access
833
} else {
834                                 constant = Constant.NotAConstant;
835                             }
836                             return this.resolvedType = fieldType;
837                         }
838                         // a field
839
FieldBinding field = (FieldBinding) this.binding;
840                         if (!field.isStatic() && scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) {
841                             scope.problemReporter().unqualifiedFieldAccess(this, field);
842                         }
843                         // perform capture conversion if read access
844
TypeBinding fieldType = checkFieldAccess(scope);
845                         return this.resolvedType =
846                             (((this.bits & IsStrictlyAssigned) == 0)
847                                 ? fieldType.capture(scope, this.sourceEnd)
848                                 : fieldType);
849                     }
850     
851                     // thus it was a type
852
bits &= ~RestrictiveFlagMASK; // clear bits
853
bits |= Binding.TYPE;
854                 case Binding.TYPE : //========only type==============
855
constant = Constant.NotAConstant;
856                     //deprecated test
857
TypeBinding type = (TypeBinding)binding;
858                     if (isTypeUseDeprecated(type, scope))
859                         scope.problemReporter().deprecatedType(type, this);
860                     type = scope.environment().convertToRawType(type);
861                     return this.resolvedType = type;
862             }
863         }
864     
865         // error scenarii
866
return this.resolvedType = this.reportError(scope);
867     }
868     
869     public void traverse(ASTVisitor visitor, BlockScope scope) {
870         visitor.visit(this, scope);
871         visitor.endVisit(this, scope);
872     }
873     
874     public void traverse(ASTVisitor visitor, ClassScope scope) {
875         visitor.visit(this, scope);
876         visitor.endVisit(this, scope);
877     }
878
879     public String JavaDoc unboundReferenceErrorName(){
880     
881         return new String JavaDoc(token);
882     }
883 }
884
Popular Tags