Source Code Cross Referenced for Expression.java in  » IDE-Eclipse » jdt » org » eclipse » jdt » internal » compiler » ast » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Eclipse » jdt » org.eclipse.jdt.internal.compiler.ast 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Copyright (c) 2000, 2007 IBM Corporation and others.
0003:         * All rights reserved. This program and the accompanying materials
0004:         * are made available under the terms of the Eclipse Public License v1.0
0005:         * which accompanies this distribution, and is available at
0006:         * http://www.eclipse.org/legal/epl-v10.html
0007:         *
0008:         * Contributors:
0009:         *     IBM Corporation - initial API and implementation
0010:         *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
0011:
0012:        import java.util.ArrayList;
0013:
0014:        import org.eclipse.jdt.core.compiler.CharOperation;
0015:        import org.eclipse.jdt.internal.compiler.ASTVisitor;
0016:        import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
0017:        import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
0018:        import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
0019:        import org.eclipse.jdt.internal.compiler.flow.FlowContext;
0020:        import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
0021:        import org.eclipse.jdt.internal.compiler.impl.Constant;
0022:        import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
0023:        import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
0024:        import org.eclipse.jdt.internal.compiler.lookup.Binding;
0025:        import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
0026:        import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
0027:        import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
0028:        import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
0029:        import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
0030:        import org.eclipse.jdt.internal.compiler.lookup.Scope;
0031:        import org.eclipse.jdt.internal.compiler.lookup.TagBits;
0032:        import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
0033:        import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
0034:        import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
0035:        import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
0036:        import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement;
0037:        import org.eclipse.jdt.internal.compiler.util.Messages;
0038:
0039:        public abstract class Expression extends Statement {
0040:
0041:            public Constant constant;
0042:
0043:            public int statementEnd = -1;
0044:
0045:            //Some expression may not be used - from a java semantic point
0046:            //of view only - as statements. Other may. In order to avoid the creation
0047:            //of wrappers around expression in order to tune them as expression
0048:            //Expression is a subclass of Statement. See the message isValidJavaStatement()
0049:
0050:            public int implicitConversion;
0051:            public TypeBinding resolvedType;
0052:
0053:            public static final boolean isConstantValueRepresentable(
0054:                    Constant constant, int constantTypeID, int targetTypeID) {
0055:                //true if there is no loss of precision while casting.
0056:                // constantTypeID == constant.typeID
0057:                if (targetTypeID == constantTypeID)
0058:                    return true;
0059:                switch (targetTypeID) {
0060:                case T_char:
0061:                    switch (constantTypeID) {
0062:                    case T_char:
0063:                        return true;
0064:                    case T_double:
0065:                        return constant.doubleValue() == constant.charValue();
0066:                    case T_float:
0067:                        return constant.floatValue() == constant.charValue();
0068:                    case T_int:
0069:                        return constant.intValue() == constant.charValue();
0070:                    case T_short:
0071:                        return constant.shortValue() == constant.charValue();
0072:                    case T_byte:
0073:                        return constant.byteValue() == constant.charValue();
0074:                    case T_long:
0075:                        return constant.longValue() == constant.charValue();
0076:                    default:
0077:                        return false;//boolean
0078:                    }
0079:
0080:                case T_float:
0081:                    switch (constantTypeID) {
0082:                    case T_char:
0083:                        return constant.charValue() == constant.floatValue();
0084:                    case T_double:
0085:                        return constant.doubleValue() == constant.floatValue();
0086:                    case T_float:
0087:                        return true;
0088:                    case T_int:
0089:                        return constant.intValue() == constant.floatValue();
0090:                    case T_short:
0091:                        return constant.shortValue() == constant.floatValue();
0092:                    case T_byte:
0093:                        return constant.byteValue() == constant.floatValue();
0094:                    case T_long:
0095:                        return constant.longValue() == constant.floatValue();
0096:                    default:
0097:                        return false;//boolean
0098:                    }
0099:
0100:                case T_double:
0101:                    switch (constantTypeID) {
0102:                    case T_char:
0103:                        return constant.charValue() == constant.doubleValue();
0104:                    case T_double:
0105:                        return true;
0106:                    case T_float:
0107:                        return constant.floatValue() == constant.doubleValue();
0108:                    case T_int:
0109:                        return constant.intValue() == constant.doubleValue();
0110:                    case T_short:
0111:                        return constant.shortValue() == constant.doubleValue();
0112:                    case T_byte:
0113:                        return constant.byteValue() == constant.doubleValue();
0114:                    case T_long:
0115:                        return constant.longValue() == constant.doubleValue();
0116:                    default:
0117:                        return false; //boolean
0118:                    }
0119:
0120:                case T_byte:
0121:                    switch (constantTypeID) {
0122:                    case T_char:
0123:                        return constant.charValue() == constant.byteValue();
0124:                    case T_double:
0125:                        return constant.doubleValue() == constant.byteValue();
0126:                    case T_float:
0127:                        return constant.floatValue() == constant.byteValue();
0128:                    case T_int:
0129:                        return constant.intValue() == constant.byteValue();
0130:                    case T_short:
0131:                        return constant.shortValue() == constant.byteValue();
0132:                    case T_byte:
0133:                        return true;
0134:                    case T_long:
0135:                        return constant.longValue() == constant.byteValue();
0136:                    default:
0137:                        return false; //boolean
0138:                    }
0139:
0140:                case T_short:
0141:                    switch (constantTypeID) {
0142:                    case T_char:
0143:                        return constant.charValue() == constant.shortValue();
0144:                    case T_double:
0145:                        return constant.doubleValue() == constant.shortValue();
0146:                    case T_float:
0147:                        return constant.floatValue() == constant.shortValue();
0148:                    case T_int:
0149:                        return constant.intValue() == constant.shortValue();
0150:                    case T_short:
0151:                        return true;
0152:                    case T_byte:
0153:                        return constant.byteValue() == constant.shortValue();
0154:                    case T_long:
0155:                        return constant.longValue() == constant.shortValue();
0156:                    default:
0157:                        return false; //boolean
0158:                    }
0159:
0160:                case T_int:
0161:                    switch (constantTypeID) {
0162:                    case T_char:
0163:                        return constant.charValue() == constant.intValue();
0164:                    case T_double:
0165:                        return constant.doubleValue() == constant.intValue();
0166:                    case T_float:
0167:                        return constant.floatValue() == constant.intValue();
0168:                    case T_int:
0169:                        return true;
0170:                    case T_short:
0171:                        return constant.shortValue() == constant.intValue();
0172:                    case T_byte:
0173:                        return constant.byteValue() == constant.intValue();
0174:                    case T_long:
0175:                        return constant.longValue() == constant.intValue();
0176:                    default:
0177:                        return false; //boolean
0178:                    }
0179:
0180:                case T_long:
0181:                    switch (constantTypeID) {
0182:                    case T_char:
0183:                        return constant.charValue() == constant.longValue();
0184:                    case T_double:
0185:                        return constant.doubleValue() == constant.longValue();
0186:                    case T_float:
0187:                        return constant.floatValue() == constant.longValue();
0188:                    case T_int:
0189:                        return constant.intValue() == constant.longValue();
0190:                    case T_short:
0191:                        return constant.shortValue() == constant.longValue();
0192:                    case T_byte:
0193:                        return constant.byteValue() == constant.longValue();
0194:                    case T_long:
0195:                        return true;
0196:                    default:
0197:                        return false; //boolean
0198:                    }
0199:
0200:                default:
0201:                    return false; //boolean
0202:                }
0203:            }
0204:
0205:            public Expression() {
0206:                super ();
0207:            }
0208:
0209:            public FlowInfo analyseCode(BlockScope currentScope,
0210:                    FlowContext flowContext, FlowInfo flowInfo) {
0211:                return flowInfo;
0212:            }
0213:
0214:            /**
0215:             * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out
0216:             * portions of expressions where no actual value is required.
0217:             * 
0218:             * @param currentScope
0219:             * @param flowContext
0220:             * @param flowInfo
0221:             * @param valueRequired
0222:             * @return The state of initialization after the analysis of the current expression
0223:             */
0224:            public FlowInfo analyseCode(BlockScope currentScope,
0225:                    FlowContext flowContext, FlowInfo flowInfo,
0226:                    boolean valueRequired) {
0227:
0228:                return analyseCode(currentScope, flowContext, flowInfo);
0229:            }
0230:
0231:            /**
0232:             * Returns false if cast is not legal. 
0233:             */
0234:            public final boolean checkCastTypesCompatibility(Scope scope,
0235:                    TypeBinding castType, TypeBinding expressionType,
0236:                    Expression expression) {
0237:
0238:                // see specifications 5.5
0239:                // handle errors and process constant when needed
0240:
0241:                // if either one of the type is null ==>
0242:                // some error has been already reported some where ==>
0243:                // we then do not report an obvious-cascade-error.
0244:
0245:                if (castType == null || expressionType == null)
0246:                    return true;
0247:
0248:                // identity conversion cannot be performed upfront, due to side-effects
0249:                // like constant propagation
0250:                boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
0251:                if (castType.isBaseType()) {
0252:                    if (expressionType.isBaseType()) {
0253:                        if (expressionType == castType) {
0254:                            if (expression != null) {
0255:                                this .constant = expression.constant; //use the same constant
0256:                            }
0257:                            tagAsUnnecessaryCast(scope, castType);
0258:                            return true;
0259:                        }
0260:                        boolean necessary = false;
0261:                        if (expressionType.isCompatibleWith(castType)
0262:                                || (necessary = BaseTypeBinding.isNarrowing(
0263:                                        castType.id, expressionType.id))) {
0264:                            if (expression != null) {
0265:                                expression.implicitConversion = (castType.id << 4)
0266:                                        + expressionType.id;
0267:                                if (expression.constant != Constant.NotAConstant) {
0268:                                    this .constant = expression.constant
0269:                                            .castTo(expression.implicitConversion);
0270:                                }
0271:                            }
0272:                            if (!necessary)
0273:                                tagAsUnnecessaryCast(scope, castType);
0274:                            return true;
0275:
0276:                        }
0277:                    } else if (use15specifics
0278:                            && scope.environment().computeBoxingType(
0279:                                    expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
0280:                        tagAsUnnecessaryCast(scope, castType);
0281:                        return true;
0282:                    }
0283:                    return false;
0284:                } else if (use15specifics
0285:                        && expressionType.isBaseType()
0286:                        && scope.environment()
0287:                                .computeBoxingType(expressionType)
0288:                                .isCompatibleWith(castType)) { // boxing - only widening match is allowed
0289:                    tagAsUnnecessaryCast(scope, castType);
0290:                    return true;
0291:                }
0292:
0293:                switch (expressionType.kind()) {
0294:                case Binding.BASE_TYPE:
0295:                    //-----------cast to something which is NOT a base type--------------------------	
0296:                    if (expressionType == TypeBinding.NULL) {
0297:                        tagAsUnnecessaryCast(scope, castType);
0298:                        return true; //null is compatible with every thing
0299:                    }
0300:                    return false;
0301:
0302:                case Binding.ARRAY_TYPE:
0303:                    if (castType == expressionType) {
0304:                        tagAsUnnecessaryCast(scope, castType);
0305:                        return true; // identity conversion
0306:                    }
0307:                    switch (castType.kind()) {
0308:                    case Binding.ARRAY_TYPE:
0309:                        // ( ARRAY ) ARRAY
0310:                        TypeBinding castElementType = ((ArrayBinding) castType)
0311:                                .elementsType();
0312:                        TypeBinding exprElementType = ((ArrayBinding) expressionType)
0313:                                .elementsType();
0314:                        if (exprElementType.isBaseType()
0315:                                || castElementType.isBaseType()) {
0316:                            if (castElementType == exprElementType) {
0317:                                tagAsNeedCheckCast();
0318:                                return true;
0319:                            }
0320:                            return false;
0321:                        }
0322:                        // recurse on array type elements
0323:                        return checkCastTypesCompatibility(scope,
0324:                                castElementType, exprElementType, expression);
0325:
0326:                    case Binding.TYPE_PARAMETER:
0327:                        // ( TYPE_PARAMETER ) ARRAY
0328:                        TypeBinding match = expressionType
0329:                                .findSuperTypeWithSameErasure(castType);
0330:                        if (match == null) {
0331:                            checkUnsafeCast(scope, castType, expressionType,
0332:                                    null /*no match*/, true);
0333:                        }
0334:                        // recurse on the type variable upper bound
0335:                        return checkCastTypesCompatibility(scope,
0336:                                ((TypeVariableBinding) castType).upperBound(),
0337:                                expressionType, expression);
0338:
0339:                    default:
0340:                        // ( CLASS/INTERFACE ) ARRAY
0341:                        switch (castType.id) {
0342:                        case T_JavaLangCloneable:
0343:                        case T_JavaIoSerializable:
0344:                            tagAsNeedCheckCast();
0345:                            return true;
0346:                        case T_JavaLangObject:
0347:                            tagAsUnnecessaryCast(scope, castType);
0348:                            return true;
0349:                        default:
0350:                            return false;
0351:                        }
0352:                    }
0353:
0354:                case Binding.TYPE_PARAMETER:
0355:                    TypeBinding match = expressionType
0356:                            .findSuperTypeWithSameErasure(castType);
0357:                    if (match != null) {
0358:                        return checkUnsafeCast(scope, castType, expressionType,
0359:                                match, false);
0360:                    }
0361:                    // recursively on the type variable upper bound
0362:                    return checkCastTypesCompatibility(
0363:                            scope,
0364:                            castType,
0365:                            ((TypeVariableBinding) expressionType).upperBound(),
0366:                            expression);
0367:
0368:                case Binding.WILDCARD_TYPE: // intersection type
0369:                    match = expressionType
0370:                            .findSuperTypeWithSameErasure(castType);
0371:                    if (match != null) {
0372:                        return checkUnsafeCast(scope, castType, expressionType,
0373:                                match, false);
0374:                    }
0375:                    // recursively on the type variable upper bound
0376:                    return checkCastTypesCompatibility(scope, castType,
0377:                            ((WildcardBinding) expressionType).bound,
0378:                            expression);
0379:
0380:                default:
0381:                    if (expressionType.isInterface()) {
0382:                        switch (castType.kind()) {
0383:                        case Binding.ARRAY_TYPE:
0384:                            // ( ARRAY ) INTERFACE
0385:                            switch (expressionType.id) {
0386:                            case T_JavaLangCloneable:
0387:                            case T_JavaIoSerializable:
0388:                                tagAsNeedCheckCast();
0389:                                return true;
0390:                            default:
0391:                                return false;
0392:                            }
0393:
0394:                        case Binding.TYPE_PARAMETER:
0395:                            // ( INTERFACE ) TYPE_PARAMETER
0396:                            match = expressionType
0397:                                    .findSuperTypeWithSameErasure(castType);
0398:                            if (match == null) {
0399:                                checkUnsafeCast(scope, castType,
0400:                                        expressionType, null /*no match*/,
0401:                                        true);
0402:                            }
0403:                            // recurse on the type variable upper bound
0404:                            return checkCastTypesCompatibility(scope,
0405:                                    ((TypeVariableBinding) castType)
0406:                                            .upperBound(), expressionType,
0407:                                    expression);
0408:
0409:                        default:
0410:                            if (castType.isInterface()) {
0411:                                // ( INTERFACE ) INTERFACE
0412:                                ReferenceBinding interfaceType = (ReferenceBinding) expressionType;
0413:                                match = interfaceType
0414:                                        .findSuperTypeWithSameErasure(castType);
0415:                                if (match != null) {
0416:                                    return checkUnsafeCast(scope, castType,
0417:                                            interfaceType, match, false);
0418:                                }
0419:                                tagAsNeedCheckCast();
0420:                                match = castType
0421:                                        .findSuperTypeWithSameErasure(interfaceType);
0422:                                if (match != null) {
0423:                                    return checkUnsafeCast(scope, castType,
0424:                                            interfaceType, match, true);
0425:                                }
0426:                                if (use15specifics) {
0427:                                    checkUnsafeCast(scope, castType,
0428:                                            expressionType, null /*no match*/,
0429:                                            true);
0430:                                    // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
0431:                                    if (interfaceType
0432:                                            .hasIncompatibleSuperType((ReferenceBinding) castType))
0433:                                        return false;
0434:                                } else {
0435:                                    // pre1.5 semantics - no covariance allowed (even if 1.5 compliant, but 1.4 source)
0436:                                    MethodBinding[] castTypeMethods = getAllInheritedMethods((ReferenceBinding) castType);
0437:                                    MethodBinding[] expressionTypeMethods = getAllInheritedMethods((ReferenceBinding) expressionType);
0438:                                    int exprMethodsLength = expressionTypeMethods.length;
0439:                                    for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) {
0440:                                        for (int j = 0; j < exprMethodsLength; j++) {
0441:                                            if ((castTypeMethods[i].returnType != expressionTypeMethods[j].returnType)
0442:                                                    && (CharOperation
0443:                                                            .equals(
0444:                                                                    castTypeMethods[i].selector,
0445:                                                                    expressionTypeMethods[j].selector))
0446:                                                    && castTypeMethods[i]
0447:                                                            .areParametersEqual(expressionTypeMethods[j])) {
0448:                                                return false;
0449:
0450:                                            }
0451:                                        }
0452:                                    }
0453:                                }
0454:                                return true;
0455:                            } else {
0456:                                // ( CLASS ) INTERFACE
0457:                                if (castType.id == TypeIds.T_JavaLangObject) { // no runtime error
0458:                                    tagAsUnnecessaryCast(scope, castType);
0459:                                    return true;
0460:                                }
0461:                                // can only be a downcast
0462:                                tagAsNeedCheckCast();
0463:                                match = castType
0464:                                        .findSuperTypeWithSameErasure(expressionType);
0465:                                if (match != null) {
0466:                                    return checkUnsafeCast(scope, castType,
0467:                                            expressionType, match, true);
0468:                                }
0469:                                if (((ReferenceBinding) castType).isFinal()) {
0470:                                    // no subclass for castType, thus compile-time check is invalid
0471:                                    return false;
0472:                                }
0473:                                if (use15specifics) {
0474:                                    checkUnsafeCast(scope, castType,
0475:                                            expressionType, null /*no match*/,
0476:                                            true);
0477:                                    // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
0478:                                    if (((ReferenceBinding) castType)
0479:                                            .hasIncompatibleSuperType((ReferenceBinding) expressionType)) {
0480:                                        return false;
0481:                                    }
0482:                                }
0483:                                return true;
0484:                            }
0485:                        }
0486:                    } else {
0487:                        switch (castType.kind()) {
0488:                        case Binding.ARRAY_TYPE:
0489:                            // ( ARRAY ) CLASS
0490:                            if (expressionType.id == TypeIds.T_JavaLangObject) { // potential runtime error
0491:                                if (use15specifics)
0492:                                    checkUnsafeCast(scope, castType,
0493:                                            expressionType, expressionType,
0494:                                            true);
0495:                                tagAsNeedCheckCast();
0496:                                return true;
0497:                            }
0498:                            return false;
0499:
0500:                        case Binding.TYPE_PARAMETER:
0501:                            // ( TYPE_PARAMETER ) CLASS
0502:                            match = expressionType
0503:                                    .findSuperTypeWithSameErasure(castType);
0504:                            if (match == null) {
0505:                                checkUnsafeCast(scope, castType,
0506:                                        expressionType, match, true);
0507:                            }
0508:                            // recurse on the type variable upper bound
0509:                            return checkCastTypesCompatibility(scope,
0510:                                    ((TypeVariableBinding) castType)
0511:                                            .upperBound(), expressionType,
0512:                                    expression);
0513:
0514:                        default:
0515:                            if (castType.isInterface()) {
0516:                                // ( INTERFACE ) CLASS
0517:                                ReferenceBinding refExprType = (ReferenceBinding) expressionType;
0518:                                match = refExprType
0519:                                        .findSuperTypeWithSameErasure(castType);
0520:                                if (match != null) {
0521:                                    return checkUnsafeCast(scope, castType,
0522:                                            expressionType, match, false);
0523:                                }
0524:                                // unless final a subclass may implement the interface ==> no check at compile time
0525:                                if (refExprType.isFinal()) {
0526:                                    return false;
0527:                                }
0528:                                tagAsNeedCheckCast();
0529:                                match = castType
0530:                                        .findSuperTypeWithSameErasure(expressionType);
0531:                                if (match != null) {
0532:                                    return checkUnsafeCast(scope, castType,
0533:                                            expressionType, match, true);
0534:                                }
0535:                                if (use15specifics) {
0536:                                    checkUnsafeCast(scope, castType,
0537:                                            expressionType, null /*no match*/,
0538:                                            true);
0539:                                    // ensure there is no collision between both interfaces: i.e. I1 extends List<String>, I2 extends List<Object>
0540:                                    if (refExprType
0541:                                            .hasIncompatibleSuperType((ReferenceBinding) castType))
0542:                                        return false;
0543:                                }
0544:                                return true;
0545:                            } else {
0546:                                // ( CLASS ) CLASS
0547:                                match = expressionType
0548:                                        .findSuperTypeWithSameErasure(castType);
0549:                                if (match != null) {
0550:                                    if (expression != null
0551:                                            && castType.id == TypeIds.T_JavaLangString)
0552:                                        this .constant = expression.constant; // (String) cst is still a constant
0553:                                    return checkUnsafeCast(scope, castType,
0554:                                            expressionType, match, false);
0555:                                }
0556:                                match = castType
0557:                                        .findSuperTypeWithSameErasure(expressionType);
0558:                                if (match != null) {
0559:                                    tagAsNeedCheckCast();
0560:                                    return checkUnsafeCast(scope, castType,
0561:                                            expressionType, match, true);
0562:                                }
0563:                                return false;
0564:                            }
0565:                        }
0566:                    }
0567:                }
0568:            }
0569:
0570:            /**
0571:             * Check the local variable of this expression, if any, against potential NPEs 
0572:             * given a flow context and an upstream flow info. If so, report the risk to
0573:             * the context. Marks the local as checked, which affects the flow info.
0574:             * @param scope the scope of the analysis
0575:             * @param flowContext the current flow context
0576:             * @param flowInfo the upstream flow info; caveat: may get modified
0577:             */
0578:            public void checkNPE(BlockScope scope, FlowContext flowContext,
0579:                    FlowInfo flowInfo) {
0580:                LocalVariableBinding local = this .localVariableBinding();
0581:                if (local != null
0582:                        && (local.type.tagBits & TagBits.IsBaseType) == 0) {
0583:                    if ((this .bits & ASTNode.IsNonNull) == 0) {
0584:                        flowContext.recordUsingNullReference(scope, local,
0585:                                this , FlowContext.MAY_NULL, flowInfo);
0586:                    }
0587:                    flowInfo.markAsComparedEqualToNonNull(local);
0588:                    // from thereon it is set
0589:                    if (flowContext.initsOnFinally != null) {
0590:                        flowContext.initsOnFinally
0591:                                .markAsComparedEqualToNonNull(local);
0592:                    }
0593:                }
0594:            }
0595:
0596:            public boolean checkUnsafeCast(Scope scope, TypeBinding castType,
0597:                    TypeBinding expressionType, TypeBinding match,
0598:                    boolean isNarrowing) {
0599:                if (match == castType) {
0600:                    if (!isNarrowing)
0601:                        tagAsUnnecessaryCast(scope, castType);
0602:                    return true;
0603:                }
0604:                if (match != null
0605:                        && (castType.isBoundParameterizedType() || expressionType
0606:                                .isBoundParameterizedType())) {
0607:
0608:                    if (match.isProvablyDistinctFrom(
0609:                            isNarrowing ? expressionType : castType, 0)) {
0610:                        return false;
0611:                    }
0612:                }
0613:                if (!isNarrowing)
0614:                    tagAsUnnecessaryCast(scope, castType);
0615:                return true;
0616:            }
0617:
0618:            /**
0619:             * Base types need that the widening is explicitly done by the compiler using some bytecode like i2f.
0620:             * Also check unsafe type operations.
0621:             */
0622:            public void computeConversion(Scope scope, TypeBinding runtimeType,
0623:                    TypeBinding compileTimeType) {
0624:
0625:                if (runtimeType == null || compileTimeType == null)
0626:                    return;
0627:                if (this .implicitConversion != 0)
0628:                    return; // already set independantly
0629:
0630:                // it is possible for a Byte to be unboxed to a byte & then converted to an int
0631:                // but it is not possible for a byte to become Byte & then assigned to an Integer,
0632:                // or to become an int before boxed into an Integer
0633:                if (runtimeType != TypeBinding.NULL && runtimeType.isBaseType()) {
0634:                    if (!compileTimeType.isBaseType()) {
0635:                        TypeBinding unboxedType = scope.environment()
0636:                                .computeBoxingType(compileTimeType);
0637:                        this .implicitConversion = TypeIds.UNBOXING;
0638:                        scope.problemReporter().autoboxing(this ,
0639:                                compileTimeType, runtimeType);
0640:                        compileTimeType = unboxedType;
0641:                    }
0642:                } else if (compileTimeType != TypeBinding.NULL
0643:                        && compileTimeType.isBaseType()) {
0644:                    TypeBinding boxedType = scope.environment()
0645:                            .computeBoxingType(runtimeType);
0646:                    if (boxedType == runtimeType) // Object o = 12;
0647:                        boxedType = compileTimeType;
0648:                    this .implicitConversion = TypeIds.BOXING
0649:                            | (boxedType.id << 4) + compileTimeType.id;
0650:                    scope.problemReporter().autoboxing(this , compileTimeType,
0651:                            scope.environment().computeBoxingType(boxedType));
0652:                    return;
0653:                } else if (this .constant != Constant.NotAConstant
0654:                        && this .constant.typeID() != TypeIds.T_JavaLangString) {
0655:                    this .implicitConversion = TypeIds.BOXING;
0656:                    return;
0657:                }
0658:                int compileTimeTypeID, runtimeTypeID;
0659:                if ((compileTimeTypeID = compileTimeType.id) == TypeIds.NoId) { // e.g. ? extends String  ==> String (103227)
0660:                    compileTimeTypeID = compileTimeType.erasure().id == TypeIds.T_JavaLangString ? TypeIds.T_JavaLangString
0661:                            : TypeIds.T_JavaLangObject;
0662:                }
0663:                switch (runtimeTypeID = runtimeType.id) {
0664:                case T_byte:
0665:                case T_short:
0666:                case T_char:
0667:                    this .implicitConversion |= (TypeIds.T_int << 4)
0668:                            + compileTimeTypeID;
0669:                    break;
0670:                case T_JavaLangString:
0671:                case T_float:
0672:                case T_boolean:
0673:                case T_double:
0674:                case T_int: //implicitConversion may result in i2i which will result in NO code gen
0675:                case T_long:
0676:                    this .implicitConversion |= (runtimeTypeID << 4)
0677:                            + compileTimeTypeID;
0678:                    break;
0679:                default: // regular object ref
0680:                //				if (compileTimeType.isRawType() && runtimeTimeType.isBoundParameterizedType()) {
0681:                //				    scope.problemReporter().unsafeRawExpression(this, compileTimeType, runtimeTimeType);
0682:                //				}		
0683:                }
0684:            }
0685:
0686:            /**
0687:             * Expression statements are plain expressions, however they generate like
0688:             * normal expressions with no value required.
0689:             *
0690:             * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
0691:             * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream 
0692:             */
0693:            public void generateCode(BlockScope currentScope,
0694:                    CodeStream codeStream) {
0695:
0696:                if ((this .bits & ASTNode.IsReachable) == 0) {
0697:                    return;
0698:                }
0699:                generateCode(currentScope, codeStream, false);
0700:            }
0701:
0702:            /**
0703:             * Every expression is responsible for generating its implicit conversion when necessary.
0704:             *
0705:             * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
0706:             * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
0707:             * @param valueRequired boolean
0708:             */
0709:            public void generateCode(BlockScope currentScope,
0710:                    CodeStream codeStream, boolean valueRequired) {
0711:
0712:                if (this .constant != Constant.NotAConstant) {
0713:                    // generate a constant expression
0714:                    int pc = codeStream.position;
0715:                    codeStream.generateConstant(this .constant,
0716:                            this .implicitConversion);
0717:                    codeStream.recordPositionsFrom(pc, this .sourceStart);
0718:                } else {
0719:                    // actual non-constant code generation
0720:                    throw new ShouldNotImplement(Messages.ast_missingCode);
0721:                }
0722:            }
0723:
0724:            /**
0725:             * Default generation of a boolean value
0726:             * @param currentScope
0727:             * @param codeStream
0728:             * @param trueLabel
0729:             * @param falseLabel
0730:             * @param valueRequired
0731:             */
0732:            public void generateOptimizedBoolean(BlockScope currentScope,
0733:                    CodeStream codeStream, BranchLabel trueLabel,
0734:                    BranchLabel falseLabel, boolean valueRequired) {
0735:
0736:                // a label valued to nil means: by default we fall through the case... 
0737:                // both nil means we leave the value on the stack
0738:
0739:                Constant cst = this .optimizedBooleanConstant();
0740:                generateCode(currentScope, codeStream, valueRequired
0741:                        && cst == Constant.NotAConstant);
0742:                if ((cst != Constant.NotAConstant)
0743:                        && (cst.typeID() == TypeIds.T_boolean)) {
0744:                    int pc = codeStream.position;
0745:                    if (cst.booleanValue() == true) {
0746:                        // constant == true
0747:                        if (valueRequired) {
0748:                            if (falseLabel == null) {
0749:                                // implicit falling through the FALSE case
0750:                                if (trueLabel != null) {
0751:                                    codeStream.goto_(trueLabel);
0752:                                }
0753:                            }
0754:                        }
0755:                    } else {
0756:                        if (valueRequired) {
0757:                            if (falseLabel != null) {
0758:                                // implicit falling through the TRUE case
0759:                                if (trueLabel == null) {
0760:                                    codeStream.goto_(falseLabel);
0761:                                }
0762:                            }
0763:                        }
0764:                    }
0765:                    codeStream.recordPositionsFrom(pc, this .sourceStart);
0766:                    return;
0767:                }
0768:                // branching
0769:                int position = codeStream.position;
0770:                if (valueRequired) {
0771:                    if (falseLabel == null) {
0772:                        if (trueLabel != null) {
0773:                            // Implicit falling through the FALSE case
0774:                            codeStream.ifne(trueLabel);
0775:                        }
0776:                    } else {
0777:                        if (trueLabel == null) {
0778:                            // Implicit falling through the TRUE case
0779:                            codeStream.ifeq(falseLabel);
0780:                        } else {
0781:                            // No implicit fall through TRUE/FALSE --> should never occur
0782:                        }
0783:                    }
0784:                }
0785:                // reposition the endPC
0786:                codeStream.updateLastRecordedEndPC(currentScope, position);
0787:            }
0788:
0789:            /* Optimized (java) code generation for string concatenations that involve StringBuffer
0790:             * creation: going through this path means that there is no need for a new StringBuffer
0791:             * creation, further operands should rather be only appended to the current one.
0792:             * By default: no optimization.
0793:             */
0794:            public void generateOptimizedStringConcatenation(
0795:                    BlockScope blockScope, CodeStream codeStream, int typeID) {
0796:
0797:                if (typeID == TypeIds.T_JavaLangString
0798:                        && this .constant != Constant.NotAConstant
0799:                        && this .constant.stringValue().length() == 0) {
0800:                    return; // optimize str + ""
0801:                }
0802:                generateCode(blockScope, codeStream, true);
0803:                codeStream.invokeStringConcatenationAppendForType(typeID);
0804:            }
0805:
0806:            /* Optimized (java) code generation for string concatenations that involve StringBuffer
0807:             * creation: going through this path means that there is no need for a new StringBuffer
0808:             * creation, further operands should rather be only appended to the current one.
0809:             */
0810:            public void generateOptimizedStringConcatenationCreation(
0811:                    BlockScope blockScope, CodeStream codeStream, int typeID) {
0812:
0813:                codeStream.newStringContatenation();
0814:                codeStream.dup();
0815:                switch (typeID) {
0816:                case T_JavaLangObject:
0817:                case T_undefined:
0818:                    // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object)
0819:                    // append(Object) returns append(valueOf(Object)), which means that the null case is handled by the next case.
0820:                    codeStream.invokeStringConcatenationDefaultConstructor();
0821:                    generateCode(blockScope, codeStream, true);
0822:                    codeStream
0823:                            .invokeStringConcatenationAppendForType(TypeIds.T_JavaLangObject);
0824:                    return;
0825:                case T_JavaLangString:
0826:                case T_null:
0827:                    if (this .constant != Constant.NotAConstant) {
0828:                        String stringValue = this .constant.stringValue();
0829:                        if (stringValue.length() == 0) { // optimize ""+<str> 
0830:                            codeStream
0831:                                    .invokeStringConcatenationDefaultConstructor();
0832:                            return;
0833:                        }
0834:                        codeStream.ldc(stringValue);
0835:                    } else {
0836:                        // null case is not a constant
0837:                        generateCode(blockScope, codeStream, true);
0838:                        codeStream
0839:                                .invokeStringValueOf(TypeIds.T_JavaLangObject);
0840:                    }
0841:                    break;
0842:                default:
0843:                    generateCode(blockScope, codeStream, true);
0844:                    codeStream.invokeStringValueOf(typeID);
0845:                }
0846:                codeStream.invokeStringConcatenationStringConstructor();
0847:            }
0848:
0849:            private MethodBinding[] getAllInheritedMethods(
0850:                    ReferenceBinding binding) {
0851:                ArrayList collector = new ArrayList();
0852:                getAllInheritedMethods0(binding, collector);
0853:                return (MethodBinding[]) collector
0854:                        .toArray(new MethodBinding[collector.size()]);
0855:            }
0856:
0857:            private void getAllInheritedMethods0(ReferenceBinding binding,
0858:                    ArrayList collector) {
0859:                if (!binding.isInterface())
0860:                    return;
0861:                MethodBinding[] methodBindings = binding.methods();
0862:                for (int i = 0, max = methodBindings.length; i < max; i++) {
0863:                    collector.add(methodBindings[i]);
0864:                }
0865:                ReferenceBinding[] super Interfaces = binding.super Interfaces();
0866:                for (int i = 0, max = super Interfaces.length; i < max; i++) {
0867:                    getAllInheritedMethods0(super Interfaces[i], collector);
0868:                }
0869:            }
0870:
0871:            public boolean isCompactableOperation() {
0872:
0873:                return false;
0874:            }
0875:
0876:            //Return true if the conversion is done AUTOMATICALLY by the vm
0877:            //while the javaVM is an int based-machine, thus for example pushing
0878:            //a byte onto the stack , will automatically create an int on the stack
0879:            //(this request some work d be done by the VM on signed numbers)
0880:            public boolean isConstantValueOfTypeAssignableToType(
0881:                    TypeBinding constantType, TypeBinding targetType) {
0882:
0883:                if (this .constant == Constant.NotAConstant)
0884:                    return false;
0885:                if (constantType == targetType)
0886:                    return true;
0887:                if (constantType.isBaseType() && targetType.isBaseType()) {
0888:                    //No free assignment conversion from anything but to integral ones.
0889:                    if ((constantType == TypeBinding.INT || BaseTypeBinding
0890:                            .isWidening(TypeIds.T_int, constantType.id))
0891:                            && (BaseTypeBinding.isNarrowing(targetType.id,
0892:                                    TypeIds.T_int))) {
0893:                        //use current explicit conversion in order to get some new value to compare with current one
0894:                        return isConstantValueRepresentable(this .constant,
0895:                                constantType.id, targetType.id);
0896:                    }
0897:                }
0898:                return false;
0899:            }
0900:
0901:            public boolean isTypeReference() {
0902:                return false;
0903:            }
0904:
0905:            /**
0906:             * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference)
0907:             * or thru a cast expression etc...
0908:             */
0909:            public LocalVariableBinding localVariableBinding() {
0910:                return null;
0911:            }
0912:
0913:            /**
0914:             * Mark this expression as being non null, per a specific tag in the
0915:             * source code.
0916:             */
0917:            // this is no more called for now, waiting for inter procedural null reference analysis
0918:            public void markAsNonNull() {
0919:                this .bits |= ASTNode.IsNonNull;
0920:            }
0921:
0922:            public int nullStatus(FlowInfo flowInfo) {
0923:
0924:                if (/* (this.bits & IsNonNull) != 0 || */
0925:                this .constant != null && this .constant != Constant.NotAConstant)
0926:                    return FlowInfo.NON_NULL; // constant expression cannot be null
0927:
0928:                LocalVariableBinding local = localVariableBinding();
0929:                if (local != null) {
0930:                    if (flowInfo.isDefinitelyNull(local))
0931:                        return FlowInfo.NULL;
0932:                    if (flowInfo.isDefinitelyNonNull(local))
0933:                        return FlowInfo.NON_NULL;
0934:                    return FlowInfo.UNKNOWN;
0935:                }
0936:                return FlowInfo.NON_NULL;
0937:            }
0938:
0939:            /**
0940:             * Constant usable for bytecode pattern optimizations, but cannot be inlined
0941:             * since it is not strictly equivalent to the definition of constant expressions.
0942:             * In particular, some side-effects may be required to occur (only the end value
0943:             * is known).
0944:             * @return Constant known to be of boolean type
0945:             */
0946:            public Constant optimizedBooleanConstant() {
0947:                return this .constant;
0948:            }
0949:
0950:            /**
0951:             * Returns the type of the expression after required implicit conversions. When expression type gets promoted
0952:             * or inserted a generic cast, the converted type will differ from the resolved type (surface side-effects from
0953:             * #computeConversion(...)).
0954:             * @return the type after implicit conversion
0955:             */
0956:            public TypeBinding postConversionType(Scope scope) {
0957:                TypeBinding convertedType = this .resolvedType;
0958:                int runtimeType = (this .implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
0959:                switch (runtimeType) {
0960:                case T_boolean:
0961:                    convertedType = TypeBinding.BOOLEAN;
0962:                    break;
0963:                case T_byte:
0964:                    convertedType = TypeBinding.BYTE;
0965:                    break;
0966:                case T_short:
0967:                    convertedType = TypeBinding.SHORT;
0968:                    break;
0969:                case T_char:
0970:                    convertedType = TypeBinding.CHAR;
0971:                    break;
0972:                case T_int:
0973:                    convertedType = TypeBinding.INT;
0974:                    break;
0975:                case T_float:
0976:                    convertedType = TypeBinding.FLOAT;
0977:                    break;
0978:                case T_long:
0979:                    convertedType = TypeBinding.LONG;
0980:                    break;
0981:                case T_double:
0982:                    convertedType = TypeBinding.DOUBLE;
0983:                    break;
0984:                default:
0985:                }
0986:                if ((this .implicitConversion & TypeIds.BOXING) != 0) {
0987:                    convertedType = scope.environment().computeBoxingType(
0988:                            convertedType);
0989:                }
0990:                return convertedType;
0991:            }
0992:
0993:            public StringBuffer print(int indent, StringBuffer output) {
0994:                printIndent(indent, output);
0995:                return printExpression(indent, output);
0996:            }
0997:
0998:            public abstract StringBuffer printExpression(int indent,
0999:                    StringBuffer output);
1000:
1001:            public StringBuffer printStatement(int indent, StringBuffer output) {
1002:                return print(indent, output).append(";"); //$NON-NLS-1$
1003:            }
1004:
1005:            public void resolve(BlockScope scope) {
1006:                // drops the returning expression's type whatever the type is.
1007:
1008:                this .resolveType(scope);
1009:                return;
1010:            }
1011:
1012:            /**
1013:             * Resolve the type of this expression in the context of a blockScope
1014:             * 
1015:             * @param scope
1016:             * @return
1017:             * 	Return the actual type of this expression after resolution
1018:             */
1019:            public TypeBinding resolveType(BlockScope scope) {
1020:                // by default... subclasses should implement a better TB if required.
1021:                return null;
1022:            }
1023:
1024:            /**
1025:             * Resolve the type of this expression in the context of a classScope
1026:             * 
1027:             * @param scope
1028:             * @return
1029:             * 	Return the actual type of this expression after resolution
1030:             */
1031:            public TypeBinding resolveType(ClassScope scope) {
1032:                // by default... subclasses should implement a better TB if required.
1033:                return null;
1034:            }
1035:
1036:            public TypeBinding resolveTypeExpecting(BlockScope scope,
1037:                    TypeBinding expectedType) {
1038:
1039:                this .setExpectedType(expectedType); // needed in case of generic method invocation
1040:                TypeBinding expressionType = this .resolveType(scope);
1041:                if (expressionType == null)
1042:                    return null;
1043:                if (expressionType == expectedType)
1044:                    return expressionType;
1045:
1046:                if (!expressionType.isCompatibleWith(expectedType)) {
1047:                    if (scope.isBoxingCompatibleWith(expressionType,
1048:                            expectedType)) {
1049:                        this .computeConversion(scope, expectedType,
1050:                                expressionType);
1051:                    } else {
1052:                        scope.problemReporter().typeMismatchError(
1053:                                expressionType, expectedType, this );
1054:                        return null;
1055:                    }
1056:                }
1057:                return expressionType;
1058:            }
1059:
1060:            /**
1061:             * Returns an object which can be used to identify identical JSR sequence targets
1062:             * (see TryStatement subroutine codegen)
1063:             * or <code>null</null> if not reusable
1064:             */
1065:            public Object reusableJSRTarget() {
1066:                if (this .constant != Constant.NotAConstant)
1067:                    return this .constant;
1068:                return null;
1069:            }
1070:
1071:            /**
1072:             * Record the type expectation before this expression is typechecked.
1073:             * e.g. String s = foo();, foo() will be tagged as being expected of type String
1074:             * Used to trigger proper inference of generic method invocations.
1075:             * 
1076:             * @param expectedType
1077:             * 	The type denoting an expectation in the context of an assignment conversion
1078:             */
1079:            public void setExpectedType(TypeBinding expectedType) {
1080:                // do nothing by default
1081:            }
1082:
1083:            public void tagAsNeedCheckCast() {
1084:                // do nothing by default		
1085:            }
1086:
1087:            /**
1088:             * Record the fact a cast expression got detected as being unnecessary.
1089:             * 
1090:             * @param scope
1091:             * @param castType
1092:             */
1093:            public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) {
1094:                // do nothing by default
1095:            }
1096:
1097:            public Expression toTypeReference() {
1098:                //by default undefined
1099:
1100:                //this method is meanly used by the parser in order to transform
1101:                //an expression that is used as a type reference in a cast ....
1102:                //--appreciate the fact that castExpression and ExpressionWithParenthesis
1103:                //--starts with the same pattern.....
1104:
1105:                return this ;
1106:            }
1107:
1108:            /**
1109:             * Traverse an expression in the context of a blockScope
1110:             * @param visitor
1111:             * @param scope
1112:             */
1113:            public void traverse(ASTVisitor visitor, BlockScope scope) {
1114:                // nothing to do
1115:            }
1116:
1117:            /**
1118:             * Traverse an expression in the context of a classScope
1119:             * @param visitor
1120:             * @param scope
1121:             */
1122:            public void traverse(ASTVisitor visitor, ClassScope scope) {
1123:                // nothing to do
1124:            }
1125:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.