added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / Expression.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import java.util.ArrayList;
14
15 import org.eclipse.jdt.core.compiler.CharOperation;
16 import org.eclipse.jdt.internal.compiler.ASTVisitor;
17 import org.eclipse.jdt.internal.compiler.impl.*;
18 import org.eclipse.jdt.internal.compiler.codegen.*;
19 import org.eclipse.jdt.internal.compiler.flow.*;
20 import org.eclipse.jdt.internal.compiler.lookup.*;
21 import org.eclipse.jdt.internal.compiler.problem.*;
22 import org.eclipse.jdt.internal.compiler.util.Util;
23
24 public abstract class Expression extends Statement {
25         
26         public static final boolean isConstantValueRepresentable(
27                 Constant constant,
28                 int constantTypeID,
29                 int targetTypeID) {
30
31                 //true if there is no loss of precision while casting.
32                 // constantTypeID == constant.typeID
33                 if (targetTypeID == constantTypeID)
34                         return true;
35                 switch (targetTypeID) {
36                         case T_char :
37                                 switch (constantTypeID) {
38                                         case T_char :
39                                                 return true;
40                                         case T_double :
41                                                 return constant.doubleValue() == constant.charValue();
42                                         case T_float :
43                                                 return constant.floatValue() == constant.charValue();
44                                         case T_int :
45                                                 return constant.intValue() == constant.charValue();
46                                         case T_short :
47                                                 return constant.shortValue() == constant.charValue();
48                                         case T_byte :
49                                                 return constant.byteValue() == constant.charValue();
50                                         case T_long :
51                                                 return constant.longValue() == constant.charValue();
52                                         default :
53                                                 return false;//boolean
54                                 } 
55
56                         case T_float :
57                                 switch (constantTypeID) {
58                                         case T_char :
59                                                 return constant.charValue() == constant.floatValue();
60                                         case T_double :
61                                                 return constant.doubleValue() == constant.floatValue();
62                                         case T_float :
63                                                 return true;
64                                         case T_int :
65                                                 return constant.intValue() == constant.floatValue();
66                                         case T_short :
67                                                 return constant.shortValue() == constant.floatValue();
68                                         case T_byte :
69                                                 return constant.byteValue() == constant.floatValue();
70                                         case T_long :
71                                                 return constant.longValue() == constant.floatValue();
72                                         default :
73                                                 return false;//boolean
74                                 } 
75                                 
76                         case T_double :
77                                 switch (constantTypeID) {
78                                         case T_char :
79                                                 return constant.charValue() == constant.doubleValue();
80                                         case T_double :
81                                                 return true;
82                                         case T_float :
83                                                 return constant.floatValue() == constant.doubleValue();
84                                         case T_int :
85                                                 return constant.intValue() == constant.doubleValue();
86                                         case T_short :
87                                                 return constant.shortValue() == constant.doubleValue();
88                                         case T_byte :
89                                                 return constant.byteValue() == constant.doubleValue();
90                                         case T_long :
91                                                 return constant.longValue() == constant.doubleValue();
92                                         default :
93                                                 return false; //boolean
94                                 } 
95                                 
96                         case T_byte :
97                                 switch (constantTypeID) {
98                                         case T_char :
99                                                 return constant.charValue() == constant.byteValue();
100                                         case T_double :
101                                                 return constant.doubleValue() == constant.byteValue();
102                                         case T_float :
103                                                 return constant.floatValue() == constant.byteValue();
104                                         case T_int :
105                                                 return constant.intValue() == constant.byteValue();
106                                         case T_short :
107                                                 return constant.shortValue() == constant.byteValue();
108                                         case T_byte :
109                                                 return true;
110                                         case T_long :
111                                                 return constant.longValue() == constant.byteValue();
112                                         default :
113                                                 return false; //boolean
114                                 } 
115                                 
116                         case T_short :
117                                 switch (constantTypeID) {
118                                         case T_char :
119                                                 return constant.charValue() == constant.shortValue();
120                                         case T_double :
121                                                 return constant.doubleValue() == constant.shortValue();
122                                         case T_float :
123                                                 return constant.floatValue() == constant.shortValue();
124                                         case T_int :
125                                                 return constant.intValue() == constant.shortValue();
126                                         case T_short :
127                                                 return true;
128                                         case T_byte :
129                                                 return constant.byteValue() == constant.shortValue();
130                                         case T_long :
131                                                 return constant.longValue() == constant.shortValue();
132                                         default :
133                                                 return false; //boolean
134                                 } 
135                                 
136                         case T_int :
137                                 switch (constantTypeID) {
138                                         case T_char :
139                                                 return constant.charValue() == constant.intValue();
140                                         case T_double :
141                                                 return constant.doubleValue() == constant.intValue();
142                                         case T_float :
143                                                 return constant.floatValue() == constant.intValue();
144                                         case T_int :
145                                                 return true;
146                                         case T_short :
147                                                 return constant.shortValue() == constant.intValue();
148                                         case T_byte :
149                                                 return constant.byteValue() == constant.intValue();
150                                         case T_long :
151                                                 return constant.longValue() == constant.intValue();
152                                         default :
153                                                 return false; //boolean
154                                 } 
155                                 
156                         case T_long :
157                                 switch (constantTypeID) {
158                                         case T_char :
159                                                 return constant.charValue() == constant.longValue();
160                                         case T_double :
161                                                 return constant.doubleValue() == constant.longValue();
162                                         case T_float :
163                                                 return constant.floatValue() == constant.longValue();
164                                         case T_int :
165                                                 return constant.intValue() == constant.longValue();
166                                         case T_short :
167                                                 return constant.shortValue() == constant.longValue();
168                                         case T_byte :
169                                                 return constant.byteValue() == constant.longValue();
170                                         case T_long :
171                                                 return true;
172                                         default :
173                                                 return false; //boolean
174                                 } 
175                                 
176                         default :
177                                 return false; //boolean
178                 } 
179         }
180         
181         public Constant constant;
182         
183         //Some expression may not be used - from a java semantic point
184         //of view only - as statements. Other may. In order to avoid the creation
185         //of wrappers around expression in order to tune them as expression
186         //Expression is a subclass of Statement. See the message isValidJavaStatement()
187
188         public int implicitConversion;
189         public TypeBinding resolvedType;
190
191         public Expression() {
192                 super();
193         }
194
195         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
196
197                 return flowInfo;
198         }
199
200         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) {
201
202                 return analyseCode(currentScope, flowContext, flowInfo);
203         }
204
205         /**
206          * Returns false if cast is not legal. 
207          */
208         public final boolean checkCastTypesCompatibility(
209                 Scope scope,
210                 TypeBinding castType,
211                 TypeBinding expressionType,
212                 Expression expression) {
213         
214                 // see specifications 5.5
215                 // handle errors and process constant when needed
216         
217                 // if either one of the type is null ==>
218                 // some error has been already reported some where ==>
219                 // we then do not report an obvious-cascade-error.
220         
221                 if (castType == null || expressionType == null) return true;
222         
223                 // identity conversion cannot be performed upfront, due to side-effects
224                 // like constant propagation
225                 LookupEnvironment env = scope.environment();
226                 boolean use15specifics = env.options.sourceLevel >= JDK1_5;
227                 if (castType.isBaseType()) {
228                         if (expressionType.isBaseType()) {
229                                 if (expressionType == castType) {
230                                         if (expression != null) {
231                                                 this.constant = expression.constant; //use the same constant
232                                         }
233                                         tagAsUnnecessaryCast(scope, castType);
234                                         return true;
235                                 }
236                                 boolean necessary = false;
237                                 if (expressionType.isCompatibleWith(castType)
238                                                 || (necessary = BaseTypeBinding.isNarrowing(castType.id, expressionType.id))) {
239                                         if (expression != null) {
240                                                 expression.implicitConversion = (castType.id << 4) + expressionType.id;
241                                                 if (expression.constant != Constant.NotAConstant) {
242                                                         constant = expression.constant.castTo(expression.implicitConversion);
243                                                 }
244                                         }
245                                         if (!necessary) tagAsUnnecessaryCast(scope, castType);
246                                         return true;
247                                         
248                                 }
249                         } else if (use15specifics) { // unboxing - only exact match is allowed
250                                 if (env.computeBoxingType(expressionType) == castType) {
251                                         // TODO (philippe) could tagAsUnnecessaryCast(scope, castType);  
252                                         return true;
253                                 }
254                         }
255                         reportIllegalCast(scope, castType, expressionType);
256                         return false;
257                 } else if (use15specifics && expressionType.isBaseType()) { // boxing - only exact match is allowed
258                         if (env.computeBoxingType(castType) == expressionType) {
259                                 // TODO (philippe) could tagAsUnnecessaryCast(scope, castType);  
260                                 return true;
261                         }
262                 }
263         
264                 //-----------cast to something which is NOT a base type--------------------------       
265                 if (expressionType == NullBinding) {
266                         tagAsUnnecessaryCast(scope, castType);
267                         return true; //null is compatible with every thing
268                 }
269                 if (expressionType.isBaseType()) {
270                         reportIllegalCast(scope, castType, expressionType);
271                         return false;
272                 }
273         
274                 if (expressionType.isArrayType()) {
275                         if (castType == expressionType) {
276                                 tagAsUnnecessaryCast(scope, castType);
277                                 return true; // identity conversion
278                         }
279         
280                         if (castType.isArrayType()) {
281                                 //------- (castType.isArray) expressionType.isArray -----------
282                                 TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType();
283                                 if (exprElementType.isBaseType()) {
284                                         // <---stop the recursion------- 
285                                         if (((ArrayBinding) castType).elementsType() == exprElementType) {
286                                                 tagAsNeedCheckCast();
287                                                 return true;
288                                         } else {
289                                                 reportIllegalCast(scope, castType, expressionType);
290                                                 return false;
291                                         }
292                                 }
293                                 // recursively on the elements...
294                                 return checkCastTypesCompatibility(
295                                         scope,
296                                         ((ArrayBinding) castType).elementsType(),
297                                         exprElementType,
298                                         expression);
299                         } else if (
300                                 castType.isClass()) {
301                                 //------(castType.isClass) expressionType.isArray ---------------       
302                                 if (castType.id == T_JavaLangObject) {
303                                         tagAsUnnecessaryCast(scope, castType);
304                                         return true;
305                                 }
306                         } else { //------- (castType.isInterface) expressionType.isArray -----------
307                                 if (castType.id == T_JavaLangCloneable || castType.id == T_JavaIoSerializable) {
308                                         tagAsNeedCheckCast();
309                                         return true;
310                                 }
311                         }
312                         reportIllegalCast(scope, castType, expressionType);
313                         return false;
314                 }
315         
316                 if (expressionType.isClass()) {
317                         if (castType.isArrayType()) {
318                                 // ---- (castType.isArray) expressionType.isClass -------
319                                 if (expressionType.id == T_JavaLangObject) { // potential runtime error
320                                         tagAsNeedCheckCast();
321                                         return true;
322                                 }
323                         } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isClass ------
324                                 
325                                 ReferenceBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType.erasure());
326                                 if (match != null) {
327                                         if (expression != null && castType.id == T_JavaLangString) this.constant = expression.constant; // (String) cst is still a constant
328                                         return checkUnsafeCast(scope, castType, expressionType, match, false);
329                                 }
330                                 match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
331                                 if (match != null) {
332                                         tagAsNeedCheckCast();
333                                         return checkUnsafeCast(scope, castType, expressionType, match, true);
334                                 }
335                         } else { // ----- (castType.isInterface) expressionType.isClass -------  
336
337                                 ReferenceBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType.erasure());
338                                 if (match != null) {
339                                         return checkUnsafeCast(scope, castType, expressionType, match, false);
340                                 }
341                                 // a subclass may implement the interface ==> no check at compile time
342                                 if (!((ReferenceBinding) expressionType).isFinal()) {
343                                         tagAsNeedCheckCast();
344                                         match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
345                                         if (match != null) {
346                                                 return checkUnsafeCast(scope, castType, expressionType, match, true);
347                                         }
348                                         return true;
349                                 }
350                                 // no subclass for expressionType, thus compile-time check is valid
351                         }
352                         reportIllegalCast(scope, castType, expressionType);
353                         return false;
354                 }
355         
356                 //      if (expressionType.isInterface()) { cannot be anything else
357                 if (castType.isArrayType()) {
358                         // ----- (castType.isArray) expressionType.isInterface ------
359                         if (expressionType.id == T_JavaLangCloneable
360                                         || expressionType.id == T_JavaIoSerializable) {// potential runtime error
361                                 tagAsNeedCheckCast();
362                                 return true;
363                         } else {
364                                 reportIllegalCast(scope, castType, expressionType);
365                                 return false;
366                         }
367                 } else if (castType.isClass()) { // ----- (castType.isClass) expressionType.isInterface --------
368
369                         if (castType.id == T_JavaLangObject) { // no runtime error
370                                 tagAsUnnecessaryCast(scope, castType);
371                                 return true;
372                         }
373                         if (((ReferenceBinding) castType).isFinal()) {
374                                 // no subclass for castType, thus compile-time check is valid
375                                 ReferenceBinding match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
376                                 if (match == null) {
377                                         // potential runtime error
378                                         reportIllegalCast(scope, castType, expressionType);
379                                         return false;
380                                 }                               
381                         }
382                 } else { // ----- (castType.isInterface) expressionType.isInterface -------
383
384                         ReferenceBinding match = ((ReferenceBinding)expressionType).findSuperTypeErasingTo((ReferenceBinding)castType.erasure());
385                         if (match != null) {
386                                 return checkUnsafeCast(scope, castType, expressionType, match, false);
387                         }
388                         
389                         match = ((ReferenceBinding)castType).findSuperTypeErasingTo((ReferenceBinding)expressionType.erasure());
390                         if (match != null) {
391                                 tagAsNeedCheckCast();
392                                 return checkUnsafeCast(scope, castType, expressionType, match, true);
393                         }  else {
394                                 MethodBinding[] castTypeMethods = getAllInheritedMethods((ReferenceBinding) castType);
395                                 MethodBinding[] expressionTypeMethods =
396                                         getAllInheritedMethods((ReferenceBinding) expressionType);
397                                 int exprMethodsLength = expressionTypeMethods.length;
398                                 for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) {
399                                         for (int j = 0; j < exprMethodsLength; j++) {
400                                                 if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
401                                                                 && (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector))
402                                                                 && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) {
403                                                         reportIllegalCast(scope, castType, expressionType);
404                                                         return false;
405
406                                                 }
407                                         }
408                                 }
409                         }
410                 }
411                 tagAsNeedCheckCast();
412                 return true;
413         }       
414         
415         public FlowInfo checkNullStatus(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int nullStatus) {
416
417                 LocalVariableBinding local = this.localVariableBinding();
418                 if (local != null) {
419                         switch(nullStatus) {
420                                 case FlowInfo.NULL :
421                                         flowContext.recordUsingNullReference(scope, local, this, FlowInfo.NULL, flowInfo);
422                                         flowInfo.markAsDefinitelyNull(local); // from thereon it is set
423                                         break;
424                                 case FlowInfo.NON_NULL :
425                                         flowContext.recordUsingNullReference(scope, local, this, FlowInfo.NON_NULL, flowInfo);
426                                         flowInfo.markAsDefinitelyNonNull(local); // from thereon it is set
427                                         break;
428                                 case FlowInfo.UNKNOWN :
429                                         break;
430                         }
431                 }
432                 return flowInfo;
433         }
434
435         private MethodBinding[] getAllInheritedMethods(ReferenceBinding binding) {
436                 ArrayList collector = new ArrayList();
437                 getAllInheritedMethods0(binding, collector);
438                 return (MethodBinding[]) collector.toArray(new MethodBinding[collector.size()]);
439         }
440         
441         private void getAllInheritedMethods0(ReferenceBinding binding, ArrayList collector) {
442                 if (!binding.isInterface()) return;
443                 MethodBinding[] methodBindings = binding.methods();
444                 for (int i = 0, max = methodBindings.length; i < max; i++) {
445                         collector.add(methodBindings[i]);
446                 }
447                 ReferenceBinding[] superInterfaces = binding.superInterfaces();
448                 for (int i = 0, max = superInterfaces.length; i < max; i++) {
449                         getAllInheritedMethods0(superInterfaces[i], collector);
450                 }
451         }
452         public void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
453                 // do nothing by default - see EqualExpression
454         }
455
456         public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) {
457                 if (match == castType) {
458                         if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
459                         return true;
460                 }
461                 if (castType.isBoundParameterizedType() || castType.isGenericType()) {
462                         if (match.isProvablyDistinctFrom(isNarrowing ? expressionType : castType, 0)) {
463                                 reportIllegalCast(scope, castType, expressionType);
464                                 return false; 
465                         }
466                 }
467                 if (!isNarrowing) tagAsUnnecessaryCast(scope, castType);
468                 return true;
469         }
470         
471         /**
472          * Base types need that the widening is explicitly done by the compiler using some bytecode like i2f.
473          * Also check unsafe type operations.
474          */ 
475         public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
476
477                 if (runtimeTimeType == null || compileTimeType == null)
478                         return;
479                 if (this.implicitConversion != 0) return; // already set independantly
480
481                 // it is possible for a Byte to be unboxed to a byte & then converted to an int
482                 // but it is not possible for a byte to become Byte & then assigned to an Integer,
483                 // or to become an int before boxed into an Integer
484                 if (runtimeTimeType != NullBinding && runtimeTimeType.isBaseType()) {
485                         if (!compileTimeType.isBaseType()) {
486                                 compileTimeType = scope.environment().computeBoxingType(compileTimeType);
487                                 this.implicitConversion = UNBOXING;
488                         }
489                 } else {
490                         if (compileTimeType != NullBinding && compileTimeType.isBaseType()) {
491                                 TypeBinding boxedType = scope.environment().computeBoxingType(runtimeTimeType);
492                                 if (boxedType == runtimeTimeType) // Object o = 12;
493                                         boxedType = compileTimeType; 
494                                 this.implicitConversion = BOXING | (boxedType.id << 4) + compileTimeType.id;
495                                 return;
496                         }
497                 }
498
499                 switch (runtimeTimeType.id) {
500                         case T_byte :
501                         case T_short :
502                         case T_char :
503                                 this.implicitConversion |= (T_int << 4) + compileTimeType.id;
504                                 break;
505                         case T_JavaLangString :
506                         case T_float :
507                         case T_boolean :
508                         case T_double :
509                         case T_int : //implicitConversion may result in i2i which will result in NO code gen
510                         case T_long :
511                                 this.implicitConversion |= (runtimeTimeType.id << 4) + compileTimeType.id;
512                                 break;
513                         default : // regular object ref
514 //                              if (compileTimeType.isRawType() && runtimeTimeType.isBoundParameterizedType()) {
515 //                                  scope.problemReporter().unsafeRawExpression(this, compileTimeType, runtimeTimeType);
516 //                              }               
517                 }
518         }       
519         /**
520          * Expression statements are plain expressions, however they generate like
521          * normal expressions with no value required.
522          *
523          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
524          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream 
525          */
526         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
527
528                 if ((bits & IsReachableMASK) == 0) {
529                         return;
530                 }
531                 generateCode(currentScope, codeStream, false);
532         }
533
534         /**
535          * Every expression is responsible for generating its implicit conversion when necessary.
536          *
537          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
538          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
539          * @param valueRequired boolean
540          */
541         public void generateCode(
542                 BlockScope currentScope,
543                 CodeStream codeStream,
544                 boolean valueRequired) {
545
546                 if (constant != NotAConstant) {
547                         // generate a constant expression
548                         int pc = codeStream.position;
549                         codeStream.generateConstant(constant, implicitConversion);
550                         codeStream.recordPositionsFrom(pc, this.sourceStart);
551                 } else {
552                         // actual non-constant code generation
553                         throw new ShouldNotImplement(Util.bind("ast.missingCode")); //$NON-NLS-1$
554                 }
555         }
556
557         /**
558          * Default generation of a boolean value
559          * @param currentScope
560          * @param codeStream
561          * @param trueLabel
562          * @param falseLabel
563          * @param valueRequired
564          */
565         public void generateOptimizedBoolean(
566                 BlockScope currentScope,
567                 CodeStream codeStream,
568                 Label trueLabel,
569                 Label falseLabel,
570                 boolean valueRequired) {
571
572                 // a label valued to nil means: by default we fall through the case... 
573                 // both nil means we leave the value on the stack
574
575                 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
576                         int pc = codeStream.position;
577                         if (constant.booleanValue() == true) {
578                                 // constant == true
579                                 if (valueRequired) {
580                                         if (falseLabel == null) {
581                                                 // implicit falling through the FALSE case
582                                                 if (trueLabel != null) {
583                                                         codeStream.goto_(trueLabel);
584                                                 }
585                                         }
586                                 }
587                         } else {
588                                 if (valueRequired) {
589                                         if (falseLabel != null) {
590                                                 // implicit falling through the TRUE case
591                                                 if (trueLabel == null) {
592                                                         codeStream.goto_(falseLabel);
593                                                 }
594                                         }
595                                 }
596                         }
597                         codeStream.recordPositionsFrom(pc, this.sourceStart);
598                         return;
599                 }
600                 generateCode(currentScope, codeStream, valueRequired);
601                 // branching
602                 int position = codeStream.position;
603                 if (valueRequired) {
604                         if (falseLabel == null) {
605                                 if (trueLabel != null) {
606                                         // Implicit falling through the FALSE case
607                                         codeStream.ifne(trueLabel);
608                                 }
609                         } else {
610                                 if (trueLabel == null) {
611                                         // Implicit falling through the TRUE case
612                                         codeStream.ifeq(falseLabel);
613                                 } else {
614                                         // No implicit fall through TRUE/FALSE --> should never occur
615                                 }
616                         }
617                 }
618                 // reposition the endPC
619                 codeStream.updateLastRecordedEndPC(position);
620         }
621
622         /* Optimized (java) code generation for string concatenations that involve StringBuffer
623          * creation: going through this path means that there is no need for a new StringBuffer
624          * creation, further operands should rather be only appended to the current one.
625          * By default: no optimization.
626          */
627         public void generateOptimizedStringConcatenation(
628                 BlockScope blockScope,
629                 CodeStream codeStream,
630                 int typeID) {
631
632                 if (typeID == T_JavaLangString && this.constant != NotAConstant && this.constant.stringValue().length() == 0) {
633                         return; // optimize str + ""
634                 }
635                 generateCode(blockScope, codeStream, true);
636                 codeStream.invokeStringConcatenationAppendForType(typeID);
637         }
638
639         /* Optimized (java) code generation for string concatenations that involve StringBuffer
640          * creation: going through this path means that there is no need for a new StringBuffer
641          * creation, further operands should rather be only appended to the current one.
642          */
643         public void generateOptimizedStringConcatenationCreation(
644                 BlockScope blockScope,
645                 CodeStream codeStream,
646                 int typeID) {
647
648                 codeStream.newStringContatenation();
649                 codeStream.dup();
650                 switch (typeID) {
651                         case T_JavaLangObject :
652                         case T_undefined :
653                                 // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
654                                 // append(Object) returns append(valueOf(Object)), which means that the null case is handled by the next case.
655                                 codeStream.invokeStringConcatenationDefaultConstructor();
656                                 generateCode(blockScope, codeStream, true);
657                                 codeStream.invokeStringConcatenationAppendForType(T_JavaLangObject);
658                                 return;
659                         case T_JavaLangString :
660                         case T_null :
661                                 if (constant != NotAConstant) {
662                                         String stringValue = constant.stringValue();
663                                         if (stringValue.length() == 0) {  // optimize ""+<str> 
664                                                 codeStream.invokeStringConcatenationDefaultConstructor();
665                                                 return;
666                                         }
667                                         codeStream.ldc(stringValue);
668                                 } else {
669                                         // null case is not a constant
670                                         generateCode(blockScope, codeStream, true);
671                                         codeStream.invokeStringValueOf(T_JavaLangObject);
672                                 }
673                                 break;
674                         default :
675                                 generateCode(blockScope, codeStream, true);
676                                 codeStream.invokeStringValueOf(typeID);
677                 }
678                 codeStream.invokeStringConcatenationStringConstructor();
679         }
680
681         public boolean isCompactableOperation() {
682
683                 return false;
684         }
685
686         //Return true if the conversion is done AUTOMATICALLY by the vm
687         //while the javaVM is an int based-machine, thus for example pushing
688         //a byte onto the stack , will automatically create an int on the stack
689         //(this request some work d be done by the VM on signed numbers)
690         public boolean isConstantValueOfTypeAssignableToType(TypeBinding constantType, TypeBinding targetType) {
691
692                 if (constant == Constant.NotAConstant)
693                         return false;
694                 if (constantType == targetType)
695                         return true;
696                 if (constantType.isBaseType() && targetType.isBaseType()) {
697                         //No free assignment conversion from anything but to integral ones.
698                         if ((constantType == IntBinding
699                                 || BaseTypeBinding.isWidening(T_int, constantType.id))
700                                 && (BaseTypeBinding.isNarrowing(targetType.id, T_int))) {
701                                 //use current explicit conversion in order to get some new value to compare with current one
702                                 return isConstantValueRepresentable(constant, constantType.id, targetType.id);
703                         }
704                 }
705                 return false;
706         }
707
708         public boolean isTypeReference() {
709                 return false;
710         }
711         
712         public int nullStatus(FlowInfo flowInfo) {
713                 
714                 if (this.constant != null && this.constant != NotAConstant)
715                         return FlowInfo.NON_NULL; // constant expression cannot be null
716                 
717                 LocalVariableBinding local = localVariableBinding();
718                 if (local != null) {
719                         if (flowInfo.isDefinitelyNull(local))
720                                 return FlowInfo.NULL;
721                         if (flowInfo.isDefinitelyNonNull(local))
722                                 return FlowInfo.NON_NULL;
723                         return FlowInfo.UNKNOWN;
724                 }
725                 return FlowInfo.NON_NULL;
726         }
727         
728         /**
729          * Constant usable for bytecode pattern optimizations, but cannot be inlined
730          * since it is not strictly equivalent to the definition of constant expressions.
731          * In particular, some side-effects may be required to occur (only the end value
732          * is known).
733          * @return Constant known to be of boolean type
734          */ 
735         public Constant optimizedBooleanConstant() {
736                 return this.constant;
737         }
738
739         public StringBuffer print(int indent, StringBuffer output) {
740                 printIndent(indent, output);
741                 return printExpression(indent, output);
742         }
743
744         public abstract StringBuffer printExpression(int indent, StringBuffer output);
745         
746         public StringBuffer printStatement(int indent, StringBuffer output) {
747                 return print(indent, output).append(";"); //$NON-NLS-1$
748         }
749
750         public void reportIllegalCast(Scope scope, TypeBinding castType, TypeBinding expressionType) {
751                 // do nothing by default
752         }
753         
754         public void resolve(BlockScope scope) {
755                 // drops the returning expression's type whatever the type is.
756
757                 this.resolveType(scope);
758                 return;
759         }
760
761         public TypeBinding resolveType(BlockScope scope) {
762                 // by default... subclasses should implement a better TC if required.
763
764                 return null;
765         }
766
767         public TypeBinding resolveType(ClassScope classScope) {
768                 // by default... subclasses should implement a better TB if required.
769                 return null;
770         }
771
772         public TypeBinding resolveTypeExpecting(
773                 BlockScope scope,
774                 TypeBinding expectedType) {
775
776                 this.setExpectedType(expectedType); // needed in case of generic method invocation
777                 TypeBinding expressionType = this.resolveType(scope);
778                 if (expressionType == null) return null;
779                 if (expressionType == expectedType) return expressionType;
780                 
781                 if (!expressionType.isCompatibleWith(expectedType)) {
782                         if (scope.isBoxingCompatibleWith(expressionType, expectedType)) {
783                                 this.computeConversion(scope, expectedType, expressionType);
784                         } else {
785                                 scope.problemReporter().typeMismatchError(expressionType, expectedType, this);
786                                 return null;
787                         }
788                 }
789                 return expressionType;
790         }
791
792         /**
793          * Record the type expectation before this expression is typechecked.
794          * e.g. String s = foo();, foo() will be tagged as being expected of type String
795          * Used to trigger proper inference of generic method invocations.
796          */
797         public void setExpectedType(TypeBinding expectedType) {
798             // do nothing by default
799         }
800
801         public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
802             // do nothing by default
803         }
804         
805         public void tagAsNeedCheckCast() {
806             // do nothing by default            
807         }
808         
809         public Expression toTypeReference() {
810                 //by default undefined
811
812                 //this method is meanly used by the parser in order to transform
813                 //an expression that is used as a type reference in a cast ....
814                 //--appreciate the fact that castExpression and ExpressionWithParenthesis
815                 //--starts with the same pattern.....
816
817                 return this;
818         }
819         
820         public void traverse(ASTVisitor visitor, BlockScope scope) {
821                 // do nothing by default
822         }
823         public void traverse(ASTVisitor visitor, ClassScope scope) {
824                 // do nothing by default
825         }
826         public void traverse(ASTVisitor visitor, CompilationUnitScope scope) {
827                 // do nothing by default
828         }
829         /**
830          * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference)
831          * or thru a cast expression etc...
832          */
833         public LocalVariableBinding localVariableBinding() {
834                 return null;
835         }
836 }