| 1 | /* | 
| 2 |  * Copyright 1999-2006 Sun Microsystems, Inc.  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.  Sun designates this | 
| 8 |  * particular file as subject to the "Classpath" exception as provided | 
| 9 |  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | 
| 22 |  * CA 95054 USA or visit www.sun.com if you need additional information or | 
| 23 |  * have any questions. | 
| 24 |  */ | 
| 25 |   | 
| 26 | package com.sun.tools.javac.jvm; | 
| 27 |   | 
| 28 | import java.io.*; | 
| 29 | import java.net.URI; | 
| 30 | import java.nio.CharBuffer; | 
| 31 | import java.util.EnumSet; | 
| 32 | import java.util.HashMap; | 
| 33 | import java.util.Map; | 
| 34 | import java.util.Set; | 
| 35 | import javax.lang.model.SourceVersion; | 
| 36 | import javax.tools.JavaFileObject; | 
| 37 | import javax.tools.JavaFileManager; | 
| 38 | import javax.tools.StandardJavaFileManager; | 
| 39 |   | 
| 40 | import com.sun.tools.javac.comp.Annotate; | 
| 41 | import com.sun.tools.javac.code.*; | 
| 42 | import com.sun.tools.javac.code.Type.*; | 
| 43 | import com.sun.tools.javac.code.Symbol.*; | 
| 44 | import com.sun.tools.javac.code.Symtab; | 
| 45 | import com.sun.tools.javac.util.*; | 
| 46 | import com.sun.tools.javac.util.List; | 
| 47 |   | 
| 48 | import static com.sun.tools.javac.code.Flags.*; | 
| 49 | import static com.sun.tools.javac.code.Kinds.*; | 
| 50 | import static com.sun.tools.javac.code.TypeTags.*; | 
| 51 | import com.sun.tools.javac.jvm.ClassFile.NameAndType; | 
| 52 | import javax.tools.JavaFileManager.Location; | 
| 53 | import static javax.tools.StandardLocation.*; | 
| 54 |   | 
| 55 | /** This class provides operations to read a classfile into an internal | 
| 56 |  *  representation. The internal representation is anchored in a | 
| 57 |  *  ClassSymbol which contains in its scope symbol representations | 
| 58 |  *  for all other definitions in the classfile. Top-level Classes themselves | 
| 59 |  *  appear as members of the scopes of PackageSymbols. | 
| 60 |  * | 
| 61 |  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If | 
| 62 |  *  you write code that depends on this, you do so at your own risk. | 
| 63 |  *  This code and its internal interfaces are subject to change or | 
| 64 |  *  deletion without notice.</b> | 
| 65 |  */ | 
| 66 | public class ClassReader extends ClassFile implements Completer { | 
| 67 |     /** The context key for the class reader. */ | 
| 68 |     protected static final Context.Key<ClassReader> classReaderKey = | 
| 69 |         new Context.Key<ClassReader>(); | 
| 70 |   | 
| 71 |     Annotate annotate; | 
| 72 |   | 
| 73 |     /** Switch: verbose output. | 
| 74 |      */ | 
| 75 |     boolean verbose; | 
| 76 |   | 
| 77 |     /** Switch: check class file for correct minor version, unrecognized | 
| 78 |      *  attributes. | 
| 79 |      */ | 
| 80 |     boolean checkClassFile; | 
| 81 |   | 
| 82 |     /** Switch: read constant pool and code sections. This switch is initially | 
| 83 |      *  set to false but can be turned on from outside. | 
| 84 |      */ | 
| 85 |     public boolean readAllOfClassFile = false; | 
| 86 |   | 
| 87 |     /** Switch: read GJ signature information. | 
| 88 |      */ | 
| 89 |     boolean allowGenerics; | 
| 90 |   | 
| 91 |     /** Switch: read varargs attribute. | 
| 92 |      */ | 
| 93 |     boolean allowVarargs; | 
| 94 |   | 
| 95 |     /** Switch: allow annotations. | 
| 96 |      */ | 
| 97 |     boolean allowAnnotations; | 
| 98 |   | 
| 99 |     /** Switch: preserve parameter names from the variable table. | 
| 100 |      */ | 
| 101 |     public boolean saveParameterNames; | 
| 102 |   | 
| 103 |     /** | 
| 104 |      * Switch: cache completion failures unless -XDdev is used | 
| 105 |      */ | 
| 106 |     private boolean cacheCompletionFailure; | 
| 107 |   | 
| 108 |     /** | 
| 109 |      * Switch: prefer source files instead of newer when both source | 
| 110 |      * and class are available | 
| 111 |      **/ | 
| 112 |     public boolean preferSource; | 
| 113 |   | 
| 114 |     /** The log to use for verbose output | 
| 115 |      */ | 
| 116 |     final Log log; | 
| 117 |   | 
| 118 |     /** The symbol table. */ | 
| 119 |     Symtab syms; | 
| 120 |   | 
| 121 |     Types types; | 
| 122 |   | 
| 123 |     /** The name table. */ | 
| 124 |     final Name.Table names; | 
| 125 |   | 
| 126 |     /** Force a completion failure on this name | 
| 127 |      */ | 
| 128 |     final Name completionFailureName; | 
| 129 |   | 
| 130 |     /** Access to files | 
| 131 |      */ | 
| 132 |     private final JavaFileManager fileManager; | 
| 133 |   | 
| 134 |     /** Can be reassigned from outside: | 
| 135 |      *  the completer to be used for ".java" files. If this remains unassigned | 
| 136 |      *  ".java" files will not be loaded. | 
| 137 |      */ | 
| 138 |     public SourceCompleter sourceCompleter = null; | 
| 139 |   | 
| 140 |     /** A hashtable containing the encountered top-level and member classes, | 
| 141 |      *  indexed by flat names. The table does not contain local classes. | 
| 142 |      */ | 
| 143 |     private Map<Name,ClassSymbol> classes; | 
| 144 |   | 
| 145 |     /** A hashtable containing the encountered packages. | 
| 146 |      */ | 
| 147 |     private Map<Name, PackageSymbol> packages; | 
| 148 |   | 
| 149 |     /** The current scope where type variables are entered. | 
| 150 |      */ | 
| 151 |     protected Scope typevars; | 
| 152 |   | 
| 153 |     /** The path name of the class file currently being read. | 
| 154 |      */ | 
| 155 |     protected JavaFileObject currentClassFile = null; | 
| 156 |   | 
| 157 |     /** The class or method currently being read. | 
| 158 |      */ | 
| 159 |     protected Symbol currentOwner = null; | 
| 160 |   | 
| 161 |     /** The buffer containing the currently read class file. | 
| 162 |      */ | 
| 163 |     byte[] buf = new byte[0x0fff0]; | 
| 164 |   | 
| 165 |     /** The current input pointer. | 
| 166 |      */ | 
| 167 |     int bp; | 
| 168 |   | 
| 169 |     /** The objects of the constant pool. | 
| 170 |      */ | 
| 171 |     Object[] poolObj; | 
| 172 |   | 
| 173 |     /** For every constant pool entry, an index into buf where the | 
| 174 |      *  defining section of the entry is found. | 
| 175 |      */ | 
| 176 |     int[] poolIdx; | 
| 177 |   | 
| 178 |     /** Get the ClassReader instance for this invocation. */ | 
| 179 |     public static ClassReader instance(Context context) { | 
| 180 |         ClassReader instance = context.get(classReaderKey); | 
| 181 |         if (instance == null) | 
| 182 |             instance = new ClassReader(context, true); | 
| 183 |         return instance; | 
| 184 |     } | 
| 185 |   | 
| 186 |     /** Initialize classes and packages, treating this as the definitive classreader. */ | 
| 187 |     public void init(Symtab syms) { | 
| 188 |         init(syms, true); | 
| 189 |     } | 
| 190 |   | 
| 191 |     /** Initialize classes and packages, optionally treating this as | 
| 192 |      *  the definitive classreader. | 
| 193 |      */ | 
| 194 |     private void init(Symtab syms, boolean definitive) { | 
| 195 |         if (classes != null) return; | 
| 196 |   | 
| 197 |         if (definitive) { | 
| 198 |             assert packages == null || packages == syms.packages; | 
| 199 |             packages = syms.packages; | 
| 200 |             assert classes == null || classes == syms.classes; | 
| 201 |             classes = syms.classes; | 
| 202 |         } else { | 
| 203 |             packages = new HashMap<Name, PackageSymbol>(); | 
| 204 |             classes = new HashMap<Name, ClassSymbol>(); | 
| 205 |         } | 
| 206 |   | 
| 207 |         packages.put(names.empty, syms.rootPackage); | 
| 208 |         syms.rootPackage.completer = this; | 
| 209 |         syms.unnamedPackage.completer = this; | 
| 210 |     } | 
| 211 |   | 
| 212 |     /** Construct a new class reader, optionally treated as the | 
| 213 |      *  definitive classreader for this invocation. | 
| 214 |      */ | 
| 215 |     protected ClassReader(Context context, boolean definitive) { | 
| 216 |         if (definitive) context.put(classReaderKey, this); | 
| 217 |   | 
| 218 |         names = Name.Table.instance(context); | 
| 219 |         syms = Symtab.instance(context); | 
| 220 |         types = Types.instance(context); | 
| 221 |         fileManager = context.get(JavaFileManager.class); | 
| 222 |         if (fileManager == null) | 
| 223 |             throw new AssertionError("FileManager initialization error"); | 
| 224 |   | 
| 225 |         init(syms, definitive); | 
| 226 |         log = Log.instance(context); | 
| 227 |   | 
| 228 |         Options options = Options.instance(context); | 
| 229 |         annotate = Annotate.instance(context); | 
| 230 |         verbose        = options.get("-verbose")        != null; | 
| 231 |         checkClassFile = options.get("-checkclassfile") != null; | 
| 232 |         Source source = Source.instance(context); | 
| 233 |         allowGenerics    = source.allowGenerics(); | 
| 234 |         allowVarargs     = source.allowVarargs(); | 
| 235 |         allowAnnotations = source.allowAnnotations(); | 
| 236 |         saveParameterNames = options.get("save-parameter-names") != null; | 
| 237 |         cacheCompletionFailure = options.get("dev") == null; | 
| 238 |         preferSource = "source".equals(options.get("-Xprefer")); | 
| 239 |   | 
| 240 |         completionFailureName = | 
| 241 |             (options.get("failcomplete") != null) | 
| 242 |             ? names.fromString(options.get("failcomplete")) | 
| 243 |             : null; | 
| 244 |   | 
| 245 |         typevars = new Scope(syms.noSymbol); | 
| 246 |     } | 
| 247 |   | 
| 248 |     /** Add member to class unless it is synthetic. | 
| 249 |      */ | 
| 250 |     private void enterMember(ClassSymbol c, Symbol sym) { | 
| 251 |         if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC) | 
| 252 |             c.members_field.enter(sym); | 
| 253 |     } | 
| 254 |   | 
| 255 | /************************************************************************ | 
| 256 |  * Error Diagnoses | 
| 257 |  ***********************************************************************/ | 
| 258 |   | 
| 259 |     public static class BadClassFile extends CompletionFailure { | 
| 260 |         private static final long serialVersionUID = 0; | 
| 261 |   | 
| 262 |         /** | 
| 263 |          * @param msg A localized message. | 
| 264 |          */ | 
| 265 |         public BadClassFile(ClassSymbol c, Object cname, Object msg) { | 
| 266 |             super(c, Log.getLocalizedString("bad.class.file.header", | 
| 267 |                                             cname, msg)); | 
| 268 |         } | 
| 269 |     } | 
| 270 |   | 
| 271 |     public BadClassFile badClassFile(String key, Object... args) { | 
| 272 |         return new BadClassFile ( | 
| 273 |             currentOwner.enclClass(), | 
| 274 |             currentClassFile, | 
| 275 |             Log.getLocalizedString(key, args)); | 
| 276 |     } | 
| 277 |   | 
| 278 | /************************************************************************ | 
| 279 |  * Buffer Access | 
| 280 |  ***********************************************************************/ | 
| 281 |   | 
| 282 |     /** Read a character. | 
| 283 |      */ | 
| 284 |     char nextChar() { | 
| 285 |         return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF)); | 
| 286 |     } | 
| 287 |   | 
| 288 |     /** Read an integer. | 
| 289 |      */ | 
| 290 |     int nextInt() { | 
| 291 |         return | 
| 292 |             ((buf[bp++] & 0xFF) << 24) + | 
| 293 |             ((buf[bp++] & 0xFF) << 16) + | 
| 294 |             ((buf[bp++] & 0xFF) << 8) + | 
| 295 |             (buf[bp++] & 0xFF); | 
| 296 |     } | 
| 297 |   | 
| 298 |     /** Extract a character at position bp from buf. | 
| 299 |      */ | 
| 300 |     char getChar(int bp) { | 
| 301 |         return | 
| 302 |             (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF)); | 
| 303 |     } | 
| 304 |   | 
| 305 |     /** Extract an integer at position bp from buf. | 
| 306 |      */ | 
| 307 |     int getInt(int bp) { | 
| 308 |         return | 
| 309 |             ((buf[bp] & 0xFF) << 24) + | 
| 310 |             ((buf[bp+1] & 0xFF) << 16) + | 
| 311 |             ((buf[bp+2] & 0xFF) << 8) + | 
| 312 |             (buf[bp+3] & 0xFF); | 
| 313 |     } | 
| 314 |   | 
| 315 |   | 
| 316 |     /** Extract a long integer at position bp from buf. | 
| 317 |      */ | 
| 318 |     long getLong(int bp) { | 
| 319 |         DataInputStream bufin = | 
| 320 |             new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); | 
| 321 |         try { | 
| 322 |             return bufin.readLong(); | 
| 323 |         } catch (IOException e) { | 
| 324 |             throw new AssertionError(e); | 
| 325 |         } | 
| 326 |     } | 
| 327 |   | 
| 328 |     /** Extract a float at position bp from buf. | 
| 329 |      */ | 
| 330 |     float getFloat(int bp) { | 
| 331 |         DataInputStream bufin = | 
| 332 |             new DataInputStream(new ByteArrayInputStream(buf, bp, 4)); | 
| 333 |         try { | 
| 334 |             return bufin.readFloat(); | 
| 335 |         } catch (IOException e) { | 
| 336 |             throw new AssertionError(e); | 
| 337 |         } | 
| 338 |     } | 
| 339 |   | 
| 340 |     /** Extract a double at position bp from buf. | 
| 341 |      */ | 
| 342 |     double getDouble(int bp) { | 
| 343 |         DataInputStream bufin = | 
| 344 |             new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); | 
| 345 |         try { | 
| 346 |             return bufin.readDouble(); | 
| 347 |         } catch (IOException e) { | 
| 348 |             throw new AssertionError(e); | 
| 349 |         } | 
| 350 |     } | 
| 351 |   | 
| 352 | /************************************************************************ | 
| 353 |  * Constant Pool Access | 
| 354 |  ***********************************************************************/ | 
| 355 |   | 
| 356 |     /** Index all constant pool entries, writing their start addresses into | 
| 357 |      *  poolIdx. | 
| 358 |      */ | 
| 359 |     void indexPool() { | 
| 360 |         poolIdx = new int[nextChar()]; | 
| 361 |         poolObj = new Object[poolIdx.length]; | 
| 362 |         int i = 1; | 
| 363 |         while (i < poolIdx.length) { | 
| 364 |             poolIdx[i++] = bp; | 
| 365 |             byte tag = buf[bp++]; | 
| 366 |             switch (tag) { | 
| 367 |             case CONSTANT_Utf8: case CONSTANT_Unicode: { | 
| 368 |                 int len = nextChar(); | 
| 369 |                 bp = bp + len; | 
| 370 |                 break; | 
| 371 |             } | 
| 372 |             case CONSTANT_Class: | 
| 373 |             case CONSTANT_String: | 
| 374 |                 bp = bp + 2; | 
| 375 |                 break; | 
| 376 |             case CONSTANT_Fieldref: | 
| 377 |             case CONSTANT_Methodref: | 
| 378 |             case CONSTANT_InterfaceMethodref: | 
| 379 |             case CONSTANT_NameandType: | 
| 380 |             case CONSTANT_Integer: | 
| 381 |             case CONSTANT_Float: | 
| 382 |                 bp = bp + 4; | 
| 383 |                 break; | 
| 384 |             case CONSTANT_Long: | 
| 385 |             case CONSTANT_Double: | 
| 386 |                 bp = bp + 8; | 
| 387 |                 i++; | 
| 388 |                 break; | 
| 389 |             default: | 
| 390 |                 throw badClassFile("bad.const.pool.tag.at", | 
| 391 |                                    Byte.toString(tag), | 
| 392 |                                    Integer.toString(bp -1)); | 
| 393 |             } | 
| 394 |         } | 
| 395 |     } | 
| 396 |   | 
| 397 |     /** Read constant pool entry at start address i, use pool as a cache. | 
| 398 |      */ | 
| 399 |     Object readPool(int i) { | 
| 400 |         Object result = poolObj[i]; | 
| 401 |         if (result != null) return result; | 
| 402 |   | 
| 403 |         int index = poolIdx[i]; | 
| 404 |         if (index == 0) return null; | 
| 405 |   | 
| 406 |         byte tag = buf[index]; | 
| 407 |         switch (tag) { | 
| 408 |         case CONSTANT_Utf8: | 
| 409 |             poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1)); | 
| 410 |             break; | 
| 411 |         case CONSTANT_Unicode: | 
| 412 |             throw badClassFile("unicode.str.not.supported"); | 
| 413 |         case CONSTANT_Class: | 
| 414 |             poolObj[i] = readClassOrType(getChar(index + 1)); | 
| 415 |             break; | 
| 416 |         case CONSTANT_String: | 
| 417 |             // FIXME: (footprint) do not use toString here | 
| 418 |             poolObj[i] = readName(getChar(index + 1)).toString(); | 
| 419 |             break; | 
| 420 |         case CONSTANT_Fieldref: { | 
| 421 |             ClassSymbol owner = readClassSymbol(getChar(index + 1)); | 
| 422 |             NameAndType nt = (NameAndType)readPool(getChar(index + 3)); | 
| 423 |             poolObj[i] = new VarSymbol(0, nt.name, nt.type, owner); | 
| 424 |             break; | 
| 425 |         } | 
| 426 |         case CONSTANT_Methodref: | 
| 427 |         case CONSTANT_InterfaceMethodref: { | 
| 428 |             ClassSymbol owner = readClassSymbol(getChar(index + 1)); | 
| 429 |             NameAndType nt = (NameAndType)readPool(getChar(index + 3)); | 
| 430 |             poolObj[i] = new MethodSymbol(0, nt.name, nt.type, owner); | 
| 431 |             break; | 
| 432 |         } | 
| 433 |         case CONSTANT_NameandType: | 
| 434 |             poolObj[i] = new NameAndType( | 
| 435 |                 readName(getChar(index + 1)), | 
| 436 |                 readType(getChar(index + 3))); | 
| 437 |             break; | 
| 438 |         case CONSTANT_Integer: | 
| 439 |             poolObj[i] = getInt(index + 1); | 
| 440 |             break; | 
| 441 |         case CONSTANT_Float: | 
| 442 |             poolObj[i] = new Float(getFloat(index + 1)); | 
| 443 |             break; | 
| 444 |         case CONSTANT_Long: | 
| 445 |             poolObj[i] = new Long(getLong(index + 1)); | 
| 446 |             break; | 
| 447 |         case CONSTANT_Double: | 
| 448 |             poolObj[i] = new Double(getDouble(index + 1)); | 
| 449 |             break; | 
| 450 |         default: | 
| 451 |             throw badClassFile("bad.const.pool.tag", Byte.toString(tag)); | 
| 452 |         } | 
| 453 |         return poolObj[i]; | 
| 454 |     } | 
| 455 |   | 
| 456 |     /** Read signature and convert to type. | 
| 457 |      */ | 
| 458 |     Type readType(int i) { | 
| 459 |         int index = poolIdx[i]; | 
| 460 |         return sigToType(buf, index + 3, getChar(index + 1)); | 
| 461 |     } | 
| 462 |   | 
| 463 |     /** If name is an array type or class signature, return the | 
| 464 |      *  corresponding type; otherwise return a ClassSymbol with given name. | 
| 465 |      */ | 
| 466 |     Object readClassOrType(int i) { | 
| 467 |         int index =  poolIdx[i]; | 
| 468 |         int len = getChar(index + 1); | 
| 469 |         int start = index + 3; | 
| 470 |         assert buf[start] == '[' || buf[start + len - 1] != ';'; | 
| 471 |         // by the above assertion, the following test can be | 
| 472 |         // simplified to (buf[start] == '[') | 
| 473 |         return (buf[start] == '[' || buf[start + len - 1] == ';') | 
| 474 |             ? (Object)sigToType(buf, start, len) | 
| 475 |             : (Object)enterClass(names.fromUtf(internalize(buf, start, | 
| 476 |                                                            len))); | 
| 477 |     } | 
| 478 |   | 
| 479 |     /** Read signature and convert to type parameters. | 
| 480 |      */ | 
| 481 |     List<Type> readTypeParams(int i) { | 
| 482 |         int index = poolIdx[i]; | 
| 483 |         return sigToTypeParams(buf, index + 3, getChar(index + 1)); | 
| 484 |     } | 
| 485 |   | 
| 486 |     /** Read class entry. | 
| 487 |      */ | 
| 488 |     ClassSymbol readClassSymbol(int i) { | 
| 489 |         return (ClassSymbol) (readPool(i)); | 
| 490 |     } | 
| 491 |   | 
| 492 |     /** Read name. | 
| 493 |      */ | 
| 494 |     Name readName(int i) { | 
| 495 |         return (Name) (readPool(i)); | 
| 496 |     } | 
| 497 |   | 
| 498 | /************************************************************************ | 
| 499 |  * Reading Types | 
| 500 |  ***********************************************************************/ | 
| 501 |   | 
| 502 |     /** The unread portion of the currently read type is | 
| 503 |      *  signature[sigp..siglimit-1]. | 
| 504 |      */ | 
| 505 |     byte[] signature; | 
| 506 |     int sigp; | 
| 507 |     int siglimit; | 
| 508 |     boolean sigEnterPhase = false; | 
| 509 |   | 
| 510 |     /** Convert signature to type, where signature is a name. | 
| 511 |      */ | 
| 512 |     Type sigToType(Name sig) { | 
| 513 |         return sig == null | 
| 514 |             ? null | 
| 515 |             : sigToType(sig.table.names, sig.index, sig.len); | 
| 516 |     } | 
| 517 |   | 
| 518 |     /** Convert signature to type, where signature is a byte array segment. | 
| 519 |      */ | 
| 520 |     Type sigToType(byte[] sig, int offset, int len) { | 
| 521 |         signature = sig; | 
| 522 |         sigp = offset; | 
| 523 |         siglimit = offset + len; | 
| 524 |         return sigToType(); | 
| 525 |     } | 
| 526 |   | 
| 527 |     /** Convert signature to type, where signature is implicit. | 
| 528 |      */ | 
| 529 |     Type sigToType() { | 
| 530 |         switch ((char) signature[sigp]) { | 
| 531 |         case 'T': | 
| 532 |             sigp++; | 
| 533 |             int start = sigp; | 
| 534 |             while (signature[sigp] != ';') sigp++; | 
| 535 |             sigp++; | 
| 536 |             return sigEnterPhase | 
| 537 |                 ? Type.noType | 
| 538 |                 : findTypeVar(names.fromUtf(signature, start, sigp - 1 - start)); | 
| 539 |         case '+': { | 
| 540 |             sigp++; | 
| 541 |             Type t = sigToType(); | 
| 542 |             return new WildcardType(t, BoundKind.EXTENDS, | 
| 543 |                                     syms.boundClass); | 
| 544 |         } | 
| 545 |         case '*': | 
| 546 |             sigp++; | 
| 547 |             return new WildcardType(syms.objectType, BoundKind.UNBOUND, | 
| 548 |                                     syms.boundClass); | 
| 549 |         case '-': { | 
| 550 |             sigp++; | 
| 551 |             Type t = sigToType(); | 
| 552 |             return new WildcardType(t, BoundKind.SUPER, | 
| 553 |                                     syms.boundClass); | 
| 554 |         } | 
| 555 |         case 'B': | 
| 556 |             sigp++; | 
| 557 |             return syms.byteType; | 
| 558 |         case 'C': | 
| 559 |             sigp++; | 
| 560 |             return syms.charType; | 
| 561 |         case 'D': | 
| 562 |             sigp++; | 
| 563 |             return syms.doubleType; | 
| 564 |         case 'F': | 
| 565 |             sigp++; | 
| 566 |             return syms.floatType; | 
| 567 |         case 'I': | 
| 568 |             sigp++; | 
| 569 |             return syms.intType; | 
| 570 |         case 'J': | 
| 571 |             sigp++; | 
| 572 |             return syms.longType; | 
| 573 |         case 'L': | 
| 574 |             { | 
| 575 |                 // int oldsigp = sigp; | 
| 576 |                 Type t = classSigToType(); | 
| 577 |                 if (sigp < siglimit && signature[sigp] == '.') | 
| 578 |                     throw badClassFile("deprecated inner class signature syntax " + | 
| 579 |                                        "(please recompile from source)"); | 
| 580 |                 /* | 
| 581 |                 System.err.println(" decoded " + | 
| 582 |                                    new String(signature, oldsigp, sigp-oldsigp) + | 
| 583 |                                    " => " + t + " outer " + t.outer()); | 
| 584 |                 */ | 
| 585 |                 return t; | 
| 586 |             } | 
| 587 |         case 'S': | 
| 588 |             sigp++; | 
| 589 |             return syms.shortType; | 
| 590 |         case 'V': | 
| 591 |             sigp++; | 
| 592 |             return syms.voidType; | 
| 593 |         case 'Z': | 
| 594 |             sigp++; | 
| 595 |             return syms.booleanType; | 
| 596 |         case '[': | 
| 597 |             sigp++; | 
| 598 |             return new ArrayType(sigToType(), syms.arrayClass); | 
| 599 |         case '(': | 
| 600 |             sigp++; | 
| 601 |             List<Type> argtypes = sigToTypes(')'); | 
| 602 |             Type restype = sigToType(); | 
| 603 |             List<Type> thrown = List.nil(); | 
| 604 |             while (signature[sigp] == '^') { | 
| 605 |                 sigp++; | 
| 606 |                 thrown = thrown.prepend(sigToType()); | 
| 607 |             } | 
| 608 |             return new MethodType(argtypes, | 
| 609 |                                   restype, | 
| 610 |                                   thrown.reverse(), | 
| 611 |                                   syms.methodClass); | 
| 612 |         case '<': | 
| 613 |             typevars = typevars.dup(currentOwner); | 
| 614 |             Type poly = new ForAll(sigToTypeParams(), sigToType()); | 
| 615 |             typevars = typevars.leave(); | 
| 616 |             return poly; | 
| 617 |         default: | 
| 618 |             throw badClassFile("bad.signature", | 
| 619 |                                Convert.utf2string(signature, sigp, 10)); | 
| 620 |         } | 
| 621 |     } | 
| 622 |   | 
| 623 |     byte[] signatureBuffer = new byte[0]; | 
| 624 |     int sbp = 0; | 
| 625 |     /** Convert class signature to type, where signature is implicit. | 
| 626 |      */ | 
| 627 |     Type classSigToType() { | 
| 628 |         if (signature[sigp] != 'L') | 
| 629 |             throw badClassFile("bad.class.signature", | 
| 630 |                                Convert.utf2string(signature, sigp, 10)); | 
| 631 |         sigp++; | 
| 632 |         Type outer = Type.noType; | 
| 633 |         int startSbp = sbp; | 
| 634 |   | 
| 635 |         while (true) { | 
| 636 |             final byte c = signature[sigp++]; | 
| 637 |             switch (c) { | 
| 638 |   | 
| 639 |             case ';': {         // end | 
| 640 |                 ClassSymbol t = enterClass(names.fromUtf(signatureBuffer, | 
| 641 |                                                          startSbp, | 
| 642 |                                                          sbp - startSbp)); | 
| 643 |                 if (outer == Type.noType) | 
| 644 |                     outer = t.erasure(types); | 
| 645 |                 else | 
| 646 |                     outer = new ClassType(outer, List.<Type>nil(), t); | 
| 647 |                 sbp = startSbp; | 
| 648 |                 return outer; | 
| 649 |             } | 
| 650 |   | 
| 651 |             case '<':           // generic arguments | 
| 652 |                 ClassSymbol t = enterClass(names.fromUtf(signatureBuffer, | 
| 653 |                                                          startSbp, | 
| 654 |                                                          sbp - startSbp)); | 
| 655 |                 outer = new ClassType(outer, sigToTypes('>'), t) { | 
| 656 |                         boolean completed = false; | 
| 657 |                         public Type getEnclosingType() { | 
| 658 |                             if (!completed) { | 
| 659 |                                 completed = true; | 
| 660 |                                 tsym.complete(); | 
| 661 |                                 Type enclosingType = tsym.type.getEnclosingType(); | 
| 662 |                                 if (enclosingType != Type.noType) { | 
| 663 |                                     List<Type> typeArgs = | 
| 664 |                                         super.getEnclosingType().allparams(); | 
| 665 |                                     List<Type> typeParams = | 
| 666 |                                         enclosingType.allparams(); | 
| 667 |                                     if (typeParams.length() != typeArgs.length()) { | 
| 668 |                                         // no "rare" types | 
| 669 |                                         super.setEnclosingType(types.erasure(enclosingType)); | 
| 670 |                                     } else { | 
| 671 |                                         super.setEnclosingType(types.subst(enclosingType, | 
| 672 |                                                                            typeParams, | 
| 673 |                                                                            typeArgs)); | 
| 674 |                                     } | 
| 675 |                                 } else { | 
| 676 |                                     super.setEnclosingType(Type.noType); | 
| 677 |                                 } | 
| 678 |                             } | 
| 679 |                             return super.getEnclosingType(); | 
| 680 |                         } | 
| 681 |                         public void setEnclosingType(Type outer) { | 
| 682 |                             throw new UnsupportedOperationException(); | 
| 683 |                         } | 
| 684 |                     }; | 
| 685 |                 switch (signature[sigp++]) { | 
| 686 |                 case ';': | 
| 687 |                     if (sigp < signature.length && signature[sigp] == '.') { | 
| 688 |                         // support old-style GJC signatures | 
| 689 |                         // The signature produced was | 
| 690 |                         // Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>; | 
| 691 |                         // rather than say | 
| 692 |                         // Lfoo/Outer<Lfoo/X;>.Inner<Lfoo/Y;>; | 
| 693 |                         // so we skip past ".Lfoo/Outer$" | 
| 694 |                         sigp += (sbp - startSbp) + // "foo/Outer" | 
| 695 |                             3;  // ".L" and "$" | 
| 696 |                         signatureBuffer[sbp++] = (byte)'$'; | 
| 697 |                         break; | 
| 698 |                     } else { | 
| 699 |                         sbp = startSbp; | 
| 700 |                         return outer; | 
| 701 |                     } | 
| 702 |                 case '.': | 
| 703 |                     signatureBuffer[sbp++] = (byte)'$'; | 
| 704 |                     break; | 
| 705 |                 default: | 
| 706 |                     throw new AssertionError(signature[sigp-1]); | 
| 707 |                 } | 
| 708 |                 continue; | 
| 709 |   | 
| 710 |             case '.': | 
| 711 |                 signatureBuffer[sbp++] = (byte)'$'; | 
| 712 |                 continue; | 
| 713 |             case '/': | 
| 714 |                 signatureBuffer[sbp++] = (byte)'.'; | 
| 715 |                 continue; | 
| 716 |             default: | 
| 717 |                 signatureBuffer[sbp++] = c; | 
| 718 |                 continue; | 
| 719 |             } | 
| 720 |         } | 
| 721 |     } | 
| 722 |   | 
| 723 |     /** Convert (implicit) signature to list of types | 
| 724 |      *  until `terminator' is encountered. | 
| 725 |      */ | 
| 726 |     List<Type> sigToTypes(char terminator) { | 
| 727 |         List<Type> head = List.of(null); | 
| 728 |         List<Type> tail = head; | 
| 729 |         while (signature[sigp] != terminator) | 
| 730 |             tail = tail.setTail(List.of(sigToType())); | 
| 731 |         sigp++; | 
| 732 |         return head.tail; | 
| 733 |     } | 
| 734 |   | 
| 735 |     /** Convert signature to type parameters, where signature is a name. | 
| 736 |      */ | 
| 737 |     List<Type> sigToTypeParams(Name name) { | 
| 738 |         return sigToTypeParams(name.table.names, name.index, name.len); | 
| 739 |     } | 
| 740 |   | 
| 741 |     /** Convert signature to type parameters, where signature is a byte | 
| 742 |      *  array segment. | 
| 743 |      */ | 
| 744 |     List<Type> sigToTypeParams(byte[] sig, int offset, int len) { | 
| 745 |         signature = sig; | 
| 746 |         sigp = offset; | 
| 747 |         siglimit = offset + len; | 
| 748 |         return sigToTypeParams(); | 
| 749 |     } | 
| 750 |   | 
| 751 |     /** Convert signature to type parameters, where signature is implicit. | 
| 752 |      */ | 
| 753 |     List<Type> sigToTypeParams() { | 
| 754 |         List<Type> tvars = List.nil(); | 
| 755 |         if (signature[sigp] == '<') { | 
| 756 |             sigp++; | 
| 757 |             int start = sigp; | 
| 758 |             sigEnterPhase = true; | 
| 759 |             while (signature[sigp] != '>') | 
| 760 |                 tvars = tvars.prepend(sigToTypeParam()); | 
| 761 |             sigEnterPhase = false; | 
| 762 |             sigp = start; | 
| 763 |             while (signature[sigp] != '>') | 
| 764 |                 sigToTypeParam(); | 
| 765 |             sigp++; | 
| 766 |         } | 
| 767 |         return tvars.reverse(); | 
| 768 |     } | 
| 769 |   | 
| 770 |     /** Convert (implicit) signature to type parameter. | 
| 771 |      */ | 
| 772 |     Type sigToTypeParam() { | 
| 773 |         int start = sigp; | 
| 774 |         while (signature[sigp] != ':') sigp++; | 
| 775 |         Name name = names.fromUtf(signature, start, sigp - start); | 
| 776 |         TypeVar tvar; | 
| 777 |         if (sigEnterPhase) { | 
| 778 |             tvar = new TypeVar(name, currentOwner, syms.botType); | 
| 779 |             typevars.enter(tvar.tsym); | 
| 780 |         } else { | 
| 781 |             tvar = (TypeVar)findTypeVar(name); | 
| 782 |         } | 
| 783 |         List<Type> bounds = List.nil(); | 
| 784 |         Type st = null; | 
| 785 |         if (signature[sigp] == ':' && signature[sigp+1] == ':') { | 
| 786 |             sigp++; | 
| 787 |             st = syms.objectType; | 
| 788 |         } | 
| 789 |         while (signature[sigp] == ':') { | 
| 790 |             sigp++; | 
| 791 |             bounds = bounds.prepend(sigToType()); | 
| 792 |         } | 
| 793 |         if (!sigEnterPhase) { | 
| 794 |             types.setBounds(tvar, bounds.reverse(), st); | 
| 795 |         } | 
| 796 |         return tvar; | 
| 797 |     } | 
| 798 |   | 
| 799 |     /** Find type variable with given name in `typevars' scope. | 
| 800 |      */ | 
| 801 |     Type findTypeVar(Name name) { | 
| 802 |         Scope.Entry e = typevars.lookup(name); | 
| 803 |         if (e.scope != null) { | 
| 804 |             return e.sym.type; | 
| 805 |         } else { | 
| 806 |             if (readingClassAttr) { | 
| 807 |                 // While reading the class attribute, the supertypes | 
| 808 |                 // might refer to a type variable from an enclosing element | 
| 809 |                 // (method or class). | 
| 810 |                 // If the type variable is defined in the enclosing class, | 
| 811 |                 // we can actually find it in | 
| 812 |                 // currentOwner.owner.type.getTypeArguments() | 
| 813 |                 // However, until we have read the enclosing method attribute | 
| 814 |                 // we don't know for sure if this owner is correct.  It could | 
| 815 |                 // be a method and there is no way to tell before reading the | 
| 816 |                 // enclosing method attribute. | 
| 817 |                 TypeVar t = new TypeVar(name, currentOwner, syms.botType); | 
| 818 |                 missingTypeVariables = missingTypeVariables.prepend(t); | 
| 819 |                 // System.err.println("Missing type var " + name); | 
| 820 |                 return t; | 
| 821 |             } | 
| 822 |             throw badClassFile("undecl.type.var", name); | 
| 823 |         } | 
| 824 |     } | 
| 825 |   | 
| 826 | /************************************************************************ | 
| 827 |  * Reading Attributes | 
| 828 |  ***********************************************************************/ | 
| 829 |   | 
| 830 |     /** Report unrecognized attribute. | 
| 831 |      */ | 
| 832 |     void unrecognized(Name attrName) { | 
| 833 |         if (checkClassFile) | 
| 834 |             printCCF("ccf.unrecognized.attribute", attrName); | 
| 835 |     } | 
| 836 |   | 
| 837 |     /** Read member attribute. | 
| 838 |      */ | 
| 839 |     void readMemberAttr(Symbol sym, Name attrName, int attrLen) { | 
| 840 |         //- System.err.println(" z " + sym + ", " + attrName + ", " + attrLen); | 
| 841 |         if (attrName == names.ConstantValue) { | 
| 842 |             Object v = readPool(nextChar()); | 
| 843 |             // Ignore ConstantValue attribute if field not final. | 
| 844 |             if ((sym.flags() & FINAL) != 0) | 
| 845 |                 ((VarSymbol)sym).setData(v); | 
| 846 |         } else if (attrName == names.Code) { | 
| 847 |             if (readAllOfClassFile || saveParameterNames) | 
| 848 |                 ((MethodSymbol)sym).code = readCode(sym); | 
| 849 |             else | 
| 850 |                 bp = bp + attrLen; | 
| 851 |         } else if (attrName == names.Exceptions) { | 
| 852 |             int nexceptions = nextChar(); | 
| 853 |             List<Type> thrown = List.nil(); | 
| 854 |             for (int j = 0; j < nexceptions; j++) | 
| 855 |                 thrown = thrown.prepend(readClassSymbol(nextChar()).type); | 
| 856 |             if (sym.type.getThrownTypes().isEmpty()) | 
| 857 |                 sym.type.asMethodType().thrown = thrown.reverse(); | 
| 858 |         } else if (attrName == names.Synthetic) { | 
| 859 |             // bridge methods are visible when generics not enabled | 
| 860 |             if (allowGenerics || (sym.flags_field & BRIDGE) == 0) | 
| 861 |                 sym.flags_field |= SYNTHETIC; | 
| 862 |         } else if (attrName == names.Bridge) { | 
| 863 |             sym.flags_field |= BRIDGE; | 
| 864 |             if (!allowGenerics) | 
| 865 |                 sym.flags_field &= ~SYNTHETIC; | 
| 866 |         } else if (attrName == names.Deprecated) { | 
| 867 |             sym.flags_field |= DEPRECATED; | 
| 868 |         } else if (attrName == names.Varargs) { | 
| 869 |             if (allowVarargs) sym.flags_field |= VARARGS; | 
| 870 |         } else if (attrName == names.Annotation) { | 
| 871 |             if (allowAnnotations) sym.flags_field |= ANNOTATION; | 
| 872 |         } else if (attrName == names.Enum) { | 
| 873 |             sym.flags_field |= ENUM; | 
| 874 |         } else if (allowGenerics && attrName == names.Signature) { | 
| 875 |             List<Type> thrown = sym.type.getThrownTypes(); | 
| 876 |             sym.type = readType(nextChar()); | 
| 877 |             //- System.err.println(" # " + sym.type); | 
| 878 |             if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) | 
| 879 |                 sym.type.asMethodType().thrown = thrown; | 
| 880 |         } else if (attrName == names.RuntimeVisibleAnnotations) { | 
| 881 |             attachAnnotations(sym); | 
| 882 |         } else if (attrName == names.RuntimeInvisibleAnnotations) { | 
| 883 |             attachAnnotations(sym); | 
| 884 |         } else if (attrName == names.RuntimeVisibleParameterAnnotations) { | 
| 885 |             attachParameterAnnotations(sym); | 
| 886 |         } else if (attrName == names.RuntimeInvisibleParameterAnnotations) { | 
| 887 |             attachParameterAnnotations(sym); | 
| 888 |         } else if (attrName == names.LocalVariableTable) { | 
| 889 |             int newbp = bp + attrLen; | 
| 890 |             if (saveParameterNames) { | 
| 891 |                 // pick up parameter names from the variable table | 
| 892 |                 List<Name> parameterNames = List.nil(); | 
| 893 |                 int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0; | 
| 894 |                 int endParam = firstParam + Code.width(sym.type.getParameterTypes()); | 
| 895 |                 int numEntries = nextChar(); | 
| 896 |                 for (int i=0; i<numEntries; i++) { | 
| 897 |                     int start_pc = nextChar(); | 
| 898 |                     int length = nextChar(); | 
| 899 |                     int nameIndex = nextChar(); | 
| 900 |                     int sigIndex = nextChar(); | 
| 901 |                     int register = nextChar(); | 
| 902 |                     if (start_pc == 0 && | 
| 903 |                         firstParam <= register && | 
| 904 |                         register < endParam) { | 
| 905 |                         int index = firstParam; | 
| 906 |                         for (Type t : sym.type.getParameterTypes()) { | 
| 907 |                             if (index == register) { | 
| 908 |                                 parameterNames = parameterNames.prepend(readName(nameIndex)); | 
| 909 |                                 break; | 
| 910 |                             } | 
| 911 |                             index += Code.width(t); | 
| 912 |                         } | 
| 913 |                     } | 
| 914 |                 } | 
| 915 |                 parameterNames = parameterNames.reverse(); | 
| 916 |                 ((MethodSymbol)sym).savedParameterNames = parameterNames; | 
| 917 |             } | 
| 918 |             bp = newbp; | 
| 919 |         } else if (attrName == names.AnnotationDefault) { | 
| 920 |             attachAnnotationDefault(sym); | 
| 921 |         } else if (attrName == names.EnclosingMethod) { | 
| 922 |             int newbp = bp + attrLen; | 
| 923 |             readEnclosingMethodAttr(sym); | 
| 924 |             bp = newbp; | 
| 925 |         } else { | 
| 926 |             unrecognized(attrName); | 
| 927 |             bp = bp + attrLen; | 
| 928 |         } | 
| 929 |     } | 
| 930 |   | 
| 931 |     void readEnclosingMethodAttr(Symbol sym) { | 
| 932 |         // sym is a nested class with an "Enclosing Method" attribute | 
| 933 |         // remove sym from it's current owners scope and place it in | 
| 934 |         // the scope specified by the attribute | 
| 935 |         sym.owner.members().remove(sym); | 
| 936 |         ClassSymbol self = (ClassSymbol)sym; | 
| 937 |         ClassSymbol c = readClassSymbol(nextChar()); | 
| 938 |         NameAndType nt = (NameAndType)readPool(nextChar()); | 
| 939 |   | 
| 940 |         MethodSymbol m = findMethod(nt, c.members_field, self.flags()); | 
| 941 |         if (nt != null && m == null) | 
| 942 |             throw badClassFile("bad.enclosing.method", self); | 
| 943 |   | 
| 944 |         self.name = simpleBinaryName(self.flatname, c.flatname) ; | 
| 945 |         self.owner = m != null ? m : c; | 
| 946 |         if (self.name.len == 0) | 
| 947 |             self.fullname = null; | 
| 948 |         else | 
| 949 |             self.fullname = ClassSymbol.formFullName(self.name, self.owner); | 
| 950 |   | 
| 951 |         if (m != null) { | 
| 952 |             ((ClassType)sym.type).setEnclosingType(m.type); | 
| 953 |         } else if ((self.flags_field & STATIC) == 0) { | 
| 954 |             ((ClassType)sym.type).setEnclosingType(c.type); | 
| 955 |         } else { | 
| 956 |             ((ClassType)sym.type).setEnclosingType(Type.noType); | 
| 957 |         } | 
| 958 |         enterTypevars(self); | 
| 959 |         if (!missingTypeVariables.isEmpty()) { | 
| 960 |             ListBuffer<Type> typeVars =  new ListBuffer<Type>(); | 
| 961 |             for (Type typevar : missingTypeVariables) { | 
| 962 |                 typeVars.append(findTypeVar(typevar.tsym.name)); | 
| 963 |             } | 
| 964 |             foundTypeVariables = typeVars.toList(); | 
| 965 |         } else { | 
| 966 |             foundTypeVariables = List.nil(); | 
| 967 |         } | 
| 968 |     } | 
| 969 |   | 
| 970 |     // See java.lang.Class | 
| 971 |     private Name simpleBinaryName(Name self, Name enclosing) { | 
| 972 |         String simpleBinaryName = self.toString().substring(enclosing.toString().length()); | 
| 973 |         if (simpleBinaryName.length() < 1 || simpleBinaryName.charAt(0) != '$') | 
| 974 |             throw badClassFile("bad.enclosing.method", self); | 
| 975 |         int index = 1; | 
| 976 |         while (index < simpleBinaryName.length() && | 
| 977 |                isAsciiDigit(simpleBinaryName.charAt(index))) | 
| 978 |             index++; | 
| 979 |         return names.fromString(simpleBinaryName.substring(index)); | 
| 980 |     } | 
| 981 |   | 
| 982 |     private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) { | 
| 983 |         if (nt == null) | 
| 984 |             return null; | 
| 985 |   | 
| 986 |         MethodType type = nt.type.asMethodType(); | 
| 987 |   | 
| 988 |         for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next()) | 
| 989 |             if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type)) | 
| 990 |                 return (MethodSymbol)e.sym; | 
| 991 |   | 
| 992 |         if (nt.name != names.init) | 
| 993 |             // not a constructor | 
| 994 |             return null; | 
| 995 |         if ((flags & INTERFACE) != 0) | 
| 996 |             // no enclosing instance | 
| 997 |             return null; | 
| 998 |         if (nt.type.getParameterTypes().isEmpty()) | 
| 999 |             // no parameters | 
| 1000 |             return null; | 
| 1001 |   | 
| 1002 |         // A constructor of an inner class. | 
| 1003 |         // Remove the first argument (the enclosing instance) | 
| 1004 |         nt.type = new MethodType(nt.type.getParameterTypes().tail, | 
| 1005 |                                  nt.type.getReturnType(), | 
| 1006 |                                  nt.type.getThrownTypes(), | 
| 1007 |                                  syms.methodClass); | 
| 1008 |         // Try searching again | 
| 1009 |         return findMethod(nt, scope, flags); | 
| 1010 |     } | 
| 1011 |   | 
| 1012 |     /** Similar to Types.isSameType but avoids completion */ | 
| 1013 |     private boolean isSameBinaryType(MethodType mt1, MethodType mt2) { | 
| 1014 |         List<Type> types1 = types.erasure(mt1.getParameterTypes()) | 
| 1015 |             .prepend(types.erasure(mt1.getReturnType())); | 
| 1016 |         List<Type> types2 = mt2.getParameterTypes().prepend(mt2.getReturnType()); | 
| 1017 |         while (!types1.isEmpty() && !types2.isEmpty()) { | 
| 1018 |             if (types1.head.tsym != types2.head.tsym) | 
| 1019 |                 return false; | 
| 1020 |             types1 = types1.tail; | 
| 1021 |             types2 = types2.tail; | 
| 1022 |         } | 
| 1023 |         return types1.isEmpty() && types2.isEmpty(); | 
| 1024 |     } | 
| 1025 |   | 
| 1026 |     /** | 
| 1027 |      * Character.isDigit answers <tt>true</tt> to some non-ascii | 
| 1028 |      * digits.  This one does not.  <b>copied from java.lang.Class</b> | 
| 1029 |      */ | 
| 1030 |     private static boolean isAsciiDigit(char c) { | 
| 1031 |         return '0' <= c && c <= '9'; | 
| 1032 |     } | 
| 1033 |   | 
| 1034 |     /** Read member attributes. | 
| 1035 |      */ | 
| 1036 |     void readMemberAttrs(Symbol sym) { | 
| 1037 |         char ac = nextChar(); | 
| 1038 |         for (int i = 0; i < ac; i++) { | 
| 1039 |             Name attrName = readName(nextChar()); | 
| 1040 |             int attrLen = nextInt(); | 
| 1041 |             readMemberAttr(sym, attrName, attrLen); | 
| 1042 |         } | 
| 1043 |     } | 
| 1044 |   | 
| 1045 |     /** Read class attribute. | 
| 1046 |      */ | 
| 1047 |     void readClassAttr(ClassSymbol c, Name attrName, int attrLen) { | 
| 1048 |         if (attrName == names.SourceFile) { | 
| 1049 |             Name n = readName(nextChar()); | 
| 1050 |             c.sourcefile = new SourceFileObject(n); | 
| 1051 |         } else if (attrName == names.InnerClasses) { | 
| 1052 |             readInnerClasses(c); | 
| 1053 |         } else if (allowGenerics && attrName == names.Signature) { | 
| 1054 |             readingClassAttr = true; | 
| 1055 |             try { | 
| 1056 |                 ClassType ct1 = (ClassType)c.type; | 
| 1057 |                 assert c == currentOwner; | 
| 1058 |                 ct1.typarams_field = readTypeParams(nextChar()); | 
| 1059 |                 ct1.supertype_field = sigToType(); | 
| 1060 |                 ListBuffer<Type> is = new ListBuffer<Type>(); | 
| 1061 |                 while (sigp != siglimit) is.append(sigToType()); | 
| 1062 |                 ct1.interfaces_field = is.toList(); | 
| 1063 |             } finally { | 
| 1064 |                 readingClassAttr = false; | 
| 1065 |             } | 
| 1066 |         } else { | 
| 1067 |             readMemberAttr(c, attrName, attrLen); | 
| 1068 |         } | 
| 1069 |     } | 
| 1070 |     private boolean readingClassAttr = false; | 
| 1071 |     private List<Type> missingTypeVariables = List.nil(); | 
| 1072 |     private List<Type> foundTypeVariables = List.nil(); | 
| 1073 |   | 
| 1074 |     /** Read class attributes. | 
| 1075 |      */ | 
| 1076 |     void readClassAttrs(ClassSymbol c) { | 
| 1077 |         char ac = nextChar(); | 
| 1078 |         for (int i = 0; i < ac; i++) { | 
| 1079 |             Name attrName = readName(nextChar()); | 
| 1080 |             int attrLen = nextInt(); | 
| 1081 |             readClassAttr(c, attrName, attrLen); | 
| 1082 |         } | 
| 1083 |     } | 
| 1084 |   | 
| 1085 |     /** Read code block. | 
| 1086 |      */ | 
| 1087 |     Code readCode(Symbol owner) { | 
| 1088 |         nextChar(); // max_stack | 
| 1089 |         nextChar(); // max_locals | 
| 1090 |         final int  code_length = nextInt(); | 
| 1091 |         bp += code_length; | 
| 1092 |         final char exception_table_length = nextChar(); | 
| 1093 |         bp += exception_table_length * 8; | 
| 1094 |         readMemberAttrs(owner); | 
| 1095 |         return null; | 
| 1096 |     } | 
| 1097 |   | 
| 1098 | /************************************************************************ | 
| 1099 |  * Reading Java-language annotations | 
| 1100 |  ***********************************************************************/ | 
| 1101 |   | 
| 1102 |     /** Attach annotations. | 
| 1103 |      */ | 
| 1104 |     void attachAnnotations(final Symbol sym) { | 
| 1105 |         int numAttributes = nextChar(); | 
| 1106 |         if (numAttributes != 0) { | 
| 1107 |             ListBuffer<CompoundAnnotationProxy> proxies = | 
| 1108 |                 new ListBuffer<CompoundAnnotationProxy>(); | 
| 1109 |             for (int i = 0; i<numAttributes; i++) { | 
| 1110 |                 CompoundAnnotationProxy proxy = readCompoundAnnotation(); | 
| 1111 |                 if (proxy.type.tsym == syms.proprietaryType.tsym) | 
| 1112 |                     sym.flags_field |= PROPRIETARY; | 
| 1113 |                 else | 
| 1114 |                     proxies.append(proxy); | 
| 1115 |             } | 
| 1116 |             annotate.later(new AnnotationCompleter(sym, proxies.toList())); | 
| 1117 |         } | 
| 1118 |     } | 
| 1119 |   | 
| 1120 |     /** Attach parameter annotations. | 
| 1121 |      */ | 
| 1122 |     void attachParameterAnnotations(final Symbol method) { | 
| 1123 |         final MethodSymbol meth = (MethodSymbol)method; | 
| 1124 |         int numParameters = buf[bp++] & 0xFF; | 
| 1125 |         List<VarSymbol> parameters = meth.params(); | 
| 1126 |         int pnum = 0; | 
| 1127 |         while (parameters.tail != null) { | 
| 1128 |             attachAnnotations(parameters.head); | 
| 1129 |             parameters = parameters.tail; | 
| 1130 |             pnum++; | 
| 1131 |         } | 
| 1132 |         if (pnum != numParameters) { | 
| 1133 |             throw badClassFile("bad.runtime.invisible.param.annotations", meth); | 
| 1134 |         } | 
| 1135 |     } | 
| 1136 |   | 
| 1137 |     /** Attach the default value for an annotation element. | 
| 1138 |      */ | 
| 1139 |     void attachAnnotationDefault(final Symbol sym) { | 
| 1140 |         final MethodSymbol meth = (MethodSymbol)sym; // only on methods | 
| 1141 |         final Attribute value = readAttributeValue(); | 
| 1142 |         annotate.later(new AnnotationDefaultCompleter(meth, value)); | 
| 1143 |     } | 
| 1144 |   | 
| 1145 |     Type readTypeOrClassSymbol(int i) { | 
| 1146 |         // support preliminary jsr175-format class files | 
| 1147 |         if (buf[poolIdx[i]] == CONSTANT_Class) | 
| 1148 |             return readClassSymbol(i).type; | 
| 1149 |         return readType(i); | 
| 1150 |     } | 
| 1151 |     Type readEnumType(int i) { | 
| 1152 |         // support preliminary jsr175-format class files | 
| 1153 |         int index = poolIdx[i]; | 
| 1154 |         int length = getChar(index + 1); | 
| 1155 |         if (buf[index + length + 2] != ';') | 
| 1156 |             return enterClass(readName(i)).type; | 
| 1157 |         return readType(i); | 
| 1158 |     } | 
| 1159 |   | 
| 1160 |     CompoundAnnotationProxy readCompoundAnnotation() { | 
| 1161 |         Type t = readTypeOrClassSymbol(nextChar()); | 
| 1162 |         int numFields = nextChar(); | 
| 1163 |         ListBuffer<Pair<Name,Attribute>> pairs = | 
| 1164 |             new ListBuffer<Pair<Name,Attribute>>(); | 
| 1165 |         for (int i=0; i<numFields; i++) { | 
| 1166 |             Name name = readName(nextChar()); | 
| 1167 |             Attribute value = readAttributeValue(); | 
| 1168 |             pairs.append(new Pair<Name,Attribute>(name, value)); | 
| 1169 |         } | 
| 1170 |         return new CompoundAnnotationProxy(t, pairs.toList()); | 
| 1171 |     } | 
| 1172 |   | 
| 1173 |     Attribute readAttributeValue() { | 
| 1174 |         char c = (char) buf[bp++]; | 
| 1175 |         switch (c) { | 
| 1176 |         case 'B': | 
| 1177 |             return new Attribute.Constant(syms.byteType, readPool(nextChar())); | 
| 1178 |         case 'C': | 
| 1179 |             return new Attribute.Constant(syms.charType, readPool(nextChar())); | 
| 1180 |         case 'D': | 
| 1181 |             return new Attribute.Constant(syms.doubleType, readPool(nextChar())); | 
| 1182 |         case 'F': | 
| 1183 |             return new Attribute.Constant(syms.floatType, readPool(nextChar())); | 
| 1184 |         case 'I': | 
| 1185 |             return new Attribute.Constant(syms.intType, readPool(nextChar())); | 
| 1186 |         case 'J': | 
| 1187 |             return new Attribute.Constant(syms.longType, readPool(nextChar())); | 
| 1188 |         case 'S': | 
| 1189 |             return new Attribute.Constant(syms.shortType, readPool(nextChar())); | 
| 1190 |         case 'Z': | 
| 1191 |             return new Attribute.Constant(syms.booleanType, readPool(nextChar())); | 
| 1192 |         case 's': | 
| 1193 |             return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString()); | 
| 1194 |         case 'e': | 
| 1195 |             return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar())); | 
| 1196 |         case 'c': | 
| 1197 |             return new Attribute.Class(types, readTypeOrClassSymbol(nextChar())); | 
| 1198 |         case '[': { | 
| 1199 |             int n = nextChar(); | 
| 1200 |             ListBuffer<Attribute> l = new ListBuffer<Attribute>(); | 
| 1201 |             for (int i=0; i<n; i++) | 
| 1202 |                 l.append(readAttributeValue()); | 
| 1203 |             return new ArrayAttributeProxy(l.toList()); | 
| 1204 |         } | 
| 1205 |         case '@': | 
| 1206 |             return readCompoundAnnotation(); | 
| 1207 |         default: | 
| 1208 |             throw new AssertionError("unknown annotation tag '" + c + "'"); | 
| 1209 |         } | 
| 1210 |     } | 
| 1211 |   | 
| 1212 |     interface ProxyVisitor extends Attribute.Visitor { | 
| 1213 |         void visitEnumAttributeProxy(EnumAttributeProxy proxy); | 
| 1214 |         void visitArrayAttributeProxy(ArrayAttributeProxy proxy); | 
| 1215 |         void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy); | 
| 1216 |     } | 
| 1217 |   | 
| 1218 |     static class EnumAttributeProxy extends Attribute { | 
| 1219 |         Type enumType; | 
| 1220 |         Name enumerator; | 
| 1221 |         public EnumAttributeProxy(Type enumType, Name enumerator) { | 
| 1222 |             super(null); | 
| 1223 |             this.enumType = enumType; | 
| 1224 |             this.enumerator = enumerator; | 
| 1225 |         } | 
| 1226 |         public void accept(Visitor v) { ((ProxyVisitor)v).visitEnumAttributeProxy(this); } | 
| 1227 |         public String toString() { | 
| 1228 |             return "/*proxy enum*/" + enumType + "." + enumerator; | 
| 1229 |         } | 
| 1230 |     } | 
| 1231 |   | 
| 1232 |     static class ArrayAttributeProxy extends Attribute { | 
| 1233 |         List<Attribute> values; | 
| 1234 |         ArrayAttributeProxy(List<Attribute> values) { | 
| 1235 |             super(null); | 
| 1236 |             this.values = values; | 
| 1237 |         } | 
| 1238 |         public void accept(Visitor v) { ((ProxyVisitor)v).visitArrayAttributeProxy(this); } | 
| 1239 |         public String toString() { | 
| 1240 |             return "{" + values + "}"; | 
| 1241 |         } | 
| 1242 |     } | 
| 1243 |   | 
| 1244 |     /** A temporary proxy representing a compound attribute. | 
| 1245 |      */ | 
| 1246 |     static class CompoundAnnotationProxy extends Attribute { | 
| 1247 |         final List<Pair<Name,Attribute>> values; | 
| 1248 |         public CompoundAnnotationProxy(Type type, | 
| 1249 |                                       List<Pair<Name,Attribute>> values) { | 
| 1250 |             super(type); | 
| 1251 |             this.values = values; | 
| 1252 |         } | 
| 1253 |         public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); } | 
| 1254 |         public String toString() { | 
| 1255 |             StringBuffer buf = new StringBuffer(); | 
| 1256 |             buf.append("@"); | 
| 1257 |             buf.append(type.tsym.getQualifiedName()); | 
| 1258 |             buf.append("/*proxy*/{"); | 
| 1259 |             boolean first = true; | 
| 1260 |             for (List<Pair<Name,Attribute>> v = values; | 
| 1261 |                  v.nonEmpty(); v = v.tail) { | 
| 1262 |                 Pair<Name,Attribute> value = v.head; | 
| 1263 |                 if (!first) buf.append(","); | 
| 1264 |                 first = false; | 
| 1265 |                 buf.append(value.fst); | 
| 1266 |                 buf.append("="); | 
| 1267 |                 buf.append(value.snd); | 
| 1268 |             } | 
| 1269 |             buf.append("}"); | 
| 1270 |             return buf.toString(); | 
| 1271 |         } | 
| 1272 |     } | 
| 1273 |   | 
| 1274 |     class AnnotationDeproxy implements ProxyVisitor { | 
| 1275 |         private ClassSymbol requestingOwner = currentOwner.kind == MTH | 
| 1276 |             ? currentOwner.enclClass() : (ClassSymbol)currentOwner; | 
| 1277 |   | 
| 1278 |         List<Attribute.Compound> deproxyCompoundList(List<CompoundAnnotationProxy> pl) { | 
| 1279 |             // also must fill in types!!!! | 
| 1280 |             ListBuffer<Attribute.Compound> buf = | 
| 1281 |                 new ListBuffer<Attribute.Compound>(); | 
| 1282 |             for (List<CompoundAnnotationProxy> l = pl; l.nonEmpty(); l=l.tail) { | 
| 1283 |                 buf.append(deproxyCompound(l.head)); | 
| 1284 |             } | 
| 1285 |             return buf.toList(); | 
| 1286 |         } | 
| 1287 |   | 
| 1288 |         Attribute.Compound deproxyCompound(CompoundAnnotationProxy a) { | 
| 1289 |             ListBuffer<Pair<Symbol.MethodSymbol,Attribute>> buf = | 
| 1290 |                 new ListBuffer<Pair<Symbol.MethodSymbol,Attribute>>(); | 
| 1291 |             for (List<Pair<Name,Attribute>> l = a.values; | 
| 1292 |                  l.nonEmpty(); | 
| 1293 |                  l = l.tail) { | 
| 1294 |                 MethodSymbol meth = findAccessMethod(a.type, l.head.fst); | 
| 1295 |                 buf.append(new Pair<Symbol.MethodSymbol,Attribute> | 
| 1296 |                            (meth, deproxy(meth.type.getReturnType(), l.head.snd))); | 
| 1297 |             } | 
| 1298 |             return new Attribute.Compound(a.type, buf.toList()); | 
| 1299 |         } | 
| 1300 |   | 
| 1301 |         MethodSymbol findAccessMethod(Type container, Name name) { | 
| 1302 |             CompletionFailure failure = null; | 
| 1303 |             try { | 
| 1304 |                 for (Scope.Entry e = container.tsym.members().lookup(name); | 
| 1305 |                      e.scope != null; | 
| 1306 |                      e = e.next()) { | 
| 1307 |                     Symbol sym = e.sym; | 
| 1308 |                     if (sym.kind == MTH && sym.type.getParameterTypes().length() == 0) | 
| 1309 |                         return (MethodSymbol) sym; | 
| 1310 |                 } | 
| 1311 |             } catch (CompletionFailure ex) { | 
| 1312 |                 failure = ex; | 
| 1313 |             } | 
| 1314 |             // The method wasn't found: emit a warning and recover | 
| 1315 |             JavaFileObject prevSource = log.useSource(requestingOwner.classfile); | 
| 1316 |             try { | 
| 1317 |                 if (failure == null) { | 
| 1318 |                     log.warning("annotation.method.not.found", | 
| 1319 |                                 container, | 
| 1320 |                                 name); | 
| 1321 |                 } else { | 
| 1322 |                     log.warning("annotation.method.not.found.reason", | 
| 1323 |                                 container, | 
| 1324 |                                 name, | 
| 1325 |                                 failure.getMessage()); | 
| 1326 |                 } | 
| 1327 |             } finally { | 
| 1328 |                 log.useSource(prevSource); | 
| 1329 |             } | 
| 1330 |             // Construct a new method type and symbol.  Use bottom | 
| 1331 |             // type (typeof null) as return type because this type is | 
| 1332 |             // a subtype of all reference types and can be converted | 
| 1333 |             // to primitive types by unboxing. | 
| 1334 |             MethodType mt = new MethodType(List.<Type>nil(), | 
| 1335 |                                            syms.botType, | 
| 1336 |                                            List.<Type>nil(), | 
| 1337 |                                            syms.methodClass); | 
| 1338 |             return new MethodSymbol(PUBLIC | ABSTRACT, name, mt, container.tsym); | 
| 1339 |         } | 
| 1340 |   | 
| 1341 |         Attribute result; | 
| 1342 |         Type type; | 
| 1343 |         Attribute deproxy(Type t, Attribute a) { | 
| 1344 |             Type oldType = type; | 
| 1345 |             try { | 
| 1346 |                 type = t; | 
| 1347 |                 a.accept(this); | 
| 1348 |                 return result; | 
| 1349 |             } finally { | 
| 1350 |                 type = oldType; | 
| 1351 |             } | 
| 1352 |         } | 
| 1353 |   | 
| 1354 |         // implement Attribute.Visitor below | 
| 1355 |   | 
| 1356 |         public void visitConstant(Attribute.Constant value) { | 
| 1357 |             // assert value.type == type; | 
| 1358 |             result = value; | 
| 1359 |         } | 
| 1360 |   | 
| 1361 |         public void visitClass(Attribute.Class clazz) { | 
| 1362 |             result = clazz; | 
| 1363 |         } | 
| 1364 |   | 
| 1365 |         public void visitEnum(Attribute.Enum e) { | 
| 1366 |             throw new AssertionError(); // shouldn't happen | 
| 1367 |         } | 
| 1368 |   | 
| 1369 |         public void visitCompound(Attribute.Compound compound) { | 
| 1370 |             throw new AssertionError(); // shouldn't happen | 
| 1371 |         } | 
| 1372 |   | 
| 1373 |         public void visitArray(Attribute.Array array) { | 
| 1374 |             throw new AssertionError(); // shouldn't happen | 
| 1375 |         } | 
| 1376 |   | 
| 1377 |         public void visitError(Attribute.Error e) { | 
| 1378 |             throw new AssertionError(); // shouldn't happen | 
| 1379 |         } | 
| 1380 |   | 
| 1381 |         public void visitEnumAttributeProxy(EnumAttributeProxy proxy) { | 
| 1382 |             // type.tsym.flatName() should == proxy.enumFlatName | 
| 1383 |             TypeSymbol enumTypeSym = proxy.enumType.tsym; | 
| 1384 |             VarSymbol enumerator = null; | 
| 1385 |             for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator); | 
| 1386 |                  e.scope != null; | 
| 1387 |                  e = e.next()) { | 
| 1388 |                 if (e.sym.kind == VAR) { | 
| 1389 |                     enumerator = (VarSymbol)e.sym; | 
| 1390 |                     break; | 
| 1391 |                 } | 
| 1392 |             } | 
| 1393 |             if (enumerator == null) { | 
| 1394 |                 log.error("unknown.enum.constant", | 
| 1395 |                           currentClassFile, enumTypeSym, proxy.enumerator); | 
| 1396 |                 result = new Attribute.Error(enumTypeSym.type); | 
| 1397 |             } else { | 
| 1398 |                 result = new Attribute.Enum(enumTypeSym.type, enumerator); | 
| 1399 |             } | 
| 1400 |         } | 
| 1401 |   | 
| 1402 |         public void visitArrayAttributeProxy(ArrayAttributeProxy proxy) { | 
| 1403 |             int length = proxy.values.length(); | 
| 1404 |             Attribute[] ats = new Attribute[length]; | 
| 1405 |             Type elemtype = types.elemtype(type); | 
| 1406 |             int i = 0; | 
| 1407 |             for (List<Attribute> p = proxy.values; p.nonEmpty(); p = p.tail) { | 
| 1408 |                 ats[i++] = deproxy(elemtype, p.head); | 
| 1409 |             } | 
| 1410 |             result = new Attribute.Array(type, ats); | 
| 1411 |         } | 
| 1412 |   | 
| 1413 |         public void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy) { | 
| 1414 |             result = deproxyCompound(proxy); | 
| 1415 |         } | 
| 1416 |     } | 
| 1417 |   | 
| 1418 |     class AnnotationDefaultCompleter extends AnnotationDeproxy implements Annotate.Annotator { | 
| 1419 |         final MethodSymbol sym; | 
| 1420 |         final Attribute value; | 
| 1421 |         final JavaFileObject classFile = currentClassFile; | 
| 1422 |         public String toString() { | 
| 1423 |             return " ClassReader store default for " + sym.owner + "." + sym + " is " + value; | 
| 1424 |         } | 
| 1425 |         AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) { | 
| 1426 |             this.sym = sym; | 
| 1427 |             this.value = value; | 
| 1428 |         } | 
| 1429 |         // implement Annotate.Annotator.enterAnnotation() | 
| 1430 |         public void enterAnnotation() { | 
| 1431 |             JavaFileObject previousClassFile = currentClassFile; | 
| 1432 |             try { | 
| 1433 |                 currentClassFile = classFile; | 
| 1434 |                 sym.defaultValue = deproxy(sym.type.getReturnType(), value); | 
| 1435 |             } finally { | 
| 1436 |                 currentClassFile = previousClassFile; | 
| 1437 |             } | 
| 1438 |         } | 
| 1439 |     } | 
| 1440 |   | 
| 1441 |     class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Annotator { | 
| 1442 |         final Symbol sym; | 
| 1443 |         final List<CompoundAnnotationProxy> l; | 
| 1444 |         final JavaFileObject classFile; | 
| 1445 |         public String toString() { | 
| 1446 |             return " ClassReader annotate " + sym.owner + "." + sym + " with " + l; | 
| 1447 |         } | 
| 1448 |         AnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l) { | 
| 1449 |             this.sym = sym; | 
| 1450 |             this.l = l; | 
| 1451 |             this.classFile = currentClassFile; | 
| 1452 |         } | 
| 1453 |         // implement Annotate.Annotator.enterAnnotation() | 
| 1454 |         public void enterAnnotation() { | 
| 1455 |             JavaFileObject previousClassFile = currentClassFile; | 
| 1456 |             try { | 
| 1457 |                 currentClassFile = classFile; | 
| 1458 |                 List<Attribute.Compound> newList = deproxyCompoundList(l); | 
| 1459 |                 sym.attributes_field = ((sym.attributes_field == null) | 
| 1460 |                                         ? newList | 
| 1461 |                                         : newList.prependList(sym.attributes_field)); | 
| 1462 |             } finally { | 
| 1463 |                 currentClassFile = previousClassFile; | 
| 1464 |             } | 
| 1465 |         } | 
| 1466 |     } | 
| 1467 |   | 
| 1468 |   | 
| 1469 | /************************************************************************ | 
| 1470 |  * Reading Symbols | 
| 1471 |  ***********************************************************************/ | 
| 1472 |   | 
| 1473 |     /** Read a field. | 
| 1474 |      */ | 
| 1475 |     VarSymbol readField() { | 
| 1476 |         long flags = adjustFieldFlags(nextChar()); | 
| 1477 |         Name name = readName(nextChar()); | 
| 1478 |         Type type = readType(nextChar()); | 
| 1479 |         VarSymbol v = new VarSymbol(flags, name, type, currentOwner); | 
| 1480 |         readMemberAttrs(v); | 
| 1481 |         return v; | 
| 1482 |     } | 
| 1483 |   | 
| 1484 |     /** Read a method. | 
| 1485 |      */ | 
| 1486 |     MethodSymbol readMethod() { | 
| 1487 |         long flags = adjustMethodFlags(nextChar()); | 
| 1488 |         Name name = readName(nextChar()); | 
| 1489 |         Type type = readType(nextChar()); | 
| 1490 |         if (name == names.init && currentOwner.hasOuterInstance()) { | 
| 1491 |             // Sometimes anonymous classes don't have an outer | 
| 1492 |             // instance, however, there is no reliable way to tell so | 
| 1493 |             // we never strip this$n | 
| 1494 |             if (currentOwner.name.len != 0) | 
| 1495 |                 type = new MethodType(type.getParameterTypes().tail, | 
| 1496 |                                       type.getReturnType(), | 
| 1497 |                                       type.getThrownTypes(), | 
| 1498 |                                       syms.methodClass); | 
| 1499 |         } | 
| 1500 |         MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner); | 
| 1501 |         Symbol prevOwner = currentOwner; | 
| 1502 |         currentOwner = m; | 
| 1503 |         try { | 
| 1504 |             readMemberAttrs(m); | 
| 1505 |         } finally { | 
| 1506 |             currentOwner = prevOwner; | 
| 1507 |         } | 
| 1508 |         return m; | 
| 1509 |     } | 
| 1510 |   | 
| 1511 |     /** Skip a field or method | 
| 1512 |      */ | 
| 1513 |     void skipMember() { | 
| 1514 |         bp = bp + 6; | 
| 1515 |         char ac = nextChar(); | 
| 1516 |         for (int i = 0; i < ac; i++) { | 
| 1517 |             bp = bp + 2; | 
| 1518 |             int attrLen = nextInt(); | 
| 1519 |             bp = bp + attrLen; | 
| 1520 |         } | 
| 1521 |     } | 
| 1522 |   | 
| 1523 |     /** Enter type variables of this classtype and all enclosing ones in | 
| 1524 |      *  `typevars'. | 
| 1525 |      */ | 
| 1526 |     protected void enterTypevars(Type t) { | 
| 1527 |         if (t.getEnclosingType() != null && t.getEnclosingType().tag == CLASS) | 
| 1528 |             enterTypevars(t.getEnclosingType()); | 
| 1529 |         for (List<Type> xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail) | 
| 1530 |             typevars.enter(xs.head.tsym); | 
| 1531 |     } | 
| 1532 |   | 
| 1533 |     protected void enterTypevars(Symbol sym) { | 
| 1534 |         if (sym.owner.kind == MTH) { | 
| 1535 |             enterTypevars(sym.owner); | 
| 1536 |             enterTypevars(sym.owner.owner); | 
| 1537 |         } | 
| 1538 |         enterTypevars(sym.type); | 
| 1539 |     } | 
| 1540 |   | 
| 1541 |     /** Read contents of a given class symbol `c'. Both external and internal | 
| 1542 |      *  versions of an inner class are read. | 
| 1543 |      */ | 
| 1544 |     void readClass(ClassSymbol c) { | 
| 1545 |         ClassType ct = (ClassType)c.type; | 
| 1546 |   | 
| 1547 |         // allocate scope for members | 
| 1548 |         c.members_field = new Scope(c); | 
| 1549 |   | 
| 1550 |         // prepare type variable table | 
| 1551 |         typevars = typevars.dup(currentOwner); | 
| 1552 |         if (ct.getEnclosingType().tag == CLASS) enterTypevars(ct.getEnclosingType()); | 
| 1553 |   | 
| 1554 |         // read flags, or skip if this is an inner class | 
| 1555 |         long flags = adjustClassFlags(nextChar()); | 
| 1556 |         if (c.owner.kind == PCK) c.flags_field = flags; | 
| 1557 |   | 
| 1558 |         // read own class name and check that it matches | 
| 1559 |         ClassSymbol self = readClassSymbol(nextChar()); | 
| 1560 |         if (c != self) | 
| 1561 |             throw badClassFile("class.file.wrong.class", | 
| 1562 |                                self.flatname); | 
| 1563 |   | 
| 1564 |         // class attributes must be read before class | 
| 1565 |         // skip ahead to read class attributes | 
| 1566 |         int startbp = bp; | 
| 1567 |         nextChar(); | 
| 1568 |         char interfaceCount = nextChar(); | 
| 1569 |         bp += interfaceCount * 2; | 
| 1570 |         char fieldCount = nextChar(); | 
| 1571 |         for (int i = 0; i < fieldCount; i++) skipMember(); | 
| 1572 |         char methodCount = nextChar(); | 
| 1573 |         for (int i = 0; i < methodCount; i++) skipMember(); | 
| 1574 |         readClassAttrs(c); | 
| 1575 |   | 
| 1576 |         if (readAllOfClassFile) { | 
| 1577 |             for (int i = 1; i < poolObj.length; i++) readPool(i); | 
| 1578 |             c.pool = new Pool(poolObj.length, poolObj); | 
| 1579 |         } | 
| 1580 |   | 
| 1581 |         // reset and read rest of classinfo | 
| 1582 |         bp = startbp; | 
| 1583 |         int n = nextChar(); | 
| 1584 |         if (ct.supertype_field == null) | 
| 1585 |             ct.supertype_field = (n == 0) | 
| 1586 |                 ? Type.noType | 
| 1587 |                 : readClassSymbol(n).erasure(types); | 
| 1588 |         n = nextChar(); | 
| 1589 |         List<Type> is = List.nil(); | 
| 1590 |         for (int i = 0; i < n; i++) { | 
| 1591 |             Type _inter = readClassSymbol(nextChar()).erasure(types); | 
| 1592 |             is = is.prepend(_inter); | 
| 1593 |         } | 
| 1594 |         if (ct.interfaces_field == null) | 
| 1595 |             ct.interfaces_field = is.reverse(); | 
| 1596 |   | 
| 1597 |         if (fieldCount != nextChar()) assert false; | 
| 1598 |         for (int i = 0; i < fieldCount; i++) enterMember(c, readField()); | 
| 1599 |         if (methodCount != nextChar()) assert false; | 
| 1600 |         for (int i = 0; i < methodCount; i++) enterMember(c, readMethod()); | 
| 1601 |   | 
| 1602 |         typevars = typevars.leave(); | 
| 1603 |     } | 
| 1604 |   | 
| 1605 |     /** Read inner class info. For each inner/outer pair allocate a | 
| 1606 |      *  member class. | 
| 1607 |      */ | 
| 1608 |     void readInnerClasses(ClassSymbol c) { | 
| 1609 |         int n = nextChar(); | 
| 1610 |         for (int i = 0; i < n; i++) { | 
| 1611 |             nextChar(); // skip inner class symbol | 
| 1612 |             ClassSymbol outer = readClassSymbol(nextChar()); | 
| 1613 |             Name name = readName(nextChar()); | 
| 1614 |             if (name == null) name = names.empty; | 
| 1615 |             long flags = adjustClassFlags(nextChar()); | 
| 1616 |             if (outer != null) { // we have a member class | 
| 1617 |                 if (name == names.empty) | 
| 1618 |                     name = names.one; | 
| 1619 |                 ClassSymbol member = enterClass(name, outer); | 
| 1620 |                 if ((flags & STATIC) == 0) { | 
| 1621 |                     ((ClassType)member.type).setEnclosingType(outer.type); | 
| 1622 |                     if (member.erasure_field != null) | 
| 1623 |                         ((ClassType)member.erasure_field).setEnclosingType(types.erasure(outer.type)); | 
| 1624 |                 } | 
| 1625 |                 if (c == outer) { | 
| 1626 |                     member.flags_field = flags; | 
| 1627 |                     enterMember(c, member); | 
| 1628 |                 } | 
| 1629 |             } | 
| 1630 |         } | 
| 1631 |     } | 
| 1632 |   | 
| 1633 |     /** Read a class file. | 
| 1634 |      */ | 
| 1635 |     private void readClassFile(ClassSymbol c) throws IOException { | 
| 1636 |         int magic = nextInt(); | 
| 1637 |         if (magic != JAVA_MAGIC) | 
| 1638 |             throw badClassFile("illegal.start.of.class.file"); | 
| 1639 |   | 
| 1640 |         int minorVersion = nextChar(); | 
| 1641 |         int majorVersion = nextChar(); | 
| 1642 |         int maxMajor = Target.MAX().majorVersion; | 
| 1643 |         int maxMinor = Target.MAX().minorVersion; | 
| 1644 |         if (majorVersion > maxMajor || | 
| 1645 |             majorVersion * 1000 + minorVersion < | 
| 1646 |             Target.MIN().majorVersion * 1000 + Target.MIN().minorVersion) | 
| 1647 |         { | 
| 1648 |             if (majorVersion == (maxMajor + 1)) | 
| 1649 |                 log.warning("big.major.version", | 
| 1650 |                             currentClassFile, | 
| 1651 |                             majorVersion, | 
| 1652 |                             maxMajor); | 
| 1653 |             else | 
| 1654 |                 throw badClassFile("wrong.version", | 
| 1655 |                                    Integer.toString(majorVersion), | 
| 1656 |                                    Integer.toString(minorVersion), | 
| 1657 |                                    Integer.toString(maxMajor), | 
| 1658 |                                    Integer.toString(maxMinor)); | 
| 1659 |         } | 
| 1660 |         else if (checkClassFile && | 
| 1661 |                  majorVersion == maxMajor && | 
| 1662 |                  minorVersion > maxMinor) | 
| 1663 |         { | 
| 1664 |             printCCF("found.later.version", | 
| 1665 |                      Integer.toString(minorVersion)); | 
| 1666 |         } | 
| 1667 |         indexPool(); | 
| 1668 |         if (signatureBuffer.length < bp) { | 
| 1669 |             int ns = Integer.highestOneBit(bp) << 1; | 
| 1670 |             signatureBuffer = new byte[ns]; | 
| 1671 |         } | 
| 1672 |         readClass(c); | 
| 1673 |     } | 
| 1674 |   | 
| 1675 | /************************************************************************ | 
| 1676 |  * Adjusting flags | 
| 1677 |  ***********************************************************************/ | 
| 1678 |   | 
| 1679 |     long adjustFieldFlags(long flags) { | 
| 1680 |         return flags; | 
| 1681 |     } | 
| 1682 |     long adjustMethodFlags(long flags) { | 
| 1683 |         if ((flags & ACC_BRIDGE) != 0) { | 
| 1684 |             flags &= ~ACC_BRIDGE; | 
| 1685 |             flags |= BRIDGE; | 
| 1686 |             if (!allowGenerics) | 
| 1687 |                 flags &= ~SYNTHETIC; | 
| 1688 |         } | 
| 1689 |         if ((flags & ACC_VARARGS) != 0) { | 
| 1690 |             flags &= ~ACC_VARARGS; | 
| 1691 |             flags |= VARARGS; | 
| 1692 |         } | 
| 1693 |         return flags; | 
| 1694 |     } | 
| 1695 |     long adjustClassFlags(long flags) { | 
| 1696 |         return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded | 
| 1697 |     } | 
| 1698 |   | 
| 1699 | /************************************************************************ | 
| 1700 |  * Loading Classes | 
| 1701 |  ***********************************************************************/ | 
| 1702 |   | 
| 1703 |     /** Define a new class given its name and owner. | 
| 1704 |      */ | 
| 1705 |     public ClassSymbol defineClass(Name name, Symbol owner) { | 
| 1706 |         ClassSymbol c = new ClassSymbol(0, name, owner); | 
| 1707 |         if (owner.kind == PCK) | 
| 1708 |             assert classes.get(c.flatname) == null : c; | 
| 1709 |         c.completer = this; | 
| 1710 |         return c; | 
| 1711 |     } | 
| 1712 |   | 
| 1713 |     /** Create a new toplevel or member class symbol with given name | 
| 1714 |      *  and owner and enter in `classes' unless already there. | 
| 1715 |      */ | 
| 1716 |     public ClassSymbol enterClass(Name name, TypeSymbol owner) { | 
| 1717 |         Name flatname = TypeSymbol.formFlatName(name, owner); | 
| 1718 |         ClassSymbol c = classes.get(flatname); | 
| 1719 |         if (c == null) { | 
| 1720 |             c = defineClass(name, owner); | 
| 1721 |             classes.put(flatname, c); | 
| 1722 |         } else if ((c.name != name || c.owner != owner) && owner.kind == TYP && c.owner.kind == PCK) { | 
| 1723 |             // reassign fields of classes that might have been loaded with | 
| 1724 |             // their flat names. | 
| 1725 |             c.owner.members().remove(c); | 
| 1726 |             c.name = name; | 
| 1727 |             c.owner = owner; | 
| 1728 |             c.fullname = ClassSymbol.formFullName(name, owner); | 
| 1729 |         } | 
| 1730 |         return c; | 
| 1731 |     } | 
| 1732 |   | 
| 1733 |     /** | 
| 1734 |      * Creates a new toplevel class symbol with given flat name and | 
| 1735 |      * given class (or source) file. | 
| 1736 |      * | 
| 1737 |      * @param flatName a fully qualified binary class name | 
| 1738 |      * @param classFile the class file or compilation unit defining | 
| 1739 |      * the class (may be {@code null}) | 
| 1740 |      * @return a newly created class symbol | 
| 1741 |      * @throws AssertionError if the class symbol already exists | 
| 1742 |      */ | 
| 1743 |     public ClassSymbol enterClass(Name flatName, JavaFileObject classFile) { | 
| 1744 |         ClassSymbol cs = classes.get(flatName); | 
| 1745 |         if (cs != null) { | 
| 1746 |             String msg = Log.format("%s: completer = %s; class file = %s; source file = %s", | 
| 1747 |                                     cs.fullname, | 
| 1748 |                                     cs.completer, | 
| 1749 |                                     cs.classfile, | 
| 1750 |                                     cs.sourcefile); | 
| 1751 |             throw new AssertionError(msg); | 
| 1752 |         } | 
| 1753 |         Name packageName = Convert.packagePart(flatName); | 
| 1754 |         PackageSymbol owner = packageName.isEmpty() | 
| 1755 |                                 ? syms.unnamedPackage | 
| 1756 |                                 : enterPackage(packageName); | 
| 1757 |         cs = defineClass(Convert.shortName(flatName), owner); | 
| 1758 |         cs.classfile = classFile; | 
| 1759 |         classes.put(flatName, cs); | 
| 1760 |         return cs; | 
| 1761 |     } | 
| 1762 |   | 
| 1763 |     /** Create a new member or toplevel class symbol with given flat name | 
| 1764 |      *  and enter in `classes' unless already there. | 
| 1765 |      */ | 
| 1766 |     public ClassSymbol enterClass(Name flatname) { | 
| 1767 |         ClassSymbol c = classes.get(flatname); | 
| 1768 |         if (c == null) | 
| 1769 |             return enterClass(flatname, (JavaFileObject)null); | 
| 1770 |         else | 
| 1771 |             return c; | 
| 1772 |     } | 
| 1773 |   | 
| 1774 |     private boolean suppressFlush = false; | 
| 1775 |   | 
| 1776 |     /** Completion for classes to be loaded. Before a class is loaded | 
| 1777 |      *  we make sure its enclosing class (if any) is loaded. | 
| 1778 |      */ | 
| 1779 |     public void complete(Symbol sym) throws CompletionFailure { | 
| 1780 |         if (sym.kind == TYP) { | 
| 1781 |             ClassSymbol c = (ClassSymbol)sym; | 
| 1782 |             c.members_field = new Scope.ErrorScope(c); // make sure it's always defined | 
| 1783 |             boolean suppressFlush = this.suppressFlush; | 
| 1784 |             this.suppressFlush = true; | 
| 1785 |             try { | 
| 1786 |                 completeOwners(c.owner); | 
| 1787 |                 completeEnclosing(c); | 
| 1788 |             } finally { | 
| 1789 |                 this.suppressFlush = suppressFlush; | 
| 1790 |             } | 
| 1791 |             fillIn(c); | 
| 1792 |         } else if (sym.kind == PCK) { | 
| 1793 |             PackageSymbol p = (PackageSymbol)sym; | 
| 1794 |             try { | 
| 1795 |                 fillIn(p); | 
| 1796 |             } catch (IOException ex) { | 
| 1797 |                 throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex); | 
| 1798 |             } | 
| 1799 |         } | 
| 1800 |         if (!filling && !suppressFlush) | 
| 1801 |             annotate.flush(); // finish attaching annotations | 
| 1802 |     } | 
| 1803 |   | 
| 1804 |     /** complete up through the enclosing package. */ | 
| 1805 |     private void completeOwners(Symbol o) { | 
| 1806 |         if (o.kind != PCK) completeOwners(o.owner); | 
| 1807 |         o.complete(); | 
| 1808 |     } | 
| 1809 |   | 
| 1810 |     /** | 
| 1811 |      * Tries to complete lexically enclosing classes if c looks like a | 
| 1812 |      * nested class.  This is similar to completeOwners but handles | 
| 1813 |      * the situation when a nested class is accessed directly as it is | 
| 1814 |      * possible with the Tree API or javax.lang.model.*. | 
| 1815 |      */ | 
| 1816 |     private void completeEnclosing(ClassSymbol c) { | 
| 1817 |         if (c.owner.kind == PCK) { | 
| 1818 |             Symbol owner = c.owner; | 
| 1819 |             for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) { | 
| 1820 |                 Symbol encl = owner.members().lookup(name).sym; | 
| 1821 |                 if (encl == null) | 
| 1822 |                     encl = classes.get(TypeSymbol.formFlatName(name, owner)); | 
| 1823 |                 if (encl != null) | 
| 1824 |                     encl.complete(); | 
| 1825 |             } | 
| 1826 |         } | 
| 1827 |     } | 
| 1828 |   | 
| 1829 |     /** We can only read a single class file at a time; this | 
| 1830 |      *  flag keeps track of when we are currently reading a class | 
| 1831 |      *  file. | 
| 1832 |      */ | 
| 1833 |     private boolean filling = false; | 
| 1834 |   | 
| 1835 |     /** Fill in definition of class `c' from corresponding class or | 
| 1836 |      *  source file. | 
| 1837 |      */ | 
| 1838 |     private void fillIn(ClassSymbol c) { | 
| 1839 |         if (completionFailureName == c.fullname) { | 
| 1840 |             throw new CompletionFailure(c, "user-selected completion failure by class name"); | 
| 1841 |         } | 
| 1842 |         currentOwner = c; | 
| 1843 |         JavaFileObject classfile = c.classfile; | 
| 1844 |         if (classfile != null) { | 
| 1845 |             JavaFileObject previousClassFile = currentClassFile; | 
| 1846 |             try { | 
| 1847 |                 assert !filling : | 
| 1848 |                     "Filling " + classfile.toUri() + | 
| 1849 |                     " during " + previousClassFile; | 
| 1850 |                 currentClassFile = classfile; | 
| 1851 |                 if (verbose) { | 
| 1852 |                     printVerbose("loading", currentClassFile.toString()); | 
| 1853 |                 } | 
| 1854 |                 if (classfile.getKind() == JavaFileObject.Kind.CLASS) { | 
| 1855 |                     filling = true; | 
| 1856 |                     try { | 
| 1857 |                         bp = 0; | 
| 1858 |                         buf = readInputStream(buf, classfile.openInputStream()); | 
| 1859 |                         readClassFile(c); | 
| 1860 |                         if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) { | 
| 1861 |                             List<Type> missing = missingTypeVariables; | 
| 1862 |                             List<Type> found = foundTypeVariables; | 
| 1863 |                             missingTypeVariables = List.nil(); | 
| 1864 |                             foundTypeVariables = List.nil(); | 
| 1865 |                             filling = false; | 
| 1866 |                             ClassType ct = (ClassType)currentOwner.type; | 
| 1867 |                             ct.supertype_field = | 
| 1868 |                                 types.subst(ct.supertype_field, missing, found); | 
| 1869 |                             ct.interfaces_field = | 
| 1870 |                                 types.subst(ct.interfaces_field, missing, found); | 
| 1871 |                         } else if (missingTypeVariables.isEmpty() != | 
| 1872 |                                    foundTypeVariables.isEmpty()) { | 
| 1873 |                             Name name = missingTypeVariables.head.tsym.name; | 
| 1874 |                             throw badClassFile("undecl.type.var", name); | 
| 1875 |                         } | 
| 1876 |                     } finally { | 
| 1877 |                         missingTypeVariables = List.nil(); | 
| 1878 |                         foundTypeVariables = List.nil(); | 
| 1879 |                         filling = false; | 
| 1880 |                     } | 
| 1881 |                 } else { | 
| 1882 |                     if (sourceCompleter != null) { | 
| 1883 |                         sourceCompleter.complete(c); | 
| 1884 |                     } else { | 
| 1885 |                         throw new IllegalStateException("Source completer required to read " | 
| 1886 |                                                         + classfile.toUri()); | 
| 1887 |                     } | 
| 1888 |                 } | 
| 1889 |                 return; | 
| 1890 |             } catch (IOException ex) { | 
| 1891 |                 throw badClassFile("unable.to.access.file", ex.getMessage()); | 
| 1892 |             } finally { | 
| 1893 |                 currentClassFile = previousClassFile; | 
| 1894 |             } | 
| 1895 |         } else { | 
| 1896 |             throw | 
| 1897 |                 newCompletionFailure(c, | 
| 1898 |                                      Log.getLocalizedString("class.file.not.found", | 
| 1899 |                                                             c.flatname)); | 
| 1900 |         } | 
| 1901 |     } | 
| 1902 |     // where | 
| 1903 |         private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException { | 
| 1904 |             try { | 
| 1905 |                 buf = ensureCapacity(buf, s.available()); | 
| 1906 |                 int r = s.read(buf); | 
| 1907 |                 int bp = 0; | 
| 1908 |                 while (r != -1) { | 
| 1909 |                     bp += r; | 
| 1910 |                     buf = ensureCapacity(buf, bp); | 
| 1911 |                     r = s.read(buf, bp, buf.length - bp); | 
| 1912 |                 } | 
| 1913 |                 return buf; | 
| 1914 |             } finally { | 
| 1915 |                 try { | 
| 1916 |                     s.close(); | 
| 1917 |                 } catch (IOException e) { | 
| 1918 |                     /* Ignore any errors, as this stream may have already | 
| 1919 |                      * thrown a related exception which is the one that | 
| 1920 |                      * should be reported. | 
| 1921 |                      */ | 
| 1922 |                 } | 
| 1923 |             } | 
| 1924 |         } | 
| 1925 |         private static byte[] ensureCapacity(byte[] buf, int needed) { | 
| 1926 |             if (buf.length < needed) { | 
| 1927 |                 byte[] old = buf; | 
| 1928 |                 buf = new byte[Integer.highestOneBit(needed) << 1]; | 
| 1929 |                 System.arraycopy(old, 0, buf, 0, old.length); | 
| 1930 |             } | 
| 1931 |             return buf; | 
| 1932 |         } | 
| 1933 |         /** Static factory for CompletionFailure objects. | 
| 1934 |          *  In practice, only one can be used at a time, so we share one | 
| 1935 |          *  to reduce the expense of allocating new exception objects. | 
| 1936 |          */ | 
| 1937 |         private CompletionFailure newCompletionFailure(ClassSymbol c, | 
| 1938 |                                                        String localized) { | 
| 1939 |             if (!cacheCompletionFailure) { | 
| 1940 |                 // log.warning("proc.messager", | 
| 1941 |                 //             Log.getLocalizedString("class.file.not.found", c.flatname)); | 
| 1942 |                 // c.debug.printStackTrace(); | 
| 1943 |                 return new CompletionFailure(c, localized); | 
| 1944 |             } else { | 
| 1945 |                 CompletionFailure result = cachedCompletionFailure; | 
| 1946 |                 result.sym = c; | 
| 1947 |                 result.errmsg = localized; | 
| 1948 |                 return result; | 
| 1949 |             } | 
| 1950 |         } | 
| 1951 |         private CompletionFailure cachedCompletionFailure = | 
| 1952 |             new CompletionFailure(null, null); | 
| 1953 |         { | 
| 1954 |             cachedCompletionFailure.setStackTrace(new StackTraceElement[0]); | 
| 1955 |         } | 
| 1956 |   | 
| 1957 |     /** Load a toplevel class with given fully qualified name | 
| 1958 |      *  The class is entered into `classes' only if load was successful. | 
| 1959 |      */ | 
| 1960 |     public ClassSymbol loadClass(Name flatname) throws CompletionFailure { | 
| 1961 |         boolean absent = classes.get(flatname) == null; | 
| 1962 |         ClassSymbol c = enterClass(flatname); | 
| 1963 |         if (c.members_field == null && c.completer != null) { | 
| 1964 |             try { | 
| 1965 |                 c.complete(); | 
| 1966 |             } catch (CompletionFailure ex) { | 
| 1967 |                 if (absent) classes.remove(flatname); | 
| 1968 |                 throw ex; | 
| 1969 |             } | 
| 1970 |         } | 
| 1971 |         return c; | 
| 1972 |     } | 
| 1973 |   | 
| 1974 | /************************************************************************ | 
| 1975 |  * Loading Packages | 
| 1976 |  ***********************************************************************/ | 
| 1977 |   | 
| 1978 |     /** Check to see if a package exists, given its fully qualified name. | 
| 1979 |      */ | 
| 1980 |     public boolean packageExists(Name fullname) { | 
| 1981 |         return enterPackage(fullname).exists(); | 
| 1982 |     } | 
| 1983 |   | 
| 1984 |     /** Make a package, given its fully qualified name. | 
| 1985 |      */ | 
| 1986 |     public PackageSymbol enterPackage(Name fullname) { | 
| 1987 |         PackageSymbol p = packages.get(fullname); | 
| 1988 |         if (p == null) { | 
| 1989 |             assert !fullname.isEmpty() : "rootPackage missing!"; | 
| 1990 |             p = new PackageSymbol( | 
| 1991 |                 Convert.shortName(fullname), | 
| 1992 |                 enterPackage(Convert.packagePart(fullname))); | 
| 1993 |             p.completer = this; | 
| 1994 |             packages.put(fullname, p); | 
| 1995 |         } | 
| 1996 |         return p; | 
| 1997 |     } | 
| 1998 |   | 
| 1999 |     /** Make a package, given its unqualified name and enclosing package. | 
| 2000 |      */ | 
| 2001 |     public PackageSymbol enterPackage(Name name, PackageSymbol owner) { | 
| 2002 |         return enterPackage(TypeSymbol.formFullName(name, owner)); | 
| 2003 |     } | 
| 2004 |   | 
| 2005 |     /** Include class corresponding to given class file in package, | 
| 2006 |      *  unless (1) we already have one the same kind (.class or .java), or | 
| 2007 |      *         (2) we have one of the other kind, and the given class file | 
| 2008 |      *             is older. | 
| 2009 |      */ | 
| 2010 |     protected void includeClassFile(PackageSymbol p, JavaFileObject file) { | 
| 2011 |         if ((p.flags_field & EXISTS) == 0) | 
| 2012 |             for (Symbol q = p; q != null && q.kind == PCK; q = q.owner) | 
| 2013 |                 q.flags_field |= EXISTS; | 
| 2014 |         JavaFileObject.Kind kind = file.getKind(); | 
| 2015 |         int seen; | 
| 2016 |         if (kind == JavaFileObject.Kind.CLASS) | 
| 2017 |             seen = CLASS_SEEN; | 
| 2018 |         else | 
| 2019 |             seen = SOURCE_SEEN; | 
| 2020 |         String binaryName = fileManager.inferBinaryName(currentLoc, file); | 
| 2021 |         int lastDot = binaryName.lastIndexOf("."); | 
| 2022 |         Name classname = names.fromString(binaryName.substring(lastDot + 1)); | 
| 2023 |         boolean isPkgInfo = classname == names.package_info; | 
| 2024 |         ClassSymbol c = isPkgInfo | 
| 2025 |             ? p.package_info | 
| 2026 |             : (ClassSymbol) p.members_field.lookup(classname).sym; | 
| 2027 |         if (c == null) { | 
| 2028 |             c = enterClass(classname, p); | 
| 2029 |             if (c.classfile == null) // only update the file if's it's newly created | 
| 2030 |                 c.classfile = file; | 
| 2031 |             if (isPkgInfo) { | 
| 2032 |                 p.package_info = c; | 
| 2033 |             } else { | 
| 2034 |                 if (c.owner == p)  // it might be an inner class | 
| 2035 |                     p.members_field.enter(c); | 
| 2036 |             } | 
| 2037 |         } else if (c.classfile != null && (c.flags_field & seen) == 0) { | 
| 2038 |             // if c.classfile == null, we are currently compiling this class | 
| 2039 |             // and no further action is necessary. | 
| 2040 |             // if (c.flags_field & seen) != 0, we have already encountered | 
| 2041 |             // a file of the same kind; again no further action is necessary. | 
| 2042 |             if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) | 
| 2043 |                 c.classfile = preferredFileObject(file, c.classfile); | 
| 2044 |         } | 
| 2045 |         c.flags_field |= seen; | 
| 2046 |     } | 
| 2047 |   | 
| 2048 |     /** Implement policy to choose to derive information from a source | 
| 2049 |      *  file or a class file when both are present.  May be overridden | 
| 2050 |      *  by subclasses. | 
| 2051 |      */ | 
| 2052 |     protected JavaFileObject preferredFileObject(JavaFileObject a, | 
| 2053 |                                            JavaFileObject b) { | 
| 2054 |   | 
| 2055 |         if (preferSource) | 
| 2056 |             return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b; | 
| 2057 |         else { | 
| 2058 |             long adate = a.getLastModified(); | 
| 2059 |             long bdate = b.getLastModified(); | 
| 2060 |             // 6449326: policy for bad lastModifiedTime in ClassReader | 
| 2061 |             //assert adate >= 0 && bdate >= 0; | 
| 2062 |             return (adate > bdate) ? a : b; | 
| 2063 |         } | 
| 2064 |     } | 
| 2065 |   | 
| 2066 |     /** | 
| 2067 |      * specifies types of files to be read when filling in a package symbol | 
| 2068 |      */ | 
| 2069 |     protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() { | 
| 2070 |         return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE); | 
| 2071 |     } | 
| 2072 |   | 
| 2073 |     /** | 
| 2074 |      * this is used to support javadoc | 
| 2075 |      */ | 
| 2076 |     protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) { | 
| 2077 |     } | 
| 2078 |   | 
| 2079 |     protected Location currentLoc; // FIXME | 
| 2080 |   | 
| 2081 |     private boolean verbosePath = true; | 
| 2082 |   | 
| 2083 |     /** Load directory of package into members scope. | 
| 2084 |      */ | 
| 2085 |     private void fillIn(PackageSymbol p) throws IOException { | 
| 2086 |         if (p.members_field == null) p.members_field = new Scope(p); | 
| 2087 |         String packageName = p.fullname.toString(); | 
| 2088 |   | 
| 2089 |         Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); | 
| 2090 |   | 
| 2091 |         fillIn(p, PLATFORM_CLASS_PATH, | 
| 2092 |                fileManager.list(PLATFORM_CLASS_PATH, | 
| 2093 |                                 packageName, | 
| 2094 |                                 EnumSet.of(JavaFileObject.Kind.CLASS), | 
| 2095 |                                 false)); | 
| 2096 |   | 
| 2097 |         Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); | 
| 2098 |         classKinds.remove(JavaFileObject.Kind.SOURCE); | 
| 2099 |         boolean wantClassFiles = !classKinds.isEmpty(); | 
| 2100 |   | 
| 2101 |         Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); | 
| 2102 |         sourceKinds.remove(JavaFileObject.Kind.CLASS); | 
| 2103 |         boolean wantSourceFiles = !sourceKinds.isEmpty(); | 
| 2104 |   | 
| 2105 |         boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH); | 
| 2106 |   | 
| 2107 |         if (verbose && verbosePath) { | 
| 2108 |             if (fileManager instanceof StandardJavaFileManager) { | 
| 2109 |                 StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; | 
| 2110 |                 if (haveSourcePath && wantSourceFiles) { | 
| 2111 |                     List<File> path = List.nil(); | 
| 2112 |                     for (File file : fm.getLocation(SOURCE_PATH)) { | 
| 2113 |                         path = path.prepend(file); | 
| 2114 |                     } | 
| 2115 |                     printVerbose("sourcepath", path.reverse().toString()); | 
| 2116 |                 } else if (wantSourceFiles) { | 
| 2117 |                     List<File> path = List.nil(); | 
| 2118 |                     for (File file : fm.getLocation(CLASS_PATH)) { | 
| 2119 |                         path = path.prepend(file); | 
| 2120 |                     } | 
| 2121 |                     printVerbose("sourcepath", path.reverse().toString()); | 
| 2122 |                 } | 
| 2123 |                 if (wantClassFiles) { | 
| 2124 |                     List<File> path = List.nil(); | 
| 2125 |                     for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) { | 
| 2126 |                         path = path.prepend(file); | 
| 2127 |                     } | 
| 2128 |                     for (File file : fm.getLocation(CLASS_PATH)) { | 
| 2129 |                         path = path.prepend(file); | 
| 2130 |                     } | 
| 2131 |                     printVerbose("classpath",  path.reverse().toString()); | 
| 2132 |                 } | 
| 2133 |             } | 
| 2134 |         } | 
| 2135 |   | 
| 2136 |         if (wantSourceFiles && !haveSourcePath) { | 
| 2137 |             fillIn(p, CLASS_PATH, | 
| 2138 |                    fileManager.list(CLASS_PATH, | 
| 2139 |                                     packageName, | 
| 2140 |                                     kinds, | 
| 2141 |                                     false)); | 
| 2142 |         } else { | 
| 2143 |             if (wantClassFiles) | 
| 2144 |                 fillIn(p, CLASS_PATH, | 
| 2145 |                        fileManager.list(CLASS_PATH, | 
| 2146 |                                         packageName, | 
| 2147 |                                         classKinds, | 
| 2148 |                                         false)); | 
| 2149 |             if (wantSourceFiles) | 
| 2150 |                 fillIn(p, SOURCE_PATH, | 
| 2151 |                        fileManager.list(SOURCE_PATH, | 
| 2152 |                                         packageName, | 
| 2153 |                                         sourceKinds, | 
| 2154 |                                         false)); | 
| 2155 |         } | 
| 2156 |         verbosePath = false; | 
| 2157 |     } | 
| 2158 |     // where | 
| 2159 |         private void fillIn(PackageSymbol p, | 
| 2160 |                             Location location, | 
| 2161 |                             Iterable<JavaFileObject> files) | 
| 2162 |         { | 
| 2163 |             currentLoc = location; | 
| 2164 |             for (JavaFileObject fo : files) { | 
| 2165 |                 switch (fo.getKind()) { | 
| 2166 |                 case CLASS: | 
| 2167 |                 case SOURCE: { | 
| 2168 |                     // TODO pass binaryName to includeClassFile | 
| 2169 |                     String binaryName = fileManager.inferBinaryName(currentLoc, fo); | 
| 2170 |                     String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); | 
| 2171 |                     if (SourceVersion.isIdentifier(simpleName) || | 
| 2172 |                         simpleName.equals("package-info")) | 
| 2173 |                         includeClassFile(p, fo); | 
| 2174 |                     break; | 
| 2175 |                 } | 
| 2176 |                 default: | 
| 2177 |                     extraFileActions(p, fo); | 
| 2178 |                 } | 
| 2179 |             } | 
| 2180 |         } | 
| 2181 |   | 
| 2182 |     /** Output for "-verbose" option. | 
| 2183 |      *  @param key The key to look up the correct internationalized string. | 
| 2184 |      *  @param arg An argument for substitution into the output string. | 
| 2185 |      */ | 
| 2186 |     private void printVerbose(String key, CharSequence arg) { | 
| 2187 |         Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg)); | 
| 2188 |     } | 
| 2189 |   | 
| 2190 |     /** Output for "-checkclassfile" option. | 
| 2191 |      *  @param key The key to look up the correct internationalized string. | 
| 2192 |      *  @param arg An argument for substitution into the output string. | 
| 2193 |      */ | 
| 2194 |     private void printCCF(String key, Object arg) { | 
| 2195 |         Log.printLines(log.noticeWriter, Log.getLocalizedString(key, arg)); | 
| 2196 |     } | 
| 2197 |   | 
| 2198 |   | 
| 2199 |     public interface SourceCompleter { | 
| 2200 |         void complete(ClassSymbol sym) | 
| 2201 |             throws CompletionFailure; | 
| 2202 |     } | 
| 2203 |   | 
| 2204 |     /** | 
| 2205 |      * A subclass of JavaFileObject for the sourcefile attribute found in a classfile. | 
| 2206 |      * The attribute is only the last component of the original filename, so is unlikely | 
| 2207 |      * to be valid as is, so operations other than those to access the name throw | 
| 2208 |      * UnsupportedOperationException | 
| 2209 |      */ | 
| 2210 |     private static class SourceFileObject extends BaseFileObject { | 
| 2211 |   | 
| 2212 |         /** The file's name. | 
| 2213 |          */ | 
| 2214 |         private Name name; | 
| 2215 |   | 
| 2216 |         public SourceFileObject(Name name) { | 
| 2217 |             this.name = name; | 
| 2218 |         } | 
| 2219 |   | 
| 2220 |         public InputStream openInputStream() { | 
| 2221 |             throw new UnsupportedOperationException(); | 
| 2222 |         } | 
| 2223 |   | 
| 2224 |         public OutputStream openOutputStream() { | 
| 2225 |             throw new UnsupportedOperationException(); | 
| 2226 |         } | 
| 2227 |   | 
| 2228 |         public Reader openReader() { | 
| 2229 |             throw new UnsupportedOperationException(); | 
| 2230 |         } | 
| 2231 |   | 
| 2232 |         public Writer openWriter() { | 
| 2233 |             throw new UnsupportedOperationException(); | 
| 2234 |         } | 
| 2235 |   | 
| 2236 |         /** @deprecated see bug 6410637 */ | 
| 2237 |         @Deprecated | 
| 2238 |         public String getName() { | 
| 2239 |             return name.toString(); | 
| 2240 |         } | 
| 2241 |   | 
| 2242 |         public long getLastModified() { | 
| 2243 |             throw new UnsupportedOperationException(); | 
| 2244 |         } | 
| 2245 |   | 
| 2246 |         public boolean delete() { | 
| 2247 |             throw new UnsupportedOperationException(); | 
| 2248 |         } | 
| 2249 |   | 
| 2250 |         public CharBuffer getCharContent(boolean ignoreEncodingErrors) { | 
| 2251 |             throw new UnsupportedOperationException(); | 
| 2252 |         } | 
| 2253 |   | 
| 2254 |         @Override | 
| 2255 |         public boolean equals(Object other) { | 
| 2256 |             if (!(other instanceof SourceFileObject)) | 
| 2257 |                 return false; | 
| 2258 |             SourceFileObject o = (SourceFileObject) other; | 
| 2259 |             return name.equals(o.name); | 
| 2260 |         } | 
| 2261 |   | 
| 2262 |         @Override | 
| 2263 |         public int hashCode() { | 
| 2264 |             return name.hashCode(); | 
| 2265 |         } | 
| 2266 |   | 
| 2267 |         public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) { | 
| 2268 |             return true; // fail-safe mode | 
| 2269 |         } | 
| 2270 |   | 
| 2271 |         public URI toUri() { | 
| 2272 |             return URI.create(name.toString()); | 
| 2273 |         } | 
| 2274 |   | 
| 2275 |         public Reader openReader(boolean ignoreEncodingErrors) throws IOException { | 
| 2276 |             throw new UnsupportedOperationException(); | 
| 2277 |         } | 
| 2278 |   | 
| 2279 |     } | 
| 2280 | } |