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 }