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