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