KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.util.ArrayList JavaDoc;
14
15 import org.eclipse.jdt.core.compiler.CharOperation;
16 import org.eclipse.jdt.internal.compiler.ASTVisitor;
17 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
18 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
19 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
20 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
21 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
22 import org.eclipse.jdt.internal.compiler.impl.Constant;
23 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
24 import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
25 import org.eclipse.jdt.internal.compiler.lookup.Binding;
26 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
27 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
28 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
29 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
30 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
31 import org.eclipse.jdt.internal.compiler.lookup.Scope;
32 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
33 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
34 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
35 import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
36 import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
37 import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
38 import org.eclipse.jdt.internal.compiler.util.Messages;
39
40 public abstract class Expression extends Statement {
41     
42     public Constant constant;
43     
44     public int statementEnd = -1;
45     
46     //Some expression may not be used - from a java semantic point
47
//of view only - as statements. Other may. In order to avoid the creation
48
//of wrappers around expression in order to tune them as expression
49
//Expression is a subclass of Statement. See the message isValidJavaStatement()
50

51     public int implicitConversion;
52     public TypeBinding resolvedType;
53
54 public static final boolean isConstantValueRepresentable(Constant constant, int constantTypeID, int targetTypeID) {
55     //true if there is no loss of precision while casting.
56
// constantTypeID == constant.typeID
57
if (targetTypeID == constantTypeID)
58         return true;
59     switch (targetTypeID) {
60         case T_char :
61             switch (constantTypeID) {
62                 case T_char :
63                     return true;
64                 case T_double :
65                     return constant.doubleValue() == constant.charValue();
66                 case T_float :
67                     return constant.floatValue() == constant.charValue();
68                 case T_int :
69                     return constant.intValue() == constant.charValue();
70                 case T_short :
71                     return constant.shortValue() == constant.charValue();
72                 case T_byte :
73                     return constant.byteValue() == constant.charValue();
74                 case T_long :
75                     return constant.longValue() == constant.charValue();
76                 default :
77                     return false;//boolean
78
}
79
80         case T_float :
81             switch (constantTypeID) {
82                 case T_char :
83                     return constant.charValue() == constant.floatValue();
84                 case T_double :
85                     return constant.doubleValue() == constant.floatValue();
86                 case T_float :
87                     return true;
88                 case T_int :
89                     return constant.intValue() == constant.floatValue();
90                 case T_short :
91                     return constant.shortValue() == constant.floatValue();
92                 case T_byte :
93                     return constant.byteValue() == constant.floatValue();
94                 case T_long :
95                     return constant.longValue() == constant.floatValue();
96                 default :
97                     return false;//boolean
98
}
99             
100         case T_double :
101             switch (constantTypeID) {
102                 case T_char :
103                     return constant.charValue() == constant.doubleValue();
104                 case T_double :
105                     return true;
106                 case T_float :
107                     return constant.floatValue() == constant.doubleValue();
108                 case T_int :
109                     return constant.intValue() == constant.doubleValue();
110                 case T_short :
111                     return constant.shortValue() == constant.doubleValue();
112                 case T_byte :
113                     return constant.byteValue() == constant.doubleValue();
114                 case T_long :
115                     return constant.longValue() == constant.doubleValue();
116                 default :
117                     return false; //boolean
118
}
119             
120         case T_byte :
121             switch (constantTypeID) {
122                 case T_char :
123                     return constant.charValue() == constant.byteValue();
124                 case T_double :
125                     return constant.doubleValue() == constant.byteValue();
126                 case T_float :
127                     return constant.floatValue() == constant.byteValue();
128                 case T_int :
129                     return constant.intValue() == constant.byteValue();
130                 case T_short :
131                     return constant.shortValue() == constant.byteValue();
132                 case T_byte :
133                     return true;
134                 case T_long :
135                     return constant.longValue() == constant.byteValue();
136                 default :
137                     return false; //boolean
138
}
139             
140         case T_short :
141             switch (constantTypeID) {
142                 case T_char :
143                     return constant.charValue() == constant.shortValue();
144                 case T_double :
145                     return constant.doubleValue() == constant.shortValue();
146                 case T_float :
147                     return constant.floatValue() == constant.shortValue();
148                 case T_int :
149                     return constant.intValue() == constant.shortValue();
150                 case T_short :
151                     return true;
152                 case T_byte :
153                     return constant.byteValue() == constant.shortValue();
154                 case T_long :
155                     return constant.longValue() == constant.shortValue();
156                 default :
157                     return false; //boolean
158
}
159             
160         case T_int :
161             switch (constantTypeID) {
162                 case T_char :
163                     return constant.charValue() == constant.intValue();
164                 case T_double :
165                     return constant.doubleValue() == constant.intValue();
166                 case T_float :
167                     return constant.floatValue() == constant.intValue();
168                 case T_int :
169                     return true;
170                 case T_short :
171                     return constant.shortValue() == constant.intValue();
172                 case T_byte :
173                     return constant.byteValue() == constant.intValue();
174                 case T_long :
175                     return constant.longValue() == constant.intValue();
176                 default :
177                     return false; //boolean
178
}
179             
180         case T_long :
181             switch (constantTypeID) {
182                 case T_char :
183                     return constant.charValue() == constant.longValue();
184                 case T_double :
185                     return constant.doubleValue() == constant.longValue();
186                 case T_float :
187                     return constant.floatValue() == constant.longValue();
188                 case T_int :
189                     return constant.intValue() == constant.longValue();
190                 case T_short :
191                     return constant.shortValue() == constant.longValue();
192                 case T_byte :
193                     return constant.byteValue() == constant.longValue();
194                 case T_long :
195                     return true;
196                 default :
197                     return false; //boolean
198
}
199             
200         default :
201             return false; //boolean
202
}
203 }
204     
205 public Expression() {
206     super();
207 }
208
209 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
210     return flowInfo;
211 }
212
213 /**
214  * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out
215  * portions of expressions where no actual value is required.
216  *
217  * @param currentScope
218  * @param flowContext
219  * @param flowInfo
220  * @param valueRequired
221  * @return The state of initialization after the analysis of the current expression
222  */

223 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
224
225     return analyseCode(currentScope, flowContext, flowInfo);
226 }
227
228 /**
229  * Returns false if cast is not legal.
230  */

231 public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castType, TypeBinding expressionType, Expression expression) {
232
233     // see specifications 5.5
234
// handle errors and process constant when needed
235

236     // if either one of the type is null ==>
237
// some error has been already reported some where ==>
238
// we then do not report an obvious-cascade-error.
239

240     if (castType == null || expressionType == null) return true;
241
242     // identity conversion cannot be performed upfront, due to side-effects
243
// like constant propagation
244
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
245     if (castType.isBaseType()) {
246         if (expressionType.isBaseType()) {
247             if (expressionType == castType) {
248                 if (expression != null) {
249                     this.constant = expression.constant; //use the same constant
250
}
251                 tagAsUnnecessaryCast(scope, castType);
252                 return true;
253             }
254             boolean necessary = false;
255             if (expressionType.isCompatibleWith(castType)
256                     || (necessary = BaseTypeBinding.isNarrowing(castType.id, expressionType.id))) {
257                 if (expression != null) {
258                     expression.implicitConversion = (castType.id << 4) + expressionType.id;
259                     if (expression.constant != Constant.NotAConstant) {
260                         this.constant = expression.constant.castTo(expression.implicitConversion);
261                     }
262                 }
263                 if (!necessary) tagAsUnnecessaryCast(scope, castType);
264                 return true;
265                 
266             }
267         } else if (use15specifics
268                             && scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
269
tagAsUnnecessaryCast(scope, castType);
270             return true;
271         }
272         return false;
273     } else if (use15specifics
274                         && expressionType.isBaseType()
275                         && scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // boxing - only widening match is allowed
276
tagAsUnnecessaryCast(scope, castType);
277         return true;
278     }
279
280     switch(expressionType.kind()) {
281         case Binding.BASE_TYPE :
282             //-----------cast to something which is NOT a base type--------------------------
283
if (expressionType == TypeBinding.NULL) {
284                 tagAsUnnecessaryCast(scope, castType);
285                 return true; //null is compatible with every thing
286
}
287             return false;
288             
289         case Binding.ARRAY_TYPE :
290             if (castType == expressionType) {
291                 tagAsUnnecessaryCast(scope, castType);
292                 return true; // identity conversion
293
}
294             switch (castType.kind()) {
295                 case Binding.ARRAY_TYPE :
296                     // ( ARRAY ) ARRAY
297
TypeBinding castElementType = ((ArrayBinding) castType).elementsType();
298                     TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType();
299                     if (exprElementType.isBaseType() || castElementType.isBaseType()) {
300                         if (castElementType == exprElementType) {
301                             tagAsNeedCheckCast();
302                             return true;
303                         }
304                         return false;
305                     }
306                     // recurse on array type elements
307
return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression);
308                     
309                 case Binding.TYPE_PARAMETER :
310                     // ( TYPE_PARAMETER ) ARRAY
311
TypeBinding match = expressionType.findSuperTypeWithSameErasure(castType);
312                     if (match == null) {
313                         checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
314                     }
315                     // recurse on the type variable upper bound
316
return checkCastTypesCompatibility(scope, ((TypeVariableBinding)castType).upperBound(), expressionType, expression);
317                     
318                 default:
319                     // ( CLASS/INTERFACE ) ARRAY
320
switch (castType.id) {
321                         case T_JavaLangCloneable :
322                         case T_JavaIoSerializable :
323                             tagAsNeedCheckCast();
324                             return true;
325                         case T_JavaLangObject :
326                             tagAsUnnecessaryCast(scope, castType);
327                             return true;
328                         default :
329                             return false;
330                     }
331             }
332                     
333         case Binding.TYPE_PARAMETER :
334             TypeBinding match = expressionType.findSuperTypeWithSameErasure(castType);
335             if (match != null) {
336                 return checkUnsafeCast(scope, castType, expressionType, match, false);
337             }
338             // recursively on the type variable upper bound
339
return checkCastTypesCompatibility(scope, castType, ((TypeVariableBinding)expressionType).upperBound(), expression);
340             
341         case Binding.WILDCARD_TYPE : // intersection type
342
match = expressionType.findSuperTypeWithSameErasure(castType);
343             if (match != null) {
344                 return checkUnsafeCast(scope, castType, expressionType, match, false);
345             }
346             // recursively on the type variable upper bound
347
return checkCastTypesCompatibility(scope, castType, ((WildcardBinding)expressionType).bound, expression);
348
349         default:
350             if (expressionType.isInterface()) {
351                 switch (castType.kind()) {
352                     case Binding.ARRAY_TYPE :
353                         // ( ARRAY ) INTERFACE
354
switch (expressionType.id) {
355                             case T_JavaLangCloneable :
356                             case T_JavaIoSerializable :
357                                 tagAsNeedCheckCast();
358                                 return true;
359                             default :
360                                 return false;
361                         }
362
363                     case Binding.TYPE_PARAMETER :
364                         // ( INTERFACE ) TYPE_PARAMETER
365
match = expressionType.findSuperTypeWithSameErasure(castType);
366                         if (match == null) {
367                             checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
368                         }
369                         // recurse on the type variable upper bound
370
return checkCastTypesCompatibility(scope, ((TypeVariableBinding)castType).upperBound(), expressionType, expression);
371
372                     default :
373                         if (castType.isInterface()) {
374                             // ( INTERFACE ) INTERFACE
375
ReferenceBinding interfaceType = (ReferenceBinding) expressionType;
376                             match = interfaceType.findSuperTypeWithSameErasure(castType);
377                             if (match != null) {
378                                 return checkUnsafeCast(scope, castType, interfaceType, match, false);
379                             }
380                             tagAsNeedCheckCast();
381                             match = castType.findSuperTypeWithSameErasure(interfaceType);
382                             if (match != null) {
383                                 return checkUnsafeCast(scope, castType, interfaceType, match, true);
384                             }
385                             if (use15specifics) {
386                                 checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
387                                 // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
388
if (interfaceType.hasIncompatibleSuperType((ReferenceBinding)castType))
389                                     return false;
390                             } else {
391                                 // pre1.5 semantics - no covariance allowed (even if 1.5 compliant, but 1.4 source)
392
MethodBinding[] castTypeMethods = getAllInheritedMethods((ReferenceBinding) castType);
393                                 MethodBinding[] expressionTypeMethods = getAllInheritedMethods((ReferenceBinding) expressionType);
394                                 int exprMethodsLength = expressionTypeMethods.length;
395                                 for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) {
396                                     for (int j = 0; j < exprMethodsLength; j++) {
397                                         if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
398                                                 && (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector))
399                                                 && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
400                                             return false;
401                 
402                                         }
403                                     }
404                                 }
405                             }
406                             return true;
407                         } else {
408                             // ( CLASS ) INTERFACE
409
if (castType.id == TypeIds.T_JavaLangObject) { // no runtime error
410
tagAsUnnecessaryCast(scope, castType);
411                                 return true;
412                             }
413                             // can only be a downcast
414
tagAsNeedCheckCast();
415                             match = castType.findSuperTypeWithSameErasure(expressionType);
416                             if (match != null) {
417                                 return checkUnsafeCast(scope, castType, expressionType, match, true);
418                             }
419                             if (((ReferenceBinding) castType).isFinal()) {
420                                 // no subclass for castType, thus compile-time check is invalid
421
return false;
422                             }
423                             if (use15specifics) {
424                                 checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
425                                 // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
426
if (((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType)) {
427                                     return false;
428                                 }
429                             }
430                             return true;
431                         }
432                 }
433             } else {
434                 switch (castType.kind()) {
435                     case Binding.ARRAY_TYPE :
436                         // ( ARRAY ) CLASS
437
if (expressionType.id == TypeIds.T_JavaLangObject) { // potential runtime error
438
if (use15specifics) checkUnsafeCast(scope, castType, expressionType, expressionType, true);
439                             tagAsNeedCheckCast();
440                             return true;
441                         }
442                         return false;
443                         
444                     case Binding.TYPE_PARAMETER :
445                         // ( TYPE_PARAMETER ) CLASS
446
match = expressionType.findSuperTypeWithSameErasure(castType);
447                         if (match == null) {
448                             checkUnsafeCast(scope, castType, expressionType, match, true);
449                         }
450                         // recurse on the type variable upper bound
451
return checkCastTypesCompatibility(scope, ((TypeVariableBinding)castType).upperBound(), expressionType, expression);
452                         
453                     default :
454                         if (castType.isInterface()) {
455                             // ( INTERFACE ) CLASS
456
ReferenceBinding refExprType = (ReferenceBinding) expressionType;
457                             match = refExprType.findSuperTypeWithSameErasure(castType);
458                             if (match != null) {
459                                 return checkUnsafeCast(scope, castType, expressionType, match, false);
460                             }
461                             // unless final a subclass may implement the interface ==> no check at compile time
462
if (refExprType.isFinal()) {
463                                 return false;
464                             }
465                             tagAsNeedCheckCast();
466                             match = castType.findSuperTypeWithSameErasure(expressionType);
467                             if (match != null) {
468                                 return checkUnsafeCast(scope, castType, expressionType, match, true);
469                             }
470                             if (use15specifics) {
471                                 checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
472                                 // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
473
if (refExprType.hasIncompatibleSuperType((ReferenceBinding) castType))
474                                     return false;
475                             }
476                             return true;
477                         } else {
478                             // ( CLASS ) CLASS
479
match = expressionType.findSuperTypeWithSameErasure(castType);
480                             if (match != null) {
481                                 if (expression != null && castType.id == TypeIds.T_JavaLangString) this.constant = expression.constant; // (String) cst is still a constant
482
return checkUnsafeCast(scope, castType, expressionType, match, false);
483                             }
484                             match = castType.findSuperTypeWithSameErasure(expressionType);
485                             if (match != null) {
486                                 tagAsNeedCheckCast();
487                                 return checkUnsafeCast(scope, castType, expressionType, match, true);
488                             }
489                             return false;
490                         }
491                 }
492             }
493     }
494 }
495     
496 /**
497  * Check the local variable of this expression, if any, against potential NPEs
498  * given a flow context and an upstream flow info. If so, report the risk to
499  * the context. Marks the local as checked, which affects the flow info.
500  * @param scope the scope of the analysis
501  * @param flowContext the current flow context
502  * @param flowInfo the upstream flow info; caveat: may get modified
503  */

504 public void checkNPE(BlockScope scope, FlowContext flowContext,
505         FlowInfo flowInfo) {
506     LocalVariableBinding local = this.localVariableBinding();
507     if (local != null &&
508             (local.type.tagBits & TagBits.IsBaseType) == 0) {
509         if ((this.bits & ASTNode.IsNonNull) == 0) {
510             flowContext.recordUsingNullReference(scope, local, this,
511                     FlowContext.MAY_NULL, flowInfo);
512         }
513         flowInfo.markAsComparedEqualToNonNull(local);
514             // from thereon it is set
515
if (flowContext.initsOnFinally != null) {
516             flowContext.initsOnFinally.markAsComparedEqualToNonNull(local);
517         }
518     }
519 }
520
521 public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
522         if (match == castType) {
523             if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
524             return true;
525         }
526         if (match != null && (
527                 castType.isBoundParameterizedType()
528                 || expressionType.isBoundParameterizedType())) {
529             
530             if (match.isProvablyDistinctFrom(isNarrowing ? expressionType : castType, 0)) {
531                 return false;
532             }
533         }
534         if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
535         return true;
536     }
537     /**
538      * Base types need that the widening is explicitly done by the compiler using some bytecode like i2f.
539      * Also check unsafe type operations.
540      */

541     public void computeConversion(Scope scope, TypeBinding runtimeType, TypeBinding compileTimeType) {
542
543         if (runtimeType == null || compileTimeType == null)
544             return;
545         if (this.implicitConversion != 0) return; // already set independantly
546

547         // it is possible for a Byte to be unboxed to a byte & then converted to an int
548
// but it is not possible for a byte to become Byte & then assigned to an Integer,
549
// or to become an int before boxed into an Integer
550
if (runtimeType != TypeBinding.NULL && runtimeType.isBaseType()) {
551             if (!compileTimeType.isBaseType()) {
552                 TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType);
553                 this.implicitConversion = TypeIds.UNBOXING;
554                 scope.problemReporter().autoboxing(this, compileTimeType, runtimeType);
555                 compileTimeType = unboxedType;
556             }
557         } else if (compileTimeType != TypeBinding.NULL && compileTimeType.isBaseType()) {
558             TypeBinding boxedType = scope.environment().computeBoxingType(runtimeType);
559             if (boxedType == runtimeType) // Object o = 12;
560
boxedType = compileTimeType;
561             this.implicitConversion = TypeIds.BOXING | (boxedType.id << 4) + compileTimeType.id;
562             scope.problemReporter().autoboxing(this, compileTimeType, scope.environment().computeBoxingType(boxedType));
563             return;
564         } else if (this.constant != Constant.NotAConstant && this.constant.typeID() != TypeIds.T_JavaLangString) {
565             this.implicitConversion = TypeIds.BOXING;
566             return;
567         }
568         int compileTimeTypeID, runtimeTypeID;
569         if ((compileTimeTypeID = compileTimeType.id) == TypeIds.NoId) { // e.g. ? extends String ==> String (103227)
570
compileTimeTypeID = compileTimeType.erasure().id == TypeIds.T_JavaLangString ? TypeIds.T_JavaLangString : TypeIds.T_JavaLangObject;
571         }
572         switch (runtimeTypeID = runtimeType.id) {
573             case T_byte :
574             case T_short :
575             case T_char :
576                 this.implicitConversion |= (TypeIds.T_int << 4) + compileTimeTypeID;
577                 break;
578             case T_JavaLangString :
579             case T_float :
580             case T_boolean :
581             case T_double :
582             case T_int : //implicitConversion may result in i2i which will result in NO code gen
583
case T_long :
584                 this.implicitConversion |= (runtimeTypeID << 4) + compileTimeTypeID;
585                 break;
586             default : // regular object ref
587
// if (compileTimeType.isRawType() && runtimeTimeType.isBoundParameterizedType()) {
588
// scope.problemReporter().unsafeRawExpression(this, compileTimeType, runtimeTimeType);
589
// }
590
}
591     }
592
593     /**
594      * Expression statements are plain expressions, however they generate like
595      * normal expressions with no value required.
596      *
597      * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
598      * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
599      */

600     public void generateCode(BlockScope currentScope, CodeStream codeStream) {
601
602         if ((this.bits & ASTNode.IsReachable) == 0) {
603             return;
604         }
605         generateCode(currentScope, codeStream, false);
606     }
607     
608     /**
609      * Every expression is responsible for generating its implicit conversion when necessary.
610      *
611      * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
612      * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
613      * @param valueRequired boolean
614      */

615     public void generateCode(
616         BlockScope currentScope,
617         CodeStream codeStream,
618         boolean valueRequired) {
619
620         if (this.constant != Constant.NotAConstant) {
621             // generate a constant expression
622
int pc = codeStream.position;
623             codeStream.generateConstant(this.constant, this.implicitConversion);
624             codeStream.recordPositionsFrom(pc, this.sourceStart);
625         } else {
626             // actual non-constant code generation
627
throw new ShouldNotImplement(Messages.ast_missingCode);
628         }
629     }
630     
631     /**
632      * Default generation of a boolean value
633      * @param currentScope
634      * @param codeStream
635      * @param trueLabel
636      * @param falseLabel
637      * @param valueRequired
638      */

639     public void generateOptimizedBoolean(
640             BlockScope currentScope,
641             CodeStream codeStream,
642             BranchLabel trueLabel,
643             BranchLabel falseLabel,
644             boolean valueRequired) {
645
646         // a label valued to nil means: by default we fall through the case...
647
// both nil means we leave the value on the stack
648

649         Constant cst = this.optimizedBooleanConstant();
650         generateCode(currentScope, codeStream, valueRequired && cst == Constant.NotAConstant);
651         if ((cst != Constant.NotAConstant) && (cst.typeID() == TypeIds.T_boolean)) {
652             int pc = codeStream.position;
653             if (cst.booleanValue() == true) {
654                 // constant == true
655
if (valueRequired) {
656                     if (falseLabel == null) {
657                         // implicit falling through the FALSE case
658
if (trueLabel != null) {
659                             codeStream.goto_(trueLabel);
660                         }
661                     }
662                 }
663             } else {
664                 if (valueRequired) {
665                     if (falseLabel != null) {
666                         // implicit falling through the TRUE case
667
if (trueLabel == null) {
668                             codeStream.goto_(falseLabel);
669                         }
670                     }
671                 }
672             }
673             codeStream.recordPositionsFrom(pc, this.sourceStart);
674             return;
675         }
676         // branching
677
int position = codeStream.position;
678         if (valueRequired) {
679             if (falseLabel == null) {
680                 if (trueLabel != null) {
681                     // Implicit falling through the FALSE case
682
codeStream.ifne(trueLabel);
683                 }
684             } else {
685                 if (trueLabel == null) {
686                     // Implicit falling through the TRUE case
687
codeStream.ifeq(falseLabel);
688                 } else {
689                     // No implicit fall through TRUE/FALSE --> should never occur
690
}
691             }
692         }
693         // reposition the endPC
694
codeStream.updateLastRecordedEndPC(currentScope, position);
695     }
696
697     /* Optimized (java) code generation for string concatenations that involve StringBuffer
698      * creation: going through this path means that there is no need for a new StringBuffer
699      * creation, further operands should rather be only appended to the current one.
700      * By default: no optimization.
701      */

702     public void generateOptimizedStringConcatenation(
703         BlockScope blockScope,
704         CodeStream codeStream,
705         int typeID) {
706
707         if (typeID == TypeIds.T_JavaLangString && this.constant != Constant.NotAConstant && this.constant.stringValue().length() == 0) {
708             return; // optimize str + ""
709
}
710         generateCode(blockScope, codeStream, true);
711         codeStream.invokeStringConcatenationAppendForType(typeID);
712     }
713
714     /* Optimized (java) code generation for string concatenations that involve StringBuffer
715      * creation: going through this path means that there is no need for a new StringBuffer
716      * creation, further operands should rather be only appended to the current one.
717      */

718     public void generateOptimizedStringConcatenationCreation(
719         BlockScope blockScope,
720         CodeStream codeStream,
721         int typeID) {
722
723         codeStream.newStringContatenation();
724         codeStream.dup();
725         switch (typeID) {
726             case T_JavaLangObject :
727             case T_undefined :
728                 // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
729
// append(Object) returns append(valueOf(Object)), which means that the null case is handled by the next case.
730
codeStream.invokeStringConcatenationDefaultConstructor();
731                 generateCode(blockScope, codeStream, true);
732                 codeStream.invokeStringConcatenationAppendForType(TypeIds.T_JavaLangObject);
733                 return;
734             case T_JavaLangString :
735             case T_null :
736                 if (this.constant != Constant.NotAConstant) {
737                     String JavaDoc stringValue = this.constant.stringValue();
738                     if (stringValue.length() == 0) { // optimize ""+<str>
739
codeStream.invokeStringConcatenationDefaultConstructor();
740                         return;
741                     }
742                     codeStream.ldc(stringValue);
743                 } else {
744                     // null case is not a constant
745
generateCode(blockScope, codeStream, true);
746                     codeStream.invokeStringValueOf(TypeIds.T_JavaLangObject);
747                 }
748                 break;
749             default :
750                 generateCode(blockScope, codeStream, true);
751                 codeStream.invokeStringValueOf(typeID);
752         }
753         codeStream.invokeStringConcatenationStringConstructor();
754     }
755
756     private MethodBinding[] getAllInheritedMethods(ReferenceBinding binding) {
757         ArrayList JavaDoc collector = new ArrayList JavaDoc();
758         getAllInheritedMethods0(binding, collector);
759         return (MethodBinding[]) collector.toArray(new MethodBinding[collector.size()]);
760     }
761
762     private void getAllInheritedMethods0(ReferenceBinding binding, ArrayList JavaDoc collector) {
763         if (!binding.isInterface()) return;
764         MethodBinding[] methodBindings = binding.methods();
765         for (int i = 0, max = methodBindings.length; i < max; i++) {
766             collector.add(methodBindings[i]);
767         }
768         ReferenceBinding[] superInterfaces = binding.superInterfaces();
769         for (int i = 0, max = superInterfaces.length; i < max; i++) {
770             getAllInheritedMethods0(superInterfaces[i], collector);
771         }
772     }
773     
774     public boolean isCompactableOperation() {
775
776         return false;
777     }
778
779     //Return true if the conversion is done AUTOMATICALLY by the vm
780
//while the javaVM is an int based-machine, thus for example pushing
781
//a byte onto the stack , will automatically create an int on the stack
782
//(this request some work d be done by the VM on signed numbers)
783
public boolean isConstantValueOfTypeAssignableToType(TypeBinding constantType, TypeBinding targetType) {
784
785         if (this.constant == Constant.NotAConstant)
786             return false;
787         if (constantType == targetType)
788             return true;
789         if (constantType.isBaseType() && targetType.isBaseType()) {
790             //No free assignment conversion from anything but to integral ones.
791
if ((constantType == TypeBinding.INT
792                 || BaseTypeBinding.isWidening(TypeIds.T_int, constantType.id))
793                 && (BaseTypeBinding.isNarrowing(targetType.id, TypeIds.T_int))) {
794                 //use current explicit conversion in order to get some new value to compare with current one
795
return isConstantValueRepresentable(this.constant, constantType.id, targetType.id);
796             }
797         }
798         return false;
799     }
800
801     public boolean isTypeReference() {
802         return false;
803     }
804
805     /**
806      * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference)
807      * or thru a cast expression etc...
808      */

809     public LocalVariableBinding localVariableBinding() {
810         return null;
811     }
812     
813 /**
814  * Mark this expression as being non null, per a specific tag in the
815  * source code.
816  */

817 // this is no more called for now, waiting for inter procedural null reference analysis
818
public void markAsNonNull() {
819     this.bits |= ASTNode.IsNonNull;
820 }
821
822     public int nullStatus(FlowInfo flowInfo) {
823         
824         if (/* (this.bits & IsNonNull) != 0 || */
825                 this.constant != null && this.constant != Constant.NotAConstant)
826             return FlowInfo.NON_NULL; // constant expression cannot be null
827

828         LocalVariableBinding local = localVariableBinding();
829         if (local != null) {
830             if (flowInfo.isDefinitelyNull(local))
831                 return FlowInfo.NULL;
832             if (flowInfo.isDefinitelyNonNull(local))
833                 return FlowInfo.NON_NULL;
834             return FlowInfo.UNKNOWN;
835         }
836         return FlowInfo.NON_NULL;
837     }
838     
839     /**
840      * Constant usable for bytecode pattern optimizations, but cannot be inlined
841      * since it is not strictly equivalent to the definition of constant expressions.
842      * In particular, some side-effects may be required to occur (only the end value
843      * is known).
844      * @return Constant known to be of boolean type
845      */

846     public Constant optimizedBooleanConstant() {
847         return this.constant;
848     }
849
850     /**
851      * Returns the type of the expression after required implicit conversions. When expression type gets promoted
852      * or inserted a generic cast, the converted type will differ from the resolved type (surface side-effects from
853      * #computeConversion(...)).
854      * @return the type after implicit conversion
855      */

856     public TypeBinding postConversionType(Scope scope) {
857         TypeBinding convertedType = this.resolvedType;
858         int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
859         switch (runtimeType) {
860             case T_boolean :
861                 convertedType = TypeBinding.BOOLEAN;
862                 break;
863             case T_byte :
864                 convertedType = TypeBinding.BYTE;
865                 break;
866             case T_short :
867                 convertedType = TypeBinding.SHORT;
868                 break;
869             case T_char :
870                 convertedType = TypeBinding.CHAR;
871                 break;
872             case T_int :
873                 convertedType = TypeBinding.INT;
874                 break;
875             case T_float :
876                 convertedType = TypeBinding.FLOAT;
877                 break;
878             case T_long :
879                 convertedType = TypeBinding.LONG;
880                 break;
881             case T_double :
882                 convertedType = TypeBinding.DOUBLE;
883                 break;
884             default :
885         }
886         if ((this.implicitConversion & TypeIds.BOXING) != 0) {
887             convertedType = scope.environment().computeBoxingType(convertedType);
888         }
889         return convertedType;
890     }
891
892     public StringBuffer JavaDoc print(int indent, StringBuffer JavaDoc output) {
893         printIndent(indent, output);
894         return printExpression(indent, output);
895     }
896     
897     public abstract StringBuffer JavaDoc printExpression(int indent, StringBuffer JavaDoc output);
898
899     public StringBuffer JavaDoc printStatement(int indent, StringBuffer JavaDoc output) {
900         return print(indent, output).append(";"); //$NON-NLS-1$
901
}
902
903     public void resolve(BlockScope scope) {
904         // drops the returning expression's type whatever the type is.
905

906         this.resolveType(scope);
907         return;
908     }
909
910     /**
911      * Resolve the type of this expression in the context of a blockScope
912      *
913      * @param scope
914      * @return
915      * Return the actual type of this expression after resolution
916      */

917     public TypeBinding resolveType(BlockScope scope) {
918         // by default... subclasses should implement a better TB if required.
919
return null;
920     }
921
922     /**
923      * Resolve the type of this expression in the context of a classScope
924      *
925      * @param scope
926      * @return
927      * Return the actual type of this expression after resolution
928      */

929     public TypeBinding resolveType(ClassScope scope) {
930         // by default... subclasses should implement a better TB if required.
931
return null;
932     }
933
934     public TypeBinding resolveTypeExpecting(
935         BlockScope scope,
936         TypeBinding expectedType) {
937
938         this.setExpectedType(expectedType); // needed in case of generic method invocation
939
TypeBinding expressionType = this.resolveType(scope);
940         if (expressionType == null) return null;
941         if (expressionType == expectedType) return expressionType;
942         
943         if (!expressionType.isCompatibleWith(expectedType)) {
944             if (scope.isBoxingCompatibleWith(expressionType, expectedType)) {
945                 this.computeConversion(scope, expectedType, expressionType);
946             } else {
947                 scope.problemReporter().typeMismatchError(expressionType, expectedType, this);
948                 return null;
949             }
950         }
951         return expressionType;
952     }
953
954     /**
955      * Returns an object which can be used to identify identical JSR sequence targets
956      * (see TryStatement subroutine codegen)
957      * or <code>null</null> if not reusable
958      */

959     public Object JavaDoc reusableJSRTarget() {
960         if (this.constant != Constant.NotAConstant)
961             return this.constant;
962         return null;
963     }
964     
965     /**
966      * Record the type expectation before this expression is typechecked.
967      * e.g. String s = foo();, foo() will be tagged as being expected of type String
968      * Used to trigger proper inference of generic method invocations.
969      *
970      * @param expectedType
971      * The type denoting an expectation in the context of an assignment conversion
972      */

973     public void setExpectedType(TypeBinding expectedType) {
974         // do nothing by default
975
}
976     
977     public void tagAsNeedCheckCast() {
978         // do nothing by default
979
}
980     
981     /**
982      * Record the fact a cast expression got detected as being unnecessary.
983      *
984      * @param scope
985      * @param castType
986      */

987     public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
988         // do nothing by default
989
}
990     
991     public Expression toTypeReference() {
992         //by default undefined
993

994         //this method is meanly used by the parser in order to transform
995
//an expression that is used as a type reference in a cast ....
996
//--appreciate the fact that castExpression and ExpressionWithParenthesis
997
//--starts with the same pattern.....
998

999         return this;
1000    }
1001    
1002    /**
1003     * Traverse an expression in the context of a blockScope
1004     * @param visitor
1005     * @param scope
1006     */

1007    public void traverse(ASTVisitor visitor, BlockScope scope) {
1008        // nothing to do
1009
}
1010    
1011    /**
1012     * Traverse an expression in the context of a classScope
1013     * @param visitor
1014     * @param scope
1015     */

1016    public void traverse(ASTVisitor visitor, ClassScope scope) {
1017        // nothing to do
1018
}
1019}
1020
Popular Tags