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