1 /*
   2  * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.tools.java;
  27 
  28 import java.util.Stack;
  29 import java.io.IOException;
  30 import sun.tools.tree.Context;
  31 //JCOV
  32 import java.io.File;
  33 //end JCOV
  34 
  35 /**
  36  * This class defines the environment for a compilation.
  37  * It is used to load classes, resolve class names and
  38  * report errors. It is an abstract class, a subclass
  39  * must define implementations for some of the functions.<p>
  40  *
  41  * An environment has a source object associated with it.
  42  * This is the thing against which errors are reported, it
  43  * is usually a file name, a field or a class.<p>
  44  *
  45  * Environments can be nested to change the source object.<p>
  46  *
  47  * WARNING: The contents of this source file are not part of any
  48  * supported API.  Code that depends on them does so at its own risk:
  49  * they are subject to change or removal without notice.
  50  *
  51  * @author      Arthur van Hoff
  52  */
  53 
  54 public class Environment implements Constants {
  55     /**
  56      * The actual environment to which everything is forwarded.
  57      */
  58     Environment env;
  59 
  60     /**
  61      * External character encoding name
  62      */
  63     String encoding;
  64 
  65     /**
  66      * The object that is currently being parsed/compiled.
  67      * It is either a file name (String) or a field (MemberDefinition)
  68      * or a class (ClassDeclaration or ClassDefinition).
  69      */
  70     Object source;
  71 
  72     public Environment(Environment env, Object source) {
  73         if (env != null && env.env != null && env.getClass() == this.getClass())
  74             env = env.env;      // a small optimization
  75         this.env = env;
  76         this.source = source;
  77     }
  78     public Environment() {
  79         this(null, null);
  80     }
  81 
  82     /**
  83      * Tells whether an Identifier refers to a package which should be
  84      * exempt from the "exists" check in Imports#resolve().
  85      */
  86     public boolean isExemptPackage(Identifier id) {
  87         return env.isExemptPackage(id);
  88     }
  89 
  90     /**
  91      * Return a class declaration given a fully qualified class name.
  92      */
  93     public ClassDeclaration getClassDeclaration(Identifier nm) {
  94         return env.getClassDeclaration(nm);
  95     }
  96 
  97     /**
  98      * Return a class definition given a fully qualified class name.
  99      * <p>
 100      * Should be called only with 'internal' class names, i.e., the result
 101      * of a call to 'resolveName' or a synthetic class name.
 102      */
 103     public final ClassDefinition getClassDefinition(Identifier nm) throws ClassNotFound {
 104         if (nm.isInner()) {
 105             ClassDefinition c = getClassDefinition(nm.getTopName());
 106             Identifier tail = nm.getFlatName();
 107         walkTail:
 108             while (tail.isQualified()) {
 109                 tail = tail.getTail();
 110                 Identifier head = tail.getHead();
 111                 //System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail);
 112                 String hname = head.toString();
 113                 // If the name is of the form 'ClassName.N$localName', where N is
 114                 // a number, the field 'N$localName' may not necessarily be a member
 115                 // of the class named by 'ClassName', but might be a member of some
 116                 // inaccessible class contained within it.  We use 'getLocalClass'
 117                 // to do the lookup in this case.  This is part of a fix for bugid
 118                 // 4054523 and 4030421.  See also 'BatchEnvironment.makeClassDefinition'.
 119                 // This should also work for anonymous class names of the form
 120                 // 'ClassName.N'.  Note that the '.' qualifications get converted to
 121                 // '$' characters when determining the external name of the class and
 122                 // the name of the class file.
 123                 if (hname.length() > 0
 124                     && Character.isDigit(hname.charAt(0))) {
 125                     ClassDefinition localClass = c.getLocalClass(hname);
 126                     if (localClass != null) {
 127                         c = localClass;
 128                         continue walkTail;
 129                     }
 130                 } else {
 131                     for (MemberDefinition f = c.getFirstMatch(head);
 132                          f != null; f = f.getNextMatch()) {
 133                         if (f.isInnerClass()) {
 134                             c = f.getInnerClass();
 135                             continue walkTail;
 136                         }
 137                     }
 138                 }
 139                 throw new ClassNotFound(Identifier.lookupInner(c.getName(), head));
 140             }
 141             //System.out.println("FOUND " + c + " FOR " + nm);
 142             return c;
 143         }
 144         return getClassDeclaration(nm).getClassDefinition(this);
 145     }
 146 
 147 
 148     /**
 149      * Return a class declaration given a type. Only works for
 150      * class types.
 151      */
 152     public ClassDeclaration getClassDeclaration(Type t) {
 153         return getClassDeclaration(t.getClassName());
 154     }
 155 
 156     /**
 157      * Return a class definition given a type. Only works for
 158      * class types.
 159      */
 160     public final ClassDefinition getClassDefinition(Type t) throws ClassNotFound {
 161         return getClassDefinition(t.getClassName());
 162     }
 163 
 164     /**
 165      * Check if a class exists (without actually loading it).
 166      * (Since inner classes cannot in general be examined without
 167      * loading source, this method does not accept inner names.)
 168      */
 169     public boolean classExists(Identifier nm) {
 170         return env.classExists(nm);
 171     }
 172 
 173     public final boolean classExists(Type t) {
 174         return !t.isType(TC_CLASS) || classExists(t.getClassName());
 175     }
 176 
 177     /**
 178      * Get the package path for a package
 179      */
 180     public Package getPackage(Identifier pkg) throws IOException {
 181         return env.getPackage(pkg);
 182     }
 183 
 184     /**
 185      * Load the definition of a class.
 186      */
 187     public void loadDefinition(ClassDeclaration c) {
 188         env.loadDefinition(c);
 189     }
 190 
 191     /**
 192      * Return the source of the environment (ie: the thing being compiled/parsed).
 193      */
 194     public final Object getSource() {
 195         return source;
 196     }
 197 
 198     /**
 199      * Resolve a type. Make sure that all the classes referred to by
 200      * the type have a definition.  Report errors.  Return true if
 201      * the type is well-formed.  Presently used for types appearing
 202      * in member declarations, which represent named types internally as
 203      * qualified identifiers.  Type names appearing in local variable
 204      * declarations and within expressions are represented as identifier
 205      * or field expressions, and are resolved by 'toType', which delegates
 206      * handling of the non-inner portion of the name to this method.
 207      * <p>
 208      * In 'toType', the various stages of qualification are represented by
 209      * separate AST nodes.  Here, we are given a single identifier which
 210      * contains the entire qualification structure.  It is not possible in
 211      * general to set the error location to the exact position of a component
 212      * that is in error, so an error message must refer to the entire qualified
 213      * name.  An attempt to keep track of the string length of the components of
 214      * the name and to offset the location accordingly fails because the initial
 215      * prefix of the name may have been rewritten by an earlier call to
 216      * 'resolveName'.  See 'SourceMember.resolveTypeStructure'.  The situation
 217      * is actually even worse than this, because only a single location is
 218      * passed in for an entire declaration, which may contain many type names.
 219      * All error messages are thus poorly localized.  These checks should be
 220      * done while traversing the parse tree for the type, not the type descriptor.
 221      * <p>
 222      * DESIGN NOTE:
 223      * As far as I can tell, the two-stage resolution of names represented in
 224      * string form is an artifact of the late implementation of inner classes
 225      * and the use of mangled names internally within the compiler.  All
 226      * qualified names should have their hiearchical structure made explicit
 227      * in the parse tree at the phase at which they are presented for static
 228      * semantic checking.  This would affect class names appearing in 'extends',
 229      * 'implements', and 'throws' clauses, as well as in member declarations.
 230      */
 231     public boolean resolve(long where, ClassDefinition c, Type t) {
 232         switch (t.getTypeCode()) {
 233           case TC_CLASS: {
 234             ClassDefinition def;
 235             try {
 236                 Identifier nm = t.getClassName();
 237                 if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) {
 238                     resolve(nm);        // elicit complaints about ambiguity
 239                 }
 240                 def = getQualifiedClassDefinition(where, nm, c, false);
 241                 if (!c.canAccess(this, def.getClassDeclaration())) {
 242                     // Reported error location may be imprecise
 243                     // if the name is qualified.
 244                     error(where, "cant.access.class", def);
 245                     return true; // return false later
 246                 }
 247                 def.noteUsedBy(c, where, env);
 248             } catch (AmbiguousClass ee) {
 249                 error(where, "ambig.class", ee.name1, ee.name2);
 250                 return false;
 251             } catch (ClassNotFound e) {
 252                 // For now, report "class.and.package" only when the code
 253                 // is going to fail anyway.
 254                 try {
 255                     if (e.name.isInner() &&
 256                             getPackage(e.name.getTopName()).exists()) {
 257                         env.error(where, "class.and.package",
 258                                   e.name.getTopName());
 259                     }
 260                 } catch (IOException ee) {
 261                     env.error(where, "io.exception", "package check");
 262                 }
 263                 // This error message is also emitted for 'new' expressions.
 264                 // error(where, "class.not.found", e.name, "declaration");
 265                 error(where, "class.not.found.no.context", e.name);
 266                 return false;
 267             }
 268             return true;
 269           }
 270 
 271           case TC_ARRAY:
 272             return resolve(where, c, t.getElementType());
 273 
 274           case TC_METHOD:
 275             boolean ok = resolve(where, c, t.getReturnType());
 276             Type args[] = t.getArgumentTypes();
 277             for (int i = args.length ; i-- > 0 ; ) {
 278                 ok &= resolve(where, c, args[i]);
 279             }
 280             return ok;
 281         }
 282         return true;
 283     }
 284 
 285     /**
 286      * Given its fully-qualified name, verify that a class is defined and accessible.
 287      * Used to check components of qualified names in contexts where a class is expected.
 288      * Like 'resolve', but is given a single type name, not a type descriptor.
 289      */
 290     public boolean resolveByName(long where, ClassDefinition c, Identifier nm) {
 291         return resolveByName(where, c, nm, false);
 292     }
 293 
 294     public boolean resolveExtendsByName(long where, ClassDefinition c, Identifier nm) {
 295         return resolveByName(where, c, nm, true);
 296     }
 297 
 298     private boolean resolveByName(long where, ClassDefinition c,
 299                                  Identifier nm, boolean isExtends) {
 300         ClassDefinition def;
 301         try {
 302             if (!nm.isQualified() && !nm.isInner() && !classExists(nm)) {
 303                 resolve(nm);    // elicit complaints about ambiguity
 304             }
 305             def = getQualifiedClassDefinition(where, nm, c, isExtends);
 306             ClassDeclaration decl = def.getClassDeclaration();
 307             if (!((!isExtends && c.canAccess(this, decl))
 308                   ||
 309                   (isExtends && c.extendsCanAccess(this, decl)))) {
 310                 error(where, "cant.access.class", def);
 311                 return true; // return false later
 312             }
 313         } catch (AmbiguousClass ee) {
 314             error(where, "ambig.class", ee.name1, ee.name2);
 315             return false;
 316         } catch (ClassNotFound e) {
 317             // For now, report "class.and.package" only when the code
 318             // is going to fail anyway.
 319             try {
 320                 if (e.name.isInner() &&
 321                     getPackage(e.name.getTopName()).exists()) {
 322                     env.error(where, "class.and.package",
 323                               e.name.getTopName());
 324                 }
 325             } catch (IOException ee) {
 326                 env.error(where, "io.exception", "package check");
 327             }
 328             error(where, "class.not.found", e.name, "type name");
 329             return false;
 330         }
 331         return true;
 332     }
 333 
 334     /**
 335      * Like 'getClassDefinition(env)', but check access on each component.
 336      * Currently called only by 'resolve' above.  It is doubtful that calls
 337      * to 'getClassDefinition(env)' are appropriate now.
 338      */
 339     public final ClassDefinition
 340     getQualifiedClassDefinition(long where,
 341                                 Identifier nm,
 342                                 ClassDefinition ctxClass,
 343                                 boolean isExtends) throws ClassNotFound {
 344         if (nm.isInner()) {
 345             ClassDefinition c = getClassDefinition(nm.getTopName());
 346             Identifier tail = nm.getFlatName();
 347         walkTail:
 348             while (tail.isQualified()) {
 349                 tail = tail.getTail();
 350                 Identifier head = tail.getHead();
 351                 // System.out.println("CLASS: " + c + " HEAD: " + head + " TAIL: " + tail);
 352                 String hname = head.toString();
 353                 // Handle synthesized names of local and anonymous classes.
 354                 // See 'getClassDefinition(env)' above.
 355                 if (hname.length() > 0
 356                     && Character.isDigit(hname.charAt(0))) {
 357                     ClassDefinition localClass = c.getLocalClass(hname);
 358                     if (localClass != null) {
 359                         c = localClass;
 360                         continue walkTail;
 361                     }
 362                 } else {
 363                     for (MemberDefinition f = c.getFirstMatch(head);
 364                          f != null; f = f.getNextMatch()) {
 365                         if (f.isInnerClass()) {
 366                             ClassDeclaration rdecl = c.getClassDeclaration();
 367                             c = f.getInnerClass();
 368                             ClassDeclaration fdecl = c.getClassDeclaration();
 369                             // This check is presumably applicable even if the
 370                             // original source-code name (expanded by 'resolveNames')
 371                             // was a simple, unqualified name.  Hopefully, JLS 2e
 372                             // will clarify the matter.
 373                             if ((!isExtends
 374                                  && !ctxClass.canAccess(env, fdecl))
 375                                 ||
 376                                 (isExtends
 377                                  && !ctxClass.extendsCanAccess(env, fdecl))) {
 378                                 // Reported error location is imprecise.
 379                                 env.error(where, "no.type.access", head, rdecl, ctxClass);
 380                             }
 381                             // The JLS 6.6.2 restrictions on access to protected members
 382                             // depend in an essential way upon the syntactic form of the name.
 383                             // Since the compiler has previously expanded the class names
 384                             // here into fully-qualified form ('resolveNames'), this check
 385                             // cannot be performed here.  Unfortunately, the original names
 386                             // are clobbered during 'basicCheck', which is also the phase that
 387                             // resolves the inheritance structure, required to implement the
 388                             // access restrictions.  Pending a large-scale revision of the
 389                             // name-resolution machinery, we forgo this check, with the result
 390                             // that the JLS 6.6.2 restrictions are not enforced for some cases
 391                             // of qualified access to inner classes.  Some qualified names are
 392                             // resolved elsewhere via a different mechanism, and will be
 393                             // treated correctly -- see 'FieldExpression.checkCommon'.
 394                             /*---------------------------------------*
 395                             if (f.isProtected()) {
 396                                 Type rty = Type.tClass(rdecl.getName()); // hack
 397                                 if (!ctxClass.protectedAccess(env, f, rty)) {
 398                                     // Reported error location is imprecise.
 399                                     env.error(where, "invalid.protected.type.use",
 400                                               head, ctxClass, rty);
 401                                 }
 402                             }
 403                             *---------------------------------------*/
 404                             continue walkTail;
 405                         }
 406                     }
 407                 }
 408                 throw new ClassNotFound(Identifier.lookupInner(c.getName(), head));
 409             }
 410             //System.out.println("FOUND " + c + " FOR " + nm);
 411             return c;
 412         }
 413         return getClassDeclaration(nm).getClassDefinition(this);
 414     }
 415 
 416     /**
 417      * Resolve the names within a type, returning the adjusted type.
 418      * Adjust class names to reflect scoping.
 419      * Do not report errors.
 420      * <p>
 421      * NOTE: It would be convenient to check for errors here, such as
 422      * verifying that each component of a qualified name exists and is
 423      * accessible.  Why must this be done in a separate phase?
 424      * <p>
 425      * If the 'synth' argument is true, indicating that the member whose
 426      * type is being resolved is synthetic, names are resolved with respect
 427      * to the package scope.  (Fix for 4097882)
 428      */
 429     public Type resolveNames(ClassDefinition c, Type t, boolean synth) {
 430         if (tracing) dtEvent("Environment.resolveNames: " + c + ", " + t);
 431         switch (t.getTypeCode()) {
 432           case TC_CLASS: {
 433             Identifier name = t.getClassName();
 434             Identifier rname;
 435             if (synth) {
 436                 rname = resolvePackageQualifiedName(name);
 437             } else {
 438                 rname = c.resolveName(this, name);
 439             }
 440             if (name != rname) {
 441                 t = Type.tClass(rname);
 442             }
 443             break;
 444           }
 445 
 446           case TC_ARRAY:
 447             t = Type.tArray(resolveNames(c, t.getElementType(), synth));
 448             break;
 449 
 450           case TC_METHOD: {
 451             Type ret = t.getReturnType();
 452             Type rret = resolveNames(c, ret, synth);
 453             Type args[] = t.getArgumentTypes();
 454             Type rargs[] = new Type[args.length];
 455             boolean changed = (ret != rret);
 456             for (int i = args.length ; i-- > 0 ; ) {
 457                 Type arg = args[i];
 458                 Type rarg = resolveNames(c, arg, synth);
 459                 rargs[i] = rarg;
 460                 if (arg != rarg) {
 461                     changed = true;
 462                 }
 463             }
 464             if (changed) {
 465                 t = Type.tMethod(rret, rargs);
 466             }
 467             break;
 468           }
 469         }
 470         return t;
 471     }
 472 
 473     /**
 474      * Resolve a class name, using only package and import directives.
 475      * Report no errors.
 476      * <p>
 477      */
 478     public Identifier resolveName(Identifier name) {
 479         // This logic is pretty exactly parallel to that of
 480         // ClassDefinition.resolveName().
 481         if (name.isQualified()) {
 482             // Try to resolve the first identifier component,
 483             // because inner class names take precedence over
 484             // package prefixes.  (Cf. ClassDefinition.resolveName.)
 485             Identifier rhead = resolveName(name.getHead());
 486 
 487             if (rhead.hasAmbigPrefix()) {
 488                 // The first identifier component refers to an
 489                 // ambiguous class.  Limp on.  We throw away the
 490                 // rest of the classname as it is irrelevant.
 491                 // (part of solution for 4059855).
 492                 return rhead;
 493             }
 494 
 495             if (!this.classExists(rhead)) {
 496                 return this.resolvePackageQualifiedName(name);
 497             }
 498             try {
 499                 return this.getClassDefinition(rhead).
 500                     resolveInnerClass(this, name.getTail());
 501             } catch (ClassNotFound ee) {
 502                 // return partially-resolved name someone else can fail on
 503                 return Identifier.lookupInner(rhead, name.getTail());
 504             }
 505         }
 506         try {
 507             return resolve(name);
 508         } catch (AmbiguousClass ee) {
 509             // Don't force a resolution of the name if it is ambiguous.
 510             // Forcing the resolution would tack the current package
 511             // name onto the front of the class, which would be wrong.
 512             // Instead, mark the name as ambiguous and let a later stage
 513             // find the error by calling env.resolve(name).
 514             // (part of solution for 4059855).
 515 
 516             if (name.hasAmbigPrefix()) {
 517                 return name;
 518             } else {
 519                 return name.addAmbigPrefix();
 520             }
 521         } catch (ClassNotFound ee) {
 522             // last chance to make something halfway sensible
 523             Imports imports = getImports();
 524             if (imports != null)
 525                 return imports.forceResolve(this, name);
 526         }
 527         return name;
 528     }
 529 
 530     /**
 531      * Discover if name consists of a package prefix, followed by the
 532      * name of a class (that actually exists), followed possibly by
 533      * some inner class names.  If we can't find a class that exists,
 534      * return the name unchanged.
 535      * <p>
 536      * This routine is used after a class name fails to
 537      * be resolved by means of imports or inner classes.
 538      * However, import processing uses this routine directly,
 539      * since import names must be exactly qualified to start with.
 540      */
 541     public final Identifier resolvePackageQualifiedName(Identifier name) {
 542         Identifier tail = null;
 543         for (;;) {
 544             if (classExists(name)) {
 545                 break;
 546             }
 547             if (!name.isQualified()) {
 548                 name = (tail == null) ? name : Identifier.lookup(name, tail);
 549                 tail = null;
 550                 break;
 551             }
 552             Identifier nm = name.getName();
 553             tail = (tail == null)? nm: Identifier.lookup(nm, tail);
 554             name = name.getQualifier();
 555         }
 556         if (tail != null)
 557             name = Identifier.lookupInner(name, tail);
 558         return name;
 559     }
 560 
 561     /**
 562      * Resolve a class name, using only package and import directives.
 563      */
 564     public Identifier resolve(Identifier nm) throws ClassNotFound {
 565         if (env == null)  return nm;    // a pretty useless no-op
 566         return env.resolve(nm);
 567     }
 568 
 569     /**
 570      * Get the imports used to resolve class names.
 571      */
 572     public Imports getImports() {
 573         if (env == null)  return null; // lame default
 574         return env.getImports();
 575     }
 576 
 577     /**
 578      * Create a new class.
 579      */
 580     public ClassDefinition makeClassDefinition(Environment origEnv, long where,
 581                                                IdentifierToken name,
 582                                                String doc, int modifiers,
 583                                                IdentifierToken superClass,
 584                                                IdentifierToken interfaces[],
 585                                                ClassDefinition outerClass) {
 586         if (env == null)  return null; // lame default
 587         return env.makeClassDefinition(origEnv, where, name,
 588                                        doc, modifiers,
 589                                        superClass, interfaces, outerClass);
 590     }
 591 
 592     /**
 593      * Create a new field.
 594      */
 595     public MemberDefinition makeMemberDefinition(Environment origEnv, long where,
 596                                                ClassDefinition clazz,
 597                                                String doc, int modifiers,
 598                                                Type type, Identifier name,
 599                                                IdentifierToken argNames[],
 600                                                IdentifierToken expIds[],
 601                                                Object value) {
 602         if (env == null)  return null; // lame default
 603         return env.makeMemberDefinition(origEnv, where, clazz, doc, modifiers,
 604                                        type, name, argNames, expIds, value);
 605     }
 606 
 607     /**
 608      * Returns true if the given method is applicable to the given arguments
 609      */
 610 
 611     public boolean isApplicable(MemberDefinition m, Type args[]) throws ClassNotFound {
 612         Type mType = m.getType();
 613         if (!mType.isType(TC_METHOD))
 614             return false;
 615         Type mArgs[] = mType.getArgumentTypes();
 616         if (args.length != mArgs.length)
 617             return false;
 618         for (int i = args.length ; --i >= 0 ;)
 619             if (!isMoreSpecific(args[i], mArgs[i]))
 620                 return false;
 621         return true;
 622     }
 623 
 624 
 625     /**
 626      * Returns true if "best" is in every argument at least as good as "other"
 627      */
 628     public boolean isMoreSpecific(MemberDefinition best, MemberDefinition other)
 629            throws ClassNotFound {
 630         Type bestType = best.getClassDeclaration().getType();
 631         Type otherType = other.getClassDeclaration().getType();
 632         boolean result = isMoreSpecific(bestType, otherType)
 633                       && isApplicable(other, best.getType().getArgumentTypes());
 634         // System.out.println("isMoreSpecific: " + best + "/" + other
 635         //                      + " => " + result);
 636         return result;
 637     }
 638 
 639     /**
 640      * Returns true if "from" is a more specific type than "to"
 641      */
 642 
 643     public boolean isMoreSpecific(Type from, Type to) throws ClassNotFound {
 644         return implicitCast(from, to);
 645     }
 646 
 647     /**
 648      * Return true if an implicit cast from this type to
 649      * the given type is allowed.
 650      */
 651     public boolean implicitCast(Type from, Type to) throws ClassNotFound {
 652         if (from == to)
 653             return true;
 654 
 655         int toTypeCode = to.getTypeCode();
 656 
 657         switch(from.getTypeCode()) {
 658         case TC_BYTE:
 659             if (toTypeCode == TC_SHORT)
 660                 return true;
 661         case TC_SHORT:
 662         case TC_CHAR:
 663             if (toTypeCode == TC_INT) return true;
 664         case TC_INT:
 665             if (toTypeCode == TC_LONG) return true;
 666         case TC_LONG:
 667             if (toTypeCode == TC_FLOAT) return true;
 668         case TC_FLOAT:
 669             if (toTypeCode == TC_DOUBLE) return true;
 670         case TC_DOUBLE:
 671         default:
 672             return false;
 673 
 674         case TC_NULL:
 675             return to.inMask(TM_REFERENCE);
 676 
 677         case TC_ARRAY:
 678             if (!to.isType(TC_ARRAY)) {
 679                 return (to == Type.tObject || to == Type.tCloneable
 680                            || to == Type.tSerializable);
 681             } else {
 682                 // both are arrays.  recurse down both until one isn't an array
 683                 do {
 684                     from = from.getElementType();
 685                     to = to.getElementType();
 686                 } while (from.isType(TC_ARRAY) && to.isType(TC_ARRAY));
 687                 if (  from.inMask(TM_ARRAY|TM_CLASS)
 688                       && to.inMask(TM_ARRAY|TM_CLASS)) {
 689                     return isMoreSpecific(from, to);
 690                 } else {
 691                     return (from.getTypeCode() == to.getTypeCode());
 692                 }
 693             }
 694 
 695         case TC_CLASS:
 696             if (toTypeCode == TC_CLASS) {
 697                 ClassDefinition fromDef = getClassDefinition(from);
 698                 ClassDefinition toDef = getClassDefinition(to);
 699                 return toDef.implementedBy(this,
 700                                            fromDef.getClassDeclaration());
 701             } else {
 702                 return false;
 703             }
 704         }
 705     }
 706 
 707 
 708     /**
 709      * Return true if an explicit cast from this type to
 710      * the given type is allowed.
 711      */
 712     public boolean explicitCast(Type from, Type to) throws ClassNotFound {
 713         if (implicitCast(from, to)) {
 714             return true;
 715         }
 716         if (from.inMask(TM_NUMBER)) {
 717             return to.inMask(TM_NUMBER);
 718         }
 719         if (from.isType(TC_CLASS) && to.isType(TC_CLASS)) {
 720             ClassDefinition fromClass = getClassDefinition(from);
 721             ClassDefinition toClass = getClassDefinition(to);
 722             if (toClass.isFinal()) {
 723                 return fromClass.implementedBy(this,
 724                                                toClass.getClassDeclaration());
 725             }
 726             if (fromClass.isFinal()) {
 727                 return toClass.implementedBy(this,
 728                                              fromClass.getClassDeclaration());
 729             }
 730 
 731             // The code here used to omit this case.  If both types
 732             // involved in a cast are interfaces, then JLS 5.5 requires
 733             // that we do a simple test -- make sure none of the methods
 734             // in toClass and fromClass have the same signature but
 735             // different return types.  (bug number 4028359)
 736             if (toClass.isInterface() && fromClass.isInterface()) {
 737                 return toClass.couldImplement(fromClass);
 738             }
 739 
 740             return toClass.isInterface() ||
 741                    fromClass.isInterface() ||
 742                    fromClass.superClassOf(this, toClass.getClassDeclaration());
 743         }
 744         if (to.isType(TC_ARRAY)) {
 745             if (from.isType(TC_ARRAY))  {
 746                 Type t1 = from.getElementType();
 747                 Type t2 = to.getElementType();
 748                 while ((t1.getTypeCode() == TC_ARRAY)
 749                        && (t2.getTypeCode() == TC_ARRAY)) {
 750                     t1 = t1.getElementType();
 751                     t2 = t2.getElementType();
 752                 }
 753                 if (t1.inMask(TM_ARRAY|TM_CLASS) &&
 754                     t2.inMask(TM_ARRAY|TM_CLASS)) {
 755                     return explicitCast(t1, t2);
 756                 }
 757             } else if (from == Type.tObject || from == Type.tCloneable
 758                           || from == Type.tSerializable)
 759                 return true;
 760         }
 761         return false;
 762     }
 763 
 764     /**
 765      * Flags.
 766      */
 767     public int getFlags() {
 768         return env.getFlags();
 769     }
 770 
 771     /**
 772      * Debugging flags.  There used to be a method debug()
 773      * that has been replaced because -g has changed meaning
 774      * (it now cooperates with -O and line number, variable
 775      * range and source file info can be toggled separately).
 776      */
 777     public final boolean debug_lines() {
 778         return (getFlags() & F_DEBUG_LINES) != 0;
 779     }
 780     public final boolean debug_vars() {
 781         return (getFlags() & F_DEBUG_VARS) != 0;
 782     }
 783     public final boolean debug_source() {
 784         return (getFlags() & F_DEBUG_SOURCE) != 0;
 785     }
 786 
 787     /**
 788      * Optimization flags.  There used to be a method optimize()
 789      * that has been replaced because -O has changed meaning in
 790      * javac to be replaced with -O and -O:interclass.
 791      */
 792     public final boolean opt() {
 793         return (getFlags() & F_OPT) != 0;
 794     }
 795     public final boolean opt_interclass() {
 796         return (getFlags() & F_OPT_INTERCLASS) != 0;
 797     }
 798 
 799     /**
 800      * Verbose
 801      */
 802     public final boolean verbose() {
 803         return (getFlags() & F_VERBOSE) != 0;
 804     }
 805 
 806     /**
 807      * Dump debugging stuff
 808      */
 809     public final boolean dump() {
 810         return (getFlags() & F_DUMP) != 0;
 811     }
 812 
 813     /**
 814      * Verbose
 815      */
 816     public final boolean warnings() {
 817         return (getFlags() & F_WARNINGS) != 0;
 818     }
 819 
 820     /**
 821      * Dependencies
 822      */
 823     public final boolean dependencies() {
 824         return (getFlags() & F_DEPENDENCIES) != 0;
 825     }
 826 
 827     /**
 828      * Print Dependencies to stdout
 829      */
 830     public final boolean print_dependencies() {
 831         return (getFlags() & F_PRINT_DEPENDENCIES) != 0;
 832     }
 833 
 834     /**
 835      * Deprecation warnings are enabled.
 836      */
 837     public final boolean deprecation() {
 838         return (getFlags() & F_DEPRECATION) != 0;
 839     }
 840 
 841     /**
 842      * Do not support virtual machines before version 1.2.
 843      * This option is not supported and is only here for testing purposes.
 844      */
 845     public final boolean version12() {
 846         return (getFlags() & F_VERSION12) != 0;
 847     }
 848 
 849     /**
 850      * Floating point is strict by default
 851      */
 852     public final boolean strictdefault() {
 853         return (getFlags() & F_STRICTDEFAULT) != 0;
 854     }
 855 
 856     /**
 857      * Release resources, if any.
 858      */
 859     public void shutdown() {
 860         if (env != null) {
 861             env.shutdown();
 862         }
 863     }
 864 
 865     /**
 866      * Issue an error.
 867      *  source   - the input source, usually a file name string
 868      *  offset   - the offset in the source of the error
 869      *  err      - the error number (as defined in this interface)
 870      *  arg1     - an optional argument to the error (null if not applicable)
 871      *  arg2     - a second optional argument to the error (null if not applicable)
 872      *  arg3     - a third optional argument to the error (null if not applicable)
 873      */
 874     public void error(Object source, long where, String err, Object arg1, Object arg2, Object arg3) {
 875         env.error(source, where, err, arg1, arg2, arg3);
 876     }
 877     public final void error(long where, String err, Object arg1, Object arg2, Object arg3) {
 878         error(source, where, err, arg1, arg2, arg3);
 879     }
 880     public final void error(long where, String err, Object arg1, Object arg2) {
 881         error(source, where, err, arg1, arg2, null);
 882     }
 883     public final void error(long where, String err, Object arg1) {
 884         error(source, where, err, arg1, null, null);
 885     }
 886     public final void error(long where, String err) {
 887         error(source, where, err, null, null, null);
 888     }
 889 
 890     /**
 891      * Output a string. This can either be an error message or something
 892      * for debugging. This should be used instead of println.
 893      */
 894     public void output(String msg) {
 895         env.output(msg);
 896     }
 897 
 898     private static boolean debugging = (System.getProperty("javac.debug") != null);
 899 
 900     public static void debugOutput(Object msg) {
 901         if (Environment.debugging)
 902             System.out.println(msg.toString());
 903     }
 904 
 905     /**
 906      * set character encoding name
 907      */
 908     public void setCharacterEncoding(String encoding) {
 909         this.encoding = encoding;
 910     }
 911 
 912     /**
 913      * Return character encoding name
 914      */
 915     public String getCharacterEncoding() {
 916         return encoding;
 917     }
 918 
 919     /**
 920      * Return major version to use in generated class files.
 921      */
 922     public short getMajorVersion() {
 923         if (env==null) return JAVA_DEFAULT_VERSION;  // needed for javah
 924         return env.getMajorVersion();
 925     }
 926 
 927     /**
 928      * Return minor version to use in generated class files.
 929      */
 930     public short getMinorVersion() {
 931         if (env==null) return JAVA_DEFAULT_MINOR_VERSION;  // needed for javah
 932         return env.getMinorVersion();
 933     }
 934 
 935 // JCOV
 936     /**
 937      *  get coverage flag
 938      */
 939     public final boolean coverage() {
 940         return (getFlags() & F_COVERAGE) != 0;
 941     }
 942 
 943     /**
 944      *  get flag of generation the coverage data file
 945      */
 946     public final boolean covdata() {
 947         return (getFlags() & F_COVDATA) != 0;
 948     }
 949 
 950     /**
 951      * Return the coverage data file
 952      */
 953     public File getcovFile() {
 954         return env.getcovFile();
 955     }
 956 
 957 // end JCOV
 958 
 959     /**
 960      * Debug tracing.
 961      * Currently, this code is used only for tracing the loading and
 962      * checking of classes, particularly the demand-driven aspects.
 963      * This code should probably be integrated with 'debugOutput' above,
 964      * but we need to give more thought to the issue of classifying debugging
 965      * messages and allowing those only those of interest to be enabled.
 966      *
 967      * Calls to these methods are generally conditioned on the final variable
 968      * 'Constants.tracing', which allows the calls to be completely omitted
 969      * in a production release to avoid space and time overhead.
 970      */
 971 
 972     private static boolean dependtrace =
 973                 (System.getProperty("javac.trace.depend") != null);
 974 
 975     public void dtEnter(String s) {
 976         if (dependtrace) System.out.println(">>> " + s);
 977     }
 978 
 979     public void dtExit(String s) {
 980         if (dependtrace) System.out.println("<<< " + s);
 981     }
 982 
 983     public void dtEvent(String s) {
 984         if (dependtrace) System.out.println(s);
 985     }
 986 
 987     /**
 988      * Enable diagnostic dump of class modifier bits, including those
 989      * in InnerClasses attributes, as they are written to the classfile.
 990      * In the future, may also enable dumping field and method modifiers.
 991      */
 992 
 993     private static boolean dumpmodifiers =
 994                 (System.getProperty("javac.dump.modifiers") != null);
 995 
 996     public boolean dumpModifiers() { return dumpmodifiers; }
 997 
 998 }