src/share/classes/com/sun/tools/javac/jvm/ClassReader.java

Sat, 01 Dec 2007 00:00:00 +0000

author
duke
date
Sat, 01 Dec 2007 00:00:00 +0000
changeset 1
9a66ca7c79fa
child 12
7366066839bb
permissions
-rw-r--r--

Initial load

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

mercurial