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.java;
0027:
0028: import java.util.Stack;
0029: import java.io.IOException;
0030: import sun.tools.tree.Context; //JCOV
0031: import java.io.File;
0032:
0033: //end JCOV
0034:
0035: /**
0036: * This class defines the environment for a compilation.
0037: * It is used to load classes, resolve class names and
0038: * report errors. It is an abstract class, a subclass
0039: * must define implementations for some of the functions.<p>
0040: *
0041: * An environment has a source object associated with it.
0042: * This is the thing against which errors are reported, it
0043: * is usually a file name, a field or a class.<p>
0044: *
0045: * Environments can be nested to change the source object.<p>
0046: *
0047: * WARNING: The contents of this source file are not part of any
0048: * supported API. Code that depends on them does so at its own risk:
0049: * they are subject to change or removal without notice.
0050: *
0051: * @author Arthur van Hoff
0052: * @version 1.82, 05/05/07
0053: */
0054:
0055: public class Environment implements Constants {
0056: /**
0057: * The actual environment to which everything is forwarded.
0058: */
0059: Environment env;
0060:
0061: /**
0062: * External character encoding name
0063: */
0064: String encoding;
0065:
0066: /**
0067: * The object that is currently being parsed/compiled.
0068: * It is either a file name (String) or a field (MemberDefinition)
0069: * or a class (ClassDeclaration or ClassDefinition).
0070: */
0071: Object source;
0072:
0073: public Environment(Environment env, Object source) {
0074: if (env != null && env.env != null
0075: && env.getClass() == this .getClass())
0076: env = env.env; // a small optimization
0077: this .env = env;
0078: this .source = source;
0079: }
0080:
0081: public Environment() {
0082: this (null, null);
0083: }
0084:
0085: /**
0086: * Tells whether an Identifier refers to a package which should be
0087: * exempt from the "exists" check in Imports#resolve().
0088: */
0089: public boolean isExemptPackage(Identifier id) {
0090: return env.isExemptPackage(id);
0091: }
0092:
0093: /**
0094: * Return a class declaration given a fully qualified class name.
0095: */
0096: public ClassDeclaration getClassDeclaration(Identifier nm) {
0097: return env.getClassDeclaration(nm);
0098: }
0099:
0100: /**
0101: * Return a class definition given a fully qualified class name.
0102: * <p>
0103: * Should be called only with 'internal' class names, i.e., the result
0104: * of a call to 'resolveName' or a synthetic class name.
0105: */
0106: public final ClassDefinition getClassDefinition(Identifier nm)
0107: throws ClassNotFound {
0108: if (nm.isInner()) {
0109: ClassDefinition c = getClassDefinition(nm.getTopName());
0110: Identifier tail = nm.getFlatName();
0111: walkTail: while (tail.isQualified()) {
0112: tail = tail.getTail();
0113: Identifier head = tail.getHead();
0114: //System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail);
0115: String hname = head.toString();
0116: // If the name is of the form 'ClassName.N$localName', where N is
0117: // a number, the field 'N$localName' may not necessarily be a member
0118: // of the class named by 'ClassName', but might be a member of some
0119: // inaccessible class contained within it. We use 'getLocalClass'
0120: // to do the lookup in this case. This is part of a fix for bugid
0121: // 4054523 and 4030421. See also 'BatchEnvironment.makeClassDefinition'.
0122: // This should also work for anonymous class names of the form
0123: // 'ClassName.N'. Note that the '.' qualifications get converted to
0124: // '$' characters when determining the external name of the class and
0125: // the name of the class file.
0126: if (hname.length() > 0
0127: && Character.isDigit(hname.charAt(0))) {
0128: ClassDefinition localClass = c.getLocalClass(hname);
0129: if (localClass != null) {
0130: c = localClass;
0131: continue walkTail;
0132: }
0133: } else {
0134: for (MemberDefinition f = c.getFirstMatch(head); f != null; f = f
0135: .getNextMatch()) {
0136: if (f.isInnerClass()) {
0137: c = f.getInnerClass();
0138: continue walkTail;
0139: }
0140: }
0141: }
0142: throw new ClassNotFound(Identifier.lookupInner(c
0143: .getName(), head));
0144: }
0145: //System.out.println("FOUND " + c + " FOR " + nm);
0146: return c;
0147: }
0148: return getClassDeclaration(nm).getClassDefinition(this );
0149: }
0150:
0151: /**
0152: * Return a class declaration given a type. Only works for
0153: * class types.
0154: */
0155: public ClassDeclaration getClassDeclaration(Type t) {
0156: return getClassDeclaration(t.getClassName());
0157: }
0158:
0159: /**
0160: * Return a class definition given a type. Only works for
0161: * class types.
0162: */
0163: public final ClassDefinition getClassDefinition(Type t)
0164: throws ClassNotFound {
0165: return getClassDefinition(t.getClassName());
0166: }
0167:
0168: /**
0169: * Check if a class exists (without actually loading it).
0170: * (Since inner classes cannot in general be examined without
0171: * loading source, this method does not accept inner names.)
0172: */
0173: public boolean classExists(Identifier nm) {
0174: return env.classExists(nm);
0175: }
0176:
0177: public final boolean classExists(Type t) {
0178: return !t.isType(TC_CLASS) || classExists(t.getClassName());
0179: }
0180:
0181: /**
0182: * Get the package path for a package
0183: */
0184: public Package getPackage(Identifier pkg) throws IOException {
0185: return env.getPackage(pkg);
0186: }
0187:
0188: /**
0189: * Load the definition of a class.
0190: */
0191: public void loadDefinition(ClassDeclaration c) {
0192: env.loadDefinition(c);
0193: }
0194:
0195: /**
0196: * Return the source of the environment (ie: the thing being compiled/parsed).
0197: */
0198: public final Object getSource() {
0199: return source;
0200: }
0201:
0202: /**
0203: * Resolve a type. Make sure that all the classes referred to by
0204: * the type have a definition. Report errors. Return true if
0205: * the type is well-formed. Presently used for types appearing
0206: * in member declarations, which represent named types internally as
0207: * qualified identifiers. Type names appearing in local variable
0208: * declarations and within expressions are represented as identifier
0209: * or field expressions, and are resolved by 'toType', which delegates
0210: * handling of the non-inner portion of the name to this method.
0211: * <p>
0212: * In 'toType', the various stages of qualification are represented by
0213: * separate AST nodes. Here, we are given a single identifier which
0214: * contains the entire qualification structure. It is not possible in
0215: * general to set the error location to the exact position of a component
0216: * that is in error, so an error message must refer to the entire qualified
0217: * name. An attempt to keep track of the string length of the components of
0218: * the name and to offset the location accordingly fails because the initial
0219: * prefix of the name may have been rewritten by an earlier call to
0220: * 'resolveName'. See 'SourceMember.resolveTypeStructure'. The situation
0221: * is actually even worse than this, because only a single location is
0222: * passed in for an entire declaration, which may contain many type names.
0223: * All error messages are thus poorly localized. These checks should be
0224: * done while traversing the parse tree for the type, not the type descriptor.
0225: * <p>
0226: * DESIGN NOTE:
0227: * As far as I can tell, the two-stage resolution of names represented in
0228: * string form is an artifact of the late implementation of inner classes
0229: * and the use of mangled names internally within the compiler. All
0230: * qualified names should have their hiearchical structure made explicit
0231: * in the parse tree at the phase at which they are presented for static
0232: * semantic checking. This would affect class names appearing in 'extends',
0233: * 'implements', and 'throws' clauses, as well as in member declarations.
0234: */
0235: public boolean resolve(long where, ClassDefinition c, Type t) {
0236: switch (t.getTypeCode()) {
0237: case TC_CLASS: {
0238: ClassDefinition def;
0239: try {
0240: Identifier nm = t.getClassName();
0241: if (!nm.isQualified() && !nm.isInner()
0242: && !classExists(nm)) {
0243: resolve(nm); // elicit complaints about ambiguity
0244: }
0245: def = getQualifiedClassDefinition(where, nm, c, false);
0246: if (!c.canAccess(this , def.getClassDeclaration())) {
0247: // Reported error location may be imprecise
0248: // if the name is qualified.
0249: error(where, "cant.access.class", def);
0250: return true; // return false later
0251: }
0252: def.noteUsedBy(c, where, env);
0253: } catch (AmbiguousClass ee) {
0254: error(where, "ambig.class", ee.name1, ee.name2);
0255: return false;
0256: } catch (ClassNotFound e) {
0257: // For now, report "class.and.package" only when the code
0258: // is going to fail anyway.
0259: try {
0260: if (e.name.isInner()
0261: && getPackage(e.name.getTopName()).exists()) {
0262: env.error(where, "class.and.package", e.name
0263: .getTopName());
0264: }
0265: } catch (IOException ee) {
0266: env.error(where, "io.exception", "package check");
0267: }
0268: // This error message is also emitted for 'new' expressions.
0269: // error(where, "class.not.found", e.name, "declaration");
0270: error(where, "class.not.found.no.context", e.name);
0271: return false;
0272: }
0273: return true;
0274: }
0275:
0276: case TC_ARRAY:
0277: return resolve(where, c, t.getElementType());
0278:
0279: case TC_METHOD:
0280: boolean ok = resolve(where, c, t.getReturnType());
0281: Type args[] = t.getArgumentTypes();
0282: for (int i = args.length; i-- > 0;) {
0283: ok &= resolve(where, c, args[i]);
0284: }
0285: return ok;
0286: }
0287: return true;
0288: }
0289:
0290: /**
0291: * Given its fully-qualified name, verify that a class is defined and accessible.
0292: * Used to check components of qualified names in contexts where a class is expected.
0293: * Like 'resolve', but is given a single type name, not a type descriptor.
0294: */
0295: public boolean resolveByName(long where, ClassDefinition c,
0296: Identifier nm) {
0297: return resolveByName(where, c, nm, false);
0298: }
0299:
0300: public boolean resolveExtendsByName(long where, ClassDefinition c,
0301: Identifier nm) {
0302: return resolveByName(where, c, nm, true);
0303: }
0304:
0305: private boolean resolveByName(long where, ClassDefinition c,
0306: Identifier nm, boolean isExtends) {
0307: ClassDefinition def;
0308: try {
0309: if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) {
0310: resolve(nm); // elicit complaints about ambiguity
0311: }
0312: def = getQualifiedClassDefinition(where, nm, c, isExtends);
0313: ClassDeclaration decl = def.getClassDeclaration();
0314: if (!((!isExtends && c.canAccess(this , decl)) || (isExtends && c
0315: .extendsCanAccess(this , decl)))) {
0316: error(where, "cant.access.class", def);
0317: return true; // return false later
0318: }
0319: } catch (AmbiguousClass ee) {
0320: error(where, "ambig.class", ee.name1, ee.name2);
0321: return false;
0322: } catch (ClassNotFound e) {
0323: // For now, report "class.and.package" only when the code
0324: // is going to fail anyway.
0325: try {
0326: if (e.name.isInner()
0327: && getPackage(e.name.getTopName()).exists()) {
0328: env.error(where, "class.and.package", e.name
0329: .getTopName());
0330: }
0331: } catch (IOException ee) {
0332: env.error(where, "io.exception", "package check");
0333: }
0334: error(where, "class.not.found", e.name, "type name");
0335: return false;
0336: }
0337: return true;
0338: }
0339:
0340: /**
0341: * Like 'getClassDefinition(env)', but check access on each component.
0342: * Currently called only by 'resolve' above. It is doubtful that calls
0343: * to 'getClassDefinition(env)' are appropriate now.
0344: */
0345: public final ClassDefinition getQualifiedClassDefinition(
0346: long where, Identifier nm, ClassDefinition ctxClass,
0347: boolean isExtends) throws ClassNotFound {
0348: if (nm.isInner()) {
0349: ClassDefinition c = getClassDefinition(nm.getTopName());
0350: Identifier tail = nm.getFlatName();
0351: walkTail: while (tail.isQualified()) {
0352: tail = tail.getTail();
0353: Identifier head = tail.getHead();
0354: // System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail);
0355: String hname = head.toString();
0356: // Handle synthesized names of local and anonymous classes.
0357: // See 'getClassDefinition(env)' above.
0358: if (hname.length() > 0
0359: && Character.isDigit(hname.charAt(0))) {
0360: ClassDefinition localClass = c.getLocalClass(hname);
0361: if (localClass != null) {
0362: c = localClass;
0363: continue walkTail;
0364: }
0365: } else {
0366: for (MemberDefinition f = c.getFirstMatch(head); f != null; f = f
0367: .getNextMatch()) {
0368: if (f.isInnerClass()) {
0369: ClassDeclaration rdecl = c
0370: .getClassDeclaration();
0371: c = f.getInnerClass();
0372: ClassDeclaration fdecl = c
0373: .getClassDeclaration();
0374: // This check is presumably applicable even if the
0375: // original source-code name (expanded by 'resolveNames')
0376: // was a simple, unqualified name. Hopefully, JLS 2e
0377: // will clarify the matter.
0378: if ((!isExtends && !ctxClass.canAccess(env,
0379: fdecl))
0380: || (isExtends && !ctxClass
0381: .extendsCanAccess(env,
0382: fdecl))) {
0383: // Reported error location is imprecise.
0384: env.error(where, "no.type.access",
0385: head, rdecl, ctxClass);
0386: }
0387: // The JLS 6.6.2 restrictions on access to protected members
0388: // depend in an essential way upon the syntactic form of the name.
0389: // Since the compiler has previously expanded the class names
0390: // here into fully-qualified form ('resolveNames'), this check
0391: // cannot be performed here. Unfortunately, the original names
0392: // are clobbered during 'basicCheck', which is also the phase that
0393: // resolves the inheritance structure, required to implement the
0394: // access restrictions. Pending a large-scale revision of the
0395: // name-resolution machinery, we forgo this check, with the result
0396: // that the JLS 6.6.2 restrictions are not enforced for some cases
0397: // of qualified access to inner classes. Some qualified names are
0398: // resolved elsewhere via a different mechanism, and will be
0399: // treated correctly -- see 'FieldExpression.checkCommon'.
0400: /*---------------------------------------*
0401: if (f.isProtected()) {
0402: Type rty = Type.tClass(rdecl.getName()); // hack
0403: if (!ctxClass.protectedAccess(env, f, rty)) {
0404: // Reported error location is imprecise.
0405: env.error(where, "invalid.protected.type.use",
0406: head, ctxClass, rty);
0407: }
0408: }
0409: *---------------------------------------*/
0410: continue walkTail;
0411: }
0412: }
0413: }
0414: throw new ClassNotFound(Identifier.lookupInner(c
0415: .getName(), head));
0416: }
0417: //System.out.println("FOUND " + c + " FOR " + nm);
0418: return c;
0419: }
0420: return getClassDeclaration(nm).getClassDefinition(this );
0421: }
0422:
0423: /**
0424: * Resolve the names within a type, returning the adjusted type.
0425: * Adjust class names to reflect scoping.
0426: * Do not report errors.
0427: * <p>
0428: * NOTE: It would be convenient to check for errors here, such as
0429: * verifying that each component of a qualified name exists and is
0430: * accessible. Why must this be done in a separate phase?
0431: * <p>
0432: * If the 'synth' argument is true, indicating that the member whose
0433: * type is being resolved is synthetic, names are resolved with respect
0434: * to the package scope. (Fix for 4097882)
0435: */
0436: public Type resolveNames(ClassDefinition c, Type t, boolean synth) {
0437: if (tracing)
0438: dtEvent("Environment.resolveNames: " + c + ", " + t);
0439: switch (t.getTypeCode()) {
0440: case TC_CLASS: {
0441: Identifier name = t.getClassName();
0442: Identifier rname;
0443: if (synth) {
0444: rname = resolvePackageQualifiedName(name);
0445: } else {
0446: rname = c.resolveName(this , name);
0447: }
0448: if (name != rname) {
0449: t = Type.tClass(rname);
0450: }
0451: break;
0452: }
0453:
0454: case TC_ARRAY:
0455: t = Type.tArray(resolveNames(c, t.getElementType(), synth));
0456: break;
0457:
0458: case TC_METHOD: {
0459: Type ret = t.getReturnType();
0460: Type rret = resolveNames(c, ret, synth);
0461: Type args[] = t.getArgumentTypes();
0462: Type rargs[] = new Type[args.length];
0463: boolean changed = (ret != rret);
0464: for (int i = args.length; i-- > 0;) {
0465: Type arg = args[i];
0466: Type rarg = resolveNames(c, arg, synth);
0467: rargs[i] = rarg;
0468: if (arg != rarg) {
0469: changed = true;
0470: }
0471: }
0472: if (changed) {
0473: t = Type.tMethod(rret, rargs);
0474: }
0475: break;
0476: }
0477: }
0478: return t;
0479: }
0480:
0481: /**
0482: * Resolve a class name, using only package and import directives.
0483: * Report no errors.
0484: * <p>
0485: */
0486: public Identifier resolveName(Identifier name) {
0487: // This logic is pretty exactly parallel to that of
0488: // ClassDefinition.resolveName().
0489: if (name.isQualified()) {
0490: // Try to resolve the first identifier component,
0491: // because inner class names take precedence over
0492: // package prefixes. (Cf. ClassDefinition.resolveName.)
0493: Identifier rhead = resolveName(name.getHead());
0494:
0495: if (rhead.hasAmbigPrefix()) {
0496: // The first identifier component refers to an
0497: // ambiguous class. Limp on. We throw away the
0498: // rest of the classname as it is irrelevant.
0499: // (part of solution for 4059855).
0500: return rhead;
0501: }
0502:
0503: if (!this .classExists(rhead)) {
0504: return this .resolvePackageQualifiedName(name);
0505: }
0506: try {
0507: return this .getClassDefinition(rhead)
0508: .resolveInnerClass(this , name.getTail());
0509: } catch (ClassNotFound ee) {
0510: // return partially-resolved name someone else can fail on
0511: return Identifier.lookupInner(rhead, name.getTail());
0512: }
0513: }
0514: try {
0515: return resolve(name);
0516: } catch (AmbiguousClass ee) {
0517: // Don't force a resolution of the name if it is ambiguous.
0518: // Forcing the resolution would tack the current package
0519: // name onto the front of the class, which would be wrong.
0520: // Instead, mark the name as ambiguous and let a later stage
0521: // find the error by calling env.resolve(name).
0522: // (part of solution for 4059855).
0523:
0524: if (name.hasAmbigPrefix()) {
0525: return name;
0526: } else {
0527: return name.addAmbigPrefix();
0528: }
0529: } catch (ClassNotFound ee) {
0530: // last chance to make something halfway sensible
0531: Imports imports = getImports();
0532: if (imports != null)
0533: return imports.forceResolve(this , name);
0534: }
0535: return name;
0536: }
0537:
0538: /**
0539: * Discover if name consists of a package prefix, followed by the
0540: * name of a class (that actually exists), followed possibly by
0541: * some inner class names. If we can't find a class that exists,
0542: * return the name unchanged.
0543: * <p>
0544: * This routine is used after a class name fails to
0545: * be resolved by means of imports or inner classes.
0546: * However, import processing uses this routine directly,
0547: * since import names must be exactly qualified to start with.
0548: */
0549: public final Identifier resolvePackageQualifiedName(Identifier name) {
0550: Identifier tail = null;
0551: for (;;) {
0552: if (classExists(name)) {
0553: break;
0554: }
0555: if (!name.isQualified()) {
0556: name = (tail == null) ? name : Identifier.lookup(name,
0557: tail);
0558: tail = null;
0559: break;
0560: }
0561: Identifier nm = name.getName();
0562: tail = (tail == null) ? nm : Identifier.lookup(nm, tail);
0563: name = name.getQualifier();
0564: }
0565: if (tail != null)
0566: name = Identifier.lookupInner(name, tail);
0567: return name;
0568: }
0569:
0570: /**
0571: * Resolve a class name, using only package and import directives.
0572: */
0573: public Identifier resolve(Identifier nm) throws ClassNotFound {
0574: if (env == null)
0575: return nm; // a pretty useless no-op
0576: return env.resolve(nm);
0577: }
0578:
0579: /**
0580: * Get the imports used to resolve class names.
0581: */
0582: public Imports getImports() {
0583: if (env == null)
0584: return null; // lame default
0585: return env.getImports();
0586: }
0587:
0588: /**
0589: * Create a new class.
0590: */
0591: public ClassDefinition makeClassDefinition(Environment origEnv,
0592: long where, IdentifierToken name, String doc,
0593: int modifiers, IdentifierToken super Class,
0594: IdentifierToken interfaces[], ClassDefinition outerClass) {
0595: if (env == null)
0596: return null; // lame default
0597: return env.makeClassDefinition(origEnv, where, name, doc,
0598: modifiers, super Class, interfaces, outerClass);
0599: }
0600:
0601: /**
0602: * Create a new field.
0603: */
0604: public MemberDefinition makeMemberDefinition(Environment origEnv,
0605: long where, ClassDefinition clazz, String doc,
0606: int modifiers, Type type, Identifier name,
0607: IdentifierToken argNames[], IdentifierToken expIds[],
0608: Object value) {
0609: if (env == null)
0610: return null; // lame default
0611: return env.makeMemberDefinition(origEnv, where, clazz, doc,
0612: modifiers, type, name, argNames, expIds, value);
0613: }
0614:
0615: /**
0616: * Returns true if the given method is applicable to the given arguments
0617: */
0618:
0619: public boolean isApplicable(MemberDefinition m, Type args[])
0620: throws ClassNotFound {
0621: Type mType = m.getType();
0622: if (!mType.isType(TC_METHOD))
0623: return false;
0624: Type mArgs[] = mType.getArgumentTypes();
0625: if (args.length != mArgs.length)
0626: return false;
0627: for (int i = args.length; --i >= 0;)
0628: if (!isMoreSpecific(args[i], mArgs[i]))
0629: return false;
0630: return true;
0631: }
0632:
0633: /**
0634: * Returns true if "best" is in every argument at least as good as "other"
0635: */
0636: public boolean isMoreSpecific(MemberDefinition best,
0637: MemberDefinition other) throws ClassNotFound {
0638: Type bestType = best.getClassDeclaration().getType();
0639: Type otherType = other.getClassDeclaration().getType();
0640: boolean result = isMoreSpecific(bestType, otherType)
0641: && isApplicable(other, best.getType()
0642: .getArgumentTypes());
0643: // System.out.println("isMoreSpecific: " + best + "/" + other
0644: // + " => " + result);
0645: return result;
0646: }
0647:
0648: /**
0649: * Returns true if "from" is a more specific type than "to"
0650: */
0651:
0652: public boolean isMoreSpecific(Type from, Type to)
0653: throws ClassNotFound {
0654: return implicitCast(from, to);
0655: }
0656:
0657: /**
0658: * Return true if an implicit cast from this type to
0659: * the given type is allowed.
0660: */
0661: public boolean implicitCast(Type from, Type to)
0662: throws ClassNotFound {
0663: if (from == to)
0664: return true;
0665:
0666: int toTypeCode = to.getTypeCode();
0667:
0668: switch (from.getTypeCode()) {
0669: case TC_BYTE:
0670: if (toTypeCode == TC_SHORT)
0671: return true;
0672: case TC_SHORT:
0673: case TC_CHAR:
0674: if (toTypeCode == TC_INT)
0675: return true;
0676: case TC_INT:
0677: if (toTypeCode == TC_LONG)
0678: return true;
0679: case TC_LONG:
0680: if (toTypeCode == TC_FLOAT)
0681: return true;
0682: case TC_FLOAT:
0683: if (toTypeCode == TC_DOUBLE)
0684: return true;
0685: case TC_DOUBLE:
0686: default:
0687: return false;
0688:
0689: case TC_NULL:
0690: return to.inMask(TM_REFERENCE);
0691:
0692: case TC_ARRAY:
0693: if (!to.isType(TC_ARRAY)) {
0694: return (to == Type.tObject || to == Type.tCloneable || to == Type.tSerializable);
0695: } else {
0696: // both are arrays. recurse down both until one isn't an array
0697: do {
0698: from = from.getElementType();
0699: to = to.getElementType();
0700: } while (from.isType(TC_ARRAY) && to.isType(TC_ARRAY));
0701: if (from.inMask(TM_ARRAY | TM_CLASS)
0702: && to.inMask(TM_ARRAY | TM_CLASS)) {
0703: return isMoreSpecific(from, to);
0704: } else {
0705: return (from.getTypeCode() == to.getTypeCode());
0706: }
0707: }
0708:
0709: case TC_CLASS:
0710: if (toTypeCode == TC_CLASS) {
0711: ClassDefinition fromDef = getClassDefinition(from);
0712: ClassDefinition toDef = getClassDefinition(to);
0713: return toDef.implementedBy(this , fromDef
0714: .getClassDeclaration());
0715: } else {
0716: return false;
0717: }
0718: }
0719: }
0720:
0721: /**
0722: * Return true if an explicit cast from this type to
0723: * the given type is allowed.
0724: */
0725: public boolean explicitCast(Type from, Type to)
0726: throws ClassNotFound {
0727: if (implicitCast(from, to)) {
0728: return true;
0729: }
0730: if (from.inMask(TM_NUMBER)) {
0731: return to.inMask(TM_NUMBER);
0732: }
0733: if (from.isType(TC_CLASS) && to.isType(TC_CLASS)) {
0734: ClassDefinition fromClass = getClassDefinition(from);
0735: ClassDefinition toClass = getClassDefinition(to);
0736: if (toClass.isFinal()) {
0737: return fromClass.implementedBy(this , toClass
0738: .getClassDeclaration());
0739: }
0740: if (fromClass.isFinal()) {
0741: return toClass.implementedBy(this , fromClass
0742: .getClassDeclaration());
0743: }
0744:
0745: // The code here used to omit this case. If both types
0746: // involved in a cast are interfaces, then JLS 5.5 requires
0747: // that we do a simple test -- make sure none of the methods
0748: // in toClass and fromClass have the same signature but
0749: // different return types. (bug number 4028359)
0750: if (toClass.isInterface() && fromClass.isInterface()) {
0751: return toClass.couldImplement(fromClass);
0752: }
0753:
0754: return toClass.isInterface()
0755: || fromClass.isInterface()
0756: || fromClass.super ClassOf(this , toClass
0757: .getClassDeclaration());
0758: }
0759: if (to.isType(TC_ARRAY)) {
0760: if (from.isType(TC_ARRAY)) {
0761: Type t1 = from.getElementType();
0762: Type t2 = to.getElementType();
0763: while ((t1.getTypeCode() == TC_ARRAY)
0764: && (t2.getTypeCode() == TC_ARRAY)) {
0765: t1 = t1.getElementType();
0766: t2 = t2.getElementType();
0767: }
0768: if (t1.inMask(TM_ARRAY | TM_CLASS)
0769: && t2.inMask(TM_ARRAY | TM_CLASS)) {
0770: return explicitCast(t1, t2);
0771: }
0772: } else if (from == Type.tObject || from == Type.tCloneable
0773: || from == Type.tSerializable)
0774: return true;
0775: }
0776: return false;
0777: }
0778:
0779: /**
0780: * Flags.
0781: */
0782: public int getFlags() {
0783: return env.getFlags();
0784: }
0785:
0786: /**
0787: * Debugging flags. There used to be a method debug()
0788: * that has been replaced because -g has changed meaning
0789: * (it now cooperates with -O and line number, variable
0790: * range and source file info can be toggled separately).
0791: */
0792: public final boolean debug_lines() {
0793: return (getFlags() & F_DEBUG_LINES) != 0;
0794: }
0795:
0796: public final boolean debug_vars() {
0797: return (getFlags() & F_DEBUG_VARS) != 0;
0798: }
0799:
0800: public final boolean debug_source() {
0801: return (getFlags() & F_DEBUG_SOURCE) != 0;
0802: }
0803:
0804: /**
0805: * Optimization flags. There used to be a method optimize()
0806: * that has been replaced because -O has changed meaning in
0807: * javac to be replaced with -O and -O:interclass.
0808: */
0809: public final boolean opt() {
0810: return (getFlags() & F_OPT) != 0;
0811: }
0812:
0813: public final boolean opt_interclass() {
0814: return (getFlags() & F_OPT_INTERCLASS) != 0;
0815: }
0816:
0817: /**
0818: * Verbose
0819: */
0820: public final boolean verbose() {
0821: return (getFlags() & F_VERBOSE) != 0;
0822: }
0823:
0824: /**
0825: * Dump debugging stuff
0826: */
0827: public final boolean dump() {
0828: return (getFlags() & F_DUMP) != 0;
0829: }
0830:
0831: /**
0832: * Verbose
0833: */
0834: public final boolean warnings() {
0835: return (getFlags() & F_WARNINGS) != 0;
0836: }
0837:
0838: /**
0839: * Dependencies
0840: */
0841: public final boolean dependencies() {
0842: return (getFlags() & F_DEPENDENCIES) != 0;
0843: }
0844:
0845: /**
0846: * Print Dependencies to stdout
0847: */
0848: public final boolean print_dependencies() {
0849: return (getFlags() & F_PRINT_DEPENDENCIES) != 0;
0850: }
0851:
0852: /**
0853: * Deprecation warnings are enabled.
0854: */
0855: public final boolean deprecation() {
0856: return (getFlags() & F_DEPRECATION) != 0;
0857: }
0858:
0859: /**
0860: * Do not support virtual machines before version 1.2.
0861: * This option is not supported and is only here for testing purposes.
0862: */
0863: public final boolean version12() {
0864: return (getFlags() & F_VERSION12) != 0;
0865: }
0866:
0867: /**
0868: * Floating point is strict by default
0869: */
0870: public final boolean strictdefault() {
0871: return (getFlags() & F_STRICTDEFAULT) != 0;
0872: }
0873:
0874: /**
0875: * Release resources, if any.
0876: */
0877: public void shutdown() {
0878: if (env != null) {
0879: env.shutdown();
0880: }
0881: }
0882:
0883: /**
0884: * Issue an error.
0885: * source - the input source, usually a file name string
0886: * offset - the offset in the source of the error
0887: * err - the error number (as defined in this interface)
0888: * arg1 - an optional argument to the error (null if not applicable)
0889: * arg2 - a second optional argument to the error (null if not applicable)
0890: * arg3 - a third optional argument to the error (null if not applicable)
0891: */
0892: public void error(Object source, long where, String err,
0893: Object arg1, Object arg2, Object arg3) {
0894: env.error(source, where, err, arg1, arg2, arg3);
0895: }
0896:
0897: public final void error(long where, String err, Object arg1,
0898: Object arg2, Object arg3) {
0899: error(source, where, err, arg1, arg2, arg3);
0900: }
0901:
0902: public final void error(long where, String err, Object arg1,
0903: Object arg2) {
0904: error(source, where, err, arg1, arg2, null);
0905: }
0906:
0907: public final void error(long where, String err, Object arg1) {
0908: error(source, where, err, arg1, null, null);
0909: }
0910:
0911: public final void error(long where, String err) {
0912: error(source, where, err, null, null, null);
0913: }
0914:
0915: /**
0916: * Output a string. This can either be an error message or something
0917: * for debugging. This should be used instead of println.
0918: */
0919: public void output(String msg) {
0920: env.output(msg);
0921: }
0922:
0923: private static boolean debugging = (System
0924: .getProperty("javac.debug") != null);
0925:
0926: public static void debugOutput(Object msg) {
0927: if (Environment.debugging)
0928: System.out.println(msg.toString());
0929: }
0930:
0931: /**
0932: * set character encoding name
0933: */
0934: public void setCharacterEncoding(String encoding) {
0935: this .encoding = encoding;
0936: }
0937:
0938: /**
0939: * Return character encoding name
0940: */
0941: public String getCharacterEncoding() {
0942: return encoding;
0943: }
0944:
0945: /**
0946: * Return major version to use in generated class files.
0947: */
0948: public short getMajorVersion() {
0949: if (env == null)
0950: return JAVA_DEFAULT_VERSION; // needed for javah
0951: return env.getMajorVersion();
0952: }
0953:
0954: /**
0955: * Return minor version to use in generated class files.
0956: */
0957: public short getMinorVersion() {
0958: if (env == null)
0959: return JAVA_DEFAULT_MINOR_VERSION; // needed for javah
0960: return env.getMinorVersion();
0961: }
0962:
0963: // JCOV
0964: /**
0965: * get coverage flag
0966: */
0967: public final boolean coverage() {
0968: return (getFlags() & F_COVERAGE) != 0;
0969: }
0970:
0971: /**
0972: * get flag of generation the coverage data file
0973: */
0974: public final boolean covdata() {
0975: return (getFlags() & F_COVDATA) != 0;
0976: }
0977:
0978: /**
0979: * Return the coverage data file
0980: */
0981: public File getcovFile() {
0982: return env.getcovFile();
0983: }
0984:
0985: // end JCOV
0986:
0987: /**
0988: * Debug tracing.
0989: * Currently, this code is used only for tracing the loading and
0990: * checking of classes, particularly the demand-driven aspects.
0991: * This code should probably be integrated with 'debugOutput' above,
0992: * but we need to give more thought to the issue of classifying debugging
0993: * messages and allowing those only those of interest to be enabled.
0994: *
0995: * Calls to these methods are generally conditioned on the final variable
0996: * 'Constants.tracing', which allows the calls to be completely omitted
0997: * in a production release to avoid space and time overhead.
0998: */
0999:
1000: private static boolean dependtrace = (System
1001: .getProperty("javac.trace.depend") != null);
1002:
1003: public void dtEnter(String s) {
1004: if (dependtrace)
1005: System.out.println(">>> " + s);
1006: }
1007:
1008: public void dtExit(String s) {
1009: if (dependtrace)
1010: System.out.println("<<< " + s);
1011: }
1012:
1013: public void dtEvent(String s) {
1014: if (dependtrace)
1015: System.out.println(s);
1016: }
1017:
1018: /**
1019: * Enable diagnostic dump of class modifier bits, including those
1020: * in InnerClasses attributes, as they are written to the classfile.
1021: * In the future, may also enable dumping field and method modifiers.
1022: */
1023:
1024: private static boolean dumpmodifiers = (System
1025: .getProperty("javac.dump.modifiers") != null);
1026:
1027: public boolean dumpModifiers() {
1028: return dumpmodifiers;
1029: }
1030:
1031: }
|