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