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 }