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    }