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(/*@non_null*/Identifier id) {
120 // CompilationUnits have no fields or local variable declarations:
121 return null;
122 }
123
124 public boolean isDuplicate(/*@non_null*/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, /*@non_null*/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(/*@non_null*/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 }