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
26package sun.tools.java;
27
28import java.util.Stack;
29import java.io.IOException;
30import sun.tools.tree.Context;
31//JCOV
32import 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
54public 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}
1000