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