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     @SuppressWarnings("fallthrough")
 652     public boolean implicitCast(Type from, Type to) throws ClassNotFound {
 653         if (from == to)
 654             return true;
 655 
 656         int toTypeCode = to.getTypeCode();
 657 
 658         switch(from.getTypeCode()) {
 659         case TC_BYTE:
 660             if (toTypeCode == TC_SHORT)
 661                 return true;
 662         case TC_SHORT:
 663         case TC_CHAR:
 664             if (toTypeCode == TC_INT) return true;
 665         case TC_INT:
 666             if (toTypeCode == TC_LONG) return true;
 667         case TC_LONG:
 668             if (toTypeCode == TC_FLOAT) return true;
 669         case TC_FLOAT:
 670             if (toTypeCode == TC_DOUBLE) return true;
 671         case TC_DOUBLE:
 672         default:
 673             return false;
 674 
 675         case TC_NULL:
 676             return to.inMask(TM_REFERENCE);
 677 
 678         case TC_ARRAY:
 679             if (!to.isType(TC_ARRAY)) {
 680                 return (to == Type.tObject || to == Type.tCloneable
 681                            || to == Type.tSerializable);
 682             } else {
 683                 // both are arrays.  recurse down both until one isn't an array
 684                 do {
 685                     from = from.getElementType();
 686                     to = to.getElementType();
 687                 } while (from.isType(TC_ARRAY) && to.isType(TC_ARRAY));
 688                 if (  from.inMask(TM_ARRAY|TM_CLASS)
 689                       && to.inMask(TM_ARRAY|TM_CLASS)) {
 690                     return isMoreSpecific(from, to);
 691                 } else {
 692                     return (from.getTypeCode() == to.getTypeCode());
 693                 }
 694             }
 695 
 696         case TC_CLASS:
 697             if (toTypeCode == TC_CLASS) {
 698                 ClassDefinition fromDef = getClassDefinition(from);
 699                 ClassDefinition toDef = getClassDefinition(to);
 700                 return toDef.implementedBy(this,
 701                                            fromDef.getClassDeclaration());
 702             } else {
 703                 return false;
 704             }
 705         }
 706     }
 707 
 708 
 709     /**
 710      * Return true if an explicit cast from this type to
 711      * the given type is allowed.
 712      */
 713     public boolean explicitCast(Type from, Type to) throws ClassNotFound {
 714         if (implicitCast(from, to)) {
 715             return true;
 716         }
 717         if (from.inMask(TM_NUMBER)) {
 718             return to.inMask(TM_NUMBER);
 719         }
 720         if (from.isType(TC_CLASS) && to.isType(TC_CLASS)) {
 721             ClassDefinition fromClass = getClassDefinition(from);
 722             ClassDefinition toClass = getClassDefinition(to);
 723             if (toClass.isFinal()) {
 724                 return fromClass.implementedBy(this,
 725                                                toClass.getClassDeclaration());
 726             }
 727             if (fromClass.isFinal()) {
 728                 return toClass.implementedBy(this,
 729                                              fromClass.getClassDeclaration());
 730             }
 731 
 732             // The code here used to omit this case.  If both types
 733             // involved in a cast are interfaces, then JLS 5.5 requires
 734             // that we do a simple test -- make sure none of the methods
 735             // in toClass and fromClass have the same signature but
 736             // different return types.  (bug number 4028359)
 737             if (toClass.isInterface() && fromClass.isInterface()) {
 738                 return toClass.couldImplement(fromClass);
 739             }
 740 
 741             return toClass.isInterface() ||
 742                    fromClass.isInterface() ||
 743                    fromClass.superClassOf(this, toClass.getClassDeclaration());
 744         }
 745         if (to.isType(TC_ARRAY)) {
 746             if (from.isType(TC_ARRAY))  {
 747                 Type t1 = from.getElementType();
 748                 Type t2 = to.getElementType();
 749                 while ((t1.getTypeCode() == TC_ARRAY)
 750                        && (t2.getTypeCode() == TC_ARRAY)) {
 751                     t1 = t1.getElementType();
 752                     t2 = t2.getElementType();
 753                 }
 754                 if (t1.inMask(TM_ARRAY|TM_CLASS) &&
 755                     t2.inMask(TM_ARRAY|TM_CLASS)) {
 756                     return explicitCast(t1, t2);
 757                 }
 758             } else if (from == Type.tObject || from == Type.tCloneable
 759                           || from == Type.tSerializable)
 760                 return true;
 761         }
 762         return false;
 763     }
 764 
 765     /**
 766      * Flags.
 767      */
 768     public int getFlags() {
 769         return env.getFlags();
 770     }
 771 
 772     /**
 773      * Debugging flags.  There used to be a method debug()
 774      * that has been replaced because -g has changed meaning
 775      * (it now cooperates with -O and line number, variable
 776      * range and source file info can be toggled separately).
 777      */
 778     public final boolean debug_lines() {
 779         return (getFlags() & F_DEBUG_LINES) != 0;
 780     }
 781     public final boolean debug_vars() {
 782         return (getFlags() & F_DEBUG_VARS) != 0;
 783     }
 784     public final boolean debug_source() {
 785         return (getFlags() & F_DEBUG_SOURCE) != 0;
 786     }
 787 
 788     /**
 789      * Optimization flags.  There used to be a method optimize()
 790      * that has been replaced because -O has changed meaning in
 791      * javac to be replaced with -O and -O:interclass.
 792      */
 793     public final boolean opt() {
 794         return (getFlags() & F_OPT) != 0;
 795     }
 796     public final boolean opt_interclass() {
 797         return (getFlags() & F_OPT_INTERCLASS) != 0;
 798     }
 799 
 800     /**
 801      * Verbose
 802      */
 803     public final boolean verbose() {
 804         return (getFlags() & F_VERBOSE) != 0;
 805     }
 806 
 807     /**
 808      * Dump debugging stuff
 809      */
 810     public final boolean dump() {
 811         return (getFlags() & F_DUMP) != 0;
 812     }
 813 
 814     /**
 815      * Verbose
 816      */
 817     public final boolean warnings() {
 818         return (getFlags() & F_WARNINGS) != 0;
 819     }
 820 
 821     /**
 822      * Dependencies
 823      */
 824     public final boolean dependencies() {
 825         return (getFlags() & F_DEPENDENCIES) != 0;
 826     }
 827 
 828     /**
 829      * Print Dependencies to stdout
 830      */
 831     public final boolean print_dependencies() {
 832         return (getFlags() & F_PRINT_DEPENDENCIES) != 0;
 833     }
 834 
 835     /**
 836      * Deprecation warnings are enabled.
 837      */
 838     public final boolean deprecation() {
 839         return (getFlags() & F_DEPRECATION) != 0;
 840     }
 841 
 842     /**
 843      * Do not support virtual machines before version 1.2.
 844      * This option is not supported and is only here for testing purposes.
 845      */
 846     public final boolean version12() {
 847         return (getFlags() & F_VERSION12) != 0;
 848     }
 849 
 850     /**
 851      * Floating point is strict by default
 852      */
 853     public final boolean strictdefault() {
 854         return (getFlags() & F_STRICTDEFAULT) != 0;
 855     }
 856 
 857     /**
 858      * Release resources, if any.
 859      */
 860     public void shutdown() {
 861         if (env != null) {
 862             env.shutdown();
 863         }
 864     }
 865 
 866     /**
 867      * Issue an error.
 868      *  source   - the input source, usually a file name string
 869      *  offset   - the offset in the source of the error
 870      *  err      - the error number (as defined in this interface)
 871      *  arg1     - an optional argument to the error (null if not applicable)
 872      *  arg2     - a second optional argument to the error (null if not applicable)
 873      *  arg3     - a third optional argument to the error (null if not applicable)
 874      */
 875     public void error(Object source, long where, String err, Object arg1, Object arg2, Object arg3) {
 876         env.error(source, where, err, arg1, arg2, arg3);
 877     }
 878     public final void error(long where, String err, Object arg1, Object arg2, Object arg3) {
 879         error(source, where, err, arg1, arg2, arg3);
 880     }
 881     public final void error(long where, String err, Object arg1, Object arg2) {
 882         error(source, where, err, arg1, arg2, null);
 883     }
 884     public final void error(long where, String err, Object arg1) {
 885         error(source, where, err, arg1, null, null);
 886     }
 887     public final void error(long where, String err) {
 888         error(source, where, err, null, null, null);
 889     }
 890 
 891     /**
 892      * Output a string. This can either be an error message or something
 893      * for debugging. This should be used instead of println.
 894      */
 895     public void output(String msg) {
 896         env.output(msg);
 897     }
 898 
 899     private static boolean debugging = (System.getProperty("javac.debug") != null);
 900 
 901     public static void debugOutput(Object msg) {
 902         if (Environment.debugging)
 903             System.out.println(msg.toString());
 904     }
 905 
 906     /**
 907      * set character encoding name
 908      */
 909     public void setCharacterEncoding(String encoding) {
 910         this.encoding = encoding;
 911     }
 912 
 913     /**
 914      * Return character encoding name
 915      */
 916     public String getCharacterEncoding() {
 917         return encoding;
 918     }
 919 
 920     /**
 921      * Return major version to use in generated class files.
 922      */
 923     public short getMajorVersion() {
 924         if (env==null) return JAVA_DEFAULT_VERSION;  // needed for javah
 925         return env.getMajorVersion();
 926     }
 927 
 928     /**
 929      * Return minor version to use in generated class files.
 930      */
 931     public short getMinorVersion() {
 932         if (env==null) return JAVA_DEFAULT_MINOR_VERSION;  // needed for javah
 933         return env.getMinorVersion();
 934     }
 935 
 936 // JCOV
 937     /**
 938      *  get coverage flag
 939      */
 940     public final boolean coverage() {
 941         return (getFlags() & F_COVERAGE) != 0;
 942     }
 943 
 944     /**
 945      *  get flag of generation the coverage data file
 946      */
 947     public final boolean covdata() {
 948         return (getFlags() & F_COVDATA) != 0;
 949     }
 950 
 951     /**
 952      * Return the coverage data file
 953      */
 954     public File getcovFile() {
 955         return env.getcovFile();
 956     }
 957 
 958 // end JCOV
 959 
 960     /**
 961      * Debug tracing.
 962      * Currently, this code is used only for tracing the loading and
 963      * checking of classes, particularly the demand-driven aspects.
 964      * This code should probably be integrated with 'debugOutput' above,
 965      * but we need to give more thought to the issue of classifying debugging
 966      * messages and allowing those only those of interest to be enabled.
 967      *
 968      * Calls to these methods are generally conditioned on the final variable
 969      * 'Constants.tracing', which allows the calls to be completely omitted
 970      * in a production release to avoid space and time overhead.
 971      */
 972 
 973     private static boolean dependtrace =
 974                 (System.getProperty("javac.trace.depend") != null);
 975 
 976     public void dtEnter(String s) {
 977         if (dependtrace) System.out.println(">>> " + s);
 978     }
 979 
 980     public void dtExit(String s) {
 981         if (dependtrace) System.out.println("<<< " + s);
 982     }
 983 
 984     public void dtEvent(String s) {
 985         if (dependtrace) System.out.println(s);
 986     }
 987 
 988     /**
 989      * Enable diagnostic dump of class modifier bits, including those
 990      * in InnerClasses attributes, as they are written to the classfile.
 991      * In the future, may also enable dumping field and method modifiers.
 992      */
 993 
 994     private static boolean dumpmodifiers =
 995                 (System.getProperty("javac.dump.modifiers") != null);
 996 
 997     public boolean dumpModifiers() { return dumpmodifiers; }
 998 
 999 }