    001    /* Copyright 2000, 2001, Compaq Computer Corporation */
    002
    003    package javafe.tc;
    004
    005
    006    import javafe.ast.*;
    007    import javafe.util.*;
    008
    009
    010    /**
    011     * EnvForCUs are used to create an Env for a CompilationUnit.
    012     */
    013
    014    public class EnvForCU extends Env {
    015
    016        /***************************************************
    017         *                                                 *
    018         * Creation:                                       *
    019         *                                                 *
    020         **************************************************/
    021
    022        /**
    023         * Our CompilationUnit.
    024         */
    025        protected /*@ non_null @*/ CompilationUnit CU;
    026
    027
    028        /**
    029         * Create an environment for a CompilationUnit.
    030         */
    031        public EnvForCU(/*@ non_null @*/ CompilationUnit CU) {
    032            this.CU = CU;
    033        }
    034
    035
    036        /***************************************************
    037         *                                                 *
    038         * Current/enclosing instances I:                  *
    039         *                                                 *
    040         **************************************************/
    041
    042
    043        /**
    044         * Is there a current instance in scope? <p>
    045         *
    046         * E.g., is "this" (or "<enclosing class>.this") legal here? <p>
    047         *
    048         * This is also refered to as "are we in a static context?".  The
    049         * legality of super also depends on this result. <p>
    050         *
    051         * The legality of C.this, C != <enclosing class> is different; see
    052         * canAccessInstance(-).
    053         */
    054        public boolean isStaticContext() { return true; }
    055
    056
    057        /**
    058         * Return the intermost class enclosing the code that is checked
    059         * in this environment. <p>
    060         *
    061         * May return null if there is no enclosing class (aka, for
    062         * environments for CompilationUnits). <p>
    063         *
    064         * If isStaticContext() returns true, then this is the type of "this".
    065         */
    066        public TypeSig getEnclosingClass() { return null; }
    067
    068
    069        /**
    070         * If there is an enclosing instance in scope, then return the
    071         * (exact) type of the innermost such instance. <p>
    072         *
    073         * Note: this is considered a current instance, not an enclosing
    074         * instance, even inside its methods.
    075         */
    076        public TypeSig getEnclosingInstance() { return null; }
    077
    078
    079        /**
    080         * Returns a new Env that acts the same as us, except that its
    081         * current instance (if any) is not accessible. <p>
    082         *
    083         * Note: this routine is somewhat inefficient and should be
    084         * avoided unless an unknown environment needs to be coerced in
    085         * this way. <p>
    086         */
    087        public Env asStaticContext() { return this; }
    088
    089
    090        /***************************************************
    091         *                                                 *
    092         * Simple names:                                   *
    093         *                                                 *
    094         **************************************************/
    095
    096        /**
    097         * Locate the lexically innermost field or local variable
    098         * declaration. <p>
    099         *
    100         * Let d be the lexically innermost field or local variable
    101         * declaration (including formals) of id (if any such declaration
    102         * exists).  Then this routine returns: <p>
    103         *
    104         *    d (a LocalVarDecl or FormalParaDecl) if d is a local
    105         *                                            variable declaration
    106         *
    107         *    the class C that lexically encloses us and contains the
    108         *    (inherited) field d if d is a field declaration
    109         *
    110         *    null if d does not exist
    111         *
    112         * Note: inherited fields are considered to lexically enclose the
    113         * code of their subclasses.  We give the class containing the
    114         * field instead of the field itself to postpone dealing with
    115         * multiple fields named id visible in the same class.<p>
    116         *
    117         * In the field case, id disambiguates to C[.this].id.<p>
    118         */
    119        public ASTNode locateFieldOrLocal(Identifier id) {
    120            // CompilationUnits have no fields or local variable declarations:
    121            return null;
    122        }
    123
    124        public boolean isDuplicate(Identifier id) {
    125            return false;
    126        }
    127
    128        /**
    129         * Attempt to lookup a simple TypeName in this environment to get
    130         * the TypeSig it denotes.  Returns null if no such type
    131         * exists.<p>
    132         *
    133         * This routine does not check that the resulting type (if any)
    134         * is actually accessable. <p>
    135         *
    136         * If id is ambiguous, then if loc != Location.NULL then a fatal
    137         * error is reported at that location via ErrorSet else one of
    138         * its possible meanings is returned.<p>
    139         */
    140        public TypeSig lookupSimpleTypeName(TypeSig caller, Identifier id, int loc) {
    141            /*
    142             * First, look at types declared in CU:
    143             */
    144            for (int i = 0; i < CU.elems.size(); i++) {
    145                TypeDecl d = CU.elems.elementAt(i);
    146                if (id == d.id) {
    147                    if (caller == null) return TypeSig.getSig(d);
    148                    if (TypeCheck.inst.canAccess(caller,TypeSig.getSig(d),d.modifiers,d.pmodifiers)) return TypeSig.getSig(d);
    149                }
    150            }
    151
    152
    153            /*
    154             * Next, look in single-type imports of CU
    155             */
    156            for(int i = 0; i < CU.imports.size(); i++) {
    157                try {
    158                    Name imp =
    159                        ((SingleTypeImportDecl)CU.imports  //@ nowarn Cast; //caught
    160                              .elementAt(i)).typeName.name;
    161                    int sz = imp.size();
    162                    String[] P = imp.toStrings(sz-1);
    163                    Identifier T = imp.identifierAt(sz-1);
    164
    165                    if (id == T) {
    166                        TypeSig r = lookupWithoutInheritence(caller, P, T.toString());
    167                        if (r != null) return r;
    168                    }
    169                } catch (ClassCastException e) { }
    170            }
    171
    172
    173            /*
    174             * Next, look in package of CU:
    175             */
    176            {
    177                String[] P = new String[0];
    178                if (CU.pkgName != null)
    179                    P = CU.pkgName.toStrings();
    180                TypeSig r = lookupWithoutInheritence(caller, P, id.toString());
    181                if (r != null) return r;
    182            }
    183
    184
    185            /*
    186             * Next, look in on-demand imports of CU:
    187             */
    188            {
    189                            // FIXME - caller argument?
    190                TypeSig r = OutsideEnv.lookup(Types.javaLangPackage(),
    191                                              id.toString());
    192                for(int i = 0; i < CU.imports.size(); i++) {
    193                    try {
    194                        OnDemandImportDecl imp =
    195                          (OnDemandImportDecl)CU.imports.elementAt(i); //@ nowarn Cast; //caught
    196                        TypeSig r2 = lookupWithoutInheritence(caller,
    197                                               imp.pkgName.toStrings(),
    198                                               id.toString());
    199                        if (r2 != null)
    200                            if (r != null && r != r2) {
    201                                if (loc != Location.NULL)
    202                                    ErrorSet.fatal(loc,
    203                                                "Ambiguous import-on-demand of \""
    204                                                + id.toString() + "\". Choices are: " + r.getExternalName() + " and " + r2.getExternalName());
    205                                else
    206                                    return r;
    207                            } else r = r2;
    208                    } catch (ClassCastException e) { }
    209                }
    210                if (r != null) return r;
    211            }
    212
    213            return null;
    214        }
    215
    216
    217        /**
    218         * Attempt to lookup the type N.I without using inheritence in
    219         * the outside environment.  (N.I may divide into package and
    220         * class parts arbitrarily.) <p>
    221         *
    222         * This routine does not check that the resulting type (if any)
    223         * is actually accessable, unless caller is non-null. <p>
    224         */
    225        //@ requires \nonnullelements(N);
    226        public static TypeSig lookupWithoutInheritence(TypeSig caller, String[] N,
    227                                                       /*@ non_null @*/ String I) {
    228            TypeSig soFar = null;
    229            int prefix = 0;
    230
    231            /*
    232             * Find the smallest prefix that denotes an package-member
    233             * type P.T:
    234             */
    235            while (++prefix<=N.length+1) {
    236                // Let P.T = first prefix ids in N.I:
    237                String[] P = new String[prefix-1];
    238                for (int i=0; i<prefix-1; i++)
    239                    P[i] = N[i];
    240                String T = (prefix<=N.length) ? N[prefix-1] : I;
    241
    242                soFar = OutsideEnv.lookup(P, T);
    243                if (soFar != null)
    244                    break;
    245            }
    246            if (soFar==null)
    247                return null;
    248
    249            // Remaining part of N.I must be a $C1$C2...$Cn expression:
    250            while (++prefix<=N.length+1) {
    251                String T = (prefix<=N.length) ? N[prefix-1] : I;
    252                soFar = soFar.lookupLocalType(caller,Identifier.intern(T));
    253                if (soFar==null)
    254                    return null;
    255            }
    256
    257            return soFar;
    258        }
    259
    260
    261        /**
    262         * Locate the lexically innermost method named id. <p>
    263         *
    264         * Returns the TypeSig for the innermost lexically enclosing type
    265         * that has a method named id or null if no such type exists.<p>
    266         *
    267         * Note: inherited methods are considered to lexically enclose
    268         * the code of their subclasses.<p>
    269         *
    270         * id disambiguates to C[.this].id.<p>
    271         */
    272        public TypeSig locateMethod(Identifier id) {
    273            // We bind no methods:
    274            return null;
    275        }
    276
    277
    278        /***************************************************
    279         *                                                 *
    280         * Debugging functions:                            *
    281         *                                                 *
    282         **************************************************/
    283
    284        /**
    285         * Display information about us to System.out.  This function is
    286         * intended only for debugging use.
    287         */
    288        public void display() {
    289            System.out.println("[[ environment for compilation unit from file \""
    290                + Location.toFileName(CU.loc) + "\" ]]");
    291        }
    292    }