View Javadoc
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 }