Source Code Cross Referenced for FieldExpression.java in  » 6.0-JDK-Modules-sun » tools » sun » tools » tree » 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 » 6.0 JDK Modules sun » tools » sun.tools.tree 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 1994-2003 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package sun.tools.tree;
0027:
0028:        import sun.tools.java.*;
0029:        import sun.tools.asm.*;
0030:        import java.io.PrintStream;
0031:        import java.util.Hashtable;
0032:
0033:        /**
0034:         * WARNING: The contents of this source file are not part of any
0035:         * supported API.  Code that depends on them does so at its own risk:
0036:         * they are subject to change or removal without notice.
0037:         */
0038:        public class FieldExpression extends UnaryExpression {
0039:            Identifier id;
0040:            MemberDefinition field;
0041:            Expression implementation;
0042:
0043:            // The class from which the field is select ed.
0044:            ClassDefinition clazz;
0045:
0046:            // For an expression of the form '<class>.super', then
0047:            // this is <class>, else null.
0048:            private ClassDefinition super Base;
0049:
0050:            /**
0051:             * constructor
0052:             */
0053:            public FieldExpression(long where, Expression right, Identifier id) {
0054:                super (FIELD, where, Type.tError, right);
0055:                this .id = id;
0056:            }
0057:
0058:            public FieldExpression(long where, Expression right,
0059:                    MemberDefinition field) {
0060:                super (FIELD, where, field.getType(), right);
0061:                this .id = field.getName();
0062:                this .field = field;
0063:            }
0064:
0065:            public Expression getImplementation() {
0066:                if (implementation != null)
0067:                    return implementation;
0068:                return this ;
0069:            }
0070:
0071:            /**
0072:             * Return true if the field is being selected from
0073:             * a qualified 'super'.
0074:             */
0075:            private boolean isQualSuper() {
0076:                return super Base != null;
0077:            }
0078:
0079:            /**
0080:             * Convert an '.' expression to a qualified identifier
0081:             */
0082:            static public Identifier toIdentifier(Expression e) {
0083:                StringBuffer buf = new StringBuffer();
0084:                while (e.op == FIELD) {
0085:                    FieldExpression fe = (FieldExpression) e;
0086:                    if (fe.id == idThis || fe.id == idClass) {
0087:                        return null;
0088:                    }
0089:                    buf.insert(0, fe.id);
0090:                    buf.insert(0, '.');
0091:                    e = fe.right;
0092:                }
0093:                if (e.op != IDENT) {
0094:                    return null;
0095:                }
0096:                buf.insert(0, ((IdentifierExpression) e).id);
0097:                return Identifier.lookup(buf.toString());
0098:            }
0099:
0100:            /**
0101:             * Convert a qualified name into a type.
0102:             * Performs a careful check of each inner-class component,
0103:             * including the JLS 6.6.1 access checks that were omitted
0104:             * in 'FieldExpression.toType'.
0105:             * <p>
0106:             * This code is similar to 'checkCommon', which could be cleaned
0107:             * up a bit long the lines we have done here.
0108:             */
0109:            /*-------------------------------------------------------*
0110:            Type toQualifiedType(Environment env, Context ctx) {
0111:            ClassDefinition ctxClass = ctx.field.getClassDefinition();
0112:            Type rty = right.toQualifiedType(env, ctx);
0113:            if (rty == Type.tPackage) {
0114:                // Is this field expression a non-inner type?
0115:                Identifier nm = toIdentifier(this);
0116:                if ((nm != null) && env.classExists(nm)) {
0117:                        Type t = Type.tClass(nm);
0118:            	if (env.resolve(where, ctxClass, t)) {
0119:            	    return t;
0120:            	} else {
0121:            	    return null;
0122:            	}
0123:                }
0124:                // Not a type.  Must be a package prefix.
0125:                return Type.tPackage;
0126:            }
0127:            if (rty == null) {
0128:                // An error was already reported, so quit.
0129:                return null;
0130:            }
0131:
0132:            // Check inner-class qualification while unwinding from recursion.
0133:            try {
0134:                ClassDefinition rightClass = env.getClassDefinition(rty);
0135:
0136:                // Local variables, which cannot be inner classes,
0137:                // are ignored here, and thus will not hide inner
0138:                // classes.  Is this correct?
0139:                MemberDefinition field = rightClass.getInnerClass(env, id);
0140:                if (field == null) {
0141:            	env.error(where, "inner.class.expected", id, rightClass);
0142:            	return Type.tError;
0143:                }
0144:
0145:                ClassDefinition innerClass = field.getInnerClass();
0146:                Type t = innerClass.getType();
0147:
0148:                if (!ctxClass.canAccess(env, field)) {
0149:            	env.error(where, "no.type.access", id, rightClass, ctxClass);
0150:            	return t;
0151:                }
0152:                if (field.isProtected()
0153:                    && !ctxClass.protectedAccess(env, field, rty)) {
0154:                    env.error(where, "invalid.protected.type.use", id, ctxClass, rty);
0155:            	return t;
0156:                }
0157:
0158:                // These were ommitted earlier in calls to 'toType', but I can't
0159:                // see any reason for that.  I think it was an oversight.  See
0160:                // 'checkCommon' and 'checkInnerClass'.
0161:                innerClass.noteUsedBy(ctxClass, where, env);
0162:                ctxClass.addDependency(field.getClassDeclaration());
0163:                
0164:                return t;
0165:
0166:            } catch (ClassNotFound e) {
0167:                env.error(where, "class.not.found", e.name, ctx.field);
0168:            }
0169:
0170:            // Class not found.
0171:            return null;
0172:            }
0173:             *-------------------------------------------------------*/
0174:
0175:            /**
0176:             * Convert an '.' expression to a type
0177:             */
0178:
0179:            // This is a rewrite to treat qualified names in a
0180:            // context in which a type name is expected in the
0181:            // same way that they are handled for an ambiguous
0182:            // or expression-expected context in 'checkCommon'
0183:            // below.  The new code is cleaner and allows better
0184:            // localization of errors.  Unfortunately, most
0185:            // qualified names appearing in types are actually
0186:            // handled by 'Environment.resolve'.  There isn't
0187:            // much point, then, in breaking out 'toType' as a 
0188:            // special case until the other cases can be cleaned
0189:            // up as well.  For the time being, we will leave this
0190:            // code disabled, thus reducing the testing requirements.
0191:            /*-------------------------------------------------------*
0192:            Type toType(Environment env, Context ctx) {
0193:            Type t = toQualifiedType(env, ctx);
0194:            if (t == null) {
0195:                return Type.tError;
0196:            }
0197:            if (t == Type.tPackage) {
0198:                FieldExpression.reportFailedPackagePrefix(env, right, true);
0199:                return Type.tError;
0200:            }
0201:            return t;
0202:            }
0203:             *-------------------------------------------------------*/
0204:
0205:            Type toType(Environment env, Context ctx) {
0206:                Identifier id = toIdentifier(this );
0207:                if (id == null) {
0208:                    env.error(where, "invalid.type.expr");
0209:                    return Type.tError;
0210:                }
0211:                Type t = Type.tClass(ctx.resolveName(env, id));
0212:                if (env.resolve(where, ctx.field.getClassDefinition(), t)) {
0213:                    return t;
0214:                }
0215:                return Type.tError;
0216:            }
0217:
0218:            /**
0219:             * Check if the present name is part of a scoping prefix.
0220:             */
0221:
0222:            public Vset checkAmbigName(Environment env, Context ctx, Vset vset,
0223:                    Hashtable exp, UnaryExpression loc) {
0224:                if (id == idThis || id == idClass) {
0225:                    loc = null; // this cannot be a type or package
0226:                }
0227:                return checkCommon(env, ctx, vset, exp, loc, false);
0228:            }
0229:
0230:            /**
0231:             * Check the expression
0232:             */
0233:
0234:            public Vset checkValue(Environment env, Context ctx, Vset vset,
0235:                    Hashtable exp) {
0236:                vset = checkCommon(env, ctx, vset, exp, null, false);
0237:                if (id == idSuper && type != Type.tError) {
0238:                    // "super" is not allowed in this context.
0239:                    // It must always qualify another name.
0240:                    env.error(where, "undef.var.super", idSuper);
0241:                }
0242:                return vset;
0243:            }
0244:
0245:            /**
0246:             * If 'checkAmbiguousName' returns 'Package.tPackage', then it was
0247:             * unable to resolve any prefix of the qualified name.  This method
0248:             * attempts to diagnose the problem.
0249:             */
0250:
0251:            static void reportFailedPackagePrefix(Environment env,
0252:                    Expression right) {
0253:                reportFailedPackagePrefix(env, right, false);
0254:            }
0255:
0256:            static void reportFailedPackagePrefix(Environment env,
0257:                    Expression right, boolean mustBeType) {
0258:                // Find the leftmost component, and put the blame on it.
0259:                Expression idp = right;
0260:                while (idp instanceof  UnaryExpression)
0261:                    idp = ((UnaryExpression) idp).right;
0262:                IdentifierExpression ie = (IdentifierExpression) idp;
0263:
0264:                // It may be that 'ie' refers to an ambiguous class.  Check this
0265:                // with a call to env.resolve(). Part of solution for 4059855.
0266:                try {
0267:                    env.resolve(ie.id);
0268:                } catch (AmbiguousClass e) {
0269:                    env.error(right.where, "ambig.class", e.name1, e.name2);
0270:                    return;
0271:                } catch (ClassNotFound e) {
0272:                }
0273:
0274:                if (idp == right) {
0275:                    if (mustBeType) {
0276:                        env.error(ie.where, "undef.class", ie.id);
0277:                    } else {
0278:                        env.error(ie.where, "undef.var.or.class", ie.id);
0279:                    }
0280:                } else {
0281:                    if (mustBeType) {
0282:                        env.error(ie.where, "undef.class.or.package", ie.id);
0283:                    } else {
0284:                        env
0285:                                .error(ie.where, "undef.var.class.or.package",
0286:                                        ie.id);
0287:                    }
0288:                }
0289:            }
0290:
0291:            /**
0292:             * Rewrite accesses to private fields of another class.
0293:             */
0294:
0295:            private Expression implementFieldAccess(Environment env,
0296:                    Context ctx, Expression base, boolean isLHS) {
0297:                ClassDefinition abase = accessBase(env, ctx);
0298:                if (abase != null) {
0299:
0300:                    // If the field is final and its initializer is a constant expression,
0301:                    // then just rewrite to the constant expression. This is not just an
0302:                    // optimization, but is required for correctness.  If an expression is
0303:                    // rewritten to use an access method, then its status as a constant
0304:                    // expression is lost.  This was the cause of bug 4098737.  Note that
0305:                    // a call to 'getValue(env)' below would not be correct, as it attempts
0306:                    // to simplify the initial value expression, which must not occur until
0307:                    // after the checking phase, for example, after definite assignment checks.
0308:                    if (field.isFinal()) {
0309:                        Expression e = (Expression) field.getValue();
0310:                        // Must not be LHS here.  Test as a precaution,
0311:                        // as we may not be careful to avoid this when
0312:                        // compiling an erroneous program.
0313:                        if ((e != null) && e.isConstant() && !isLHS) {
0314:                            return e.copyInline(ctx);
0315:                        }
0316:                    }
0317:
0318:                    //System.out.println("Finding access method for " + field);
0319:                    MemberDefinition af = abase.getAccessMember(env, ctx,
0320:                            field, isQualSuper());
0321:                    //System.out.println("Using access method " + af);
0322:
0323:                    if (!isLHS) {
0324:                        //System.out.println("Reading " + field + 
0325:                        //				" via access method " + af);
0326:                        // If referencing the value of the field, then replace
0327:                        // with a call to the access method.  If assigning to
0328:                        // the field, a call to the update method will be
0329:                        // generated later. It is important that
0330:                        // 'implementation' not be set to non-null if the
0331:                        // expression is a valid assignment target.
0332:                        // (See 'checkLHS'.)
0333:                        if (field.isStatic()) {
0334:                            Expression args[] = {};
0335:                            Expression call = new MethodExpression(where, null,
0336:                                    af, args);
0337:                            return new CommaExpression(where, base, call);
0338:                        } else {
0339:                            Expression args[] = { base };
0340:                            return new MethodExpression(where, null, af, args);
0341:                        }
0342:                    }
0343:                }
0344:
0345:                return null;
0346:            }
0347:
0348:            /**
0349:             * Determine if an access method is required, and, if so, return
0350:             * the class in which it should appear, else return null.
0351:             */
0352:            private ClassDefinition accessBase(Environment env, Context ctx) {
0353:                if (field.isPrivate()) {
0354:                    ClassDefinition cdef = field.getClassDefinition();
0355:                    ClassDefinition ctxClass = ctx.field.getClassDefinition();
0356:                    if (cdef == ctxClass) {
0357:                        // If access from same class as field, then no access
0358:                        // method is needed.
0359:                        return null;
0360:                    }
0361:                    // An access method is needed in the class containing the field.
0362:                    return cdef;
0363:                } else if (field.isProtected()) {
0364:                    if (super Base == null) {
0365:                        // If access is not via qualified super, then it is either
0366:                        // OK without an access method, or it is an illegal access
0367:                        // for which an error message should have been issued.
0368:                        // Legal accesses include unqualified 'super.foo'.
0369:                        return null;
0370:                    }
0371:                    ClassDefinition cdef = field.getClassDefinition();
0372:                    ClassDefinition ctxClass = ctx.field.getClassDefinition();
0373:                    if (cdef.inSamePackage(ctxClass)) {
0374:                        // Access to protected member in same package always allowed.
0375:                        return null;
0376:                    }
0377:                    // Access via qualified super.
0378:                    // An access method is needed in the qualifying class, an
0379:                    // immediate subclass of the class containing the selected
0380:                    // field.  NOTE: The fact that the returned class is 'superBase'
0381:                    // carries the additional bit of information (that a special
0382:                    // superclass access method is being created) which is provided
0383:                    // to 'getAccessMember' via its 'isSuper' argument.
0384:                    return super Base;
0385:                } else {
0386:                    // No access method needed.
0387:                    return null;
0388:                }
0389:            }
0390:
0391:            /**
0392:             * Determine if a type is accessible from a given class.
0393:             */
0394:            static boolean isTypeAccessible(long where, Environment env,
0395:                    Type t, ClassDefinition c) {
0396:                switch (t.getTypeCode()) {
0397:                case TC_CLASS:
0398:                    try {
0399:                        Identifier nm = t.getClassName();
0400:                        // Why not just use 'Environment.getClassDeclaration' here?
0401:                        // But 'Environment.getClassDeclation' has special treatment
0402:                        // for local classes that is probably necessary.  This code
0403:                        // was adapted from 'Environment.resolve'.
0404:                        ClassDefinition def = env.getClassDefinition(t);
0405:                        return c.canAccess(env, def.getClassDeclaration());
0406:                    } catch (ClassNotFound e) {
0407:                    } // Ignore -- reported elsewhere.
0408:                    return true;
0409:                case TC_ARRAY:
0410:                    return isTypeAccessible(where, env, t.getElementType(), c);
0411:                default:
0412:                    return true;
0413:                }
0414:            }
0415:
0416:            /**
0417:             * Common code for checkValue and checkAmbigName
0418:             */
0419:
0420:            private Vset checkCommon(Environment env, Context ctx, Vset vset,
0421:                    Hashtable exp, UnaryExpression loc, boolean isLHS) {
0422:
0423:                // Handle class literal, e.g., 'x.class'.
0424:                if (id == idClass) {
0425:
0426:                    // In 'x.class', 'x' must be a type name, possibly qualified.
0427:                    Type t = right.toType(env, ctx);
0428:
0429:                    if (!t.isType(TC_CLASS) && !t.isType(TC_ARRAY)) {
0430:                        if (t.isType(TC_ERROR)) {
0431:                            type = Type.tClassDesc;
0432:                            return vset;
0433:                        }
0434:                        String wrc = null;
0435:                        switch (t.getTypeCode()) {
0436:                        case TC_VOID:
0437:                            wrc = "Void";
0438:                            break;
0439:                        case TC_BOOLEAN:
0440:                            wrc = "Boolean";
0441:                            break;
0442:                        case TC_BYTE:
0443:                            wrc = "Byte";
0444:                            break;
0445:                        case TC_CHAR:
0446:                            wrc = "Character";
0447:                            break;
0448:                        case TC_SHORT:
0449:                            wrc = "Short";
0450:                            break;
0451:                        case TC_INT:
0452:                            wrc = "Integer";
0453:                            break;
0454:                        case TC_FLOAT:
0455:                            wrc = "Float";
0456:                            break;
0457:                        case TC_LONG:
0458:                            wrc = "Long";
0459:                            break;
0460:                        case TC_DOUBLE:
0461:                            wrc = "Double";
0462:                            break;
0463:                        default:
0464:                            env.error(right.where, "invalid.type.expr");
0465:                            return vset;
0466:                        }
0467:                        Identifier wid = Identifier.lookup(idJavaLang + "."
0468:                                + wrc);
0469:                        Expression wcls = new TypeExpression(where, Type
0470:                                .tClass(wid));
0471:                        implementation = new FieldExpression(where, wcls,
0472:                                idTYPE);
0473:                        vset = implementation.checkValue(env, ctx, vset, exp);
0474:                        type = implementation.type; // java.lang.Class
0475:                        return vset;
0476:                    }
0477:
0478:                    // Check for the bogus type `array of void'
0479:                    if (t.isVoidArray()) {
0480:                        type = Type.tClassDesc;
0481:                        env.error(right.where, "void.array");
0482:                        return vset;
0483:                    }
0484:
0485:                    // it is a class or array
0486:                    long fwhere = ctx.field.getWhere();
0487:                    ClassDefinition fcls = ctx.field.getClassDefinition();
0488:                    MemberDefinition lookup = fcls
0489:                            .getClassLiteralLookup(fwhere);
0490:
0491:                    String sig = t.getTypeSignature();
0492:                    String className;
0493:                    if (t.isType(TC_CLASS)) {
0494:                        // sig is like "Lfoo/bar;", name is like "foo.bar".
0495:                        // We assume SIG_CLASS and SIG_ENDCLASS are 1 char each.
0496:                        className = sig.substring(1, sig.length() - 1).replace(
0497:                                SIGC_PACKAGE, '.');
0498:                    } else {
0499:                        // sig is like "[Lfoo/bar;" or "[I";
0500:                        // name is like "[Lfoo.bar" or (again) "[I".
0501:                        className = sig.replace(SIGC_PACKAGE, '.');
0502:                    }
0503:
0504:                    if (fcls.isInterface()) {
0505:                        // The immediately-enclosing type is an interface.
0506:                        // The class literal can only appear in an initialization 
0507:                        // expression, so don't bother caching it.  (This could
0508:                        // lose if many initializations use the same class literal,
0509:                        // but saves time and code space otherwise.)
0510:                        implementation = makeClassLiteralInlineRef(env, ctx,
0511:                                lookup, className);
0512:                    } else {
0513:                        // Cache the call to the helper, as it may be executed
0514:                        // many times (e.g., if the class literal is inside a loop).
0515:                        ClassDefinition inClass = lookup.getClassDefinition();
0516:                        MemberDefinition cfld = getClassLiteralCache(env, ctx,
0517:                                className, inClass);
0518:                        implementation = makeClassLiteralCacheRef(env, ctx,
0519:                                lookup, cfld, className);
0520:                    }
0521:
0522:                    vset = implementation.checkValue(env, ctx, vset, exp);
0523:                    type = implementation.type; // java.lang.Class
0524:                    return vset;
0525:                }
0526:
0527:                // Arrive here if not a class literal.
0528:
0529:                if (field != null) {
0530:
0531:                    // The field as been pre-set, e.g., as the result of transforming
0532:                    // an 'IdentifierExpression'. Most error-checking has already been
0533:                    // performed at this point.
0534:                    // QUERY: Why don't we further unify checking of identifier
0535:                    // expressions and field expressions that denote instance and
0536:                    // class variables?
0537:
0538:                    implementation = implementFieldAccess(env, ctx, right,
0539:                            isLHS);
0540:                    return (right == null) ? vset : right.checkAmbigName(env,
0541:                            ctx, vset, exp, this );
0542:                }
0543:
0544:                // Does the qualifier have a meaning of its own?
0545:                vset = right.checkAmbigName(env, ctx, vset, exp, this );
0546:                if (right.type == Type.tPackage) {
0547:                    // Are we out of options?
0548:                    if (loc == null) {
0549:                        FieldExpression.reportFailedPackagePrefix(env, right);
0550:                        return vset;
0551:                    }
0552:
0553:                    // ASSERT(loc.right == this)
0554:
0555:                    // Nope.  Is this field expression a type?
0556:                    Identifier nm = toIdentifier(this );
0557:                    if ((nm != null) && env.classExists(nm)) {
0558:                        loc.right = new TypeExpression(where, Type.tClass(nm));
0559:                        // Check access. (Cf. IdentifierExpression.toResolvedType.)
0560:                        ClassDefinition ctxClass = ctx.field
0561:                                .getClassDefinition();
0562:                        env.resolve(where, ctxClass, loc.right.type);
0563:                        return vset;
0564:                    }
0565:
0566:                    // Let the caller make sense of it, then.
0567:                    type = Type.tPackage;
0568:                    return vset;
0569:                }
0570:
0571:                // Good; we have a well-defined qualifier type.
0572:
0573:                ClassDefinition ctxClass = ctx.field.getClassDefinition();
0574:                boolean staticRef = (right instanceof  TypeExpression);
0575:
0576:                try {
0577:
0578:                    // Handle array 'length' field, e.g., 'x.length'.
0579:
0580:                    if (!right.type.isType(TC_CLASS)) {
0581:                        if (right.type.isType(TC_ARRAY) && id.equals(idLength)) {
0582:                            // Verify that the type of the base expression is accessible.
0583:                            // Required by JLS 6.6.1.  Fixes 4094658.
0584:                            if (!FieldExpression.isTypeAccessible(where, env,
0585:                                    right.type, ctxClass)) {
0586:                                ClassDeclaration cdecl = ctxClass
0587:                                        .getClassDeclaration();
0588:                                if (staticRef) {
0589:                                    env.error(where, "no.type.access", id,
0590:                                            right.type.toString(), cdecl);
0591:                                } else {
0592:                                    env.error(where, "cant.access.member.type",
0593:                                            id, right.type.toString(), cdecl);
0594:                                }
0595:                            }
0596:                            type = Type.tInt;
0597:                            implementation = new LengthExpression(where, right);
0598:                            return vset;
0599:                        }
0600:                        if (!right.type.isType(TC_ERROR)) {
0601:                            env.error(where, "invalid.field.reference", id,
0602:                                    right.type);
0603:                        }
0604:                        return vset;
0605:                    }
0606:
0607:                    // At this point, we know that 'right.type' is a class type.
0608:
0609:                    // Note that '<expr>.super(...)' and '<expr>.this(...)' cases never
0610:                    // reach here.  Instead, '<expr>' is stored as the 'outerArg' field
0611:                    // of a 'SuperExpression' or 'ThisExpression' node.
0612:
0613:                    // If our prefix is of the form '<class>.super', then we are
0614:                    // about to do a field selection '<class>.super.<field>'.
0615:                    // Save the qualifying class in 'superBase', which is non-null
0616:                    // only if the current FieldExpression is a qualified 'super' form.
0617:                    // Also, set 'sourceClass' to the "effective accessing class" relative
0618:                    // to which access checks will be performed.  Normally, this is the
0619:                    // immediately enclosing class.  For '<class>.this' and '<class>.super',
0620:                    // however, we use <class>.
0621:
0622:                    ClassDefinition sourceClass = ctxClass;
0623:                    if (right instanceof  FieldExpression) {
0624:                        Identifier id = ((FieldExpression) right).id;
0625:                        if (id == idThis) {
0626:                            sourceClass = ((FieldExpression) right).clazz;
0627:                        } else if (id == idSuper) {
0628:                            sourceClass = ((FieldExpression) right).clazz;
0629:                            super Base = sourceClass;
0630:                        }
0631:                    }
0632:
0633:                    // Handle 'class.this' and 'class.super'.
0634:                    //
0635:                    // Suppose 'super.name' appears within a class C with immediate
0636:                    // superclass S. According to JLS 15.10.2, 'super.name' in this
0637:                    // case is equivalent to '((S)this).name'.  Analogously, we interpret
0638:                    // 'class.super.name' as '((S)(class.this)).name', where S is the
0639:                    // immediate superclass of (enclosing) class 'class'.
0640:                    // Note that 'super' may not stand alone as an expression, but must
0641:                    // occur as the qualifying expression of a field access or a method
0642:                    // invocation.  This is enforced in 'SuperExpression.checkValue' and
0643:                    // 'FieldExpression.checkValue', and need not concern us here.
0644:
0645:                    //ClassDefinition clazz = env.getClassDefinition(right.type);
0646:                    clazz = env.getClassDefinition(right.type);
0647:                    if (id == idThis || id == idSuper) {
0648:                        if (!staticRef) {
0649:                            env.error(right.where, "invalid.type.expr");
0650:                        }
0651:
0652:                        // We used to check that 'right.type' is accessible here,
0653:                        // per JLS 6.6.1.  As a result of the fix for 4102393, however,
0654:                        // the qualifying class name must exactly match an enclosing
0655:                        // outer class, which is necessarily accessible.
0656:
0657:                        /*** Temporary assertion check ***/
0658:                        if (ctx.field.isSynthetic())
0659:                            throw new CompilerError("synthetic qualified this");
0660:                        /*********************************/
0661:
0662:                        // A.this means we're inside an A and we want its self ptr.
0663:                        // C.this is always the same as this when C is innermost.
0664:                        // Another A.this means we skip out to get a "hidden" this,
0665:                        // just as ASuper.foo skips out to get a hidden variable.
0666:                        // Last argument 'true' means we want an exact class match,
0667:                        // not a subclass of the specified class ('clazz').
0668:                        implementation = ctx.findOuterLink(env, where, clazz,
0669:                                null, true);
0670:                        vset = implementation.checkValue(env, ctx, vset, exp);
0671:                        if (id == idSuper) {
0672:                            type = clazz.getSuperClass().getType();
0673:                        } else {
0674:                            type = clazz.getType();
0675:                        }
0676:                        return vset;
0677:                    }
0678:
0679:                    // Field should be an instance variable or class variable.
0680:                    field = clazz.getVariable(env, id, sourceClass);
0681:
0682:                    if (field == null && staticRef && loc != null) {
0683:                        // Is this field expression an inner type?
0684:                        // Search the class and its supers (but not its outers).
0685:                        // QUERY: We may need to get the inner class from a
0686:                        // superclass of 'clazz'.  This call is prepared to 
0687:                        // resolve the superclass if necessary.  Can we arrange
0688:                        // to assure that it is always previously resolved?
0689:                        // This is one of a small number of problematic calls that
0690:                        // requires 'getSuperClass' to resolve superclasses on demand.
0691:                        // See 'ClassDefinition.getInnerClass(env, nm)'.
0692:                        field = clazz.getInnerClass(env, id);
0693:                        if (field != null) {
0694:                            return checkInnerClass(env, ctx, vset, exp, loc);
0695:                        }
0696:                    }
0697:
0698:                    // If not a variable reference, diagnose error if name is
0699:                    // that of a method.
0700:
0701:                    if (field == null) {
0702:                        if ((field = clazz.findAnyMethod(env, id)) != null) {
0703:                            env.error(where, "invalid.field", id, field
0704:                                    .getClassDeclaration());
0705:                        } else {
0706:                            env.error(where, "no.such.field", id, clazz);
0707:                        }
0708:                        return vset;
0709:                    }
0710:
0711:                    // At this point, we have identified a valid field.
0712:
0713:                    // Required by JLS 6.6.1.  Fixes 4094658.
0714:                    if (!FieldExpression.isTypeAccessible(where, env,
0715:                            right.type, sourceClass)) {
0716:                        ClassDeclaration cdecl = sourceClass
0717:                                .getClassDeclaration();
0718:                        if (staticRef) {
0719:                            env.error(where, "no.type.access", id, right.type
0720:                                    .toString(), cdecl);
0721:                        } else {
0722:                            env.error(where, "cant.access.member.type", id,
0723:                                    right.type.toString(), cdecl);
0724:                        }
0725:                    }
0726:
0727:                    type = field.getType();
0728:
0729:                    if (!sourceClass.canAccess(env, field)) {
0730:                        env.error(where, "no.field.access", id, clazz,
0731:                                sourceClass.getClassDeclaration());
0732:                        return vset;
0733:                    }
0734:
0735:                    if (staticRef && !field.isStatic()) {
0736:                        // 'Class.field' is not legal when field is not static;
0737:                        // see JLS 15.13.1.  This case was permitted by javac
0738:                        // prior to 1.2; static refs were silently changed to
0739:                        // be dynamic access of the form 'this.field'.
0740:                        env.error(where, "no.static.field.access", id, clazz);
0741:                        return vset;
0742:                    } else {
0743:                        // Rewrite access to use an access method if necessary.		
0744:                        implementation = implementFieldAccess(env, ctx, right,
0745:                                isLHS);
0746:                    }
0747:
0748:                    // Check for invalid access to protected field.
0749:                    if (field.isProtected()
0750:                            && !(right instanceof  SuperExpression
0751:                            // Extension of JLS 6.6.2 for qualified 'super'.
0752:                            || (right instanceof  FieldExpression && ((FieldExpression) right).id == idSuper))
0753:                            && !sourceClass.protectedAccess(env, field,
0754:                                    right.type)) {
0755:                        env.error(where, "invalid.protected.field.use", field
0756:                                .getName(), field.getClassDeclaration(),
0757:                                right.type);
0758:                        return vset;
0759:                    }
0760:
0761:                    if ((!field.isStatic()) && (right.op == THIS)
0762:                            && !vset.testVar(ctx.getThisNumber())) {
0763:                        env.error(where, "access.inst.before.super", id);
0764:                    }
0765:
0766:                    if (field.reportDeprecated(env)) {
0767:                        env.error(where, "warn." + "field.is.deprecated", id,
0768:                                field.getClassDefinition());
0769:                    }
0770:
0771:                    // When a package-private class defines public or protected
0772:                    // members, those members may sometimes be accessed from
0773:                    // outside of the package in public subclasses.  In these
0774:                    // cases, we need to massage the getField to refer to
0775:                    // to an accessible subclass rather than the package-private
0776:                    // parent class.  Part of fix for 4135692.
0777:
0778:                    // Find out if the class which contains this field
0779:                    // reference has access to the class which declares the
0780:                    // public or protected field.
0781:                    if (sourceClass == ctxClass) {
0782:                        ClassDefinition declarer = field.getClassDefinition();
0783:                        if (declarer.isPackagePrivate()
0784:                                && !declarer.getName().getQualifier().equals(
0785:                                        sourceClass.getName().getQualifier())) {
0786:
0787:                            //System.out.println("The access of member " +
0788:                            //		   field + " declared in class " +
0789:                            //		   declarer +
0790:                            //		   " is not allowed by the VM from class  " +
0791:                            //		   ctxClass +
0792:                            //		   ".  Replacing with an access of class " +
0793:                            //		   clazz);
0794:
0795:                            // We cannot make this access at the VM level.
0796:                            // Construct a member which will stand for this
0797:                            // field in ctxClass and set `field' to refer to it.
0798:                            field = MemberDefinition.makeProxyMember(field,
0799:                                    clazz, env);
0800:                        }
0801:                    }
0802:
0803:                    sourceClass.addDependency(field.getClassDeclaration());
0804:
0805:                } catch (ClassNotFound e) {
0806:                    env.error(where, "class.not.found", e.name, ctx.field);
0807:
0808:                } catch (AmbiguousMember e) {
0809:                    env.error(where, "ambig.field", id, e.field1
0810:                            .getClassDeclaration(), e.field2
0811:                            .getClassDeclaration());
0812:                }
0813:                return vset;
0814:            }
0815:
0816:            /**
0817:             * Return a <code>FieldUpdater</code> object to be used in updating the
0818:             * value of the location denoted by <code>this</code>, which must be an
0819:             * expression suitable for the left-hand side of an assignment.
0820:             * This is used for implementing assignments to private fields for which
0821:             * an access method is required.  Returns null if no access method is
0822:             * needed, in which case the assignment is handled in the usual way, by 
0823:             * direct access.  Only simple assignment expressions are handled here
0824:             * Assignment operators and pre/post increment/decrement operators are
0825:             * are handled by 'getUpdater' below.
0826:             * <p>
0827:             * Must be called after 'checkValue', else 'right' will be invalid.
0828:             */
0829:
0830:            public FieldUpdater getAssigner(Environment env, Context ctx) {
0831:                if (field == null) {
0832:                    // Field can legitimately be null if the field name was
0833:                    // undefined, in which case an error was reported, but 
0834:                    // no value for 'field' is available.
0835:                    //   throw new CompilerError("getAssigner");
0836:                    return null;
0837:                }
0838:                ClassDefinition abase = accessBase(env, ctx);
0839:                if (abase != null) {
0840:                    MemberDefinition setter = abase.getUpdateMember(env, ctx,
0841:                            field, isQualSuper());
0842:                    // It may not be necessary to copy 'right' here.
0843:                    Expression base = (right == null) ? null : right
0844:                            .copyInline(ctx);
0845:                    // Created 'FieldUpdater' has no getter method.
0846:                    return new FieldUpdater(where, field, base, null, setter);
0847:                }
0848:                return null;
0849:            }
0850:
0851:            /**
0852:             * Return a <code>FieldUpdater</code> object to be used in updating the
0853:             * value of the location denoted by <code>this</code>, which must be an
0854:             * expression suitable for the left-hand side of an assignment.  This is
0855:             * used for implementing the assignment operators and the increment and
0856:             * decrement operators on private fields that are accessed from another
0857:             * class, e.g, uplevel from an inner class. Returns null if no access
0858:             * method is needed.
0859:             * <p>
0860:             * Must be called after 'checkValue', else 'right' will be invalid.
0861:             */
0862:
0863:            public FieldUpdater getUpdater(Environment env, Context ctx) {
0864:                if (field == null) {
0865:                    // Field can legitimately be null if the field name was
0866:                    // undefined, in which case an error was reported, but 
0867:                    // no value for 'field' is available.
0868:                    //   throw new CompilerError("getUpdater");
0869:                    return null;
0870:                }
0871:                ClassDefinition abase = accessBase(env, ctx);
0872:                if (abase != null) {
0873:                    MemberDefinition getter = abase.getAccessMember(env, ctx,
0874:                            field, isQualSuper());
0875:                    MemberDefinition setter = abase.getUpdateMember(env, ctx,
0876:                            field, isQualSuper());
0877:                    // It may not be necessary to copy 'right' here.
0878:                    Expression base = (right == null) ? null : right
0879:                            .copyInline(ctx);
0880:                    return new FieldUpdater(where, field, base, getter, setter);
0881:                }
0882:                return null;
0883:            }
0884:
0885:            /**
0886:             * This field expression is an inner class reference.
0887:             * Finish checking it.
0888:             */
0889:            private Vset checkInnerClass(Environment env, Context ctx,
0890:                    Vset vset, Hashtable exp, UnaryExpression loc) {
0891:                ClassDefinition inner = field.getInnerClass();
0892:                type = inner.getType();
0893:
0894:                if (!inner.isTopLevel()) {
0895:                    env.error(where, "inner.static.ref", inner.getName());
0896:                }
0897:
0898:                Expression te = new TypeExpression(where, type);
0899:
0900:                // check access
0901:                ClassDefinition ctxClass = ctx.field.getClassDefinition();
0902:                try {
0903:                    if (!ctxClass.canAccess(env, field)) {
0904:                        ClassDefinition clazz = env
0905:                                .getClassDefinition(right.type);
0906:                        //env.error(where, "no.type.access",
0907:                        //          id, clazz, ctx.field.getClassDeclaration());
0908:                        env.error(where, "no.type.access", id, clazz, ctxClass
0909:                                .getClassDeclaration());
0910:                        return vset;
0911:                    }
0912:
0913:                    if (field.isProtected()
0914:                            && !(right instanceof  SuperExpression
0915:                            // Extension of JLS 6.6.2 for qualified 'super'.
0916:                            || (right instanceof  FieldExpression && ((FieldExpression) right).id == idSuper))
0917:                            && !ctxClass
0918:                                    .protectedAccess(env, field, right.type)) {
0919:                        env.error(where, "invalid.protected.field.use", field
0920:                                .getName(), field.getClassDeclaration(),
0921:                                right.type);
0922:                        return vset;
0923:                    }
0924:
0925:                    inner.noteUsedBy(ctxClass, where, env);
0926:
0927:                } catch (ClassNotFound e) {
0928:                    env.error(where, "class.not.found", e.name, ctx.field);
0929:                }
0930:
0931:                ctxClass.addDependency(field.getClassDeclaration());
0932:                if (loc == null)
0933:                    // Complain about a free-floating type name.
0934:                    return te.checkValue(env, ctx, vset, exp);
0935:                loc.right = te;
0936:                return vset;
0937:            }
0938:
0939:            /**
0940:             * Check the expression if it appears on the LHS of an assignment
0941:             */
0942:            public Vset checkLHS(Environment env, Context ctx, Vset vset,
0943:                    Hashtable exp) {
0944:                boolean hadField = (field != null);
0945:
0946:                //checkValue(env, ctx, vset, exp);
0947:                checkCommon(env, ctx, vset, exp, null, true);
0948:
0949:                // If 'implementation' is set to a non-null value, then the
0950:                // field expression does not denote an assignable location,
0951:                // e.g., the 'length' field of an array.
0952:                if (implementation != null) {
0953:                    // This just reports an error and recovers.
0954:                    return super .checkLHS(env, ctx, vset, exp);
0955:                }
0956:
0957:                if (field != null && field.isFinal() && !hadField) {
0958:                    if (field.isBlankFinal()) {
0959:                        if (field.isStatic()) {
0960:                            if (right != null) {
0961:                                env.error(where,
0962:                                        "qualified.static.final.assign");
0963:                            }
0964:                            // Continue with checking anyhow.
0965:                            // In fact, it would be easy to allow this case.
0966:                        } else {
0967:                            if ((right != null) && (right.op != THIS)) {
0968:                                env.error(where, "bad.qualified.final.assign",
0969:                                        field.getName());
0970:                                // The actual instance could be anywhere, so don't
0971:                                // continue with checking the definite assignment status.
0972:                                return vset;
0973:                            }
0974:                        }
0975:                        vset = checkFinalAssign(env, ctx, vset, where, field);
0976:                    } else {
0977:                        env.error(where, "assign.to.final", id);
0978:                    }
0979:                }
0980:                return vset;
0981:            }
0982:
0983:            /**
0984:             * Check the expression if it appears on the LHS of an op= expression 
0985:             */
0986:            public Vset checkAssignOp(Environment env, Context ctx, Vset vset,
0987:                    Hashtable exp, Expression outside) {
0988:
0989:                //checkValue(env, ctx, vset, exp);
0990:                checkCommon(env, ctx, vset, exp, null, true);
0991:
0992:                // If 'implementation' is set to a non-null value, then the
0993:                // field expression does not denote an assignable location,
0994:                // e.g., the 'length' field of an array.
0995:                if (implementation != null) {
0996:                    return super .checkLHS(env, ctx, vset, exp);
0997:                }
0998:                if (field != null && field.isFinal()) {
0999:                    env.error(where, "assign.to.final", id);
1000:                }
1001:                return vset;
1002:            }
1003:
1004:            /**
1005:             * There is a simple assignment being made to the given final field.
1006:             * The field was named either by a simple name or by an almost-simple
1007:             * expression of the form "this.v".
1008:             * Check if this is a legal assignment.
1009:             * <p>
1010:             * Blank final variables can be set in initializers or constructor
1011:             * bodies.  In all cases there must be definite single assignment.
1012:             * (All instance and instance variable initializers and each
1013:             * constructor body are treated as if concatenated for the purposes
1014:             * of this check.  Assignment to "this.x" is treated as a definite
1015:             * assignment to the simple name "x" which names the instance variable.)
1016:             */
1017:
1018:            public static Vset checkFinalAssign(Environment env, Context ctx,
1019:                    Vset vset, long where, MemberDefinition field) {
1020:                if (field.isBlankFinal()
1021:                        && field.getClassDefinition() == ctx.field
1022:                                .getClassDefinition()) {
1023:                    int number = ctx.getFieldNumber(field);
1024:                    if (number >= 0 && vset.testVarUnassigned(number)) {
1025:                        // definite single assignment
1026:                        vset = vset.addVar(number);
1027:                    } else {
1028:                        // it is a blank final in this class, but not assignable
1029:                        Identifier id = field.getName();
1030:                        env.error(where, "assign.to.blank.final", id);
1031:                    }
1032:                } else {
1033:                    // give the generic error message
1034:                    Identifier id = field.getName();
1035:                    env.error(where, "assign.to.final", id);
1036:                }
1037:                return vset;
1038:            }
1039:
1040:            private static MemberDefinition getClassLiteralCache(
1041:                    Environment env, Context ctx, String className,
1042:                    ClassDefinition c) {
1043:                // Given a class name, look for a static field to cache it.
1044:                //	className	lname
1045:                //	pkg.Foo		class$pkg$Foo
1046:                //	[Lpkg.Foo;	array$Lpkg$Foo
1047:                //	[[Lpkg.Foo;	array$$Lpkg$Foo
1048:                //	[I		array$I
1049:                //	[[I		array$$I
1050:                String lname;
1051:                if (!className.startsWith(SIG_ARRAY)) {
1052:                    lname = prefixClass + className.replace('.', '$');
1053:                } else {
1054:                    lname = prefixArray + className.substring(1);
1055:                    lname = lname.replace(SIGC_ARRAY, '$'); // [[[I => array$$$I
1056:                    if (className.endsWith(SIG_ENDCLASS)) {
1057:                        // [Lpkg.Foo; => array$Lpkg$Foo
1058:                        lname = lname.substring(0, lname.length() - 1);
1059:                        lname = lname.replace('.', '$');
1060:                    }
1061:                    // else [I => array$I or some such; lname is already OK
1062:                }
1063:                Identifier fname = Identifier.lookup(lname);
1064:
1065:                // The class to put the cache in is now given as an argument.
1066:                //
1067:                // ClassDefinition c = ctx.field.getClassDefinition();
1068:                // while (c.isInnerClass()) {
1069:                //     c = c.getOuterClass();
1070:
1071:                MemberDefinition cfld;
1072:                try {
1073:                    cfld = c.getVariable(env, fname, c);
1074:                } catch (ClassNotFound ee) {
1075:                    return null;
1076:                } catch (AmbiguousMember ee) {
1077:                    return null;
1078:                }
1079:
1080:                // Ignore inherited field.  Each top-level class
1081:                // containing a given class literal must have its own copy,
1082:                // both for reasons of binary compatibility and to prevent
1083:                // access violations should the superclass be in another
1084:                // package.  Part of fix 4106051.
1085:                if (cfld != null && cfld.getClassDefinition() == c) {
1086:                    return cfld;
1087:                }
1088:
1089:                // Since each class now has its own copy, we might as well
1090:                // tighten up the access to private (previously default).
1091:                // Part of fix for 4106051.
1092:                // ** Temporarily retract this, as it tickles 4098316.
1093:                return env.makeMemberDefinition(env, c.getWhere(), c, null,
1094:                        M_STATIC | M_SYNTHETIC, // M_PRIVATE,
1095:                        Type.tClassDesc, fname, null, null, null);
1096:            }
1097:
1098:            private Expression makeClassLiteralCacheRef(Environment env,
1099:                    Context ctx, MemberDefinition lookup,
1100:                    MemberDefinition cfld, String className) {
1101:                Expression ccls = new TypeExpression(where, cfld
1102:                        .getClassDefinition().getType());
1103:                Expression cache = new FieldExpression(where, ccls, cfld);
1104:                Expression cacheOK = new NotEqualExpression(where, cache
1105:                        .copyInline(ctx), new NullExpression(where));
1106:                Expression lcls = new TypeExpression(where, lookup
1107:                        .getClassDefinition().getType());
1108:                Expression name = new StringExpression(where, className);
1109:                Expression namearg[] = { name };
1110:                Expression setCache = new MethodExpression(where, lcls, lookup,
1111:                        namearg);
1112:                setCache = new AssignExpression(where, cache.copyInline(ctx),
1113:                        setCache);
1114:                return new ConditionalExpression(where, cacheOK, cache,
1115:                        setCache);
1116:            }
1117:
1118:            private Expression makeClassLiteralInlineRef(Environment env,
1119:                    Context ctx, MemberDefinition lookup, String className) {
1120:                Expression lcls = new TypeExpression(where, lookup
1121:                        .getClassDefinition().getType());
1122:                Expression name = new StringExpression(where, className);
1123:                Expression namearg[] = { name };
1124:                Expression getClass = new MethodExpression(where, lcls, lookup,
1125:                        namearg);
1126:                return getClass;
1127:            }
1128:
1129:            /**
1130:             * Check if constant:  Will it inline away?
1131:             */
1132:            public boolean isConstant() {
1133:                if (implementation != null)
1134:                    return implementation.isConstant();
1135:                if ((field != null)
1136:                        && (right == null || right instanceof  TypeExpression || (right.op == THIS && right.where == where))) {
1137:                    return field.isConstant();
1138:                }
1139:                return false;
1140:            }
1141:
1142:            /**
1143:             * Inline
1144:             */
1145:            public Expression inline(Environment env, Context ctx) {
1146:                if (implementation != null)
1147:                    return implementation.inline(env, ctx);
1148:                // A field expression may have the side effect of causing
1149:                // a NullPointerException, so evaluate it even though
1150:                // the value is not needed.  Similarly, static field dereferences
1151:                // may cause class initialization, so they mustn't be omitted
1152:                // either.
1153:                //
1154:                // However, NullPointerException can't happen and initialization must
1155:                // already have occured if you are dotting into 'this'.  So
1156:                // allow fields of 'this' to be eliminated as a special case.
1157:                Expression e = inlineValue(env, ctx);
1158:                if (e instanceof  FieldExpression) {
1159:                    FieldExpression fe = (FieldExpression) e;
1160:                    if ((fe.right != null) && (fe.right.op == THIS))
1161:                        return null;
1162:                    // It should be possible to split this into two checks: one using
1163:                    // isNonNull() for non-statics and a different check for statics.
1164:                    // That would make the inlining slightly less conservative by
1165:                    // allowing, for example, dotting into String constants.
1166:                }
1167:                return e;
1168:            }
1169:
1170:            public Expression inlineValue(Environment env, Context ctx) {
1171:                if (implementation != null)
1172:                    return implementation.inlineValue(env, ctx);
1173:                try {
1174:                    if (field == null) {
1175:                        return this ;
1176:                    }
1177:
1178:                    if (field.isFinal()) {
1179:                        Expression e = (Expression) field.getValue(env);
1180:                        if ((e != null) && e.isConstant()) {
1181:                            // remove bogus line-number info
1182:                            e = e.copyInline(ctx);
1183:                            e.where = where;
1184:                            return new CommaExpression(where, right, e)
1185:                                    .inlineValue(env, ctx);
1186:                        }
1187:                    }
1188:
1189:                    if (right != null) {
1190:                        if (field.isStatic()) {
1191:                            Expression e = right.inline(env, ctx);
1192:                            right = null;
1193:                            if (e != null) {
1194:                                return new CommaExpression(where, e, this );
1195:                            }
1196:                        } else {
1197:                            right = right.inlineValue(env, ctx);
1198:                        }
1199:                    }
1200:                    return this ;
1201:
1202:                } catch (ClassNotFound e) {
1203:                    throw new CompilerError(e);
1204:                }
1205:            }
1206:
1207:            public Expression inlineLHS(Environment env, Context ctx) {
1208:                if (implementation != null)
1209:                    return implementation.inlineLHS(env, ctx);
1210:                if (right != null) {
1211:                    if (field.isStatic()) {
1212:                        Expression e = right.inline(env, ctx);
1213:                        right = null;
1214:                        if (e != null) {
1215:                            return new CommaExpression(where, e, this );
1216:                        }
1217:                    } else {
1218:                        right = right.inlineValue(env, ctx);
1219:                    }
1220:                }
1221:                return this ;
1222:            }
1223:
1224:            public Expression copyInline(Context ctx) {
1225:                if (implementation != null)
1226:                    return implementation.copyInline(ctx);
1227:                return super .copyInline(ctx);
1228:            }
1229:
1230:            /**
1231:             * The cost of inlining this expression
1232:             */
1233:            public int costInline(int thresh, Environment env, Context ctx) {
1234:                if (implementation != null)
1235:                    return implementation.costInline(thresh, env, ctx);
1236:                if (ctx == null) {
1237:                    return 3 + ((right == null) ? 0 : right.costInline(thresh,
1238:                            env, ctx));
1239:                }
1240:                // ctxClass is the current class trying to inline this method 
1241:                ClassDefinition ctxClass = ctx.field.getClassDefinition();
1242:                try {
1243:                    // We only allow the inlining if the current class can access 
1244:                    // the field, the field's class, and right's declared type.
1245:                    if (ctxClass.permitInlinedAccess(env, field
1246:                            .getClassDeclaration())
1247:                            && ctxClass.permitInlinedAccess(env, field)) {
1248:                        if (right == null) {
1249:                            return 3;
1250:                        } else {
1251:                            ClassDeclaration rt = env
1252:                                    .getClassDeclaration(right.type);
1253:                            if (ctxClass.permitInlinedAccess(env, rt)) {
1254:                                return 3 + right.costInline(thresh, env, ctx);
1255:                            }
1256:                        }
1257:                    }
1258:                } catch (ClassNotFound e) {
1259:                }
1260:                return thresh;
1261:            }
1262:
1263:            /**
1264:             * Code
1265:             */
1266:            int codeLValue(Environment env, Context ctx, Assembler asm) {
1267:                if (implementation != null)
1268:                    throw new CompilerError("codeLValue");
1269:                if (field.isStatic()) {
1270:                    if (right != null) {
1271:                        right.code(env, ctx, asm);
1272:                        return 1;
1273:                    }
1274:                    return 0;
1275:                }
1276:                right.codeValue(env, ctx, asm);
1277:                return 1;
1278:            }
1279:
1280:            void codeLoad(Environment env, Context ctx, Assembler asm) {
1281:                if (field == null) {
1282:                    throw new CompilerError("should not be null");
1283:                }
1284:                if (field.isStatic()) {
1285:                    asm.add(where, opc_getstatic, field);
1286:                } else {
1287:                    asm.add(where, opc_getfield, field);
1288:                }
1289:            }
1290:
1291:            void codeStore(Environment env, Context ctx, Assembler asm) {
1292:                if (field.isStatic()) {
1293:                    asm.add(where, opc_putstatic, field);
1294:                } else {
1295:                    asm.add(where, opc_putfield, field);
1296:                }
1297:            }
1298:
1299:            public void codeValue(Environment env, Context ctx, Assembler asm) {
1300:                codeLValue(env, ctx, asm);
1301:                codeLoad(env, ctx, asm);
1302:            }
1303:
1304:            /**
1305:             * Print
1306:             */
1307:            public void print(PrintStream out) {
1308:                out.print("(");
1309:                if (right != null) {
1310:                    right.print(out);
1311:                } else {
1312:                    out.print("<empty>");
1313:                }
1314:                out.print("." + id + ")");
1315:                if (implementation != null) {
1316:                    out.print("/IMPL=");
1317:                    implementation.print(out);
1318:                }
1319:            }
1320:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.