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