/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.tree; import sun.tools.java.*;import sun.tools.asm.*;import java.io.PrintStream;import java.util.Hashtable; /** * WARNING: The contents of this source file are not part of any * supported API. Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */publicclass FieldExpression extends UnaryExpression { Identifier id; MemberDefinition field; Expression implementation; // The class from which the field is select ed. ClassDefinition clazz; // For an expression of the form '<class>.super', then // this is <class>, else null. private ClassDefinition superBase; /** * constructor */ public FieldExpression(long where, Expression right, Identifier id) { super(FIELD, where, Type.tError, right); this.id = id; } public FieldExpression(long where, Expression right, MemberDefinition field) { super(FIELD, where, field.getType(), right); this.id = field.getName(); this.field = field; } public Expression getImplementation() { if (implementation != null) return implementation; return this; } /** * Return true if the field is being selected from * a qualified 'super'. */ private boolean isQualSuper() { return superBase != null; } /** * Convert an '.' expression to a qualified identifier */ static public Identifier toIdentifier(Expression e) { StringBuffer buf = new StringBuffer(); while (e.op == FIELD) { FieldExpression fe = (FieldExpression)e; if (fe.id == idThis || fe.id == idClass) { return null; } buf.insert(0, fe.id); buf.insert(0, '.'); e = fe.right; } if (e.op != IDENT) { return null; } buf.insert(0, ((IdentifierExpression)e).id); return Identifier.lookup(buf.toString()); } /** * Convert a qualified name into a type. * Performs a careful check of each inner-class component, * including the JLS 6.6.1 access checks that were omitted * in 'FieldExpression.toType'. * <p> * This code is similar to 'checkCommon', which could be cleaned * up a bit long the lines we have done here. */ /*-------------------------------------------------------* Type toQualifiedType(Environment env, Context ctx) { ClassDefinition ctxClass = ctx.field.getClassDefinition(); Type rty = right.toQualifiedType(env, ctx); if (rty == Type.tPackage) { // Is this field expression a non-inner type? Identifier nm = toIdentifier(this); if ((nm != null) && env.classExists(nm)) { Type t = Type.tClass(nm); if (env.resolve(where, ctxClass, t)) { return t; } else { return null; } } // Not a type. Must be a package prefix. return Type.tPackage; } if (rty == null) { // An error was already reported, so quit. return null; } // Check inner-class qualification while unwinding from recursion. try { ClassDefinition rightClass = env.getClassDefinition(rty); // Local variables, which cannot be inner classes, // are ignored here, and thus will not hide inner // classes. Is this correct? MemberDefinition field = rightClass.getInnerClass(env, id); if (field == null) { env.error(where, "inner.class.expected", id, rightClass); return Type.tError; } ClassDefinition innerClass = field.getInnerClass(); Type t = innerClass.getType(); if (!ctxClass.canAccess(env, field)) { env.error(where, "no.type.access", id, rightClass, ctxClass); return t; } if (field.isProtected() && !ctxClass.protectedAccess(env, field, rty)) { env.error(where, "invalid.protected.type.use", id, ctxClass, rty); return t; } // These were ommitted earlier in calls to 'toType', but I can't // see any reason for that. I think it was an oversight. See // 'checkCommon' and 'checkInnerClass'. innerClass.noteUsedBy(ctxClass, where, env); ctxClass.addDependency(field.getClassDeclaration()); return t; } catch (ClassNotFound e) { env.error(where, "class.not.found", e.name, ctx.field); } // Class not found. return null; } *-------------------------------------------------------*/ /** * Convert an '.' expression to a type */ // This is a rewrite to treat qualified names in a // context in which a type name is expected in the // same way that they are handled for an ambiguous // or expression-expected context in 'checkCommon' // below. The new code is cleaner and allows better // localization of errors. Unfortunately, most // qualified names appearing in types are actually // handled by 'Environment.resolve'. There isn't // much point, then, in breaking out 'toType' as a // special case until the other cases can be cleaned // up as well. For the time being, we will leave this // code disabled, thus reducing the testing requirements. /*-------------------------------------------------------* Type toType(Environment env, Context ctx) { Type t = toQualifiedType(env, ctx); if (t == null) { return Type.tError; } if (t == Type.tPackage) { FieldExpression.reportFailedPackagePrefix(env, right, true); return Type.tError; } return t; } *-------------------------------------------------------*/ Type toType(Environment env, Context ctx) { Identifier id = toIdentifier(this); if (id == null) { env.error(where, "invalid.type.expr"); return Type.tError; } Type t = Type.tClass(ctx.resolveName(env, id)); if (env.resolve(where, ctx.field.getClassDefinition(), t)) { return t; } return Type.tError; } /** * Check if the present name is part of a scoping prefix. */ public Vset checkAmbigName(Environment env, Context ctx, Vset vset, Hashtable exp, UnaryExpression loc) { if (id == idThis || id == idClass) { loc = null; // this cannot be a type or package } return checkCommon(env, ctx, vset, exp, loc, false); } /** * Check the expression */ public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) { vset = checkCommon(env, ctx, vset, exp, null, false); if (id == idSuper && type != Type.tError) { // "super" is not allowed in this context. // It must always qualify another name. env.error(where, "undef.var.super", idSuper); } return vset; } /** * If 'checkAmbiguousName' returns 'Package.tPackage', then it was * unable to resolve any prefix of the qualified name. This method * attempts to diagnose the problem. */ static void reportFailedPackagePrefix(Environment env, Expression right) { reportFailedPackagePrefix(env, right, false); } static void reportFailedPackagePrefix(Environment env, Expression right, boolean mustBeType) { // Find the leftmost component, and put the blame on it. Expression idp = right; while (idp instanceof UnaryExpression) idp = ((UnaryExpression)idp).right; IdentifierExpression ie = (IdentifierExpression)idp; // It may be that 'ie' refers to an ambiguous class. Check this // with a call to env.resolve(). Part of solution for 4059855. try { env.resolve(ie.id); } catch (AmbiguousClass e) { env.error(right.where, "ambig.class", e.name1, e.name2); return; } catch (ClassNotFound e) { } if (idp == right) { if (mustBeType) { env.error(ie.where, "undef.class", ie.id); } else { env.error(ie.where, "undef.var.or.class", ie.id); } } else { if (mustBeType) { env.error(ie.where, "undef.class.or.package", ie.id); } else { env.error(ie.where, "undef.var.class.or.package", ie.id); } } } /** * Rewrite accesses to private fields of another class. */ private Expression implementFieldAccess(Environment env, Context ctx, Expression base, boolean isLHS) { ClassDefinition abase = accessBase(env, ctx); if (abase != null) { // If the field is final and its initializer is a constant expression, // then just rewrite to the constant expression. This is not just an // optimization, but is required for correctness. If an expression is // rewritten to use an access method, then its status as a constant // expression is lost. This was the cause of bug 4098737. Note that // a call to 'getValue(env)' below would not be correct, as it attempts // to simplify the initial value expression, which must not occur until // after the checking phase, for example, after definite assignment checks. if (field.isFinal()) { Expression e = (Expression)field.getValue(); // Must not be LHS here. Test as a precaution, // as we may not be careful to avoid this when // compiling an erroneous program. if ((e != null) && e.isConstant() && !isLHS) { return e.copyInline(ctx); } } //System.out.println("Finding access method for " + field); MemberDefinition af = abase.getAccessMember(env, ctx, field, isQualSuper()); //System.out.println("Using access method " + af); if (!isLHS) { //System.out.println("Reading " + field + // " via access method " + af); // If referencing the value of the field, then replace // with a call to the access method. If assigning to // the field, a call to the update method will be // generated later. It is important that // 'implementation' not be set to non-null if the // expression is a valid assignment target. // (See 'checkLHS'.) if (field.isStatic()) { Expression args[] = { }; Expression call = new MethodExpression(where, null, af, args); return new CommaExpression(where, base, call); } else { Expression args[] = { base }; return new MethodExpression(where, null, af, args); } } } return null; } /** * Determine if an access method is required, and, if so, return * the class in which it should appear, else return null. */ private ClassDefinition accessBase(Environment env, Context ctx) { if (field.isPrivate()) { ClassDefinition cdef = field.getClassDefinition(); ClassDefinition ctxClass = ctx.field.getClassDefinition(); if (cdef == ctxClass){ // If access from same class as field, then no access // method is needed. return null; } // An access method is needed in the class containing the field. return cdef; } else if (field.isProtected()) { if (superBase == null) { // If access is not via qualified super, then it is either // OK without an access method, or it is an illegal access // for which an error message should have been issued. // Legal accesses include unqualified 'super.foo'. return null; } ClassDefinition cdef = field.getClassDefinition(); ClassDefinition ctxClass = ctx.field.getClassDefinition(); if (cdef.inSamePackage(ctxClass)) { // Access to protected member in same package always allowed. return null; } // Access via qualified super. // An access method is needed in the qualifying class, an // immediate subclass of the class containing the selected // field. NOTE: The fact that the returned class is 'superBase' // carries the additional bit of information (that a special // superclass access method is being created) which is provided // to 'getAccessMember' via its 'isSuper' argument. return superBase; } else { // No access method needed. return null; } } /** * Determine if a type is accessible from a given class. */ static boolean isTypeAccessible(long where, Environment env, Type t, ClassDefinition c) { switch (t.getTypeCode()) { case TC_CLASS: try { Identifier nm = t.getClassName(); // Why not just use 'Environment.getClassDeclaration' here? // But 'Environment.getClassDeclation' has special treatment // for local classes that is probably necessary. This code // was adapted from 'Environment.resolve'. ClassDefinition def = env.getClassDefinition(t); return c.canAccess(env, def.getClassDeclaration()); } catch (ClassNotFound e) {} // Ignore -- reported elsewhere. return true; case TC_ARRAY: return isTypeAccessible(where, env, t.getElementType(), c); default: return true; } } /** * Common code for checkValue and checkAmbigName */ private Vset checkCommon(Environment env, Context ctx, Vset vset, Hashtable exp, UnaryExpression loc, boolean isLHS) { // Handle class literal, e.g., 'x.class'. if (id == idClass) { // In 'x.class', 'x' must be a type name, possibly qualified. Type t = right.toType(env, ctx); if (!t.isType(TC_CLASS) && !t.isType(TC_ARRAY)) { if (t.isType(TC_ERROR)) { type = Type.tClassDesc; return vset; } String wrc = null; switch (t.getTypeCode()) { case TC_VOID: wrc = "Void"; break; case TC_BOOLEAN: wrc = "Boolean"; break; case TC_BYTE: wrc = "Byte"; break; case TC_CHAR: wrc = "Character"; break; case TC_SHORT: wrc = "Short"; break; case TC_INT: wrc = "Integer"; break; case TC_FLOAT: wrc = "Float"; break; case TC_LONG: wrc = "Long"; break; case TC_DOUBLE: wrc = "Double"; break; default: env.error(right.where, "invalid.type.expr"); return vset; } Identifier wid = Identifier.lookup(idJavaLang+"."+wrc); Expression wcls = new TypeExpression(where, Type.tClass(wid)); implementation = new FieldExpression(where, wcls, idTYPE); vset = implementation.checkValue(env, ctx, vset, exp); type = implementation.type; // java.lang.Class return vset; } // Check for the bogus type `array of void' if (t.isVoidArray()) { type = Type.tClassDesc; env.error(right.where, "void.array"); return vset; } // it is a class or array long fwhere = ctx.field.getWhere(); ClassDefinition fcls = ctx.field.getClassDefinition(); MemberDefinition lookup = fcls.getClassLiteralLookup(fwhere); String sig = t.getTypeSignature(); String className; if (t.isType(TC_CLASS)) { // sig is like "Lfoo/bar;", name is like "foo.bar". // We assume SIG_CLASS and SIG_ENDCLASS are 1 char each. className = sig.substring(1, sig.length()-1) .replace(SIGC_PACKAGE, '.'); } else { // sig is like "[Lfoo/bar;" or "[I"; // name is like "[Lfoo.bar" or (again) "[I". className = sig.replace(SIGC_PACKAGE, '.'); } if (fcls.isInterface()) { // The immediately-enclosing type is an interface. // The class literal can only appear in an initialization // expression, so don't bother caching it. (This could // lose if many initializations use the same class literal, // but saves time and code space otherwise.) implementation = makeClassLiteralInlineRef(env, ctx, lookup, className); } else { // Cache the call to the helper, as it may be executed // many times (e.g., if the class literal is inside a loop). ClassDefinition inClass = lookup.getClassDefinition(); MemberDefinition cfld = getClassLiteralCache(env, ctx, className, inClass); implementation = makeClassLiteralCacheRef(env, ctx, lookup, cfld, className); } vset = implementation.checkValue(env, ctx, vset, exp); type = implementation.type; // java.lang.ClassLines 1–500 of 1282. Load more
/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.tree; import sun.tools.java.*; import sun.tools.asm.*; import java.io.PrintStream; import java.util.Hashtable; /** * WARNING: The contents of this source file are not part of any * supported API. Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */ public class FieldExpression extends UnaryExpression { Identifier id; MemberDefinition field; Expression implementation; // The class from which the field is select ed. ClassDefinition clazz; // For an expression of the form '<class>.super', then // this is <class>, else null. private ClassDefinition superBase; /** * constructor */ public FieldExpression(long where, Expression right, Identifier id) { super(FIELD, where, Type.tError, right); this.id = id; } public FieldExpression(long where, Expression right, MemberDefinition field) { super(FIELD, where, field.getType(), right); this.id = field.getName(); this.field = field; } public Expression getImplementation() { if (implementation != null) return implementation; return this; } /** * Return true if the field is being selected from * a qualified 'super'. */ private boolean isQualSuper() { return superBase != null; } /** * Convert an '.' expression to a qualified identifier */ static public Identifier toIdentifier(Expression e) { StringBuffer buf = new StringBuffer(); while (e.op == FIELD) { FieldExpression fe = (FieldExpression)e; if (fe.id == idThis || fe.id == idClass) { return null; } buf.insert(0, fe.id); buf.insert(0, '.'); e = fe.right; } if (e.op != IDENT) { return null; } buf.insert(0, ((IdentifierExpression)e).id); return Identifier.lookup(buf.toString()); } /** * Convert a qualified name into a type. * Performs a careful check of each inner-class component, * including the JLS 6.6.1 access checks that were omitted * in 'FieldExpression.toType'. * <p> * This code is similar to 'checkCommon', which could be cleaned * up a bit long the lines we have done here. */ /*-------------------------------------------------------* Type toQualifiedType(Environment env, Context ctx) { ClassDefinition ctxClass = ctx.field.getClassDefinition(); Type rty = right.toQualifiedType(env, ctx); if (rty == Type.tPackage) { // Is this field expression a non-inner type? Identifier nm = toIdentifier(this); if ((nm != null) && env.classExists(nm)) { Type t = Type.tClass(nm); if (env.resolve(where, ctxClass, t)) { return t; } else { return null; } } // Not a type. Must be a package prefix. return Type.tPackage; } if (rty == null) { // An error was already reported, so quit. return null; } // Check inner-class qualification while unwinding from recursion. try { ClassDefinition rightClass = env.getClassDefinition(rty); // Local variables, which cannot be inner classes, // are ignored here, and thus will not hide inner // classes. Is this correct? MemberDefinition field = rightClass.getInnerClass(env, id); if (field == null) { env.error(where, "inner.class.expected", id, rightClass); return Type.tError; } ClassDefinition innerClass = field.getInnerClass(); Type t = innerClass.getType(); if (!ctxClass.canAccess(env, field)) { env.error(where, "no.type.access", id, rightClass, ctxClass); return t; } if (field.isProtected() && !ctxClass.protectedAccess(env, field, rty)) { env.error(where, "invalid.protected.type.use", id, ctxClass, rty); return t; } // These were ommitted earlier in calls to 'toType', but I can't // see any reason for that. I think it was an oversight. See // 'checkCommon' and 'checkInnerClass'. innerClass.noteUsedBy(ctxClass, where, env); ctxClass.addDependency(field.getClassDeclaration()); return t; } catch (ClassNotFound e) { env.error(where, "class.not.found", e.name, ctx.field); } // Class not found. return null; } *-------------------------------------------------------*/ /** * Convert an '.' expression to a type */ // This is a rewrite to treat qualified names in a // context in which a type name is expected in the // same way that they are handled for an ambiguous // or expression-expected context in 'checkCommon' // below. The new code is cleaner and allows better // localization of errors. Unfortunately, most // qualified names appearing in types are actually // handled by 'Environment.resolve'. There isn't // much point, then, in breaking out 'toType' as a // special case until the other cases can be cleaned // up as well. For the time being, we will leave this // code disabled, thus reducing the testing requirements. /*-------------------------------------------------------* Type toType(Environment env, Context ctx) { Type t = toQualifiedType(env, ctx); if (t == null) { return Type.tError; } if (t == Type.tPackage) { FieldExpression.reportFailedPackagePrefix(env, right, true); return Type.tError; } return t; } *-------------------------------------------------------*/ Type toType(Environment env, Context ctx) { Identifier id = toIdentifier(this); if (id == null) { env.error(where, "invalid.type.expr"); return Type.tError; } Type t = Type.tClass(ctx.resolveName(env, id)); if (env.resolve(where, ctx.field.getClassDefinition(), t)) { return t; } return Type.tError; } /** * Check if the present name is part of a scoping prefix. */ public Vset checkAmbigName(Environment env, Context ctx, Vset vset, Hashtable exp, UnaryExpression loc) { if (id == idThis || id == idClass) { loc = null; // this cannot be a type or package } return checkCommon(env, ctx, vset, exp, loc, false); } /** * Check the expression */ public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) { vset = checkCommon(env, ctx, vset, exp, null, false); if (id == idSuper && type != Type.tError) { // "super" is not allowed in this context. // It must always qualify another name. env.error(where, "undef.var.super", idSuper); } return vset; } /** * If 'checkAmbiguousName' returns 'Package.tPackage', then it was * unable to resolve any prefix of the qualified name. This method * attempts to diagnose the problem. */ static void reportFailedPackagePrefix(Environment env, Expression right) { reportFailedPackagePrefix(env, right, false); } static void reportFailedPackagePrefix(Environment env, Expression right, boolean mustBeType) { // Find the leftmost component, and put the blame on it. Expression idp = right; while (idp instanceof UnaryExpression) idp = ((UnaryExpression)idp).right; IdentifierExpression ie = (IdentifierExpression)idp; // It may be that 'ie' refers to an ambiguous class. Check this // with a call to env.resolve(). Part of solution for 4059855. try { env.resolve(ie.id); } catch (AmbiguousClass e) { env.error(right.where, "ambig.class", e.name1, e.name2); return; } catch (ClassNotFound e) { } if (idp == right) { if (mustBeType) { env.error(ie.where, "undef.class", ie.id); } else { env.error(ie.where, "undef.var.or.class", ie.id); } } else { if (mustBeType) { env.error(ie.where, "undef.class.or.package", ie.id); } else { env.error(ie.where, "undef.var.class.or.package", ie.id); } } } /** * Rewrite accesses to private fields of another class. */ private Expression implementFieldAccess(Environment env, Context ctx, Expression base, boolean isLHS) { ClassDefinition abase = accessBase(env, ctx); if (abase != null) { // If the field is final and its initializer is a constant expression, // then just rewrite to the constant expression. This is not just an // optimization, but is required for correctness. If an expression is // rewritten to use an access method, then its status as a constant // expression is lost. This was the cause of bug 4098737. Note that // a call to 'getValue(env)' below would not be correct, as it attempts // to simplify the initial value expression, which must not occur until // after the checking phase, for example, after definite assignment checks. if (field.isFinal()) { Expression e = (Expression)field.getValue(); // Must not be LHS here. Test as a precaution, // as we may not be careful to avoid this when // compiling an erroneous program. if ((e != null) && e.isConstant() && !isLHS) { return e.copyInline(ctx); } } //System.out.println("Finding access method for " + field); MemberDefinition af = abase.getAccessMember(env, ctx, field, isQualSuper()); //System.out.println("Using access method " + af); if (!isLHS) { //System.out.println("Reading " + field + // " via access method " + af); // If referencing the value of the field, then replace // with a call to the access method. If assigning to // the field, a call to the update method will be // generated later. It is important that // 'implementation' not be set to non-null if the // expression is a valid assignment target. // (See 'checkLHS'.) if (field.isStatic()) { Expression args[] = { }; Expression call = new MethodExpression(where, null, af, args); return new CommaExpression(where, base, call); } else { Expression args[] = { base }; return new MethodExpression(where, null, af, args); } } } return null; } /** * Determine if an access method is required, and, if so, return * the class in which it should appear, else return null. */ private ClassDefinition accessBase(Environment env, Context ctx) { if (field.isPrivate()) { ClassDefinition cdef = field.getClassDefinition(); ClassDefinition ctxClass = ctx.field.getClassDefinition(); if (cdef == ctxClass){ // If access from same class as field, then no access // method is needed. return null; } // An access method is needed in the class containing the field. return cdef; } else if (field.isProtected()) { if (superBase == null) { // If access is not via qualified super, then it is either // OK without an access method, or it is an illegal access // for which an error message should have been issued. // Legal accesses include unqualified 'super.foo'. return null; } ClassDefinition cdef = field.getClassDefinition(); ClassDefinition ctxClass = ctx.field.getClassDefinition(); if (cdef.inSamePackage(ctxClass)) { // Access to protected member in same package always allowed. return null; } // Access via qualified super. // An access method is needed in the qualifying class, an // immediate subclass of the class containing the selected // field. NOTE: The fact that the returned class is 'superBase' // carries the additional bit of information (that a special // superclass access method is being created) which is provided // to 'getAccessMember' via its 'isSuper' argument. return superBase; } else { // No access method needed. return null; } } /** * Determine if a type is accessible from a given class. */ static boolean isTypeAccessible(long where, Environment env, Type t, ClassDefinition c) { switch (t.getTypeCode()) { case TC_CLASS: try { Identifier nm = t.getClassName(); // Why not just use 'Environment.getClassDeclaration' here? // But 'Environment.getClassDeclation' has special treatment // for local classes that is probably necessary. This code // was adapted from 'Environment.resolve'. ClassDefinition def = env.getClassDefinition(t); return c.canAccess(env, def.getClassDeclaration()); } catch (ClassNotFound e) {} // Ignore -- reported elsewhere. return true; case TC_ARRAY: return isTypeAccessible(where, env, t.getElementType(), c); default: return true; } } /** * Common code for checkValue and checkAmbigName */ private Vset checkCommon(Environment env, Context ctx, Vset vset, Hashtable exp, UnaryExpression loc, boolean isLHS) { // Handle class literal, e.g., 'x.class'. if (id == idClass) { // In 'x.class', 'x' must be a type name, possibly qualified. Type t = right.toType(env, ctx); if (!t.isType(TC_CLASS) && !t.isType(TC_ARRAY)) { if (t.isType(TC_ERROR)) { type = Type.tClassDesc; return vset; } String wrc = null; switch (t.getTypeCode()) { case TC_VOID: wrc = "Void"; break; case TC_BOOLEAN: wrc = "Boolean"; break; case TC_BYTE: wrc = "Byte"; break; case TC_CHAR: wrc = "Character"; break; case TC_SHORT: wrc = "Short"; break; case TC_INT: wrc = "Integer"; break; case TC_FLOAT: wrc = "Float"; break; case TC_LONG: wrc = "Long"; break; case TC_DOUBLE: wrc = "Double"; break; default: env.error(right.where, "invalid.type.expr"); return vset; } Identifier wid = Identifier.lookup(idJavaLang+"."+wrc); Expression wcls = new TypeExpression(where, Type.tClass(wid)); implementation = new FieldExpression(where, wcls, idTYPE); vset = implementation.checkValue(env, ctx, vset, exp); type = implementation.type; // java.lang.Class return vset; } // Check for the bogus type `array of void' if (t.isVoidArray()) { type = Type.tClassDesc; env.error(right.where, "void.array"); return vset; } // it is a class or array long fwhere = ctx.field.getWhere(); ClassDefinition fcls = ctx.field.getClassDefinition(); MemberDefinition lookup = fcls.getClassLiteralLookup(fwhere); String sig = t.getTypeSignature(); String className; if (t.isType(TC_CLASS)) { // sig is like "Lfoo/bar;", name is like "foo.bar". // We assume SIG_CLASS and SIG_ENDCLASS are 1 char each. className = sig.substring(1, sig.length()-1) .replace(SIGC_PACKAGE, '.'); } else { // sig is like "[Lfoo/bar;" or "[I"; // name is like "[Lfoo.bar" or (again) "[I". className = sig.replace(SIGC_PACKAGE, '.'); } if (fcls.isInterface()) { // The immediately-enclosing type is an interface. // The class literal can only appear in an initialization // expression, so don't bother caching it. (This could // lose if many initializations use the same class literal, // but saves time and code space otherwise.) implementation = makeClassLiteralInlineRef(env, ctx, lookup, className); } else { // Cache the call to the helper, as it may be executed // many times (e.g., if the class literal is inside a loop). ClassDefinition inClass = lookup.getClassDefinition(); MemberDefinition cfld = getClassLiteralCache(env, ctx, className, inClass); implementation = makeClassLiteralCacheRef(env, ctx, lookup, cfld, className); } vset = implementation.checkValue(env, ctx, vset, exp); type = implementation.type; // java.lang.Class