Sun, 04 Nov 2012 10:59:42 +0000
7192246: Add type-checking support for default methods
Summary: Add type-checking support for default methods as per Featherweight-Defender document
Reviewed-by: jjg, dlsmith
1 /*
2 * Copyright (c) 1999, 2012, 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.TypeTag.CLASS;
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.Option.*;
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;
118 /** Switch: allow default methods
119 */
120 boolean allowDefaultMethods;
122 /** Switch: preserve parameter names from the variable table.
123 */
124 public boolean saveParameterNames;
126 /**
127 * Switch: cache completion failures unless -XDdev is used
128 */
129 private boolean cacheCompletionFailure;
131 /**
132 * Switch: prefer source files instead of newer when both source
133 * and class are available
134 **/
135 public boolean preferSource;
137 /** The log to use for verbose output
138 */
139 final Log log;
141 /** The symbol table. */
142 Symtab syms;
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 protected 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 /** A table to hold the constant pool indices for method parameter
211 * names, as given in LocalVariableTable attributes.
212 */
213 int[] parameterNameIndices;
215 /**
216 * Whether or not any parameter names have been found.
217 */
218 boolean haveParameterNameIndices;
220 /**
221 * The set of attribute names for which warnings have been generated for the current class
222 */
223 Set<Name> warnedAttrs = new HashSet<Name>();
225 /** Get the ClassReader instance for this invocation. */
226 public static ClassReader instance(Context context) {
227 ClassReader instance = context.get(classReaderKey);
228 if (instance == null)
229 instance = new ClassReader(context, true);
230 return instance;
231 }
233 /** Initialize classes and packages, treating this as the definitive classreader. */
234 public void init(Symtab syms) {
235 init(syms, true);
236 }
238 /** Initialize classes and packages, optionally treating this as
239 * the definitive classreader.
240 */
241 private void init(Symtab syms, boolean definitive) {
242 if (classes != null) return;
244 if (definitive) {
245 Assert.check(packages == null || packages == syms.packages);
246 packages = syms.packages;
247 Assert.check(classes == null || classes == syms.classes);
248 classes = syms.classes;
249 } else {
250 packages = new HashMap<Name, PackageSymbol>();
251 classes = new HashMap<Name, ClassSymbol>();
252 }
254 packages.put(names.empty, syms.rootPackage);
255 syms.rootPackage.completer = this;
256 syms.unnamedPackage.completer = this;
257 }
259 /** Construct a new class reader, optionally treated as the
260 * definitive classreader for this invocation.
261 */
262 protected ClassReader(Context context, boolean definitive) {
263 if (definitive) context.put(classReaderKey, this);
265 names = Names.instance(context);
266 syms = Symtab.instance(context);
267 types = Types.instance(context);
268 fileManager = context.get(JavaFileManager.class);
269 if (fileManager == null)
270 throw new AssertionError("FileManager initialization error");
271 diagFactory = JCDiagnostic.Factory.instance(context);
273 init(syms, definitive);
274 log = Log.instance(context);
276 Options options = Options.instance(context);
277 annotate = Annotate.instance(context);
278 verbose = options.isSet(VERBOSE);
279 checkClassFile = options.isSet("-checkclassfile");
280 Source source = Source.instance(context);
281 allowGenerics = source.allowGenerics();
282 allowVarargs = source.allowVarargs();
283 allowAnnotations = source.allowAnnotations();
284 allowSimplifiedVarargs = source.allowSimplifiedVarargs();
285 allowDefaultMethods = source.allowDefaultMethods();
286 saveParameterNames = options.isSet("save-parameter-names");
287 cacheCompletionFailure = options.isUnset("dev");
288 preferSource = "source".equals(options.get("-Xprefer"));
290 completionFailureName =
291 options.isSet("failcomplete")
292 ? names.fromString(options.get("failcomplete"))
293 : null;
295 typevars = new Scope(syms.noSymbol);
297 lintClassfile = Lint.instance(context).isEnabled(LintCategory.CLASSFILE);
299 initAttributeReaders();
300 }
302 /** Add member to class unless it is synthetic.
303 */
304 private void enterMember(ClassSymbol c, Symbol sym) {
305 if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC)
306 c.members_field.enter(sym);
307 }
309 /************************************************************************
310 * Error Diagnoses
311 ***********************************************************************/
314 public class BadClassFile extends CompletionFailure {
315 private static final long serialVersionUID = 0;
317 public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag) {
318 super(sym, createBadClassFileDiagnostic(file, diag));
319 }
320 }
321 // where
322 private JCDiagnostic createBadClassFileDiagnostic(JavaFileObject file, JCDiagnostic diag) {
323 String key = (file.getKind() == JavaFileObject.Kind.SOURCE
324 ? "bad.source.file.header" : "bad.class.file.header");
325 return diagFactory.fragment(key, file, diag);
326 }
328 public BadClassFile badClassFile(String key, Object... args) {
329 return new BadClassFile (
330 currentOwner.enclClass(),
331 currentClassFile,
332 diagFactory.fragment(key, args));
333 }
335 /************************************************************************
336 * Buffer Access
337 ***********************************************************************/
339 /** Read a character.
340 */
341 char nextChar() {
342 return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
343 }
345 /** Read a byte.
346 */
347 byte nextByte() {
348 return buf[bp++];
349 }
351 /** Read an integer.
352 */
353 int nextInt() {
354 return
355 ((buf[bp++] & 0xFF) << 24) +
356 ((buf[bp++] & 0xFF) << 16) +
357 ((buf[bp++] & 0xFF) << 8) +
358 (buf[bp++] & 0xFF);
359 }
361 /** Extract a character at position bp from buf.
362 */
363 char getChar(int bp) {
364 return
365 (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
366 }
368 /** Extract an integer at position bp from buf.
369 */
370 int getInt(int bp) {
371 return
372 ((buf[bp] & 0xFF) << 24) +
373 ((buf[bp+1] & 0xFF) << 16) +
374 ((buf[bp+2] & 0xFF) << 8) +
375 (buf[bp+3] & 0xFF);
376 }
379 /** Extract a long integer at position bp from buf.
380 */
381 long getLong(int bp) {
382 DataInputStream bufin =
383 new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
384 try {
385 return bufin.readLong();
386 } catch (IOException e) {
387 throw new AssertionError(e);
388 }
389 }
391 /** Extract a float at position bp from buf.
392 */
393 float getFloat(int bp) {
394 DataInputStream bufin =
395 new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
396 try {
397 return bufin.readFloat();
398 } catch (IOException e) {
399 throw new AssertionError(e);
400 }
401 }
403 /** Extract a double at position bp from buf.
404 */
405 double getDouble(int bp) {
406 DataInputStream bufin =
407 new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
408 try {
409 return bufin.readDouble();
410 } catch (IOException e) {
411 throw new AssertionError(e);
412 }
413 }
415 /************************************************************************
416 * Constant Pool Access
417 ***********************************************************************/
419 /** Index all constant pool entries, writing their start addresses into
420 * poolIdx.
421 */
422 void indexPool() {
423 poolIdx = new int[nextChar()];
424 poolObj = new Object[poolIdx.length];
425 int i = 1;
426 while (i < poolIdx.length) {
427 poolIdx[i++] = bp;
428 byte tag = buf[bp++];
429 switch (tag) {
430 case CONSTANT_Utf8: case CONSTANT_Unicode: {
431 int len = nextChar();
432 bp = bp + len;
433 break;
434 }
435 case CONSTANT_Class:
436 case CONSTANT_String:
437 case CONSTANT_MethodType:
438 bp = bp + 2;
439 break;
440 case CONSTANT_MethodHandle:
441 bp = bp + 3;
442 break;
443 case CONSTANT_Fieldref:
444 case CONSTANT_Methodref:
445 case CONSTANT_InterfaceMethodref:
446 case CONSTANT_NameandType:
447 case CONSTANT_Integer:
448 case CONSTANT_Float:
449 case CONSTANT_InvokeDynamic:
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 case CONSTANT_MethodHandle:
519 skipBytes(4);
520 break;
521 case CONSTANT_MethodType:
522 skipBytes(3);
523 break;
524 case CONSTANT_InvokeDynamic:
525 skipBytes(5);
526 break;
527 default:
528 throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
529 }
530 return poolObj[i];
531 }
533 /** Read signature and convert to type.
534 */
535 Type readType(int i) {
536 int index = poolIdx[i];
537 return sigToType(buf, index + 3, getChar(index + 1));
538 }
540 /** If name is an array type or class signature, return the
541 * corresponding type; otherwise return a ClassSymbol with given name.
542 */
543 Object readClassOrType(int i) {
544 int index = poolIdx[i];
545 int len = getChar(index + 1);
546 int start = index + 3;
547 Assert.check(buf[start] == '[' || buf[start + len - 1] != ';');
548 // by the above assertion, the following test can be
549 // simplified to (buf[start] == '[')
550 return (buf[start] == '[' || buf[start + len - 1] == ';')
551 ? (Object)sigToType(buf, start, len)
552 : (Object)enterClass(names.fromUtf(internalize(buf, start,
553 len)));
554 }
556 /** Read signature and convert to type parameters.
557 */
558 List<Type> readTypeParams(int i) {
559 int index = poolIdx[i];
560 return sigToTypeParams(buf, index + 3, getChar(index + 1));
561 }
563 /** Read class entry.
564 */
565 ClassSymbol readClassSymbol(int i) {
566 return (ClassSymbol) (readPool(i));
567 }
569 /** Read name.
570 */
571 Name readName(int i) {
572 return (Name) (readPool(i));
573 }
575 /************************************************************************
576 * Reading Types
577 ***********************************************************************/
579 /** The unread portion of the currently read type is
580 * signature[sigp..siglimit-1].
581 */
582 byte[] signature;
583 int sigp;
584 int siglimit;
585 boolean sigEnterPhase = false;
587 /** Convert signature to type, where signature is a byte array segment.
588 */
589 Type sigToType(byte[] sig, int offset, int len) {
590 signature = sig;
591 sigp = offset;
592 siglimit = offset + len;
593 return sigToType();
594 }
596 /** Convert signature to type, where signature is implicit.
597 */
598 Type sigToType() {
599 switch ((char) signature[sigp]) {
600 case 'T':
601 sigp++;
602 int start = sigp;
603 while (signature[sigp] != ';') sigp++;
604 sigp++;
605 return sigEnterPhase
606 ? Type.noType
607 : findTypeVar(names.fromUtf(signature, start, sigp - 1 - start));
608 case '+': {
609 sigp++;
610 Type t = sigToType();
611 return new WildcardType(t, BoundKind.EXTENDS,
612 syms.boundClass);
613 }
614 case '*':
615 sigp++;
616 return new WildcardType(syms.objectType, BoundKind.UNBOUND,
617 syms.boundClass);
618 case '-': {
619 sigp++;
620 Type t = sigToType();
621 return new WildcardType(t, BoundKind.SUPER,
622 syms.boundClass);
623 }
624 case 'B':
625 sigp++;
626 return syms.byteType;
627 case 'C':
628 sigp++;
629 return syms.charType;
630 case 'D':
631 sigp++;
632 return syms.doubleType;
633 case 'F':
634 sigp++;
635 return syms.floatType;
636 case 'I':
637 sigp++;
638 return syms.intType;
639 case 'J':
640 sigp++;
641 return syms.longType;
642 case 'L':
643 {
644 // int oldsigp = sigp;
645 Type t = classSigToType();
646 if (sigp < siglimit && signature[sigp] == '.')
647 throw badClassFile("deprecated inner class signature syntax " +
648 "(please recompile from source)");
649 /*
650 System.err.println(" decoded " +
651 new String(signature, oldsigp, sigp-oldsigp) +
652 " => " + t + " outer " + t.outer());
653 */
654 return t;
655 }
656 case 'S':
657 sigp++;
658 return syms.shortType;
659 case 'V':
660 sigp++;
661 return syms.voidType;
662 case 'Z':
663 sigp++;
664 return syms.booleanType;
665 case '[':
666 sigp++;
667 return new ArrayType(sigToType(), syms.arrayClass);
668 case '(':
669 sigp++;
670 List<Type> argtypes = sigToTypes(')');
671 Type restype = sigToType();
672 List<Type> thrown = List.nil();
673 while (signature[sigp] == '^') {
674 sigp++;
675 thrown = thrown.prepend(sigToType());
676 }
677 return new MethodType(argtypes,
678 restype,
679 thrown.reverse(),
680 syms.methodClass);
681 case '<':
682 typevars = typevars.dup(currentOwner);
683 Type poly = new ForAll(sigToTypeParams(), sigToType());
684 typevars = typevars.leave();
685 return poly;
686 default:
687 throw badClassFile("bad.signature",
688 Convert.utf2string(signature, sigp, 10));
689 }
690 }
692 byte[] signatureBuffer = new byte[0];
693 int sbp = 0;
694 /** Convert class signature to type, where signature is implicit.
695 */
696 Type classSigToType() {
697 if (signature[sigp] != 'L')
698 throw badClassFile("bad.class.signature",
699 Convert.utf2string(signature, sigp, 10));
700 sigp++;
701 Type outer = Type.noType;
702 int startSbp = sbp;
704 while (true) {
705 final byte c = signature[sigp++];
706 switch (c) {
708 case ';': { // end
709 ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
710 startSbp,
711 sbp - startSbp));
712 if (outer == Type.noType)
713 outer = t.erasure(types);
714 else
715 outer = new ClassType(outer, List.<Type>nil(), t);
716 sbp = startSbp;
717 return outer;
718 }
720 case '<': // generic arguments
721 ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
722 startSbp,
723 sbp - startSbp));
724 outer = new ClassType(outer, sigToTypes('>'), t) {
725 boolean completed = false;
726 @Override
727 public Type getEnclosingType() {
728 if (!completed) {
729 completed = true;
730 tsym.complete();
731 Type enclosingType = tsym.type.getEnclosingType();
732 if (enclosingType != Type.noType) {
733 List<Type> typeArgs =
734 super.getEnclosingType().allparams();
735 List<Type> typeParams =
736 enclosingType.allparams();
737 if (typeParams.length() != typeArgs.length()) {
738 // no "rare" types
739 super.setEnclosingType(types.erasure(enclosingType));
740 } else {
741 super.setEnclosingType(types.subst(enclosingType,
742 typeParams,
743 typeArgs));
744 }
745 } else {
746 super.setEnclosingType(Type.noType);
747 }
748 }
749 return super.getEnclosingType();
750 }
751 @Override
752 public void setEnclosingType(Type outer) {
753 throw new UnsupportedOperationException();
754 }
755 };
756 switch (signature[sigp++]) {
757 case ';':
758 if (sigp < signature.length && signature[sigp] == '.') {
759 // support old-style GJC signatures
760 // The signature produced was
761 // Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>;
762 // rather than say
763 // Lfoo/Outer<Lfoo/X;>.Inner<Lfoo/Y;>;
764 // so we skip past ".Lfoo/Outer$"
765 sigp += (sbp - startSbp) + // "foo/Outer"
766 3; // ".L" and "$"
767 signatureBuffer[sbp++] = (byte)'$';
768 break;
769 } else {
770 sbp = startSbp;
771 return outer;
772 }
773 case '.':
774 signatureBuffer[sbp++] = (byte)'$';
775 break;
776 default:
777 throw new AssertionError(signature[sigp-1]);
778 }
779 continue;
781 case '.':
782 signatureBuffer[sbp++] = (byte)'$';
783 continue;
784 case '/':
785 signatureBuffer[sbp++] = (byte)'.';
786 continue;
787 default:
788 signatureBuffer[sbp++] = c;
789 continue;
790 }
791 }
792 }
794 /** Convert (implicit) signature to list of types
795 * until `terminator' is encountered.
796 */
797 List<Type> sigToTypes(char terminator) {
798 List<Type> head = List.of(null);
799 List<Type> tail = head;
800 while (signature[sigp] != terminator)
801 tail = tail.setTail(List.of(sigToType()));
802 sigp++;
803 return head.tail;
804 }
806 /** Convert signature to type parameters, where signature is a byte
807 * array segment.
808 */
809 List<Type> sigToTypeParams(byte[] sig, int offset, int len) {
810 signature = sig;
811 sigp = offset;
812 siglimit = offset + len;
813 return sigToTypeParams();
814 }
816 /** Convert signature to type parameters, where signature is implicit.
817 */
818 List<Type> sigToTypeParams() {
819 List<Type> tvars = List.nil();
820 if (signature[sigp] == '<') {
821 sigp++;
822 int start = sigp;
823 sigEnterPhase = true;
824 while (signature[sigp] != '>')
825 tvars = tvars.prepend(sigToTypeParam());
826 sigEnterPhase = false;
827 sigp = start;
828 while (signature[sigp] != '>')
829 sigToTypeParam();
830 sigp++;
831 }
832 return tvars.reverse();
833 }
835 /** Convert (implicit) signature to type parameter.
836 */
837 Type sigToTypeParam() {
838 int start = sigp;
839 while (signature[sigp] != ':') sigp++;
840 Name name = names.fromUtf(signature, start, sigp - start);
841 TypeVar tvar;
842 if (sigEnterPhase) {
843 tvar = new TypeVar(name, currentOwner, syms.botType);
844 typevars.enter(tvar.tsym);
845 } else {
846 tvar = (TypeVar)findTypeVar(name);
847 }
848 List<Type> bounds = List.nil();
849 Type st = null;
850 if (signature[sigp] == ':' && signature[sigp+1] == ':') {
851 sigp++;
852 st = syms.objectType;
853 }
854 while (signature[sigp] == ':') {
855 sigp++;
856 bounds = bounds.prepend(sigToType());
857 }
858 if (!sigEnterPhase) {
859 types.setBounds(tvar, bounds.reverse(), st);
860 }
861 return tvar;
862 }
864 /** Find type variable with given name in `typevars' scope.
865 */
866 Type findTypeVar(Name name) {
867 Scope.Entry e = typevars.lookup(name);
868 if (e.scope != null) {
869 return e.sym.type;
870 } else {
871 if (readingClassAttr) {
872 // While reading the class attribute, the supertypes
873 // might refer to a type variable from an enclosing element
874 // (method or class).
875 // If the type variable is defined in the enclosing class,
876 // we can actually find it in
877 // currentOwner.owner.type.getTypeArguments()
878 // However, until we have read the enclosing method attribute
879 // we don't know for sure if this owner is correct. It could
880 // be a method and there is no way to tell before reading the
881 // enclosing method attribute.
882 TypeVar t = new TypeVar(name, currentOwner, syms.botType);
883 missingTypeVariables = missingTypeVariables.prepend(t);
884 // System.err.println("Missing type var " + name);
885 return t;
886 }
887 throw badClassFile("undecl.type.var", name);
888 }
889 }
891 /************************************************************************
892 * Reading Attributes
893 ***********************************************************************/
895 protected enum AttributeKind { CLASS, MEMBER };
896 protected abstract class AttributeReader {
897 protected AttributeReader(Name name, ClassFile.Version version, Set<AttributeKind> kinds) {
898 this.name = name;
899 this.version = version;
900 this.kinds = kinds;
901 }
903 protected boolean accepts(AttributeKind kind) {
904 if (kinds.contains(kind)) {
905 if (majorVersion > version.major || (majorVersion == version.major && minorVersion >= version.minor))
906 return true;
908 if (lintClassfile && !warnedAttrs.contains(name)) {
909 JavaFileObject prev = log.useSource(currentClassFile);
910 try {
911 log.warning(LintCategory.CLASSFILE, (DiagnosticPosition) null, "future.attr",
912 name, version.major, version.minor, majorVersion, minorVersion);
913 } finally {
914 log.useSource(prev);
915 }
916 warnedAttrs.add(name);
917 }
918 }
919 return false;
920 }
922 protected abstract void read(Symbol sym, int attrLen);
924 protected final Name name;
925 protected final ClassFile.Version version;
926 protected final Set<AttributeKind> kinds;
927 }
929 protected Set<AttributeKind> CLASS_ATTRIBUTE =
930 EnumSet.of(AttributeKind.CLASS);
931 protected Set<AttributeKind> MEMBER_ATTRIBUTE =
932 EnumSet.of(AttributeKind.MEMBER);
933 protected Set<AttributeKind> CLASS_OR_MEMBER_ATTRIBUTE =
934 EnumSet.of(AttributeKind.CLASS, AttributeKind.MEMBER);
936 protected Map<Name, AttributeReader> attributeReaders = new HashMap<Name, AttributeReader>();
938 private void initAttributeReaders() {
939 AttributeReader[] readers = {
940 // v45.3 attributes
942 new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
943 protected void read(Symbol sym, int attrLen) {
944 if (currentOwner.isInterface() &&
945 (sym.flags_field & ABSTRACT) == 0 && !name.equals(names.clinit)) {
946 if (majorVersion > Target.JDK1_8.majorVersion ||
947 //todo replace with Target.Version when available
948 (majorVersion == Target.JDK1_8.majorVersion && minorVersion >= Target.JDK1_8.minorVersion)) {
949 currentOwner.flags_field |= DEFAULT;
950 sym.flags_field |= DEFAULT | ABSTRACT;
951 } else {
952 //protect against ill-formed classfiles
953 throw new CompletionFailure(currentOwner, "default method found in pre JDK 8 classfile");
954 }
955 }
956 if (readAllOfClassFile || saveParameterNames)
957 ((MethodSymbol)sym).code = readCode(sym);
958 else
959 bp = bp + attrLen;
960 }
961 },
963 new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
964 protected void read(Symbol sym, int attrLen) {
965 Object v = readPool(nextChar());
966 // Ignore ConstantValue attribute if field not final.
967 if ((sym.flags() & FINAL) != 0)
968 ((VarSymbol) sym).setData(v);
969 }
970 },
972 new AttributeReader(names.Deprecated, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
973 protected void read(Symbol sym, int attrLen) {
974 sym.flags_field |= DEPRECATED;
975 }
976 },
978 new AttributeReader(names.Exceptions, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
979 protected void read(Symbol sym, int attrLen) {
980 int nexceptions = nextChar();
981 List<Type> thrown = List.nil();
982 for (int j = 0; j < nexceptions; j++)
983 thrown = thrown.prepend(readClassSymbol(nextChar()).type);
984 if (sym.type.getThrownTypes().isEmpty())
985 sym.type.asMethodType().thrown = thrown.reverse();
986 }
987 },
989 new AttributeReader(names.InnerClasses, V45_3, CLASS_ATTRIBUTE) {
990 protected void read(Symbol sym, int attrLen) {
991 ClassSymbol c = (ClassSymbol) sym;
992 readInnerClasses(c);
993 }
994 },
996 new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
997 protected void read(Symbol sym, int attrLen) {
998 int newbp = bp + attrLen;
999 if (saveParameterNames) {
1000 // Pick up parameter names from the variable table.
1001 // Parameter names are not explicitly identified as such,
1002 // but all parameter name entries in the LocalVariableTable
1003 // have a start_pc of 0. Therefore, we record the name
1004 // indicies of all slots with a start_pc of zero in the
1005 // parameterNameIndicies array.
1006 // Note that this implicitly honors the JVMS spec that
1007 // there may be more than one LocalVariableTable, and that
1008 // there is no specified ordering for the entries.
1009 int numEntries = nextChar();
1010 for (int i = 0; i < numEntries; i++) {
1011 int start_pc = nextChar();
1012 int length = nextChar();
1013 int nameIndex = nextChar();
1014 int sigIndex = nextChar();
1015 int register = nextChar();
1016 if (start_pc == 0) {
1017 // ensure array large enough
1018 if (register >= parameterNameIndices.length) {
1019 int newSize = Math.max(register, parameterNameIndices.length + 8);
1020 parameterNameIndices =
1021 Arrays.copyOf(parameterNameIndices, newSize);
1022 }
1023 parameterNameIndices[register] = nameIndex;
1024 haveParameterNameIndices = true;
1025 }
1026 }
1027 }
1028 bp = newbp;
1029 }
1030 },
1032 new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
1033 protected void read(Symbol sym, int attrLen) {
1034 ClassSymbol c = (ClassSymbol) sym;
1035 Name n = readName(nextChar());
1036 c.sourcefile = new SourceFileObject(n, c.flatname);
1037 // If the class is a toplevel class, originating from a Java source file,
1038 // but the class name does not match the file name, then it is
1039 // an auxiliary class.
1040 String sn = n.toString();
1041 if (c.owner.kind == Kinds.PCK &&
1042 sn.endsWith(".java") &&
1043 !sn.equals(c.name.toString()+".java")) {
1044 c.flags_field |= AUXILIARY;
1045 }
1046 }
1047 },
1049 new AttributeReader(names.Synthetic, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
1050 protected void read(Symbol sym, int attrLen) {
1051 // bridge methods are visible when generics not enabled
1052 if (allowGenerics || (sym.flags_field & BRIDGE) == 0)
1053 sym.flags_field |= SYNTHETIC;
1054 }
1055 },
1057 // standard v49 attributes
1059 new AttributeReader(names.EnclosingMethod, V49, CLASS_ATTRIBUTE) {
1060 protected void read(Symbol sym, int attrLen) {
1061 int newbp = bp + attrLen;
1062 readEnclosingMethodAttr(sym);
1063 bp = newbp;
1064 }
1065 },
1067 new AttributeReader(names.Signature, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1068 @Override
1069 protected boolean accepts(AttributeKind kind) {
1070 return super.accepts(kind) && allowGenerics;
1071 }
1073 protected void read(Symbol sym, int attrLen) {
1074 if (sym.kind == TYP) {
1075 ClassSymbol c = (ClassSymbol) sym;
1076 readingClassAttr = true;
1077 try {
1078 ClassType ct1 = (ClassType)c.type;
1079 Assert.check(c == currentOwner);
1080 ct1.typarams_field = readTypeParams(nextChar());
1081 ct1.supertype_field = sigToType();
1082 ListBuffer<Type> is = new ListBuffer<Type>();
1083 while (sigp != siglimit) is.append(sigToType());
1084 ct1.interfaces_field = is.toList();
1085 } finally {
1086 readingClassAttr = false;
1087 }
1088 } else {
1089 List<Type> thrown = sym.type.getThrownTypes();
1090 sym.type = readType(nextChar());
1091 //- System.err.println(" # " + sym.type);
1092 if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
1093 sym.type.asMethodType().thrown = thrown;
1095 }
1096 }
1097 },
1099 // v49 annotation attributes
1101 new AttributeReader(names.AnnotationDefault, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1102 protected void read(Symbol sym, int attrLen) {
1103 attachAnnotationDefault(sym);
1104 }
1105 },
1107 new AttributeReader(names.RuntimeInvisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1108 protected void read(Symbol sym, int attrLen) {
1109 attachAnnotations(sym);
1110 }
1111 },
1113 new AttributeReader(names.RuntimeInvisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1114 protected void read(Symbol sym, int attrLen) {
1115 attachParameterAnnotations(sym);
1116 }
1117 },
1119 new AttributeReader(names.RuntimeVisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1120 protected void read(Symbol sym, int attrLen) {
1121 attachAnnotations(sym);
1122 }
1123 },
1125 new AttributeReader(names.RuntimeVisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1126 protected void read(Symbol sym, int attrLen) {
1127 attachParameterAnnotations(sym);
1128 }
1129 },
1131 // additional "legacy" v49 attributes, superceded by flags
1133 new AttributeReader(names.Annotation, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1134 protected void read(Symbol sym, int attrLen) {
1135 if (allowAnnotations)
1136 sym.flags_field |= ANNOTATION;
1137 }
1138 },
1140 new AttributeReader(names.Bridge, V49, MEMBER_ATTRIBUTE) {
1141 protected void read(Symbol sym, int attrLen) {
1142 sym.flags_field |= BRIDGE;
1143 if (!allowGenerics)
1144 sym.flags_field &= ~SYNTHETIC;
1145 }
1146 },
1148 new AttributeReader(names.Enum, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1149 protected void read(Symbol sym, int attrLen) {
1150 sym.flags_field |= ENUM;
1151 }
1152 },
1154 new AttributeReader(names.Varargs, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
1155 protected void read(Symbol sym, int attrLen) {
1156 if (allowVarargs)
1157 sym.flags_field |= VARARGS;
1158 }
1159 },
1161 // The following attributes for a Code attribute are not currently handled
1162 // StackMapTable
1163 // SourceDebugExtension
1164 // LineNumberTable
1165 // LocalVariableTypeTable
1166 };
1168 for (AttributeReader r: readers)
1169 attributeReaders.put(r.name, r);
1170 }
1172 /** Report unrecognized attribute.
1173 */
1174 void unrecognized(Name attrName) {
1175 if (checkClassFile)
1176 printCCF("ccf.unrecognized.attribute", attrName);
1177 }
1181 protected void readEnclosingMethodAttr(Symbol sym) {
1182 // sym is a nested class with an "Enclosing Method" attribute
1183 // remove sym from it's current owners scope and place it in
1184 // the scope specified by the attribute
1185 sym.owner.members().remove(sym);
1186 ClassSymbol self = (ClassSymbol)sym;
1187 ClassSymbol c = readClassSymbol(nextChar());
1188 NameAndType nt = (NameAndType)readPool(nextChar());
1190 if (c.members_field == null)
1191 throw badClassFile("bad.enclosing.class", self, c);
1193 MethodSymbol m = findMethod(nt, c.members_field, self.flags());
1194 if (nt != null && m == null)
1195 throw badClassFile("bad.enclosing.method", self);
1197 self.name = simpleBinaryName(self.flatname, c.flatname) ;
1198 self.owner = m != null ? m : c;
1199 if (self.name.isEmpty())
1200 self.fullname = names.empty;
1201 else
1202 self.fullname = ClassSymbol.formFullName(self.name, self.owner);
1204 if (m != null) {
1205 ((ClassType)sym.type).setEnclosingType(m.type);
1206 } else if ((self.flags_field & STATIC) == 0) {
1207 ((ClassType)sym.type).setEnclosingType(c.type);
1208 } else {
1209 ((ClassType)sym.type).setEnclosingType(Type.noType);
1210 }
1211 enterTypevars(self);
1212 if (!missingTypeVariables.isEmpty()) {
1213 ListBuffer<Type> typeVars = new ListBuffer<Type>();
1214 for (Type typevar : missingTypeVariables) {
1215 typeVars.append(findTypeVar(typevar.tsym.name));
1216 }
1217 foundTypeVariables = typeVars.toList();
1218 } else {
1219 foundTypeVariables = List.nil();
1220 }
1221 }
1223 // See java.lang.Class
1224 private Name simpleBinaryName(Name self, Name enclosing) {
1225 String simpleBinaryName = self.toString().substring(enclosing.toString().length());
1226 if (simpleBinaryName.length() < 1 || simpleBinaryName.charAt(0) != '$')
1227 throw badClassFile("bad.enclosing.method", self);
1228 int index = 1;
1229 while (index < simpleBinaryName.length() &&
1230 isAsciiDigit(simpleBinaryName.charAt(index)))
1231 index++;
1232 return names.fromString(simpleBinaryName.substring(index));
1233 }
1235 private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) {
1236 if (nt == null)
1237 return null;
1239 MethodType type = nt.type.asMethodType();
1241 for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next())
1242 if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type))
1243 return (MethodSymbol)e.sym;
1245 if (nt.name != names.init)
1246 // not a constructor
1247 return null;
1248 if ((flags & INTERFACE) != 0)
1249 // no enclosing instance
1250 return null;
1251 if (nt.type.getParameterTypes().isEmpty())
1252 // no parameters
1253 return null;
1255 // A constructor of an inner class.
1256 // Remove the first argument (the enclosing instance)
1257 nt.type = new MethodType(nt.type.getParameterTypes().tail,
1258 nt.type.getReturnType(),
1259 nt.type.getThrownTypes(),
1260 syms.methodClass);
1261 // Try searching again
1262 return findMethod(nt, scope, flags);
1263 }
1265 /** Similar to Types.isSameType but avoids completion */
1266 private boolean isSameBinaryType(MethodType mt1, MethodType mt2) {
1267 List<Type> types1 = types.erasure(mt1.getParameterTypes())
1268 .prepend(types.erasure(mt1.getReturnType()));
1269 List<Type> types2 = mt2.getParameterTypes().prepend(mt2.getReturnType());
1270 while (!types1.isEmpty() && !types2.isEmpty()) {
1271 if (types1.head.tsym != types2.head.tsym)
1272 return false;
1273 types1 = types1.tail;
1274 types2 = types2.tail;
1275 }
1276 return types1.isEmpty() && types2.isEmpty();
1277 }
1279 /**
1280 * Character.isDigit answers <tt>true</tt> to some non-ascii
1281 * digits. This one does not. <b>copied from java.lang.Class</b>
1282 */
1283 private static boolean isAsciiDigit(char c) {
1284 return '0' <= c && c <= '9';
1285 }
1287 /** Read member attributes.
1288 */
1289 void readMemberAttrs(Symbol sym) {
1290 readAttrs(sym, AttributeKind.MEMBER);
1291 }
1293 void readAttrs(Symbol sym, AttributeKind kind) {
1294 char ac = nextChar();
1295 for (int i = 0; i < ac; i++) {
1296 Name attrName = readName(nextChar());
1297 int attrLen = nextInt();
1298 AttributeReader r = attributeReaders.get(attrName);
1299 if (r != null && r.accepts(kind))
1300 r.read(sym, attrLen);
1301 else {
1302 unrecognized(attrName);
1303 bp = bp + attrLen;
1304 }
1305 }
1306 }
1308 private boolean readingClassAttr = false;
1309 private List<Type> missingTypeVariables = List.nil();
1310 private List<Type> foundTypeVariables = List.nil();
1312 /** Read class attributes.
1313 */
1314 void readClassAttrs(ClassSymbol c) {
1315 readAttrs(c, AttributeKind.CLASS);
1316 }
1318 /** Read code block.
1319 */
1320 Code readCode(Symbol owner) {
1321 nextChar(); // max_stack
1322 nextChar(); // max_locals
1323 final int code_length = nextInt();
1324 bp += code_length;
1325 final char exception_table_length = nextChar();
1326 bp += exception_table_length * 8;
1327 readMemberAttrs(owner);
1328 return null;
1329 }
1331 /************************************************************************
1332 * Reading Java-language annotations
1333 ***********************************************************************/
1335 /** Attach annotations.
1336 */
1337 void attachAnnotations(final Symbol sym) {
1338 int numAttributes = nextChar();
1339 if (numAttributes != 0) {
1340 ListBuffer<CompoundAnnotationProxy> proxies =
1341 new ListBuffer<CompoundAnnotationProxy>();
1342 for (int i = 0; i<numAttributes; i++) {
1343 CompoundAnnotationProxy proxy = readCompoundAnnotation();
1344 if (proxy.type.tsym == syms.proprietaryType.tsym)
1345 sym.flags_field |= PROPRIETARY;
1346 else
1347 proxies.append(proxy);
1348 }
1349 annotate.normal(new AnnotationCompleter(sym, proxies.toList()));
1350 }
1351 }
1353 /** Attach parameter annotations.
1354 */
1355 void attachParameterAnnotations(final Symbol method) {
1356 final MethodSymbol meth = (MethodSymbol)method;
1357 int numParameters = buf[bp++] & 0xFF;
1358 List<VarSymbol> parameters = meth.params();
1359 int pnum = 0;
1360 while (parameters.tail != null) {
1361 attachAnnotations(parameters.head);
1362 parameters = parameters.tail;
1363 pnum++;
1364 }
1365 if (pnum != numParameters) {
1366 throw badClassFile("bad.runtime.invisible.param.annotations", meth);
1367 }
1368 }
1370 /** Attach the default value for an annotation element.
1371 */
1372 void attachAnnotationDefault(final Symbol sym) {
1373 final MethodSymbol meth = (MethodSymbol)sym; // only on methods
1374 final Attribute value = readAttributeValue();
1375 annotate.normal(new AnnotationDefaultCompleter(meth, value));
1376 }
1378 Type readTypeOrClassSymbol(int i) {
1379 // support preliminary jsr175-format class files
1380 if (buf[poolIdx[i]] == CONSTANT_Class)
1381 return readClassSymbol(i).type;
1382 return readType(i);
1383 }
1384 Type readEnumType(int i) {
1385 // support preliminary jsr175-format class files
1386 int index = poolIdx[i];
1387 int length = getChar(index + 1);
1388 if (buf[index + length + 2] != ';')
1389 return enterClass(readName(i)).type;
1390 return readType(i);
1391 }
1393 CompoundAnnotationProxy readCompoundAnnotation() {
1394 Type t = readTypeOrClassSymbol(nextChar());
1395 int numFields = nextChar();
1396 ListBuffer<Pair<Name,Attribute>> pairs =
1397 new ListBuffer<Pair<Name,Attribute>>();
1398 for (int i=0; i<numFields; i++) {
1399 Name name = readName(nextChar());
1400 Attribute value = readAttributeValue();
1401 pairs.append(new Pair<Name,Attribute>(name, value));
1402 }
1403 return new CompoundAnnotationProxy(t, pairs.toList());
1404 }
1406 Attribute readAttributeValue() {
1407 char c = (char) buf[bp++];
1408 switch (c) {
1409 case 'B':
1410 return new Attribute.Constant(syms.byteType, readPool(nextChar()));
1411 case 'C':
1412 return new Attribute.Constant(syms.charType, readPool(nextChar()));
1413 case 'D':
1414 return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
1415 case 'F':
1416 return new Attribute.Constant(syms.floatType, readPool(nextChar()));
1417 case 'I':
1418 return new Attribute.Constant(syms.intType, readPool(nextChar()));
1419 case 'J':
1420 return new Attribute.Constant(syms.longType, readPool(nextChar()));
1421 case 'S':
1422 return new Attribute.Constant(syms.shortType, readPool(nextChar()));
1423 case 'Z':
1424 return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
1425 case 's':
1426 return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
1427 case 'e':
1428 return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
1429 case 'c':
1430 return new Attribute.Class(types, readTypeOrClassSymbol(nextChar()));
1431 case '[': {
1432 int n = nextChar();
1433 ListBuffer<Attribute> l = new ListBuffer<Attribute>();
1434 for (int i=0; i<n; i++)
1435 l.append(readAttributeValue());
1436 return new ArrayAttributeProxy(l.toList());
1437 }
1438 case '@':
1439 return readCompoundAnnotation();
1440 default:
1441 throw new AssertionError("unknown annotation tag '" + c + "'");
1442 }
1443 }
1445 interface ProxyVisitor extends Attribute.Visitor {
1446 void visitEnumAttributeProxy(EnumAttributeProxy proxy);
1447 void visitArrayAttributeProxy(ArrayAttributeProxy proxy);
1448 void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy);
1449 }
1451 static class EnumAttributeProxy extends Attribute {
1452 Type enumType;
1453 Name enumerator;
1454 public EnumAttributeProxy(Type enumType, Name enumerator) {
1455 super(null);
1456 this.enumType = enumType;
1457 this.enumerator = enumerator;
1458 }
1459 public void accept(Visitor v) { ((ProxyVisitor)v).visitEnumAttributeProxy(this); }
1460 @Override
1461 public String toString() {
1462 return "/*proxy enum*/" + enumType + "." + enumerator;
1463 }
1464 }
1466 static class ArrayAttributeProxy extends Attribute {
1467 List<Attribute> values;
1468 ArrayAttributeProxy(List<Attribute> values) {
1469 super(null);
1470 this.values = values;
1471 }
1472 public void accept(Visitor v) { ((ProxyVisitor)v).visitArrayAttributeProxy(this); }
1473 @Override
1474 public String toString() {
1475 return "{" + values + "}";
1476 }
1477 }
1479 /** A temporary proxy representing a compound attribute.
1480 */
1481 static class CompoundAnnotationProxy extends Attribute {
1482 final List<Pair<Name,Attribute>> values;
1483 public CompoundAnnotationProxy(Type type,
1484 List<Pair<Name,Attribute>> values) {
1485 super(type);
1486 this.values = values;
1487 }
1488 public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); }
1489 @Override
1490 public String toString() {
1491 StringBuilder buf = new StringBuilder();
1492 buf.append("@");
1493 buf.append(type.tsym.getQualifiedName());
1494 buf.append("/*proxy*/{");
1495 boolean first = true;
1496 for (List<Pair<Name,Attribute>> v = values;
1497 v.nonEmpty(); v = v.tail) {
1498 Pair<Name,Attribute> value = v.head;
1499 if (!first) buf.append(",");
1500 first = false;
1501 buf.append(value.fst);
1502 buf.append("=");
1503 buf.append(value.snd);
1504 }
1505 buf.append("}");
1506 return buf.toString();
1507 }
1508 }
1510 /** A temporary proxy representing a type annotation.
1511 */
1512 static class TypeAnnotationProxy {
1513 final CompoundAnnotationProxy compound;
1514 final TypeAnnotationPosition position;
1515 public TypeAnnotationProxy(CompoundAnnotationProxy compound,
1516 TypeAnnotationPosition position) {
1517 this.compound = compound;
1518 this.position = position;
1519 }
1520 }
1522 class AnnotationDeproxy implements ProxyVisitor {
1523 private ClassSymbol requestingOwner = currentOwner.kind == MTH
1524 ? currentOwner.enclClass() : (ClassSymbol)currentOwner;
1526 List<Attribute.Compound> deproxyCompoundList(List<CompoundAnnotationProxy> pl) {
1527 // also must fill in types!!!!
1528 ListBuffer<Attribute.Compound> buf =
1529 new ListBuffer<Attribute.Compound>();
1530 for (List<CompoundAnnotationProxy> l = pl; l.nonEmpty(); l=l.tail) {
1531 buf.append(deproxyCompound(l.head));
1532 }
1533 return buf.toList();
1534 }
1536 Attribute.Compound deproxyCompound(CompoundAnnotationProxy a) {
1537 ListBuffer<Pair<Symbol.MethodSymbol,Attribute>> buf =
1538 new ListBuffer<Pair<Symbol.MethodSymbol,Attribute>>();
1539 for (List<Pair<Name,Attribute>> l = a.values;
1540 l.nonEmpty();
1541 l = l.tail) {
1542 MethodSymbol meth = findAccessMethod(a.type, l.head.fst);
1543 buf.append(new Pair<Symbol.MethodSymbol,Attribute>
1544 (meth, deproxy(meth.type.getReturnType(), l.head.snd)));
1545 }
1546 return new Attribute.Compound(a.type, buf.toList());
1547 }
1549 MethodSymbol findAccessMethod(Type container, Name name) {
1550 CompletionFailure failure = null;
1551 try {
1552 for (Scope.Entry e = container.tsym.members().lookup(name);
1553 e.scope != null;
1554 e = e.next()) {
1555 Symbol sym = e.sym;
1556 if (sym.kind == MTH && sym.type.getParameterTypes().length() == 0)
1557 return (MethodSymbol) sym;
1558 }
1559 } catch (CompletionFailure ex) {
1560 failure = ex;
1561 }
1562 // The method wasn't found: emit a warning and recover
1563 JavaFileObject prevSource = log.useSource(requestingOwner.classfile);
1564 try {
1565 if (failure == null) {
1566 log.warning("annotation.method.not.found",
1567 container,
1568 name);
1569 } else {
1570 log.warning("annotation.method.not.found.reason",
1571 container,
1572 name,
1573 failure.getDetailValue());//diagnostic, if present
1574 }
1575 } finally {
1576 log.useSource(prevSource);
1577 }
1578 // Construct a new method type and symbol. Use bottom
1579 // type (typeof null) as return type because this type is
1580 // a subtype of all reference types and can be converted
1581 // to primitive types by unboxing.
1582 MethodType mt = new MethodType(List.<Type>nil(),
1583 syms.botType,
1584 List.<Type>nil(),
1585 syms.methodClass);
1586 return new MethodSymbol(PUBLIC | ABSTRACT, name, mt, container.tsym);
1587 }
1589 Attribute result;
1590 Type type;
1591 Attribute deproxy(Type t, Attribute a) {
1592 Type oldType = type;
1593 try {
1594 type = t;
1595 a.accept(this);
1596 return result;
1597 } finally {
1598 type = oldType;
1599 }
1600 }
1602 // implement Attribute.Visitor below
1604 public void visitConstant(Attribute.Constant value) {
1605 // assert value.type == type;
1606 result = value;
1607 }
1609 public void visitClass(Attribute.Class clazz) {
1610 result = clazz;
1611 }
1613 public void visitEnum(Attribute.Enum e) {
1614 throw new AssertionError(); // shouldn't happen
1615 }
1617 public void visitCompound(Attribute.Compound compound) {
1618 throw new AssertionError(); // shouldn't happen
1619 }
1621 public void visitArray(Attribute.Array array) {
1622 throw new AssertionError(); // shouldn't happen
1623 }
1625 public void visitError(Attribute.Error e) {
1626 throw new AssertionError(); // shouldn't happen
1627 }
1629 public void visitEnumAttributeProxy(EnumAttributeProxy proxy) {
1630 // type.tsym.flatName() should == proxy.enumFlatName
1631 TypeSymbol enumTypeSym = proxy.enumType.tsym;
1632 VarSymbol enumerator = null;
1633 CompletionFailure failure = null;
1634 try {
1635 for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
1636 e.scope != null;
1637 e = e.next()) {
1638 if (e.sym.kind == VAR) {
1639 enumerator = (VarSymbol)e.sym;
1640 break;
1641 }
1642 }
1643 }
1644 catch (CompletionFailure ex) {
1645 failure = ex;
1646 }
1647 if (enumerator == null) {
1648 if (failure != null) {
1649 log.warning("unknown.enum.constant.reason",
1650 currentClassFile, enumTypeSym, proxy.enumerator,
1651 failure.getDiagnostic());
1652 } else {
1653 log.warning("unknown.enum.constant",
1654 currentClassFile, enumTypeSym, proxy.enumerator);
1655 }
1656 result = new Attribute.Enum(enumTypeSym.type,
1657 new VarSymbol(0, proxy.enumerator, syms.botType, enumTypeSym));
1658 } else {
1659 result = new Attribute.Enum(enumTypeSym.type, enumerator);
1660 }
1661 }
1663 public void visitArrayAttributeProxy(ArrayAttributeProxy proxy) {
1664 int length = proxy.values.length();
1665 Attribute[] ats = new Attribute[length];
1666 Type elemtype = types.elemtype(type);
1667 int i = 0;
1668 for (List<Attribute> p = proxy.values; p.nonEmpty(); p = p.tail) {
1669 ats[i++] = deproxy(elemtype, p.head);
1670 }
1671 result = new Attribute.Array(type, ats);
1672 }
1674 public void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy) {
1675 result = deproxyCompound(proxy);
1676 }
1677 }
1679 class AnnotationDefaultCompleter extends AnnotationDeproxy implements Annotate.Annotator {
1680 final MethodSymbol sym;
1681 final Attribute value;
1682 final JavaFileObject classFile = currentClassFile;
1683 @Override
1684 public String toString() {
1685 return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
1686 }
1687 AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) {
1688 this.sym = sym;
1689 this.value = value;
1690 }
1691 // implement Annotate.Annotator.enterAnnotation()
1692 public void enterAnnotation() {
1693 JavaFileObject previousClassFile = currentClassFile;
1694 try {
1695 currentClassFile = classFile;
1696 sym.defaultValue = deproxy(sym.type.getReturnType(), value);
1697 } finally {
1698 currentClassFile = previousClassFile;
1699 }
1700 }
1701 }
1703 class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Annotator {
1704 final Symbol sym;
1705 final List<CompoundAnnotationProxy> l;
1706 final JavaFileObject classFile;
1707 @Override
1708 public String toString() {
1709 return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
1710 }
1711 AnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l) {
1712 this.sym = sym;
1713 this.l = l;
1714 this.classFile = currentClassFile;
1715 }
1716 // implement Annotate.Annotator.enterAnnotation()
1717 public void enterAnnotation() {
1718 JavaFileObject previousClassFile = currentClassFile;
1719 try {
1720 currentClassFile = classFile;
1721 Annotations annotations = sym.annotations;
1722 List<Attribute.Compound> newList = deproxyCompoundList(l);
1723 if (annotations.pendingCompletion()) {
1724 annotations.setAttributes(newList);
1725 } else {
1726 annotations.append(newList);
1727 }
1728 } finally {
1729 currentClassFile = previousClassFile;
1730 }
1731 }
1732 }
1735 /************************************************************************
1736 * Reading Symbols
1737 ***********************************************************************/
1739 /** Read a field.
1740 */
1741 VarSymbol readField() {
1742 long flags = adjustFieldFlags(nextChar());
1743 Name name = readName(nextChar());
1744 Type type = readType(nextChar());
1745 VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
1746 readMemberAttrs(v);
1747 return v;
1748 }
1750 /** Read a method.
1751 */
1752 MethodSymbol readMethod() {
1753 long flags = adjustMethodFlags(nextChar());
1754 Name name = readName(nextChar());
1755 Type type = readType(nextChar());
1756 if (name == names.init && currentOwner.hasOuterInstance()) {
1757 // Sometimes anonymous classes don't have an outer
1758 // instance, however, there is no reliable way to tell so
1759 // we never strip this$n
1760 if (!currentOwner.name.isEmpty())
1761 type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()),
1762 type.getReturnType(),
1763 type.getThrownTypes(),
1764 syms.methodClass);
1765 }
1766 MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner);
1767 if (saveParameterNames)
1768 initParameterNames(m);
1769 Symbol prevOwner = currentOwner;
1770 currentOwner = m;
1771 try {
1772 readMemberAttrs(m);
1773 } finally {
1774 currentOwner = prevOwner;
1775 }
1776 if (saveParameterNames)
1777 setParameterNames(m, type);
1778 return m;
1779 }
1781 private List<Type> adjustMethodParams(long flags, List<Type> args) {
1782 boolean isVarargs = (flags & VARARGS) != 0;
1783 if (isVarargs) {
1784 Type varargsElem = args.last();
1785 ListBuffer<Type> adjustedArgs = ListBuffer.lb();
1786 for (Type t : args) {
1787 adjustedArgs.append(t != varargsElem ?
1788 t :
1789 ((ArrayType)t).makeVarargs());
1790 }
1791 args = adjustedArgs.toList();
1792 }
1793 return args.tail;
1794 }
1796 /**
1797 * Init the parameter names array.
1798 * Parameter names are currently inferred from the names in the
1799 * LocalVariableTable attributes of a Code attribute.
1800 * (Note: this means parameter names are currently not available for
1801 * methods without a Code attribute.)
1802 * This method initializes an array in which to store the name indexes
1803 * of parameter names found in LocalVariableTable attributes. It is
1804 * slightly supersized to allow for additional slots with a start_pc of 0.
1805 */
1806 void initParameterNames(MethodSymbol sym) {
1807 // make allowance for synthetic parameters.
1808 final int excessSlots = 4;
1809 int expectedParameterSlots =
1810 Code.width(sym.type.getParameterTypes()) + excessSlots;
1811 if (parameterNameIndices == null
1812 || parameterNameIndices.length < expectedParameterSlots) {
1813 parameterNameIndices = new int[expectedParameterSlots];
1814 } else
1815 Arrays.fill(parameterNameIndices, 0);
1816 haveParameterNameIndices = false;
1817 }
1819 /**
1820 * Set the parameter names for a symbol from the name index in the
1821 * parameterNameIndicies array. The type of the symbol may have changed
1822 * while reading the method attributes (see the Signature attribute).
1823 * This may be because of generic information or because anonymous
1824 * synthetic parameters were added. The original type (as read from
1825 * the method descriptor) is used to help guess the existence of
1826 * anonymous synthetic parameters.
1827 * On completion, sym.savedParameter names will either be null (if
1828 * no parameter names were found in the class file) or will be set to a
1829 * list of names, one per entry in sym.type.getParameterTypes, with
1830 * any missing names represented by the empty name.
1831 */
1832 void setParameterNames(MethodSymbol sym, Type jvmType) {
1833 // if no names were found in the class file, there's nothing more to do
1834 if (!haveParameterNameIndices)
1835 return;
1837 int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
1838 // the code in readMethod may have skipped the first parameter when
1839 // setting up the MethodType. If so, we make a corresponding allowance
1840 // here for the position of the first parameter. Note that this
1841 // assumes the skipped parameter has a width of 1 -- i.e. it is not
1842 // a double width type (long or double.)
1843 if (sym.name == names.init && currentOwner.hasOuterInstance()) {
1844 // Sometimes anonymous classes don't have an outer
1845 // instance, however, there is no reliable way to tell so
1846 // we never strip this$n
1847 if (!currentOwner.name.isEmpty())
1848 firstParam += 1;
1849 }
1851 if (sym.type != jvmType) {
1852 // reading the method attributes has caused the symbol's type to
1853 // be changed. (i.e. the Signature attribute.) This may happen if
1854 // there are hidden (synthetic) parameters in the descriptor, but
1855 // not in the Signature. The position of these hidden parameters
1856 // is unspecified; for now, assume they are at the beginning, and
1857 // so skip over them. The primary case for this is two hidden
1858 // parameters passed into Enum constructors.
1859 int skip = Code.width(jvmType.getParameterTypes())
1860 - Code.width(sym.type.getParameterTypes());
1861 firstParam += skip;
1862 }
1863 List<Name> paramNames = List.nil();
1864 int index = firstParam;
1865 for (Type t: sym.type.getParameterTypes()) {
1866 int nameIdx = (index < parameterNameIndices.length
1867 ? parameterNameIndices[index] : 0);
1868 Name name = nameIdx == 0 ? names.empty : readName(nameIdx);
1869 paramNames = paramNames.prepend(name);
1870 index += Code.width(t);
1871 }
1872 sym.savedParameterNames = paramNames.reverse();
1873 }
1875 /**
1876 * skip n bytes
1877 */
1878 void skipBytes(int n) {
1879 bp = bp + n;
1880 }
1882 /** Skip a field or method
1883 */
1884 void skipMember() {
1885 bp = bp + 6;
1886 char ac = nextChar();
1887 for (int i = 0; i < ac; i++) {
1888 bp = bp + 2;
1889 int attrLen = nextInt();
1890 bp = bp + attrLen;
1891 }
1892 }
1894 /** Enter type variables of this classtype and all enclosing ones in
1895 * `typevars'.
1896 */
1897 protected void enterTypevars(Type t) {
1898 if (t.getEnclosingType() != null && t.getEnclosingType().hasTag(CLASS))
1899 enterTypevars(t.getEnclosingType());
1900 for (List<Type> xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail)
1901 typevars.enter(xs.head.tsym);
1902 }
1904 protected void enterTypevars(Symbol sym) {
1905 if (sym.owner.kind == MTH) {
1906 enterTypevars(sym.owner);
1907 enterTypevars(sym.owner.owner);
1908 }
1909 enterTypevars(sym.type);
1910 }
1912 /** Read contents of a given class symbol `c'. Both external and internal
1913 * versions of an inner class are read.
1914 */
1915 void readClass(ClassSymbol c) {
1916 ClassType ct = (ClassType)c.type;
1918 // allocate scope for members
1919 c.members_field = new Scope(c);
1921 // prepare type variable table
1922 typevars = typevars.dup(currentOwner);
1923 if (ct.getEnclosingType().hasTag(CLASS))
1924 enterTypevars(ct.getEnclosingType());
1926 // read flags, or skip if this is an inner class
1927 long flags = adjustClassFlags(nextChar());
1928 if (c.owner.kind == PCK) c.flags_field = flags;
1930 // read own class name and check that it matches
1931 ClassSymbol self = readClassSymbol(nextChar());
1932 if (c != self)
1933 throw badClassFile("class.file.wrong.class",
1934 self.flatname);
1936 // class attributes must be read before class
1937 // skip ahead to read class attributes
1938 int startbp = bp;
1939 nextChar();
1940 char interfaceCount = nextChar();
1941 bp += interfaceCount * 2;
1942 char fieldCount = nextChar();
1943 for (int i = 0; i < fieldCount; i++) skipMember();
1944 char methodCount = nextChar();
1945 for (int i = 0; i < methodCount; i++) skipMember();
1946 readClassAttrs(c);
1948 if (readAllOfClassFile) {
1949 for (int i = 1; i < poolObj.length; i++) readPool(i);
1950 c.pool = new Pool(poolObj.length, poolObj);
1951 }
1953 // reset and read rest of classinfo
1954 bp = startbp;
1955 int n = nextChar();
1956 if (ct.supertype_field == null)
1957 ct.supertype_field = (n == 0)
1958 ? Type.noType
1959 : readClassSymbol(n).erasure(types);
1960 n = nextChar();
1961 List<Type> is = List.nil();
1962 for (int i = 0; i < n; i++) {
1963 Type _inter = readClassSymbol(nextChar()).erasure(types);
1964 is = is.prepend(_inter);
1965 }
1966 if (ct.interfaces_field == null)
1967 ct.interfaces_field = is.reverse();
1969 Assert.check(fieldCount == nextChar());
1970 for (int i = 0; i < fieldCount; i++) enterMember(c, readField());
1971 Assert.check(methodCount == nextChar());
1972 for (int i = 0; i < methodCount; i++) enterMember(c, readMethod());
1974 typevars = typevars.leave();
1975 }
1977 /** Read inner class info. For each inner/outer pair allocate a
1978 * member class.
1979 */
1980 void readInnerClasses(ClassSymbol c) {
1981 int n = nextChar();
1982 for (int i = 0; i < n; i++) {
1983 nextChar(); // skip inner class symbol
1984 ClassSymbol outer = readClassSymbol(nextChar());
1985 Name name = readName(nextChar());
1986 if (name == null) name = names.empty;
1987 long flags = adjustClassFlags(nextChar());
1988 if (outer != null) { // we have a member class
1989 if (name == names.empty)
1990 name = names.one;
1991 ClassSymbol member = enterClass(name, outer);
1992 if ((flags & STATIC) == 0) {
1993 ((ClassType)member.type).setEnclosingType(outer.type);
1994 if (member.erasure_field != null)
1995 ((ClassType)member.erasure_field).setEnclosingType(types.erasure(outer.type));
1996 }
1997 if (c == outer) {
1998 member.flags_field = flags;
1999 enterMember(c, member);
2000 }
2001 }
2002 }
2003 }
2005 /** Read a class file.
2006 */
2007 private void readClassFile(ClassSymbol c) throws IOException {
2008 int magic = nextInt();
2009 if (magic != JAVA_MAGIC)
2010 throw badClassFile("illegal.start.of.class.file");
2012 minorVersion = nextChar();
2013 majorVersion = nextChar();
2014 int maxMajor = Target.MAX().majorVersion;
2015 int maxMinor = Target.MAX().minorVersion;
2016 if (majorVersion > maxMajor ||
2017 majorVersion * 1000 + minorVersion <
2018 Target.MIN().majorVersion * 1000 + Target.MIN().minorVersion)
2019 {
2020 if (majorVersion == (maxMajor + 1))
2021 log.warning("big.major.version",
2022 currentClassFile,
2023 majorVersion,
2024 maxMajor);
2025 else
2026 throw badClassFile("wrong.version",
2027 Integer.toString(majorVersion),
2028 Integer.toString(minorVersion),
2029 Integer.toString(maxMajor),
2030 Integer.toString(maxMinor));
2031 }
2032 else if (checkClassFile &&
2033 majorVersion == maxMajor &&
2034 minorVersion > maxMinor)
2035 {
2036 printCCF("found.later.version",
2037 Integer.toString(minorVersion));
2038 }
2039 indexPool();
2040 if (signatureBuffer.length < bp) {
2041 int ns = Integer.highestOneBit(bp) << 1;
2042 signatureBuffer = new byte[ns];
2043 }
2044 readClass(c);
2045 }
2047 /************************************************************************
2048 * Adjusting flags
2049 ***********************************************************************/
2051 long adjustFieldFlags(long flags) {
2052 return flags;
2053 }
2054 long adjustMethodFlags(long flags) {
2055 if ((flags & ACC_BRIDGE) != 0) {
2056 flags &= ~ACC_BRIDGE;
2057 flags |= BRIDGE;
2058 if (!allowGenerics)
2059 flags &= ~SYNTHETIC;
2060 }
2061 if ((flags & ACC_VARARGS) != 0) {
2062 flags &= ~ACC_VARARGS;
2063 flags |= VARARGS;
2064 }
2065 return flags;
2066 }
2067 long adjustClassFlags(long flags) {
2068 return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
2069 }
2071 /************************************************************************
2072 * Loading Classes
2073 ***********************************************************************/
2075 /** Define a new class given its name and owner.
2076 */
2077 public ClassSymbol defineClass(Name name, Symbol owner) {
2078 ClassSymbol c = new ClassSymbol(0, name, owner);
2079 if (owner.kind == PCK)
2080 Assert.checkNull(classes.get(c.flatname), c);
2081 c.completer = this;
2082 return c;
2083 }
2085 /** Create a new toplevel or member class symbol with given name
2086 * and owner and enter in `classes' unless already there.
2087 */
2088 public ClassSymbol enterClass(Name name, TypeSymbol owner) {
2089 Name flatname = TypeSymbol.formFlatName(name, owner);
2090 ClassSymbol c = classes.get(flatname);
2091 if (c == null) {
2092 c = defineClass(name, owner);
2093 classes.put(flatname, c);
2094 } else if ((c.name != name || c.owner != owner) && owner.kind == TYP && c.owner.kind == PCK) {
2095 // reassign fields of classes that might have been loaded with
2096 // their flat names.
2097 c.owner.members().remove(c);
2098 c.name = name;
2099 c.owner = owner;
2100 c.fullname = ClassSymbol.formFullName(name, owner);
2101 }
2102 return c;
2103 }
2105 /**
2106 * Creates a new toplevel class symbol with given flat name and
2107 * given class (or source) file.
2108 *
2109 * @param flatName a fully qualified binary class name
2110 * @param classFile the class file or compilation unit defining
2111 * the class (may be {@code null})
2112 * @return a newly created class symbol
2113 * @throws AssertionError if the class symbol already exists
2114 */
2115 public ClassSymbol enterClass(Name flatName, JavaFileObject classFile) {
2116 ClassSymbol cs = classes.get(flatName);
2117 if (cs != null) {
2118 String msg = Log.format("%s: completer = %s; class file = %s; source file = %s",
2119 cs.fullname,
2120 cs.completer,
2121 cs.classfile,
2122 cs.sourcefile);
2123 throw new AssertionError(msg);
2124 }
2125 Name packageName = Convert.packagePart(flatName);
2126 PackageSymbol owner = packageName.isEmpty()
2127 ? syms.unnamedPackage
2128 : enterPackage(packageName);
2129 cs = defineClass(Convert.shortName(flatName), owner);
2130 cs.classfile = classFile;
2131 classes.put(flatName, cs);
2132 return cs;
2133 }
2135 /** Create a new member or toplevel class symbol with given flat name
2136 * and enter in `classes' unless already there.
2137 */
2138 public ClassSymbol enterClass(Name flatname) {
2139 ClassSymbol c = classes.get(flatname);
2140 if (c == null)
2141 return enterClass(flatname, (JavaFileObject)null);
2142 else
2143 return c;
2144 }
2146 private boolean suppressFlush = false;
2148 /** Completion for classes to be loaded. Before a class is loaded
2149 * we make sure its enclosing class (if any) is loaded.
2150 */
2151 public void complete(Symbol sym) throws CompletionFailure {
2152 if (sym.kind == TYP) {
2153 ClassSymbol c = (ClassSymbol)sym;
2154 c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
2155 boolean saveSuppressFlush = suppressFlush;
2156 suppressFlush = true;
2157 try {
2158 completeOwners(c.owner);
2159 completeEnclosing(c);
2160 } finally {
2161 suppressFlush = saveSuppressFlush;
2162 }
2163 fillIn(c);
2164 } else if (sym.kind == PCK) {
2165 PackageSymbol p = (PackageSymbol)sym;
2166 try {
2167 fillIn(p);
2168 } catch (IOException ex) {
2169 throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);
2170 }
2171 }
2172 if (!filling && !suppressFlush)
2173 annotate.flush(); // finish attaching annotations
2174 }
2176 /** complete up through the enclosing package. */
2177 private void completeOwners(Symbol o) {
2178 if (o.kind != PCK) completeOwners(o.owner);
2179 o.complete();
2180 }
2182 /**
2183 * Tries to complete lexically enclosing classes if c looks like a
2184 * nested class. This is similar to completeOwners but handles
2185 * the situation when a nested class is accessed directly as it is
2186 * possible with the Tree API or javax.lang.model.*.
2187 */
2188 private void completeEnclosing(ClassSymbol c) {
2189 if (c.owner.kind == PCK) {
2190 Symbol owner = c.owner;
2191 for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) {
2192 Symbol encl = owner.members().lookup(name).sym;
2193 if (encl == null)
2194 encl = classes.get(TypeSymbol.formFlatName(name, owner));
2195 if (encl != null)
2196 encl.complete();
2197 }
2198 }
2199 }
2201 /** We can only read a single class file at a time; this
2202 * flag keeps track of when we are currently reading a class
2203 * file.
2204 */
2205 private boolean filling = false;
2207 /** Fill in definition of class `c' from corresponding class or
2208 * source file.
2209 */
2210 private void fillIn(ClassSymbol c) {
2211 if (completionFailureName == c.fullname) {
2212 throw new CompletionFailure(c, "user-selected completion failure by class name");
2213 }
2214 currentOwner = c;
2215 warnedAttrs.clear();
2216 JavaFileObject classfile = c.classfile;
2217 if (classfile != null) {
2218 JavaFileObject previousClassFile = currentClassFile;
2219 try {
2220 if (filling) {
2221 Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
2222 }
2223 currentClassFile = classfile;
2224 if (verbose) {
2225 log.printVerbose("loading", currentClassFile.toString());
2226 }
2227 if (classfile.getKind() == JavaFileObject.Kind.CLASS) {
2228 filling = true;
2229 try {
2230 bp = 0;
2231 buf = readInputStream(buf, classfile.openInputStream());
2232 readClassFile(c);
2233 if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) {
2234 List<Type> missing = missingTypeVariables;
2235 List<Type> found = foundTypeVariables;
2236 missingTypeVariables = List.nil();
2237 foundTypeVariables = List.nil();
2238 filling = false;
2239 ClassType ct = (ClassType)currentOwner.type;
2240 ct.supertype_field =
2241 types.subst(ct.supertype_field, missing, found);
2242 ct.interfaces_field =
2243 types.subst(ct.interfaces_field, missing, found);
2244 } else if (missingTypeVariables.isEmpty() !=
2245 foundTypeVariables.isEmpty()) {
2246 Name name = missingTypeVariables.head.tsym.name;
2247 throw badClassFile("undecl.type.var", name);
2248 }
2249 } finally {
2250 missingTypeVariables = List.nil();
2251 foundTypeVariables = List.nil();
2252 filling = false;
2253 }
2254 } else {
2255 if (sourceCompleter != null) {
2256 sourceCompleter.complete(c);
2257 } else {
2258 throw new IllegalStateException("Source completer required to read "
2259 + classfile.toUri());
2260 }
2261 }
2262 return;
2263 } catch (IOException ex) {
2264 throw badClassFile("unable.to.access.file", ex.getMessage());
2265 } finally {
2266 currentClassFile = previousClassFile;
2267 }
2268 } else {
2269 JCDiagnostic diag =
2270 diagFactory.fragment("class.file.not.found", c.flatname);
2271 throw
2272 newCompletionFailure(c, diag);
2273 }
2274 }
2275 // where
2276 private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
2277 try {
2278 buf = ensureCapacity(buf, s.available());
2279 int r = s.read(buf);
2280 int bp = 0;
2281 while (r != -1) {
2282 bp += r;
2283 buf = ensureCapacity(buf, bp);
2284 r = s.read(buf, bp, buf.length - bp);
2285 }
2286 return buf;
2287 } finally {
2288 try {
2289 s.close();
2290 } catch (IOException e) {
2291 /* Ignore any errors, as this stream may have already
2292 * thrown a related exception which is the one that
2293 * should be reported.
2294 */
2295 }
2296 }
2297 }
2298 /*
2299 * ensureCapacity will increase the buffer as needed, taking note that
2300 * the new buffer will always be greater than the needed and never
2301 * exactly equal to the needed size or bp. If equal then the read (above)
2302 * will infinitely loop as buf.length - bp == 0.
2303 */
2304 private static byte[] ensureCapacity(byte[] buf, int needed) {
2305 if (buf.length <= needed) {
2306 byte[] old = buf;
2307 buf = new byte[Integer.highestOneBit(needed) << 1];
2308 System.arraycopy(old, 0, buf, 0, old.length);
2309 }
2310 return buf;
2311 }
2312 /** Static factory for CompletionFailure objects.
2313 * In practice, only one can be used at a time, so we share one
2314 * to reduce the expense of allocating new exception objects.
2315 */
2316 private CompletionFailure newCompletionFailure(TypeSymbol c,
2317 JCDiagnostic diag) {
2318 if (!cacheCompletionFailure) {
2319 // log.warning("proc.messager",
2320 // Log.getLocalizedString("class.file.not.found", c.flatname));
2321 // c.debug.printStackTrace();
2322 return new CompletionFailure(c, diag);
2323 } else {
2324 CompletionFailure result = cachedCompletionFailure;
2325 result.sym = c;
2326 result.diag = diag;
2327 return result;
2328 }
2329 }
2330 private CompletionFailure cachedCompletionFailure =
2331 new CompletionFailure(null, (JCDiagnostic) null);
2332 {
2333 cachedCompletionFailure.setStackTrace(new StackTraceElement[0]);
2334 }
2336 /** Load a toplevel class with given fully qualified name
2337 * The class is entered into `classes' only if load was successful.
2338 */
2339 public ClassSymbol loadClass(Name flatname) throws CompletionFailure {
2340 boolean absent = classes.get(flatname) == null;
2341 ClassSymbol c = enterClass(flatname);
2342 if (c.members_field == null && c.completer != null) {
2343 try {
2344 c.complete();
2345 } catch (CompletionFailure ex) {
2346 if (absent) classes.remove(flatname);
2347 throw ex;
2348 }
2349 }
2350 return c;
2351 }
2353 /************************************************************************
2354 * Loading Packages
2355 ***********************************************************************/
2357 /** Check to see if a package exists, given its fully qualified name.
2358 */
2359 public boolean packageExists(Name fullname) {
2360 return enterPackage(fullname).exists();
2361 }
2363 /** Make a package, given its fully qualified name.
2364 */
2365 public PackageSymbol enterPackage(Name fullname) {
2366 PackageSymbol p = packages.get(fullname);
2367 if (p == null) {
2368 Assert.check(!fullname.isEmpty(), "rootPackage missing!");
2369 p = new PackageSymbol(
2370 Convert.shortName(fullname),
2371 enterPackage(Convert.packagePart(fullname)));
2372 p.completer = this;
2373 packages.put(fullname, p);
2374 }
2375 return p;
2376 }
2378 /** Make a package, given its unqualified name and enclosing package.
2379 */
2380 public PackageSymbol enterPackage(Name name, PackageSymbol owner) {
2381 return enterPackage(TypeSymbol.formFullName(name, owner));
2382 }
2384 /** Include class corresponding to given class file in package,
2385 * unless (1) we already have one the same kind (.class or .java), or
2386 * (2) we have one of the other kind, and the given class file
2387 * is older.
2388 */
2389 protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
2390 if ((p.flags_field & EXISTS) == 0)
2391 for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
2392 q.flags_field |= EXISTS;
2393 JavaFileObject.Kind kind = file.getKind();
2394 int seen;
2395 if (kind == JavaFileObject.Kind.CLASS)
2396 seen = CLASS_SEEN;
2397 else
2398 seen = SOURCE_SEEN;
2399 String binaryName = fileManager.inferBinaryName(currentLoc, file);
2400 int lastDot = binaryName.lastIndexOf(".");
2401 Name classname = names.fromString(binaryName.substring(lastDot + 1));
2402 boolean isPkgInfo = classname == names.package_info;
2403 ClassSymbol c = isPkgInfo
2404 ? p.package_info
2405 : (ClassSymbol) p.members_field.lookup(classname).sym;
2406 if (c == null) {
2407 c = enterClass(classname, p);
2408 if (c.classfile == null) // only update the file if's it's newly created
2409 c.classfile = file;
2410 if (isPkgInfo) {
2411 p.package_info = c;
2412 } else {
2413 if (c.owner == p) // it might be an inner class
2414 p.members_field.enter(c);
2415 }
2416 } else if (c.classfile != null && (c.flags_field & seen) == 0) {
2417 // if c.classfile == null, we are currently compiling this class
2418 // and no further action is necessary.
2419 // if (c.flags_field & seen) != 0, we have already encountered
2420 // a file of the same kind; again no further action is necessary.
2421 if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0)
2422 c.classfile = preferredFileObject(file, c.classfile);
2423 }
2424 c.flags_field |= seen;
2425 }
2427 /** Implement policy to choose to derive information from a source
2428 * file or a class file when both are present. May be overridden
2429 * by subclasses.
2430 */
2431 protected JavaFileObject preferredFileObject(JavaFileObject a,
2432 JavaFileObject b) {
2434 if (preferSource)
2435 return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b;
2436 else {
2437 long adate = a.getLastModified();
2438 long bdate = b.getLastModified();
2439 // 6449326: policy for bad lastModifiedTime in ClassReader
2440 //assert adate >= 0 && bdate >= 0;
2441 return (adate > bdate) ? a : b;
2442 }
2443 }
2445 /**
2446 * specifies types of files to be read when filling in a package symbol
2447 */
2448 protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() {
2449 return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE);
2450 }
2452 /**
2453 * this is used to support javadoc
2454 */
2455 protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) {
2456 }
2458 protected Location currentLoc; // FIXME
2460 private boolean verbosePath = true;
2462 /** Load directory of package into members scope.
2463 */
2464 private void fillIn(PackageSymbol p) throws IOException {
2465 if (p.members_field == null) p.members_field = new Scope(p);
2466 String packageName = p.fullname.toString();
2468 Set<JavaFileObject.Kind> kinds = getPackageFileKinds();
2470 fillIn(p, PLATFORM_CLASS_PATH,
2471 fileManager.list(PLATFORM_CLASS_PATH,
2472 packageName,
2473 EnumSet.of(JavaFileObject.Kind.CLASS),
2474 false));
2476 Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds);
2477 classKinds.remove(JavaFileObject.Kind.SOURCE);
2478 boolean wantClassFiles = !classKinds.isEmpty();
2480 Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds);
2481 sourceKinds.remove(JavaFileObject.Kind.CLASS);
2482 boolean wantSourceFiles = !sourceKinds.isEmpty();
2484 boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH);
2486 if (verbose && verbosePath) {
2487 if (fileManager instanceof StandardJavaFileManager) {
2488 StandardJavaFileManager fm = (StandardJavaFileManager)fileManager;
2489 if (haveSourcePath && wantSourceFiles) {
2490 List<File> path = List.nil();
2491 for (File file : fm.getLocation(SOURCE_PATH)) {
2492 path = path.prepend(file);
2493 }
2494 log.printVerbose("sourcepath", path.reverse().toString());
2495 } else if (wantSourceFiles) {
2496 List<File> path = List.nil();
2497 for (File file : fm.getLocation(CLASS_PATH)) {
2498 path = path.prepend(file);
2499 }
2500 log.printVerbose("sourcepath", path.reverse().toString());
2501 }
2502 if (wantClassFiles) {
2503 List<File> path = List.nil();
2504 for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) {
2505 path = path.prepend(file);
2506 }
2507 for (File file : fm.getLocation(CLASS_PATH)) {
2508 path = path.prepend(file);
2509 }
2510 log.printVerbose("classpath", path.reverse().toString());
2511 }
2512 }
2513 }
2515 if (wantSourceFiles && !haveSourcePath) {
2516 fillIn(p, CLASS_PATH,
2517 fileManager.list(CLASS_PATH,
2518 packageName,
2519 kinds,
2520 false));
2521 } else {
2522 if (wantClassFiles)
2523 fillIn(p, CLASS_PATH,
2524 fileManager.list(CLASS_PATH,
2525 packageName,
2526 classKinds,
2527 false));
2528 if (wantSourceFiles)
2529 fillIn(p, SOURCE_PATH,
2530 fileManager.list(SOURCE_PATH,
2531 packageName,
2532 sourceKinds,
2533 false));
2534 }
2535 verbosePath = false;
2536 }
2537 // where
2538 private void fillIn(PackageSymbol p,
2539 Location location,
2540 Iterable<JavaFileObject> files)
2541 {
2542 currentLoc = location;
2543 for (JavaFileObject fo : files) {
2544 switch (fo.getKind()) {
2545 case CLASS:
2546 case SOURCE: {
2547 // TODO pass binaryName to includeClassFile
2548 String binaryName = fileManager.inferBinaryName(currentLoc, fo);
2549 String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
2550 if (SourceVersion.isIdentifier(simpleName) ||
2551 simpleName.equals("package-info"))
2552 includeClassFile(p, fo);
2553 break;
2554 }
2555 default:
2556 extraFileActions(p, fo);
2557 }
2558 }
2559 }
2561 /** Output for "-checkclassfile" option.
2562 * @param key The key to look up the correct internationalized string.
2563 * @param arg An argument for substitution into the output string.
2564 */
2565 private void printCCF(String key, Object arg) {
2566 log.printLines(key, arg);
2567 }
2570 public interface SourceCompleter {
2571 void complete(ClassSymbol sym)
2572 throws CompletionFailure;
2573 }
2575 /**
2576 * A subclass of JavaFileObject for the sourcefile attribute found in a classfile.
2577 * The attribute is only the last component of the original filename, so is unlikely
2578 * to be valid as is, so operations other than those to access the name throw
2579 * UnsupportedOperationException
2580 */
2581 private static class SourceFileObject extends BaseFileObject {
2583 /** The file's name.
2584 */
2585 private Name name;
2586 private Name flatname;
2588 public SourceFileObject(Name name, Name flatname) {
2589 super(null); // no file manager; never referenced for this file object
2590 this.name = name;
2591 this.flatname = flatname;
2592 }
2594 @Override
2595 public URI toUri() {
2596 try {
2597 return new URI(null, name.toString(), null);
2598 } catch (URISyntaxException e) {
2599 throw new CannotCreateUriError(name.toString(), e);
2600 }
2601 }
2603 @Override
2604 public String getName() {
2605 return name.toString();
2606 }
2608 @Override
2609 public String getShortName() {
2610 return getName();
2611 }
2613 @Override
2614 public JavaFileObject.Kind getKind() {
2615 return getKind(getName());
2616 }
2618 @Override
2619 public InputStream openInputStream() {
2620 throw new UnsupportedOperationException();
2621 }
2623 @Override
2624 public OutputStream openOutputStream() {
2625 throw new UnsupportedOperationException();
2626 }
2628 @Override
2629 public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
2630 throw new UnsupportedOperationException();
2631 }
2633 @Override
2634 public Reader openReader(boolean ignoreEncodingErrors) {
2635 throw new UnsupportedOperationException();
2636 }
2638 @Override
2639 public Writer openWriter() {
2640 throw new UnsupportedOperationException();
2641 }
2643 @Override
2644 public long getLastModified() {
2645 throw new UnsupportedOperationException();
2646 }
2648 @Override
2649 public boolean delete() {
2650 throw new UnsupportedOperationException();
2651 }
2653 @Override
2654 protected String inferBinaryName(Iterable<? extends File> path) {
2655 return flatname.toString();
2656 }
2658 @Override
2659 public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {
2660 return true; // fail-safe mode
2661 }
2663 /**
2664 * Check if two file objects are equal.
2665 * SourceFileObjects are just placeholder objects for the value of a
2666 * SourceFile attribute, and do not directly represent specific files.
2667 * Two SourceFileObjects are equal if their names are equal.
2668 */
2669 @Override
2670 public boolean equals(Object other) {
2671 if (this == other)
2672 return true;
2674 if (!(other instanceof SourceFileObject))
2675 return false;
2677 SourceFileObject o = (SourceFileObject) other;
2678 return name.equals(o.name);
2679 }
2681 @Override
2682 public int hashCode() {
2683 return name.hashCode();
2684 }
2685 }
2686 }