ClassReader.java revision 399
0N/A/*
4278N/A * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation. Sun designates this
0N/A * particular file as subject to the "Classpath" exception as provided
0N/A * by Sun in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
1472N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1472N/A *
1472N/A * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0N/A * CA 95054 USA or visit www.sun.com if you need additional information or
0N/A * have any questions.
0N/A */
1879N/A
1879N/Apackage com.sun.tools.javac.jvm;
1879N/A
1879N/Aimport java.io.*;
1879N/Aimport java.net.URI;
1879N/Aimport java.net.URISyntaxException;
1879N/Aimport java.nio.CharBuffer;
1879N/Aimport java.util.EnumSet;
1879N/Aimport java.util.HashMap;
1879N/Aimport java.util.Map;
1879N/Aimport java.util.Set;
1879N/Aimport javax.lang.model.SourceVersion;
1879N/Aimport javax.tools.JavaFileObject;
1879N/Aimport javax.tools.JavaFileManager;
1879N/Aimport javax.tools.JavaFileManager.Location;
1879N/Aimport javax.tools.StandardJavaFileManager;
1879N/A
1879N/Aimport static javax.tools.StandardLocation.*;
1879N/A
1879N/Aimport com.sun.tools.javac.comp.Annotate;
1879N/Aimport com.sun.tools.javac.code.*;
4340N/Aimport com.sun.tools.javac.code.Type.*;
1879N/Aimport com.sun.tools.javac.code.Symbol.*;
1879N/Aimport com.sun.tools.javac.code.Symtab;
1879N/Aimport com.sun.tools.javac.file.BaseFileObject;
1879N/Aimport com.sun.tools.javac.util.*;
1879N/A
1879N/Aimport static com.sun.tools.javac.code.Flags.*;
1879N/Aimport static com.sun.tools.javac.code.Kinds.*;
1879N/Aimport static com.sun.tools.javac.code.TypeTags.*;
1879N/Aimport static com.sun.tools.javac.jvm.ClassFile.*;
1879N/Aimport static com.sun.tools.javac.jvm.ClassFile.Version.*;
1879N/A
1879N/A/** This class provides operations to read a classfile into an internal
4299N/A * representation. The internal representation is anchored in a
1879N/A * ClassSymbol which contains in its scope symbol representations
1879N/A * for all other definitions in the classfile. Top-level Classes themselves
1929N/A * appear as members of the scopes of PackageSymbols.
1879N/A *
1879N/A * <p><b>This is NOT part of any API supported by Sun Microsystems. If
4340N/A * you write code that depends on this, you do so at your own risk.
1879N/A * This code and its internal interfaces are subject to change or
1879N/A * deletion without notice.</b>
1879N/A */
1879N/Apublic class ClassReader implements Completer {
1879N/A /** The context key for the class reader. */
1879N/A protected static final Context.Key<ClassReader> classReaderKey =
1879N/A new Context.Key<ClassReader>();
1879N/A
1879N/A Annotate annotate;
1879N/A
1879N/A /** Switch: verbose output.
1879N/A */
1879N/A boolean verbose;
1879N/A
2073N/A /** Switch: check class file for correct minor version, unrecognized
2073N/A * attributes.
2073N/A */
2073N/A boolean checkClassFile;
2073N/A
2073N/A /** Switch: read constant pool and code sections. This switch is initially
2073N/A * set to false but can be turned on from outside.
2073N/A */
0N/A public boolean readAllOfClassFile = false;
0N/A
0N/A /** Switch: read GJ signature information.
0N/A */
1601N/A boolean allowGenerics;
1601N/A
0N/A /** Switch: read varargs attribute.
0N/A */
0N/A boolean allowVarargs;
0N/A
0N/A /** Switch: allow annotations.
0N/A */
0N/A boolean allowAnnotations;
0N/A
0N/A /** Switch: preserve parameter names from the variable table.
0N/A */
0N/A public boolean saveParameterNames;
0N/A
0N/A /**
0N/A * Switch: cache completion failures unless -XDdev is used
0N/A */
0N/A private boolean cacheCompletionFailure;
0N/A
0N/A /**
0N/A * Switch: prefer source files instead of newer when both source
0N/A * and class are available
0N/A **/
0N/A public boolean preferSource;
0N/A
0N/A /** The log to use for verbose output
0N/A */
1320N/A final Log log;
1320N/A
1940N/A /** The symbol table. */
0N/A Symtab syms;
0N/A
0N/A Types types;
0N/A
0N/A /** The name table. */
0N/A final Names names;
2085N/A
0N/A /** Force a completion failure on this name
0N/A */
0N/A final Name completionFailureName;
0N/A
0N/A /** Access to files
0N/A */
0N/A private final JavaFileManager fileManager;
0N/A
0N/A /** Factory for diagnostics
0N/A */
0N/A JCDiagnostic.Factory diagFactory;
0N/A
0N/A /** Can be reassigned from outside:
0N/A * the completer to be used for ".java" files. If this remains unassigned
0N/A * ".java" files will not be loaded.
199N/A */
199N/A public SourceCompleter sourceCompleter = null;
0N/A
0N/A /** A hashtable containing the encountered top-level and member classes,
0N/A * indexed by flat names. The table does not contain local classes.
0N/A */
0N/A private Map<Name,ClassSymbol> classes;
0N/A
0N/A /** A hashtable containing the encountered packages.
0N/A */
0N/A private Map<Name, PackageSymbol> packages;
0N/A
0N/A /** The current scope where type variables are entered.
0N/A */
0N/A protected Scope typevars;
0N/A
0N/A /** The path name of the class file currently being read.
0N/A */
0N/A protected JavaFileObject currentClassFile = null;
242N/A
242N/A /** The class or method currently being read.
242N/A */
4433N/A protected Symbol currentOwner = null;
4433N/A
4433N/A /** The buffer containing the currently read class file.
2627N/A */
2627N/A byte[] buf = new byte[0x0fff0];
2627N/A
2627N/A /** The current input pointer.
2627N/A */
2627N/A int bp;
2627N/A
2627N/A /** The objects of the constant pool.
2627N/A */
2627N/A Object[] poolObj;
2627N/A
2627N/A /** For every constant pool entry, an index into buf where the
2627N/A * defining section of the entry is found.
2627N/A */
2627N/A int[] poolIdx;
2627N/A
2627N/A /** The major version number of the class file being read. */
2627N/A int majorVersion;
2627N/A /** The minor version number of the class file being read. */
2627N/A int minorVersion;
2627N/A
2627N/A /** Switch: debug output for JSR 308-related operations.
2627N/A */
2627N/A boolean debugJSR308;
2627N/A
2627N/A /** Get the ClassReader instance for this invocation. */
2627N/A public static ClassReader instance(Context context) {
2627N/A ClassReader instance = context.get(classReaderKey);
2627N/A if (instance == null)
0N/A instance = new ClassReader(context, true);
0N/A return instance;
0N/A }
0N/A
0N/A /** Initialize classes and packages, treating this as the definitive classreader. */
0N/A public void init(Symtab syms) {
0N/A init(syms, true);
0N/A }
0N/A
0N/A /** Initialize classes and packages, optionally treating this as
0N/A * the definitive classreader.
0N/A */
0N/A private void init(Symtab syms, boolean definitive) {
0N/A if (classes != null) return;
0N/A
0N/A if (definitive) {
0N/A assert packages == null || packages == syms.packages;
0N/A packages = syms.packages;
0N/A assert classes == null || classes == syms.classes;
0N/A classes = syms.classes;
0N/A } else {
20N/A packages = new HashMap<Name, PackageSymbol>();
20N/A classes = new HashMap<Name, ClassSymbol>();
20N/A }
20N/A
20N/A packages.put(names.empty, syms.rootPackage);
20N/A syms.rootPackage.completer = this;
20N/A syms.unnamedPackage.completer = this;
20N/A }
20N/A
20N/A /** Construct a new class reader, optionally treated as the
20N/A * definitive classreader for this invocation.
20N/A */
20N/A protected ClassReader(Context context, boolean definitive) {
20N/A if (definitive) context.put(classReaderKey, this);
0N/A
0N/A names = Names.instance(context);
0N/A syms = Symtab.instance(context);
0N/A types = Types.instance(context);
0N/A fileManager = context.get(JavaFileManager.class);
0N/A if (fileManager == null)
0N/A throw new AssertionError("FileManager initialization error");
0N/A diagFactory = JCDiagnostic.Factory.instance(context);
0N/A
0N/A init(syms, definitive);
0N/A log = Log.instance(context);
0N/A
0N/A Options options = Options.instance(context);
0N/A annotate = Annotate.instance(context);
0N/A verbose = options.get("-verbose") != null;
0N/A checkClassFile = options.get("-checkclassfile") != null;
0N/A Source source = Source.instance(context);
0N/A allowGenerics = source.allowGenerics();
0N/A allowVarargs = source.allowVarargs();
0N/A allowAnnotations = source.allowAnnotations();
0N/A saveParameterNames = options.get("save-parameter-names") != null;
0N/A cacheCompletionFailure = options.get("dev") == null;
0N/A preferSource = "source".equals(options.get("-Xprefer"));
0N/A
0N/A completionFailureName =
0N/A (options.get("failcomplete") != null)
0N/A ? names.fromString(options.get("failcomplete"))
0N/A : null;
0N/A
0N/A typevars = new Scope(syms.noSymbol);
0N/A debugJSR308 = options.get("TA:reader") != null;
0N/A
0N/A initAttributeReaders();
0N/A }
0N/A
0N/A /** Add member to class unless it is synthetic.
0N/A */
0N/A private void enterMember(ClassSymbol c, Symbol sym) {
0N/A if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC)
0N/A c.members_field.enter(sym);
0N/A }
0N/A
0N/A/************************************************************************
1010N/A * Error Diagnoses
1010N/A ***********************************************************************/
1010N/A
0N/A
0N/A public class BadClassFile extends CompletionFailure {
0N/A private static final long serialVersionUID = 0;
0N/A
0N/A public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag) {
1601N/A super(sym, createBadClassFileDiagnostic(file, diag));
1601N/A }
1601N/A }
1601N/A // where
0N/A private JCDiagnostic createBadClassFileDiagnostic(JavaFileObject file, JCDiagnostic diag) {
0N/A String key = (file.getKind() == JavaFileObject.Kind.SOURCE
0N/A ? "bad.source.file.header" : "bad.class.file.header");
0N/A return diagFactory.fragment(key, file, diag);
0N/A }
0N/A
0N/A public BadClassFile badClassFile(String key, Object... args) {
0N/A return new BadClassFile (
0N/A currentOwner.enclClass(),
0N/A currentClassFile,
0N/A diagFactory.fragment(key, args));
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Buffer Access
0N/A ***********************************************************************/
0N/A
0N/A /** Read a character.
0N/A */
0N/A char nextChar() {
0N/A return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF));
0N/A }
0N/A
0N/A /** Read a byte.
0N/A */
0N/A byte nextByte() {
0N/A return buf[bp++];
0N/A }
0N/A
0N/A /** Read an integer.
0N/A */
0N/A int nextInt() {
0N/A return
0N/A ((buf[bp++] & 0xFF) << 24) +
199N/A ((buf[bp++] & 0xFF) << 16) +
199N/A ((buf[bp++] & 0xFF) << 8) +
199N/A (buf[bp++] & 0xFF);
0N/A }
0N/A
1123N/A /** Extract a character at position bp from buf.
1123N/A */
0N/A char getChar(int bp) {
0N/A return
0N/A (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF));
0N/A }
0N/A
0N/A /** Extract an integer at position bp from buf.
0N/A */
0N/A int getInt(int bp) {
0N/A return
0N/A ((buf[bp] & 0xFF) << 24) +
0N/A ((buf[bp+1] & 0xFF) << 16) +
1123N/A ((buf[bp+2] & 0xFF) << 8) +
0N/A (buf[bp+3] & 0xFF);
0N/A }
0N/A
0N/A
0N/A /** Extract a long integer at position bp from buf.
0N/A */
0N/A long getLong(int bp) {
0N/A DataInputStream bufin =
0N/A new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
0N/A try {
0N/A return bufin.readLong();
0N/A } catch (IOException e) {
0N/A throw new AssertionError(e);
0N/A }
0N/A }
0N/A
0N/A /** Extract a float at position bp from buf.
0N/A */
0N/A float getFloat(int bp) {
0N/A DataInputStream bufin =
0N/A new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
0N/A try {
0N/A return bufin.readFloat();
0N/A } catch (IOException e) {
0N/A throw new AssertionError(e);
0N/A }
0N/A }
0N/A
0N/A /** Extract a double at position bp from buf.
0N/A */
0N/A double getDouble(int bp) {
0N/A DataInputStream bufin =
0N/A new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
3863N/A try {
0N/A return bufin.readDouble();
0N/A } catch (IOException e) {
0N/A throw new AssertionError(e);
0N/A }
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Constant Pool Access
0N/A ***********************************************************************/
0N/A
509N/A /** Index all constant pool entries, writing their start addresses into
509N/A * poolIdx.
509N/A */
0N/A void indexPool() {
509N/A poolIdx = new int[nextChar()];
0N/A poolObj = new Object[poolIdx.length];
0N/A int i = 1;
0N/A while (i < poolIdx.length) {
0N/A poolIdx[i++] = bp;
0N/A byte tag = buf[bp++];
0N/A switch (tag) {
0N/A case CONSTANT_Utf8: case CONSTANT_Unicode: {
0N/A int len = nextChar();
0N/A bp = bp + len;
0N/A break;
0N/A }
0N/A case CONSTANT_Class:
0N/A case CONSTANT_String:
0N/A bp = bp + 2;
0N/A break;
0N/A case CONSTANT_Fieldref:
0N/A case CONSTANT_Methodref:
0N/A case CONSTANT_InterfaceMethodref:
0N/A case CONSTANT_NameandType:
0N/A case CONSTANT_Integer:
0N/A case CONSTANT_Float:
0N/A bp = bp + 4;
0N/A break;
0N/A case CONSTANT_Long:
0N/A case CONSTANT_Double:
0N/A bp = bp + 8;
0N/A i++;
0N/A break;
0N/A default:
0N/A throw badClassFile("bad.const.pool.tag.at",
0N/A Byte.toString(tag),
0N/A Integer.toString(bp -1));
0N/A }
0N/A }
0N/A }
0N/A
0N/A /** Read constant pool entry at start address i, use pool as a cache.
0N/A */
0N/A Object readPool(int i) {
0N/A Object result = poolObj[i];
0N/A if (result != null) return result;
0N/A
0N/A int index = poolIdx[i];
0N/A if (index == 0) return null;
0N/A
0N/A byte tag = buf[index];
0N/A switch (tag) {
0N/A case CONSTANT_Utf8:
0N/A poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1));
0N/A break;
0N/A case CONSTANT_Unicode:
0N/A throw badClassFile("unicode.str.not.supported");
0N/A case CONSTANT_Class:
0N/A poolObj[i] = readClassOrType(getChar(index + 1));
0N/A break;
0N/A case CONSTANT_String:
0N/A // FIXME: (footprint) do not use toString here
0N/A poolObj[i] = readName(getChar(index + 1)).toString();
0N/A break;
0N/A case CONSTANT_Fieldref: {
0N/A ClassSymbol owner = readClassSymbol(getChar(index + 1));
0N/A NameAndType nt = (NameAndType)readPool(getChar(index + 3));
0N/A poolObj[i] = new VarSymbol(0, nt.name, nt.type, owner);
0N/A break;
0N/A }
0N/A case CONSTANT_Methodref:
0N/A case CONSTANT_InterfaceMethodref: {
0N/A ClassSymbol owner = readClassSymbol(getChar(index + 1));
0N/A NameAndType nt = (NameAndType)readPool(getChar(index + 3));
0N/A poolObj[i] = new MethodSymbol(0, nt.name, nt.type, owner);
0N/A break;
0N/A }
0N/A case CONSTANT_NameandType:
0N/A poolObj[i] = new NameAndType(
0N/A readName(getChar(index + 1)),
0N/A readType(getChar(index + 3)));
0N/A break;
0N/A case CONSTANT_Integer:
0N/A poolObj[i] = getInt(index + 1);
0N/A break;
0N/A case CONSTANT_Float:
0N/A poolObj[i] = new Float(getFloat(index + 1));
0N/A break;
0N/A case CONSTANT_Long:
0N/A poolObj[i] = new Long(getLong(index + 1));
0N/A break;
0N/A case CONSTANT_Double:
0N/A poolObj[i] = new Double(getDouble(index + 1));
0N/A break;
0N/A default:
0N/A throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
0N/A }
0N/A return poolObj[i];
0N/A }
0N/A
0N/A /** Read signature and convert to type.
0N/A */
0N/A Type readType(int i) {
0N/A int index = poolIdx[i];
0N/A return sigToType(buf, index + 3, getChar(index + 1));
0N/A }
0N/A
0N/A /** If name is an array type or class signature, return the
0N/A * corresponding type; otherwise return a ClassSymbol with given name.
0N/A */
0N/A Object readClassOrType(int i) {
0N/A int index = poolIdx[i];
0N/A int len = getChar(index + 1);
0N/A int start = index + 3;
0N/A assert buf[start] == '[' || buf[start + len - 1] != ';';
0N/A // by the above assertion, the following test can be
0N/A // simplified to (buf[start] == '[')
0N/A return (buf[start] == '[' || buf[start + len - 1] == ';')
0N/A ? (Object)sigToType(buf, start, len)
0N/A : (Object)enterClass(names.fromUtf(internalize(buf, start,
0N/A len)));
0N/A }
0N/A
0N/A /** Read signature and convert to type parameters.
0N/A */
0N/A List<Type> readTypeParams(int i) {
0N/A int index = poolIdx[i];
0N/A return sigToTypeParams(buf, index + 3, getChar(index + 1));
0N/A }
0N/A
0N/A /** Read class entry.
0N/A */
0N/A ClassSymbol readClassSymbol(int i) {
0N/A return (ClassSymbol) (readPool(i));
0N/A }
0N/A
0N/A /** Read name.
0N/A */
0N/A Name readName(int i) {
0N/A return (Name) (readPool(i));
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Reading Types
0N/A ***********************************************************************/
0N/A
0N/A /** The unread portion of the currently read type is
0N/A * signature[sigp..siglimit-1].
0N/A */
0N/A byte[] signature;
0N/A int sigp;
0N/A int siglimit;
0N/A boolean sigEnterPhase = false;
0N/A
0N/A /** Convert signature to type, where signature is a byte array segment.
0N/A */
0N/A Type sigToType(byte[] sig, int offset, int len) {
0N/A signature = sig;
0N/A sigp = offset;
0N/A siglimit = offset + len;
0N/A return sigToType();
0N/A }
0N/A
0N/A /** Convert signature to type, where signature is implicit.
0N/A */
0N/A Type sigToType() {
0N/A switch ((char) signature[sigp]) {
0N/A case 'T':
0N/A sigp++;
0N/A int start = sigp;
0N/A while (signature[sigp] != ';') sigp++;
0N/A sigp++;
0N/A return sigEnterPhase
0N/A ? Type.noType
0N/A : findTypeVar(names.fromUtf(signature, start, sigp - 1 - start));
0N/A case '+': {
0N/A sigp++;
0N/A Type t = sigToType();
0N/A return new WildcardType(t, BoundKind.EXTENDS,
0N/A syms.boundClass);
0N/A }
0N/A case '*':
0N/A sigp++;
0N/A return new WildcardType(syms.objectType, BoundKind.UNBOUND,
0N/A syms.boundClass);
0N/A case '-': {
0N/A sigp++;
0N/A Type t = sigToType();
0N/A return new WildcardType(t, BoundKind.SUPER,
0N/A syms.boundClass);
0N/A }
0N/A case 'B':
0N/A sigp++;
0N/A return syms.byteType;
0N/A case 'C':
0N/A sigp++;
0N/A return syms.charType;
0N/A case 'D':
0N/A sigp++;
0N/A return syms.doubleType;
0N/A case 'F':
0N/A sigp++;
0N/A return syms.floatType;
0N/A case 'I':
0N/A sigp++;
0N/A return syms.intType;
0N/A case 'J':
0N/A sigp++;
0N/A return syms.longType;
0N/A case 'L':
0N/A {
0N/A // int oldsigp = sigp;
0N/A Type t = classSigToType();
0N/A if (sigp < siglimit && signature[sigp] == '.')
0N/A throw badClassFile("deprecated inner class signature syntax " +
0N/A "(please recompile from source)");
0N/A /*
0N/A System.err.println(" decoded " +
0N/A new String(signature, oldsigp, sigp-oldsigp) +
0N/A " => " + t + " outer " + t.outer());
0N/A */
0N/A return t;
0N/A }
0N/A case 'S':
0N/A sigp++;
0N/A return syms.shortType;
0N/A case 'V':
0N/A sigp++;
0N/A return syms.voidType;
0N/A case 'Z':
0N/A sigp++;
0N/A return syms.booleanType;
0N/A case '[':
0N/A sigp++;
0N/A return new ArrayType(sigToType(), syms.arrayClass);
0N/A case '(':
0N/A sigp++;
0N/A List<Type> argtypes = sigToTypes(')');
0N/A Type restype = sigToType();
0N/A List<Type> thrown = List.nil();
0N/A while (signature[sigp] == '^') {
0N/A sigp++;
0N/A thrown = thrown.prepend(sigToType());
0N/A }
0N/A return new MethodType(argtypes,
0N/A restype,
0N/A thrown.reverse(),
0N/A syms.methodClass);
0N/A case '<':
0N/A typevars = typevars.dup(currentOwner);
0N/A Type poly = new ForAll(sigToTypeParams(), sigToType());
0N/A typevars = typevars.leave();
0N/A return poly;
0N/A default:
0N/A throw badClassFile("bad.signature",
0N/A Convert.utf2string(signature, sigp, 10));
0N/A }
3863N/A }
0N/A
0N/A byte[] signatureBuffer = new byte[0];
0N/A int sbp = 0;
0N/A /** Convert class signature to type, where signature is implicit.
0N/A */
0N/A Type classSigToType() {
0N/A if (signature[sigp] != 'L')
0N/A throw badClassFile("bad.class.signature",
0N/A Convert.utf2string(signature, sigp, 10));
0N/A sigp++;
0N/A Type outer = Type.noType;
0N/A int startSbp = sbp;
3863N/A
0N/A while (true) {
0N/A final byte c = signature[sigp++];
0N/A switch (c) {
199N/A
199N/A case ';': { // end
199N/A ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
199N/A startSbp,
0N/A sbp - startSbp));
199N/A if (outer == Type.noType)
199N/A outer = t.erasure(types);
199N/A else
199N/A outer = new ClassType(outer, List.<Type>nil(), t);
199N/A sbp = startSbp;
199N/A return outer;
0N/A }
0N/A
199N/A case '<': // generic arguments
199N/A ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
0N/A startSbp,
0N/A sbp - startSbp));
0N/A outer = new ClassType(outer, sigToTypes('>'), t) {
0N/A boolean completed = false;
0N/A @Override
0N/A public Type getEnclosingType() {
0N/A if (!completed) {
0N/A completed = true;
0N/A tsym.complete();
0N/A Type enclosingType = tsym.type.getEnclosingType();
0N/A if (enclosingType != Type.noType) {
0N/A List<Type> typeArgs =
0N/A super.getEnclosingType().allparams();
0N/A List<Type> typeParams =
0N/A enclosingType.allparams();
0N/A if (typeParams.length() != typeArgs.length()) {
0N/A // no "rare" types
0N/A super.setEnclosingType(types.erasure(enclosingType));
0N/A } else {
0N/A super.setEnclosingType(types.subst(enclosingType,
0N/A typeParams,
0N/A typeArgs));
0N/A }
0N/A } else {
0N/A super.setEnclosingType(Type.noType);
0N/A }
0N/A }
0N/A return super.getEnclosingType();
0N/A }
0N/A @Override
0N/A public void setEnclosingType(Type outer) {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A };
0N/A switch (signature[sigp++]) {
0N/A case ';':
0N/A if (sigp < signature.length && signature[sigp] == '.') {
0N/A // support old-style GJC signatures
0N/A // The signature produced was
0N/A // Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>;
0N/A // rather than say
0N/A // Lfoo/Outer<Lfoo/X;>.Inner<Lfoo/Y;>;
0N/A // so we skip past ".Lfoo/Outer$"
0N/A sigp += (sbp - startSbp) + // "foo/Outer"
0N/A 3; // ".L" and "$"
0N/A signatureBuffer[sbp++] = (byte)'$';
0N/A break;
0N/A } else {
0N/A sbp = startSbp;
0N/A return outer;
0N/A }
0N/A case '.':
0N/A signatureBuffer[sbp++] = (byte)'$';
0N/A break;
0N/A default:
0N/A throw new AssertionError(signature[sigp-1]);
0N/A }
0N/A continue;
0N/A
0N/A case '.':
0N/A signatureBuffer[sbp++] = (byte)'$';
0N/A continue;
0N/A case '/':
0N/A signatureBuffer[sbp++] = (byte)'.';
0N/A continue;
0N/A default:
0N/A signatureBuffer[sbp++] = c;
0N/A continue;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /** Convert (implicit) signature to list of types
0N/A * until `terminator' is encountered.
0N/A */
0N/A List<Type> sigToTypes(char terminator) {
0N/A List<Type> head = List.of(null);
0N/A List<Type> tail = head;
0N/A while (signature[sigp] != terminator)
0N/A tail = tail.setTail(List.of(sigToType()));
0N/A sigp++;
0N/A return head.tail;
0N/A }
0N/A
0N/A /** Convert signature to type parameters, where signature is a byte
0N/A * array segment.
0N/A */
0N/A List<Type> sigToTypeParams(byte[] sig, int offset, int len) {
0N/A signature = sig;
0N/A sigp = offset;
0N/A siglimit = offset + len;
0N/A return sigToTypeParams();
0N/A }
0N/A
0N/A /** Convert signature to type parameters, where signature is implicit.
0N/A */
0N/A List<Type> sigToTypeParams() {
0N/A List<Type> tvars = List.nil();
0N/A if (signature[sigp] == '<') {
0N/A sigp++;
0N/A int start = sigp;
0N/A sigEnterPhase = true;
0N/A while (signature[sigp] != '>')
0N/A tvars = tvars.prepend(sigToTypeParam());
0N/A sigEnterPhase = false;
0N/A sigp = start;
0N/A while (signature[sigp] != '>')
0N/A sigToTypeParam();
0N/A sigp++;
0N/A }
0N/A return tvars.reverse();
0N/A }
0N/A
0N/A /** Convert (implicit) signature to type parameter.
0N/A */
0N/A Type sigToTypeParam() {
0N/A int start = sigp;
0N/A while (signature[sigp] != ':') sigp++;
0N/A Name name = names.fromUtf(signature, start, sigp - start);
0N/A TypeVar tvar;
0N/A if (sigEnterPhase) {
0N/A tvar = new TypeVar(name, currentOwner, syms.botType);
0N/A typevars.enter(tvar.tsym);
0N/A } else {
0N/A tvar = (TypeVar)findTypeVar(name);
0N/A }
0N/A List<Type> bounds = List.nil();
0N/A Type st = null;
0N/A if (signature[sigp] == ':' && signature[sigp+1] == ':') {
0N/A sigp++;
0N/A st = syms.objectType;
0N/A }
0N/A while (signature[sigp] == ':') {
0N/A sigp++;
0N/A bounds = bounds.prepend(sigToType());
0N/A }
0N/A if (!sigEnterPhase) {
0N/A types.setBounds(tvar, bounds.reverse(), st);
0N/A }
0N/A return tvar;
0N/A }
0N/A
0N/A /** Find type variable with given name in `typevars' scope.
0N/A */
0N/A Type findTypeVar(Name name) {
0N/A Scope.Entry e = typevars.lookup(name);
0N/A if (e.scope != null) {
0N/A return e.sym.type;
0N/A } else {
0N/A if (readingClassAttr) {
0N/A // While reading the class attribute, the supertypes
0N/A // might refer to a type variable from an enclosing element
0N/A // (method or class).
0N/A // If the type variable is defined in the enclosing class,
0N/A // we can actually find it in
0N/A // currentOwner.owner.type.getTypeArguments()
0N/A // However, until we have read the enclosing method attribute
0N/A // we don't know for sure if this owner is correct. It could
0N/A // be a method and there is no way to tell before reading the
0N/A // enclosing method attribute.
0N/A TypeVar t = new TypeVar(name, currentOwner, syms.botType);
0N/A missingTypeVariables = missingTypeVariables.prepend(t);
0N/A // System.err.println("Missing type var " + name);
0N/A return t;
0N/A }
0N/A throw badClassFile("undecl.type.var", name);
0N/A }
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Reading Attributes
0N/A ***********************************************************************/
0N/A
0N/A protected enum AttributeKind { CLASS, MEMBER };
0N/A protected abstract class AttributeReader {
0N/A AttributeReader(Name name, Version version, Set<AttributeKind> kinds) {
0N/A this.name = name;
0N/A this.version = version;
0N/A this.kinds = kinds;
0N/A }
0N/A
0N/A boolean accepts(AttributeKind kind) {
0N/A return kinds.contains(kind) && majorVersion >= version.major;
0N/A }
0N/A
0N/A abstract void read(Symbol sym, int attrLen);
0N/A
0N/A final Name name;
0N/A final Version version;
0N/A final Set<AttributeKind> kinds;
0N/A }
0N/A
0N/A protected Set<AttributeKind> CLASS_ATTRIBUTE =
0N/A EnumSet.of(AttributeKind.CLASS);
0N/A protected Set<AttributeKind> MEMBER_ATTRIBUTE =
0N/A EnumSet.of(AttributeKind.MEMBER);
0N/A protected Set<AttributeKind> CLASS_OR_MEMBER_ATTRIBUTE =
0N/A EnumSet.of(AttributeKind.CLASS, AttributeKind.MEMBER);
0N/A
0N/A protected Map<Name, AttributeReader> attributeReaders = new HashMap<Name, AttributeReader>();
0N/A
0N/A protected void initAttributeReaders() {
0N/A AttributeReader[] readers = {
0N/A // v45.3 attributes
0N/A
0N/A new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A if (readAllOfClassFile || saveParameterNames)
0N/A ((MethodSymbol)sym).code = readCode(sym);
0N/A else
0N/A bp = bp + attrLen;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A Object v = readPool(nextChar());
0N/A // Ignore ConstantValue attribute if field not final.
0N/A if ((sym.flags() & FINAL) != 0)
0N/A ((VarSymbol) sym).setData(v);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Deprecated, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A sym.flags_field |= DEPRECATED;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Exceptions, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A int nexceptions = nextChar();
0N/A List<Type> thrown = List.nil();
0N/A for (int j = 0; j < nexceptions; j++)
0N/A thrown = thrown.prepend(readClassSymbol(nextChar()).type);
0N/A if (sym.type.getThrownTypes().isEmpty())
0N/A sym.type.asMethodType().thrown = thrown.reverse();
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.InnerClasses, V45_3, CLASS_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A ClassSymbol c = (ClassSymbol) sym;
0N/A readInnerClasses(c);
0N/A }
0N/A },
0N/A
1787N/A new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
1787N/A void read(Symbol sym, int attrLen) {
1787N/A int newbp = bp + attrLen;
1787N/A if (saveParameterNames) {
0N/A // pick up parameter names from the variable table
0N/A List<Name> parameterNames = List.nil();
0N/A int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
0N/A int endParam = firstParam + Code.width(sym.type.getParameterTypes());
0N/A int numEntries = nextChar();
0N/A for (int i=0; i<numEntries; i++) {
0N/A int start_pc = nextChar();
0N/A int length = nextChar();
0N/A int nameIndex = nextChar();
0N/A int sigIndex = nextChar();
0N/A int register = nextChar();
0N/A if (start_pc == 0 &&
0N/A firstParam <= register &&
0N/A register < endParam) {
0N/A int index = firstParam;
0N/A for (Type t : sym.type.getParameterTypes()) {
0N/A if (index == register) {
0N/A parameterNames = parameterNames.prepend(readName(nameIndex));
0N/A break;
0N/A }
0N/A index += Code.width(t);
0N/A }
0N/A }
0N/A }
0N/A parameterNames = parameterNames.reverse();
0N/A ((MethodSymbol)sym).savedParameterNames = parameterNames;
0N/A }
0N/A bp = newbp;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A ClassSymbol c = (ClassSymbol) sym;
0N/A Name n = readName(nextChar());
0N/A c.sourcefile = new SourceFileObject(n, c.flatname);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Synthetic, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A // bridge methods are visible when generics not enabled
0N/A if (allowGenerics || (sym.flags_field & BRIDGE) == 0)
0N/A sym.flags_field |= SYNTHETIC;
0N/A }
0N/A },
0N/A
0N/A // standard v49 attributes
0N/A
0N/A new AttributeReader(names.EnclosingMethod, V49, CLASS_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A int newbp = bp + attrLen;
0N/A readEnclosingMethodAttr(sym);
0N/A bp = newbp;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Signature, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A @Override
0N/A boolean accepts(AttributeKind kind) {
0N/A return super.accepts(kind) && allowGenerics;
0N/A }
0N/A
0N/A void read(Symbol sym, int attrLen) {
0N/A if (sym.kind == TYP) {
0N/A ClassSymbol c = (ClassSymbol) sym;
0N/A readingClassAttr = true;
0N/A try {
0N/A ClassType ct1 = (ClassType)c.type;
0N/A assert c == currentOwner;
0N/A ct1.typarams_field = readTypeParams(nextChar());
0N/A ct1.supertype_field = sigToType();
0N/A ListBuffer<Type> is = new ListBuffer<Type>();
0N/A while (sigp != siglimit) is.append(sigToType());
0N/A ct1.interfaces_field = is.toList();
0N/A } finally {
0N/A readingClassAttr = false;
0N/A }
0N/A } else {
0N/A List<Type> thrown = sym.type.getThrownTypes();
0N/A sym.type = readType(nextChar());
0N/A //- System.err.println(" # " + sym.type);
0N/A if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
0N/A sym.type.asMethodType().thrown = thrown;
0N/A
0N/A }
0N/A }
0N/A },
0N/A
0N/A // v49 annotation attributes
0N/A
0N/A new AttributeReader(names.AnnotationDefault, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachAnnotationDefault(sym);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.RuntimeInvisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachAnnotations(sym);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.RuntimeInvisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachParameterAnnotations(sym);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.RuntimeVisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachAnnotations(sym);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.RuntimeVisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachParameterAnnotations(sym);
0N/A }
0N/A },
0N/A
0N/A // additional "legacy" v49 attributes, superceded by flags
0N/A
0N/A new AttributeReader(names.Annotation, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A if (allowAnnotations)
0N/A sym.flags_field |= ANNOTATION;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Bridge, V49, MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A sym.flags_field |= BRIDGE;
0N/A if (!allowGenerics)
0N/A sym.flags_field &= ~SYNTHETIC;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Enum, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A sym.flags_field |= ENUM;
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.Varargs, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A if (allowVarargs)
0N/A sym.flags_field |= VARARGS;
0N/A }
0N/A },
0N/A
0N/A // v51 attributes
0N/A new AttributeReader(names.RuntimeVisibleTypeAnnotations, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachTypeAnnotations(sym);
0N/A }
0N/A },
0N/A
0N/A new AttributeReader(names.RuntimeInvisibleTypeAnnotations, V51, CLASS_OR_MEMBER_ATTRIBUTE) {
0N/A void read(Symbol sym, int attrLen) {
0N/A attachTypeAnnotations(sym);
0N/A }
0N/A },
0N/A
0N/A
0N/A // The following attributes for a Code attribute are not currently handled
0N/A // StackMapTable
0N/A // SourceDebugExtension
0N/A // LineNumberTable
0N/A // LocalVariableTypeTable
0N/A };
0N/A
0N/A for (AttributeReader r: readers)
0N/A attributeReaders.put(r.name, r);
0N/A }
0N/A
0N/A /** Report unrecognized attribute.
0N/A */
0N/A void unrecognized(Name attrName) {
0N/A if (checkClassFile)
0N/A printCCF("ccf.unrecognized.attribute", attrName);
0N/A }
0N/A
0N/A
0N/A
0N/A void readEnclosingMethodAttr(Symbol sym) {
0N/A // sym is a nested class with an "Enclosing Method" attribute
0N/A // remove sym from it's current owners scope and place it in
0N/A // the scope specified by the attribute
0N/A sym.owner.members().remove(sym);
0N/A ClassSymbol self = (ClassSymbol)sym;
0N/A ClassSymbol c = readClassSymbol(nextChar());
0N/A NameAndType nt = (NameAndType)readPool(nextChar());
0N/A
0N/A MethodSymbol m = findMethod(nt, c.members_field, self.flags());
0N/A if (nt != null && m == null)
0N/A throw badClassFile("bad.enclosing.method", self);
0N/A
0N/A self.name = simpleBinaryName(self.flatname, c.flatname) ;
0N/A self.owner = m != null ? m : c;
0N/A if (self.name.isEmpty())
0N/A self.fullname = null;
0N/A else
0N/A self.fullname = ClassSymbol.formFullName(self.name, self.owner);
0N/A
0N/A if (m != null) {
0N/A ((ClassType)sym.type).setEnclosingType(m.type);
0N/A } else if ((self.flags_field & STATIC) == 0) {
0N/A ((ClassType)sym.type).setEnclosingType(c.type);
0N/A } else {
0N/A ((ClassType)sym.type).setEnclosingType(Type.noType);
0N/A }
0N/A enterTypevars(self);
0N/A if (!missingTypeVariables.isEmpty()) {
0N/A ListBuffer<Type> typeVars = new ListBuffer<Type>();
0N/A for (Type typevar : missingTypeVariables) {
0N/A typeVars.append(findTypeVar(typevar.tsym.name));
0N/A }
0N/A foundTypeVariables = typeVars.toList();
0N/A } else {
0N/A foundTypeVariables = List.nil();
0N/A }
0N/A }
0N/A
0N/A // See java.lang.Class
0N/A private Name simpleBinaryName(Name self, Name enclosing) {
0N/A String simpleBinaryName = self.toString().substring(enclosing.toString().length());
0N/A if (simpleBinaryName.length() < 1 || simpleBinaryName.charAt(0) != '$')
0N/A throw badClassFile("bad.enclosing.method", self);
0N/A int index = 1;
0N/A while (index < simpleBinaryName.length() &&
0N/A isAsciiDigit(simpleBinaryName.charAt(index)))
0N/A index++;
0N/A return names.fromString(simpleBinaryName.substring(index));
0N/A }
0N/A
0N/A private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) {
0N/A if (nt == null)
0N/A return null;
0N/A
0N/A MethodType type = nt.type.asMethodType();
0N/A
0N/A for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next())
0N/A if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type))
0N/A return (MethodSymbol)e.sym;
0N/A
0N/A if (nt.name != names.init)
0N/A // not a constructor
0N/A return null;
0N/A if ((flags & INTERFACE) != 0)
0N/A // no enclosing instance
0N/A return null;
0N/A if (nt.type.getParameterTypes().isEmpty())
0N/A // no parameters
0N/A return null;
0N/A
0N/A // A constructor of an inner class.
0N/A // Remove the first argument (the enclosing instance)
0N/A nt.type = new MethodType(nt.type.getParameterTypes().tail,
0N/A nt.type.getReturnType(),
0N/A nt.type.getThrownTypes(),
0N/A syms.methodClass);
0N/A // Try searching again
0N/A return findMethod(nt, scope, flags);
0N/A }
0N/A
0N/A /** Similar to Types.isSameType but avoids completion */
0N/A private boolean isSameBinaryType(MethodType mt1, MethodType mt2) {
0N/A List<Type> types1 = types.erasure(mt1.getParameterTypes())
0N/A .prepend(types.erasure(mt1.getReturnType()));
0N/A List<Type> types2 = mt2.getParameterTypes().prepend(mt2.getReturnType());
0N/A while (!types1.isEmpty() && !types2.isEmpty()) {
0N/A if (types1.head.tsym != types2.head.tsym)
0N/A return false;
0N/A types1 = types1.tail;
0N/A types2 = types2.tail;
0N/A }
0N/A return types1.isEmpty() && types2.isEmpty();
0N/A }
0N/A
0N/A /**
0N/A * Character.isDigit answers <tt>true</tt> to some non-ascii
0N/A * digits. This one does not. <b>copied from java.lang.Class</b>
0N/A */
0N/A private static boolean isAsciiDigit(char c) {
0N/A return '0' <= c && c <= '9';
0N/A }
0N/A
0N/A /** Read member attributes.
0N/A */
0N/A void readMemberAttrs(Symbol sym) {
0N/A readAttrs(sym, AttributeKind.MEMBER);
0N/A }
0N/A
0N/A void readAttrs(Symbol sym, AttributeKind kind) {
0N/A char ac = nextChar();
0N/A for (int i = 0; i < ac; i++) {
0N/A Name attrName = readName(nextChar());
0N/A int attrLen = nextInt();
0N/A AttributeReader r = attributeReaders.get(attrName);
0N/A if (r != null && r.accepts(kind))
0N/A r.read(sym, attrLen);
0N/A else {
0N/A unrecognized(attrName);
0N/A bp = bp + attrLen;
0N/A }
0N/A }
0N/A }
0N/A
0N/A private boolean readingClassAttr = false;
0N/A private List<Type> missingTypeVariables = List.nil();
0N/A private List<Type> foundTypeVariables = List.nil();
0N/A
0N/A /** Read class attributes.
1601N/A */
1601N/A void readClassAttrs(ClassSymbol c) {
0N/A readAttrs(c, AttributeKind.CLASS);
0N/A }
0N/A
0N/A /** Read code block.
0N/A */
0N/A Code readCode(Symbol owner) {
0N/A nextChar(); // max_stack
0N/A nextChar(); // max_locals
0N/A final int code_length = nextInt();
0N/A bp += code_length;
0N/A final char exception_table_length = nextChar();
0N/A bp += exception_table_length * 8;
0N/A readMemberAttrs(owner);
0N/A return null;
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Reading Java-language annotations
0N/A ***********************************************************************/
0N/A
0N/A /** Attach annotations.
0N/A */
0N/A void attachAnnotations(final Symbol sym) {
0N/A int numAttributes = nextChar();
0N/A if (numAttributes != 0) {
0N/A ListBuffer<CompoundAnnotationProxy> proxies =
0N/A new ListBuffer<CompoundAnnotationProxy>();
0N/A for (int i = 0; i<numAttributes; i++) {
0N/A CompoundAnnotationProxy proxy = readCompoundAnnotation();
1601N/A if (proxy.type.tsym == syms.proprietaryType.tsym)
1601N/A sym.flags_field |= PROPRIETARY;
1601N/A else
1601N/A proxies.append(proxy);
1601N/A }
1601N/A annotate.later(new AnnotationCompleter(sym, proxies.toList()));
0N/A }
0N/A }
0N/A
0N/A /** Attach parameter annotations.
0N/A */
0N/A void attachParameterAnnotations(final Symbol method) {
0N/A final MethodSymbol meth = (MethodSymbol)method;
0N/A int numParameters = buf[bp++] & 0xFF;
0N/A List<VarSymbol> parameters = meth.params();
0N/A int pnum = 0;
0N/A while (parameters.tail != null) {
0N/A attachAnnotations(parameters.head);
0N/A parameters = parameters.tail;
0N/A pnum++;
0N/A }
0N/A if (pnum != numParameters) {
0N/A throw badClassFile("bad.runtime.invisible.param.annotations", meth);
0N/A }
0N/A }
1601N/A
1601N/A void attachTypeAnnotations(final Symbol sym) {
1601N/A int numAttributes = nextChar();
1601N/A if (numAttributes != 0) {
1601N/A ListBuffer<TypeAnnotationProxy> proxies =
1601N/A ListBuffer.lb();
1601N/A for (int i = 0; i < numAttributes; i++)
0N/A proxies.append(readTypeAnnotation());
0N/A annotate.later(new TypeAnnotationCompleter(sym, proxies.toList()));
1601N/A }
1601N/A }
1601N/A
0N/A /** Attach the default value for an annotation element.
0N/A */
0N/A void attachAnnotationDefault(final Symbol sym) {
0N/A final MethodSymbol meth = (MethodSymbol)sym; // only on methods
0N/A final Attribute value = readAttributeValue();
0N/A annotate.later(new AnnotationDefaultCompleter(meth, value));
0N/A }
0N/A
0N/A Type readTypeOrClassSymbol(int i) {
0N/A // support preliminary jsr175-format class files
0N/A if (buf[poolIdx[i]] == CONSTANT_Class)
0N/A return readClassSymbol(i).type;
0N/A return readType(i);
0N/A }
0N/A Type readEnumType(int i) {
0N/A // support preliminary jsr175-format class files
0N/A int index = poolIdx[i];
0N/A int length = getChar(index + 1);
0N/A if (buf[index + length + 2] != ';')
0N/A return enterClass(readName(i)).type;
0N/A return readType(i);
0N/A }
0N/A
0N/A CompoundAnnotationProxy readCompoundAnnotation() {
0N/A Type t = readTypeOrClassSymbol(nextChar());
0N/A int numFields = nextChar();
0N/A ListBuffer<Pair<Name,Attribute>> pairs =
0N/A new ListBuffer<Pair<Name,Attribute>>();
0N/A for (int i=0; i<numFields; i++) {
0N/A Name name = readName(nextChar());
0N/A Attribute value = readAttributeValue();
0N/A pairs.append(new Pair<Name,Attribute>(name, value));
0N/A }
0N/A return new CompoundAnnotationProxy(t, pairs.toList());
0N/A }
0N/A
0N/A TypeAnnotationProxy readTypeAnnotation() {
0N/A CompoundAnnotationProxy proxy = readCompoundAnnotation();
0N/A TypeAnnotationPosition position = readPosition();
0N/A
0N/A if (debugJSR308)
0N/A System.out.println("TA: reading: " + proxy + " @ " + position
0N/A + " in " + log.currentSourceFile());
0N/A
0N/A return new TypeAnnotationProxy(proxy, position);
0N/A }
0N/A
0N/A TypeAnnotationPosition readPosition() {
0N/A byte tag = nextByte();
0N/A
0N/A if (!TargetType.isValidTargetTypeValue(tag))
0N/A throw this.badClassFile("bad.type.annotation.value", tag);
0N/A
0N/A TypeAnnotationPosition position = new TypeAnnotationPosition();
0N/A TargetType type = TargetType.fromTargetTypeValue(tag);
0N/A
0N/A position.type = type;
0N/A
0N/A switch (type) {
0N/A // type case
0N/A case TYPECAST:
0N/A case TYPECAST_GENERIC_OR_ARRAY:
0N/A // object creation
0N/A case INSTANCEOF:
0N/A case INSTANCEOF_GENERIC_OR_ARRAY:
0N/A // new expression
0N/A case NEW:
0N/A case NEW_GENERIC_OR_ARRAY:
0N/A position.offset = nextChar();
0N/A break;
0N/A // local variable
0N/A case LOCAL_VARIABLE:
342N/A case LOCAL_VARIABLE_GENERIC_OR_ARRAY:
342N/A int table_length = nextChar();
342N/A position.lvarOffset = new int[table_length];
342N/A position.lvarLength = new int[table_length];
342N/A position.lvarIndex = new int[table_length];
342N/A
342N/A for (int i = 0; i < table_length; ++i) {
342N/A position.lvarOffset[i] = nextChar();
342N/A position.lvarLength[i] = nextChar();
342N/A position.lvarIndex[i] = nextChar();
342N/A }
61N/A break;
0N/A // method receiver
0N/A case METHOD_RECEIVER:
0N/A // Do nothing
0N/A break;
0N/A // type parameters
0N/A case CLASS_TYPE_PARAMETER:
0N/A case METHOD_TYPE_PARAMETER:
0N/A position.parameter_index = nextByte();
0N/A break;
0N/A // type parameter bounds
0N/A case CLASS_TYPE_PARAMETER_BOUND:
0N/A case CLASS_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY:
0N/A case METHOD_TYPE_PARAMETER_BOUND:
0N/A case METHOD_TYPE_PARAMETER_BOUND_GENERIC_OR_ARRAY:
0N/A position.parameter_index = nextByte();
0N/A position.bound_index = nextByte();
0N/A break;
0N/A // wildcard
0N/A case WILDCARD_BOUND:
0N/A case WILDCARD_BOUND_GENERIC_OR_ARRAY:
0N/A position.wildcard_position = readPosition();
0N/A break;
0N/A // Class extends and implements clauses
0N/A case CLASS_EXTENDS:
0N/A case CLASS_EXTENDS_GENERIC_OR_ARRAY:
0N/A position.type_index = nextByte();
0N/A break;
0N/A // throws
0N/A case THROWS:
0N/A position.type_index = nextByte();
0N/A break;
0N/A case CLASS_LITERAL:
0N/A case CLASS_LITERAL_GENERIC_OR_ARRAY:
0N/A position.offset = nextChar();
0N/A break;
0N/A // method parameter: not specified
0N/A case METHOD_PARAMETER_GENERIC_OR_ARRAY:
0N/A position.parameter_index = nextByte();
0N/A break;
0N/A // method type argument: wasn't specified
0N/A case NEW_TYPE_ARGUMENT:
0N/A case NEW_TYPE_ARGUMENT_GENERIC_OR_ARRAY:
0N/A case METHOD_TYPE_ARGUMENT:
0N/A case METHOD_TYPE_ARGUMENT_GENERIC_OR_ARRAY:
0N/A position.offset = nextChar();
0N/A position.type_index = nextByte();
0N/A break;
0N/A // We don't need to worry abut these
0N/A case METHOD_RETURN_GENERIC_OR_ARRAY:
0N/A case FIELD_GENERIC_OR_ARRAY:
1601N/A break;
0N/A case UNKNOWN:
1601N/A break;
1601N/A default:
0N/A throw new AssertionError("unknown type: " + position);
0N/A }
1601N/A
1601N/A if (type.hasLocation()) {
0N/A int len = nextChar();
0N/A ListBuffer<Integer> loc = ListBuffer.lb();
0N/A for (int i = 0; i < len; i++)
0N/A loc = loc.append((int)nextByte());
0N/A position.location = loc.toList();
0N/A }
0N/A
0N/A return position;
0N/A }
0N/A Attribute readAttributeValue() {
0N/A char c = (char) buf[bp++];
0N/A switch (c) {
0N/A case 'B':
0N/A return new Attribute.Constant(syms.byteType, readPool(nextChar()));
0N/A case 'C':
0N/A return new Attribute.Constant(syms.charType, readPool(nextChar()));
0N/A case 'D':
0N/A return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
0N/A case 'F':
0N/A return new Attribute.Constant(syms.floatType, readPool(nextChar()));
0N/A case 'I':
0N/A return new Attribute.Constant(syms.intType, readPool(nextChar()));
0N/A case 'J':
0N/A return new Attribute.Constant(syms.longType, readPool(nextChar()));
0N/A case 'S':
0N/A return new Attribute.Constant(syms.shortType, readPool(nextChar()));
0N/A case 'Z':
0N/A return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
0N/A case 's':
0N/A return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
0N/A case 'e':
0N/A return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
0N/A case 'c':
0N/A return new Attribute.Class(types, readTypeOrClassSymbol(nextChar()));
0N/A case '[': {
0N/A int n = nextChar();
0N/A ListBuffer<Attribute> l = new ListBuffer<Attribute>();
0N/A for (int i=0; i<n; i++)
0N/A l.append(readAttributeValue());
0N/A return new ArrayAttributeProxy(l.toList());
0N/A }
0N/A case '@':
0N/A return readCompoundAnnotation();
0N/A default:
0N/A throw new AssertionError("unknown annotation tag '" + c + "'");
0N/A }
0N/A }
0N/A
0N/A interface ProxyVisitor extends Attribute.Visitor {
0N/A void visitEnumAttributeProxy(EnumAttributeProxy proxy);
0N/A void visitArrayAttributeProxy(ArrayAttributeProxy proxy);
0N/A void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy);
0N/A }
0N/A
0N/A static class EnumAttributeProxy extends Attribute {
0N/A Type enumType;
0N/A Name enumerator;
0N/A public EnumAttributeProxy(Type enumType, Name enumerator) {
0N/A super(null);
0N/A this.enumType = enumType;
0N/A this.enumerator = enumerator;
0N/A }
0N/A public void accept(Visitor v) { ((ProxyVisitor)v).visitEnumAttributeProxy(this); }
0N/A @Override
0N/A public String toString() {
0N/A return "/*proxy enum*/" + enumType + "." + enumerator;
0N/A }
0N/A }
0N/A
0N/A static class ArrayAttributeProxy extends Attribute {
0N/A List<Attribute> values;
0N/A ArrayAttributeProxy(List<Attribute> values) {
0N/A super(null);
0N/A this.values = values;
0N/A }
0N/A public void accept(Visitor v) { ((ProxyVisitor)v).visitArrayAttributeProxy(this); }
0N/A @Override
0N/A public String toString() {
0N/A return "{" + values + "}";
0N/A }
0N/A }
0N/A
0N/A /** A temporary proxy representing a compound attribute.
0N/A */
0N/A static class CompoundAnnotationProxy extends Attribute {
0N/A final List<Pair<Name,Attribute>> values;
0N/A public CompoundAnnotationProxy(Type type,
0N/A List<Pair<Name,Attribute>> values) {
0N/A super(type);
0N/A this.values = values;
0N/A }
0N/A public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); }
0N/A @Override
0N/A public String toString() {
0N/A StringBuffer buf = new StringBuffer();
0N/A buf.append("@");
548N/A buf.append(type.tsym.getQualifiedName());
548N/A buf.append("/*proxy*/{");
548N/A boolean first = true;
548N/A for (List<Pair<Name,Attribute>> v = values;
0N/A v.nonEmpty(); v = v.tail) {
0N/A Pair<Name,Attribute> value = v.head;
0N/A if (!first) buf.append(",");
0N/A first = false;
0N/A buf.append(value.fst);
0N/A buf.append("=");
0N/A buf.append(value.snd);
0N/A }
0N/A buf.append("}");
0N/A return buf.toString();
0N/A }
0N/A }
0N/A
0N/A /** A temporary proxy representing a type annotation.
0N/A */
0N/A static class TypeAnnotationProxy {
0N/A final CompoundAnnotationProxy compound;
0N/A final TypeAnnotationPosition position;
0N/A public TypeAnnotationProxy(CompoundAnnotationProxy compound,
0N/A TypeAnnotationPosition position) {
0N/A this.compound = compound;
0N/A this.position = position;
0N/A }
0N/A }
0N/A
0N/A class AnnotationDeproxy implements ProxyVisitor {
0N/A private ClassSymbol requestingOwner = currentOwner.kind == MTH
0N/A ? currentOwner.enclClass() : (ClassSymbol)currentOwner;
0N/A
0N/A List<Attribute.Compound> deproxyCompoundList(List<CompoundAnnotationProxy> pl) {
0N/A // also must fill in types!!!!
0N/A ListBuffer<Attribute.Compound> buf =
0N/A new ListBuffer<Attribute.Compound>();
0N/A for (List<CompoundAnnotationProxy> l = pl; l.nonEmpty(); l=l.tail) {
0N/A buf.append(deproxyCompound(l.head));
0N/A }
0N/A return buf.toList();
0N/A }
0N/A
0N/A Attribute.Compound deproxyCompound(CompoundAnnotationProxy a) {
0N/A ListBuffer<Pair<Symbol.MethodSymbol,Attribute>> buf =
0N/A new ListBuffer<Pair<Symbol.MethodSymbol,Attribute>>();
0N/A for (List<Pair<Name,Attribute>> l = a.values;
0N/A l.nonEmpty();
0N/A l = l.tail) {
0N/A MethodSymbol meth = findAccessMethod(a.type, l.head.fst);
0N/A buf.append(new Pair<Symbol.MethodSymbol,Attribute>
0N/A (meth, deproxy(meth.type.getReturnType(), l.head.snd)));
0N/A }
0N/A return new Attribute.Compound(a.type, buf.toList());
0N/A }
0N/A
0N/A MethodSymbol findAccessMethod(Type container, Name name) {
0N/A CompletionFailure failure = null;
1887N/A try {
1887N/A for (Scope.Entry e = container.tsym.members().lookup(name);
1887N/A e.scope != null;
1887N/A e = e.next()) {
1887N/A Symbol sym = e.sym;
1887N/A if (sym.kind == MTH && sym.type.getParameterTypes().length() == 0)
1887N/A return (MethodSymbol) sym;
1887N/A }
1887N/A } catch (CompletionFailure ex) {
1887N/A failure = ex;
1887N/A }
1887N/A // The method wasn't found: emit a warning and recover
1887N/A JavaFileObject prevSource = log.useSource(requestingOwner.classfile);
1887N/A try {
1887N/A if (failure == null) {
1887N/A log.warning("annotation.method.not.found",
1887N/A container,
1887N/A name);
0N/A } else {
0N/A log.warning("annotation.method.not.found.reason",
0N/A container,
0N/A name,
0N/A failure.getDetailValue());//diagnostic, if present
0N/A }
0N/A } finally {
0N/A log.useSource(prevSource);
0N/A }
0N/A // Construct a new method type and symbol. Use bottom
0N/A // type (typeof null) as return type because this type is
0N/A // a subtype of all reference types and can be converted
0N/A // to primitive types by unboxing.
0N/A MethodType mt = new MethodType(List.<Type>nil(),
0N/A syms.botType,
0N/A List.<Type>nil(),
0N/A syms.methodClass);
0N/A return new MethodSymbol(PUBLIC | ABSTRACT, name, mt, container.tsym);
0N/A }
0N/A
0N/A Attribute result;
0N/A Type type;
0N/A Attribute deproxy(Type t, Attribute a) {
0N/A Type oldType = type;
0N/A try {
0N/A type = t;
2015N/A a.accept(this);
2015N/A return result;
2015N/A } finally {
0N/A type = oldType;
691N/A }
691N/A }
691N/A
691N/A // implement Attribute.Visitor below
691N/A
691N/A public void visitConstant(Attribute.Constant value) {
691N/A // assert value.type == type;
691N/A result = value;
691N/A }
691N/A
691N/A public void visitClass(Attribute.Class clazz) {
242N/A result = clazz;
242N/A }
691N/A
242N/A public void visitEnum(Attribute.Enum e) {
242N/A throw new AssertionError(); // shouldn't happen
242N/A }
242N/A
242N/A public void visitCompound(Attribute.Compound compound) {
242N/A throw new AssertionError(); // shouldn't happen
691N/A }
691N/A
691N/A public void visitArray(Attribute.Array array) {
691N/A throw new AssertionError(); // shouldn't happen
691N/A }
691N/A
691N/A public void visitError(Attribute.Error e) {
691N/A throw new AssertionError(); // shouldn't happen
691N/A }
691N/A
691N/A public void visitEnumAttributeProxy(EnumAttributeProxy proxy) {
691N/A // type.tsym.flatName() should == proxy.enumFlatName
691N/A TypeSymbol enumTypeSym = proxy.enumType.tsym;
691N/A VarSymbol enumerator = null;
691N/A for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
691N/A e.scope != null;
691N/A e = e.next()) {
3863N/A if (e.sym.kind == VAR) {
691N/A enumerator = (VarSymbol)e.sym;
691N/A break;
691N/A }
3863N/A }
691N/A if (enumerator == null) {
242N/A log.error("unknown.enum.constant",
691N/A currentClassFile, enumTypeSym, proxy.enumerator);
242N/A result = new Attribute.Error(enumTypeSym.type);
242N/A } else {
242N/A result = new Attribute.Enum(enumTypeSym.type, enumerator);
0N/A }
0N/A }
0N/A
0N/A public void visitArrayAttributeProxy(ArrayAttributeProxy proxy) {
0N/A int length = proxy.values.length();
0N/A Attribute[] ats = new Attribute[length];
0N/A Type elemtype = types.elemtype(type);
0N/A int i = 0;
0N/A for (List<Attribute> p = proxy.values; p.nonEmpty(); p = p.tail) {
0N/A ats[i++] = deproxy(elemtype, p.head);
0N/A }
0N/A result = new Attribute.Array(type, ats);
0N/A }
0N/A
0N/A public void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy) {
0N/A result = deproxyCompound(proxy);
0N/A }
0N/A }
0N/A
0N/A class AnnotationDefaultCompleter extends AnnotationDeproxy implements Annotate.Annotator {
0N/A final MethodSymbol sym;
0N/A final Attribute value;
0N/A final JavaFileObject classFile = currentClassFile;
0N/A @Override
0N/A public String toString() {
0N/A return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
0N/A }
1929N/A AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) {
1929N/A this.sym = sym;
1929N/A this.value = value;
1929N/A }
1929N/A // implement Annotate.Annotator.enterAnnotation()
1929N/A public void enterAnnotation() {
0N/A JavaFileObject previousClassFile = currentClassFile;
1929N/A try {
1929N/A currentClassFile = classFile;
3084N/A sym.defaultValue = deproxy(sym.type.getReturnType(), value);
1929N/A } finally {
1929N/A currentClassFile = previousClassFile;
0N/A }
1929N/A }
1929N/A }
1929N/A
1929N/A class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Annotator {
0N/A final Symbol sym;
0N/A final List<CompoundAnnotationProxy> l;
0N/A final JavaFileObject classFile;
0N/A @Override
0N/A public String toString() {
0N/A return " ClassReader annotate " + sym.owner + "." + sym + " with " + l;
0N/A }
0N/A AnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l) {
0N/A this.sym = sym;
0N/A this.l = l;
0N/A this.classFile = currentClassFile;
0N/A }
0N/A // implement Annotate.Annotator.enterAnnotation()
0N/A public void enterAnnotation() {
0N/A JavaFileObject previousClassFile = currentClassFile;
0N/A try {
0N/A currentClassFile = classFile;
0N/A List<Attribute.Compound> newList = deproxyCompoundList(l);
0N/A sym.attributes_field = ((sym.attributes_field == null)
0N/A ? newList
0N/A : newList.prependList(sym.attributes_field));
0N/A } finally {
0N/A currentClassFile = previousClassFile;
0N/A }
0N/A }
0N/A }
0N/A
0N/A class TypeAnnotationCompleter extends AnnotationCompleter {
0N/A
0N/A List<TypeAnnotationProxy> proxies;
0N/A
0N/A TypeAnnotationCompleter(Symbol sym,
0N/A List<TypeAnnotationProxy> proxies) {
0N/A super(sym, List.<CompoundAnnotationProxy>nil());
0N/A this.proxies = proxies;
0N/A }
0N/A
0N/A List<Attribute.TypeCompound> deproxyTypeCompoundList(List<TypeAnnotationProxy> proxies) {
0N/A ListBuffer<Attribute.TypeCompound> buf = ListBuffer.lb();
0N/A for (TypeAnnotationProxy proxy: proxies) {
0N/A Attribute.Compound compound = deproxyCompound(proxy.compound);
0N/A Attribute.TypeCompound typeCompound = new Attribute.TypeCompound(compound, proxy.position);
0N/A buf.add(typeCompound);
0N/A }
0N/A return buf.toList();
0N/A }
0N/A
0N/A @Override
0N/A public void enterAnnotation() {
0N/A JavaFileObject previousClassFile = currentClassFile;
0N/A try {
0N/A currentClassFile = classFile;
0N/A List<Attribute.TypeCompound> newList = deproxyTypeCompoundList(proxies);
0N/A if (debugJSR308)
0N/A System.out.println("TA: reading: adding " + newList
0N/A + " to symbol " + sym + " in " + log.currentSourceFile());
0N/A sym.typeAnnotations = ((sym.typeAnnotations == null)
0N/A ? newList
0N/A : newList.prependList(sym.typeAnnotations));
0N/A
0N/A } finally {
0N/A currentClassFile = previousClassFile;
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A/************************************************************************
0N/A * Reading Symbols
0N/A ***********************************************************************/
0N/A
0N/A /** Read a field.
0N/A */
0N/A VarSymbol readField() {
0N/A long flags = adjustFieldFlags(nextChar());
0N/A Name name = readName(nextChar());
0N/A Type type = readType(nextChar());
0N/A VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
0N/A readMemberAttrs(v);
0N/A return v;
0N/A }
4340N/A
4340N/A /** Read a method.
4340N/A */
4340N/A MethodSymbol readMethod() {
4340N/A long flags = adjustMethodFlags(nextChar());
4340N/A Name name = readName(nextChar());
4340N/A Type type = readType(nextChar());
4340N/A if (name == names.init && currentOwner.hasOuterInstance()) {
4340N/A // Sometimes anonymous classes don't have an outer
4340N/A // instance, however, there is no reliable way to tell so
4340N/A // we never strip this$n
4340N/A if (!currentOwner.name.isEmpty())
4340N/A type = new MethodType(type.getParameterTypes().tail,
4340N/A type.getReturnType(),
4340N/A type.getThrownTypes(),
4340N/A syms.methodClass);
4340N/A }
4340N/A MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner);
4340N/A Symbol prevOwner = currentOwner;
4340N/A currentOwner = m;
4340N/A try {
4340N/A readMemberAttrs(m);
4340N/A } finally {
4340N/A currentOwner = prevOwner;
4340N/A }
4340N/A return m;
0N/A }
0N/A
4340N/A /** Skip a field or method
4340N/A */
4340N/A void skipMember() {
4340N/A bp = bp + 6;
4340N/A char ac = nextChar();
4340N/A for (int i = 0; i < ac; i++) {
4340N/A bp = bp + 2;
4340N/A int attrLen = nextInt();
4340N/A bp = bp + attrLen;
4340N/A }
4340N/A }
4340N/A
4340N/A /** Enter type variables of this classtype and all enclosing ones in
4340N/A * `typevars'.
4340N/A */
4340N/A protected void enterTypevars(Type t) {
4340N/A if (t.getEnclosingType() != null && t.getEnclosingType().tag == CLASS)
4340N/A enterTypevars(t.getEnclosingType());
4340N/A for (List<Type> xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail)
4340N/A typevars.enter(xs.head.tsym);
4340N/A }
4340N/A
4340N/A protected void enterTypevars(Symbol sym) {
4340N/A if (sym.owner.kind == MTH) {
4340N/A enterTypevars(sym.owner);
4340N/A enterTypevars(sym.owner.owner);
4340N/A }
4340N/A enterTypevars(sym.type);
4340N/A }
4340N/A
4340N/A /** Read contents of a given class symbol `c'. Both external and internal
4340N/A * versions of an inner class are read.
4340N/A */
4340N/A void readClass(ClassSymbol c) {
4340N/A ClassType ct = (ClassType)c.type;
4340N/A
4340N/A // allocate scope for members
4340N/A c.members_field = new Scope(c);
4340N/A
4340N/A // prepare type variable table
4340N/A typevars = typevars.dup(currentOwner);
4340N/A if (ct.getEnclosingType().tag == CLASS)
4340N/A enterTypevars(ct.getEnclosingType());
4340N/A
4340N/A // read flags, or skip if this is an inner class
4340N/A long flags = adjustClassFlags(nextChar());
4340N/A if (c.owner.kind == PCK) c.flags_field = flags;
4340N/A
4340N/A // read own class name and check that it matches
4340N/A ClassSymbol self = readClassSymbol(nextChar());
4340N/A if (c != self)
4340N/A throw badClassFile("class.file.wrong.class",
4340N/A self.flatname);
4340N/A
4340N/A // class attributes must be read before class
4340N/A // skip ahead to read class attributes
4340N/A int startbp = bp;
4340N/A nextChar();
4340N/A char interfaceCount = nextChar();
4340N/A bp += interfaceCount * 2;
4340N/A char fieldCount = nextChar();
0N/A for (int i = 0; i < fieldCount; i++) skipMember();
0N/A char methodCount = nextChar();
0N/A for (int i = 0; i < methodCount; i++) skipMember();
0N/A readClassAttrs(c);
0N/A
0N/A if (readAllOfClassFile) {
0N/A for (int i = 1; i < poolObj.length; i++) readPool(i);
0N/A c.pool = new Pool(poolObj.length, poolObj);
0N/A }
0N/A
0N/A // reset and read rest of classinfo
0N/A bp = startbp;
0N/A int n = nextChar();
0N/A if (ct.supertype_field == null)
0N/A ct.supertype_field = (n == 0)
0N/A ? Type.noType
0N/A : readClassSymbol(n).erasure(types);
0N/A n = nextChar();
0N/A List<Type> is = List.nil();
0N/A for (int i = 0; i < n; i++) {
0N/A Type _inter = readClassSymbol(nextChar()).erasure(types);
0N/A is = is.prepend(_inter);
0N/A }
0N/A if (ct.interfaces_field == null)
0N/A ct.interfaces_field = is.reverse();
0N/A
0N/A if (fieldCount != nextChar()) assert false;
0N/A for (int i = 0; i < fieldCount; i++) enterMember(c, readField());
0N/A if (methodCount != nextChar()) assert false;
0N/A for (int i = 0; i < methodCount; i++) enterMember(c, readMethod());
0N/A
0N/A typevars = typevars.leave();
0N/A }
0N/A
0N/A /** Read inner class info. For each inner/outer pair allocate a
0N/A * member class.
0N/A */
0N/A void readInnerClasses(ClassSymbol c) {
0N/A int n = nextChar();
0N/A for (int i = 0; i < n; i++) {
0N/A nextChar(); // skip inner class symbol
0N/A ClassSymbol outer = readClassSymbol(nextChar());
0N/A Name name = readName(nextChar());
0N/A if (name == null) name = names.empty;
0N/A long flags = adjustClassFlags(nextChar());
0N/A if (outer != null) { // we have a member class
0N/A if (name == names.empty)
0N/A name = names.one;
0N/A ClassSymbol member = enterClass(name, outer);
0N/A if ((flags & STATIC) == 0) {
0N/A ((ClassType)member.type).setEnclosingType(outer.type);
0N/A if (member.erasure_field != null)
0N/A ((ClassType)member.erasure_field).setEnclosingType(types.erasure(outer.type));
1010N/A }
1010N/A if (c == outer) {
1010N/A member.flags_field = flags;
1010N/A enterMember(c, member);
1010N/A }
1010N/A }
1010N/A }
1010N/A }
0N/A
0N/A /** Read a class file.
0N/A */
0N/A private void readClassFile(ClassSymbol c) throws IOException {
0N/A int magic = nextInt();
0N/A if (magic != JAVA_MAGIC)
0N/A throw badClassFile("illegal.start.of.class.file");
0N/A
0N/A minorVersion = nextChar();
0N/A majorVersion = nextChar();
0N/A int maxMajor = Target.MAX().majorVersion;
0N/A int maxMinor = Target.MAX().minorVersion;
0N/A if (majorVersion > maxMajor ||
0N/A majorVersion * 1000 + minorVersion <
0N/A Target.MIN().majorVersion * 1000 + Target.MIN().minorVersion)
0N/A {
1010N/A if (majorVersion == (maxMajor + 1))
1010N/A log.warning("big.major.version",
1010N/A currentClassFile,
1010N/A majorVersion,
1010N/A maxMajor);
1010N/A else
1010N/A throw badClassFile("wrong.version",
1010N/A Integer.toString(majorVersion),
1010N/A Integer.toString(minorVersion),
1010N/A Integer.toString(maxMajor),
1010N/A Integer.toString(maxMinor));
1010N/A }
1010N/A else if (checkClassFile &&
1010N/A majorVersion == maxMajor &&
0N/A minorVersion > maxMinor)
0N/A {
1010N/A printCCF("found.later.version",
0N/A Integer.toString(minorVersion));
0N/A }
0N/A indexPool();
0N/A if (signatureBuffer.length < bp) {
0N/A int ns = Integer.highestOneBit(bp) << 1;
0N/A signatureBuffer = new byte[ns];
0N/A }
0N/A readClass(c);
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Adjusting flags
0N/A ***********************************************************************/
0N/A
0N/A long adjustFieldFlags(long flags) {
0N/A return flags;
0N/A }
0N/A long adjustMethodFlags(long flags) {
0N/A if ((flags & ACC_BRIDGE) != 0) {
0N/A flags &= ~ACC_BRIDGE;
0N/A flags |= BRIDGE;
0N/A if (!allowGenerics)
0N/A flags &= ~SYNTHETIC;
0N/A }
0N/A if ((flags & ACC_VARARGS) != 0) {
0N/A flags &= ~ACC_VARARGS;
0N/A flags |= VARARGS;
0N/A }
0N/A return flags;
0N/A }
0N/A long adjustClassFlags(long flags) {
1010N/A return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Loading Classes
1010N/A ***********************************************************************/
0N/A
0N/A /** Define a new class given its name and owner.
0N/A */
0N/A public ClassSymbol defineClass(Name name, Symbol owner) {
0N/A ClassSymbol c = new ClassSymbol(0, name, owner);
0N/A if (owner.kind == PCK)
0N/A assert classes.get(c.flatname) == null : c;
0N/A c.completer = this;
0N/A return c;
0N/A }
0N/A
0N/A /** Create a new toplevel or member class symbol with given name
0N/A * and owner and enter in `classes' unless already there.
0N/A */
0N/A public ClassSymbol enterClass(Name name, TypeSymbol owner) {
0N/A Name flatname = TypeSymbol.formFlatName(name, owner);
0N/A ClassSymbol c = classes.get(flatname);
4340N/A if (c == null) {
4340N/A c = defineClass(name, owner);
4340N/A classes.put(flatname, c);
4340N/A } else if ((c.name != name || c.owner != owner) && owner.kind == TYP && c.owner.kind == PCK) {
4340N/A // reassign fields of classes that might have been loaded with
4340N/A // their flat names.
4340N/A c.owner.members().remove(c);
4340N/A c.name = name;
4340N/A c.owner = owner;
4340N/A c.fullname = ClassSymbol.formFullName(name, owner);
4340N/A }
4340N/A return c;
4340N/A }
4340N/A
4340N/A /**
4340N/A * Creates a new toplevel class symbol with given flat name and
4340N/A * given class (or source) file.
4340N/A *
4340N/A * @param flatName a fully qualified binary class name
4340N/A * @param classFile the class file or compilation unit defining
4340N/A * the class (may be {@code null})
4340N/A * @return a newly created class symbol
4340N/A * @throws AssertionError if the class symbol already exists
4340N/A */
4340N/A public ClassSymbol enterClass(Name flatName, JavaFileObject classFile) {
4340N/A ClassSymbol cs = classes.get(flatName);
4340N/A if (cs != null) {
4340N/A String msg = Log.format("%s: completer = %s; class file = %s; source file = %s",
4340N/A cs.fullname,
4340N/A cs.completer,
4340N/A cs.classfile,
4340N/A cs.sourcefile);
4340N/A throw new AssertionError(msg);
4340N/A }
4340N/A Name packageName = Convert.packagePart(flatName);
4340N/A PackageSymbol owner = packageName.isEmpty()
4340N/A ? syms.unnamedPackage
4340N/A : enterPackage(packageName);
4340N/A cs = defineClass(Convert.shortName(flatName), owner);
4340N/A cs.classfile = classFile;
4340N/A classes.put(flatName, cs);
242N/A return cs;
242N/A }
242N/A
242N/A /** Create a new member or toplevel class symbol with given flat name
242N/A * and enter in `classes' unless already there.
242N/A */
242N/A public ClassSymbol enterClass(Name flatname) {
242N/A ClassSymbol c = classes.get(flatname);
242N/A if (c == null)
242N/A return enterClass(flatname, (JavaFileObject)null);
242N/A else
0N/A return c;
0N/A }
1887N/A
1887N/A private boolean suppressFlush = false;
0N/A
0N/A /** Completion for classes to be loaded. Before a class is loaded
0N/A * we make sure its enclosing class (if any) is loaded.
0N/A */
0N/A public void complete(Symbol sym) throws CompletionFailure {
0N/A if (sym.kind == TYP) {
1887N/A ClassSymbol c = (ClassSymbol)sym;
0N/A c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
0N/A boolean saveSuppressFlush = suppressFlush;
0N/A suppressFlush = true;
1887N/A try {
0N/A completeOwners(c.owner);
0N/A completeEnclosing(c);
0N/A } finally {
0N/A suppressFlush = saveSuppressFlush;
0N/A }
0N/A fillIn(c);
0N/A } else if (sym.kind == PCK) {
0N/A PackageSymbol p = (PackageSymbol)sym;
0N/A try {
0N/A fillIn(p);
0N/A } catch (IOException ex) {
0N/A throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);
0N/A }
0N/A }
0N/A if (!filling && !suppressFlush)
0N/A annotate.flush(); // finish attaching annotations
0N/A }
3748N/A
3748N/A /** complete up through the enclosing package. */
3748N/A private void completeOwners(Symbol o) {
3748N/A if (o.kind != PCK) completeOwners(o.owner);
3748N/A o.complete();
3748N/A }
3748N/A
3748N/A /**
0N/A * Tries to complete lexically enclosing classes if c looks like a
0N/A * nested class. This is similar to completeOwners but handles
0N/A * the situation when a nested class is accessed directly as it is
0N/A * possible with the Tree API or javax.lang.model.*.
3748N/A */
3748N/A private void completeEnclosing(ClassSymbol c) {
3748N/A if (c.owner.kind == PCK) {
3748N/A Symbol owner = c.owner;
3748N/A for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) {
3748N/A Symbol encl = owner.members().lookup(name).sym;
3748N/A if (encl == null)
3748N/A encl = classes.get(TypeSymbol.formFlatName(name, owner));
3748N/A if (encl != null)
3748N/A encl.complete();
3748N/A }
3748N/A }
3748N/A }
3748N/A
3748N/A /** We can only read a single class file at a time; this
3748N/A * flag keeps track of when we are currently reading a class
3748N/A * file.
3748N/A */
3748N/A private boolean filling = false;
3748N/A
3748N/A /** Fill in definition of class `c' from corresponding class or
3748N/A * source file.
3748N/A */
3748N/A private void fillIn(ClassSymbol c) {
3748N/A if (completionFailureName == c.fullname) {
0N/A throw new CompletionFailure(c, "user-selected completion failure by class name");
0N/A }
0N/A currentOwner = c;
0N/A JavaFileObject classfile = c.classfile;
0N/A if (classfile != null) {
0N/A JavaFileObject previousClassFile = currentClassFile;
1601N/A try {
1601N/A assert !filling :
1601N/A "Filling " + classfile.toUri() +
0N/A " during " + previousClassFile;
0N/A currentClassFile = classfile;
0N/A if (verbose) {
3748N/A printVerbose("loading", currentClassFile.toString());
3748N/A }
3748N/A if (classfile.getKind() == JavaFileObject.Kind.CLASS) {
0N/A filling = true;
0N/A try {
0N/A bp = 0;
0N/A buf = readInputStream(buf, classfile.openInputStream());
0N/A readClassFile(c);
0N/A if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) {
0N/A List<Type> missing = missingTypeVariables;
0N/A List<Type> found = foundTypeVariables;
3748N/A missingTypeVariables = List.nil();
3748N/A foundTypeVariables = List.nil();
3748N/A filling = false;
3748N/A ClassType ct = (ClassType)currentOwner.type;
3748N/A ct.supertype_field =
3748N/A types.subst(ct.supertype_field, missing, found);
2625N/A ct.interfaces_field =
2625N/A types.subst(ct.interfaces_field, missing, found);
0N/A } else if (missingTypeVariables.isEmpty() !=
0N/A foundTypeVariables.isEmpty()) {
0N/A Name name = missingTypeVariables.head.tsym.name;
0N/A throw badClassFile("undecl.type.var", name);
0N/A }
0N/A } finally {
0N/A missingTypeVariables = List.nil();
0N/A foundTypeVariables = List.nil();
0N/A filling = false;
0N/A }
0N/A } else {
0N/A if (sourceCompleter != null) {
0N/A sourceCompleter.complete(c);
0N/A } else {
0N/A throw new IllegalStateException("Source completer required to read "
0N/A + classfile.toUri());
0N/A }
0N/A }
0N/A return;
0N/A } catch (IOException ex) {
3748N/A throw badClassFile("unable.to.access.file", ex.getMessage());
3748N/A } finally {
3748N/A currentClassFile = previousClassFile;
3748N/A }
3748N/A } else {
3748N/A JCDiagnostic diag =
3748N/A diagFactory.fragment("class.file.not.found", c.flatname);
3748N/A throw
0N/A newCompletionFailure(c, diag);
0N/A }
0N/A }
0N/A // where
0N/A private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException {
0N/A try {
0N/A buf = ensureCapacity(buf, s.available());
0N/A int r = s.read(buf);
0N/A int bp = 0;
0N/A while (r != -1) {
0N/A bp += r;
0N/A buf = ensureCapacity(buf, bp);
0N/A r = s.read(buf, bp, buf.length - bp);
0N/A }
0N/A return buf;
0N/A } finally {
0N/A try {
0N/A s.close();
0N/A } catch (IOException e) {
0N/A /* Ignore any errors, as this stream may have already
0N/A * thrown a related exception which is the one that
0N/A * should be reported.
0N/A */
0N/A }
0N/A }
0N/A }
0N/A private static byte[] ensureCapacity(byte[] buf, int needed) {
0N/A if (buf.length < needed) {
0N/A byte[] old = buf;
0N/A buf = new byte[Integer.highestOneBit(needed) << 1];
0N/A System.arraycopy(old, 0, buf, 0, old.length);
0N/A }
0N/A return buf;
0N/A }
0N/A /** Static factory for CompletionFailure objects.
0N/A * In practice, only one can be used at a time, so we share one
0N/A * to reduce the expense of allocating new exception objects.
0N/A */
0N/A private CompletionFailure newCompletionFailure(TypeSymbol c,
0N/A JCDiagnostic diag) {
0N/A if (!cacheCompletionFailure) {
0N/A // log.warning("proc.messager",
0N/A // Log.getLocalizedString("class.file.not.found", c.flatname));
0N/A // c.debug.printStackTrace();
0N/A return new CompletionFailure(c, diag);
0N/A } else {
0N/A CompletionFailure result = cachedCompletionFailure;
0N/A result.sym = c;
0N/A result.diag = diag;
0N/A return result;
0N/A }
0N/A }
0N/A private CompletionFailure cachedCompletionFailure =
0N/A new CompletionFailure(null, (JCDiagnostic) null);
0N/A {
0N/A cachedCompletionFailure.setStackTrace(new StackTraceElement[0]);
0N/A }
0N/A
0N/A /** Load a toplevel class with given fully qualified name
0N/A * The class is entered into `classes' only if load was successful.
0N/A */
0N/A public ClassSymbol loadClass(Name flatname) throws CompletionFailure {
0N/A boolean absent = classes.get(flatname) == null;
0N/A ClassSymbol c = enterClass(flatname);
0N/A if (c.members_field == null && c.completer != null) {
0N/A try {
0N/A c.complete();
0N/A } catch (CompletionFailure ex) {
0N/A if (absent) classes.remove(flatname);
0N/A throw ex;
0N/A }
0N/A }
0N/A return c;
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Loading Packages
0N/A ***********************************************************************/
0N/A
0N/A /** Check to see if a package exists, given its fully qualified name.
0N/A */
0N/A public boolean packageExists(Name fullname) {
0N/A return enterPackage(fullname).exists();
0N/A }
0N/A
0N/A /** Make a package, given its fully qualified name.
1562N/A */
0N/A public PackageSymbol enterPackage(Name fullname) {
1562N/A PackageSymbol p = packages.get(fullname);
0N/A if (p == null) {
0N/A assert !fullname.isEmpty() : "rootPackage missing!";
0N/A p = new PackageSymbol(
0N/A Convert.shortName(fullname),
0N/A enterPackage(Convert.packagePart(fullname)));
0N/A p.completer = this;
0N/A packages.put(fullname, p);
0N/A }
0N/A return p;
0N/A }
0N/A
0N/A /** Make a package, given its unqualified name and enclosing package.
0N/A */
0N/A public PackageSymbol enterPackage(Name name, PackageSymbol owner) {
0N/A return enterPackage(TypeSymbol.formFullName(name, owner));
1601N/A }
1601N/A
513N/A /** Include class corresponding to given class file in package,
0N/A * unless (1) we already have one the same kind (.class or .java), or
2149N/A * (2) we have one of the other kind, and the given class file
0N/A * is older.
0N/A */
0N/A protected void includeClassFile(PackageSymbol p, JavaFileObject file) {
0N/A if ((p.flags_field & EXISTS) == 0)
0N/A for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
0N/A q.flags_field |= EXISTS;
0N/A JavaFileObject.Kind kind = file.getKind();
0N/A int seen;
0N/A if (kind == JavaFileObject.Kind.CLASS)
0N/A seen = CLASS_SEEN;
0N/A else
0N/A seen = SOURCE_SEEN;
0N/A String binaryName = fileManager.inferBinaryName(currentLoc, file);
0N/A int lastDot = binaryName.lastIndexOf(".");
0N/A Name classname = names.fromString(binaryName.substring(lastDot + 1));
0N/A boolean isPkgInfo = classname == names.package_info;
1562N/A ClassSymbol c = isPkgInfo
1562N/A ? p.package_info
1562N/A : (ClassSymbol) p.members_field.lookup(classname).sym;
0N/A if (c == null) {
0N/A c = enterClass(classname, p);
0N/A if (c.classfile == null) // only update the file if's it's newly created
0N/A c.classfile = file;
0N/A if (isPkgInfo) {
1601N/A p.package_info = c;
1601N/A } else {
513N/A if (c.owner == p) // it might be an inner class
1562N/A p.members_field.enter(c);
1562N/A }
1562N/A } else if (c.classfile != null && (c.flags_field & seen) == 0) {
1562N/A // if c.classfile == null, we are currently compiling this class
1562N/A // and no further action is necessary.
1562N/A // if (c.flags_field & seen) != 0, we have already encountered
1562N/A // a file of the same kind; again no further action is necessary.
1562N/A if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0)
1562N/A c.classfile = preferredFileObject(file, c.classfile);
1562N/A }
0N/A c.flags_field |= seen;
0N/A }
0N/A
0N/A /** Implement policy to choose to derive information from a source
1562N/A * file or a class file when both are present. May be overridden
1562N/A * by subclasses.
0N/A */
0N/A protected JavaFileObject preferredFileObject(JavaFileObject a,
1601N/A JavaFileObject b) {
1601N/A
513N/A if (preferSource)
0N/A return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b;
0N/A else {
0N/A long adate = a.getLastModified();
0N/A long bdate = b.getLastModified();
0N/A // 6449326: policy for bad lastModifiedTime in ClassReader
0N/A //assert adate >= 0 && bdate >= 0;
0N/A return (adate > bdate) ? a : b;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * specifies types of files to be read when filling in a package symbol
0N/A */
0N/A protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() {
0N/A return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE);
0N/A }
0N/A
0N/A /**
0N/A * this is used to support javadoc
0N/A */
0N/A protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) {
0N/A }
0N/A
0N/A protected Location currentLoc; // FIXME
0N/A
0N/A private boolean verbosePath = true;
0N/A
0N/A /** Load directory of package into members scope.
0N/A */
0N/A private void fillIn(PackageSymbol p) throws IOException {
0N/A if (p.members_field == null) p.members_field = new Scope(p);
0N/A String packageName = p.fullname.toString();
0N/A
0N/A Set<JavaFileObject.Kind> kinds = getPackageFileKinds();
0N/A
0N/A fillIn(p, PLATFORM_CLASS_PATH,
0N/A fileManager.list(PLATFORM_CLASS_PATH,
0N/A packageName,
0N/A EnumSet.of(JavaFileObject.Kind.CLASS),
0N/A false));
0N/A
0N/A Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds);
4433N/A classKinds.remove(JavaFileObject.Kind.SOURCE);
4433N/A boolean wantClassFiles = !classKinds.isEmpty();
4433N/A
4433N/A Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds);
4433N/A sourceKinds.remove(JavaFileObject.Kind.CLASS);
4433N/A boolean wantSourceFiles = !sourceKinds.isEmpty();
4433N/A
4433N/A boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH);
4433N/A
4433N/A if (verbose && verbosePath) {
4433N/A if (fileManager instanceof StandardJavaFileManager) {
4433N/A StandardJavaFileManager fm = (StandardJavaFileManager)fileManager;
4433N/A if (haveSourcePath && wantSourceFiles) {
4433N/A List<File> path = List.nil();
4433N/A for (File file : fm.getLocation(SOURCE_PATH)) {
4433N/A path = path.prepend(file);
4433N/A }
4433N/A printVerbose("sourcepath", path.reverse().toString());
4433N/A } else if (wantSourceFiles) {
4433N/A List<File> path = List.nil();
4433N/A for (File file : fm.getLocation(CLASS_PATH)) {
4433N/A path = path.prepend(file);
4433N/A }
4433N/A printVerbose("sourcepath", path.reverse().toString());
4433N/A }
4433N/A if (wantClassFiles) {
4433N/A List<File> path = List.nil();
4433N/A for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) {
4433N/A path = path.prepend(file);
4433N/A }
4433N/A for (File file : fm.getLocation(CLASS_PATH)) {
4433N/A path = path.prepend(file);
4433N/A }
4433N/A printVerbose("classpath", path.reverse().toString());
4433N/A }
4433N/A }
4433N/A }
4433N/A
4433N/A if (wantSourceFiles && !haveSourcePath) {
4433N/A fillIn(p, CLASS_PATH,
4433N/A fileManager.list(CLASS_PATH,
4433N/A packageName,
4433N/A kinds,
4433N/A false));
4433N/A } else {
4433N/A if (wantClassFiles)
4433N/A fillIn(p, CLASS_PATH,
4433N/A fileManager.list(CLASS_PATH,
4433N/A packageName,
4433N/A classKinds,
4433N/A false));
0N/A if (wantSourceFiles)
0N/A fillIn(p, SOURCE_PATH,
0N/A fileManager.list(SOURCE_PATH,
0N/A packageName,
0N/A sourceKinds,
0N/A false));
0N/A }
0N/A verbosePath = false;
0N/A }
0N/A // where
0N/A private void fillIn(PackageSymbol p,
0N/A Location location,
0N/A Iterable<JavaFileObject> files)
0N/A {
0N/A currentLoc = location;
0N/A for (JavaFileObject fo : files) {
0N/A switch (fo.getKind()) {
0N/A case CLASS:
0N/A case SOURCE: {
0N/A // TODO pass binaryName to includeClassFile
0N/A String binaryName = fileManager.inferBinaryName(currentLoc, fo);
0N/A String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
0N/A if (SourceVersion.isIdentifier(simpleName) ||
0N/A fo.getKind() == JavaFileObject.Kind.CLASS ||
0N/A simpleName.equals("package-info"))
0N/A includeClassFile(p, fo);
0N/A break;
0N/A }
0N/A default:
0N/A extraFileActions(p, fo);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /** Output for "-verbose" option.
0N/A * @param key The key to look up the correct internationalized string.
0N/A * @param arg An argument for substitution into the output string.
0N/A */
0N/A private void printVerbose(String key, CharSequence arg) {
4433N/A Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg));
0N/A }
0N/A
0N/A /** Output for "-checkclassfile" option.
0N/A * @param key The key to look up the correct internationalized string.
0N/A * @param arg An argument for substitution into the output string.
0N/A */
0N/A private void printCCF(String key, Object arg) {
0N/A Log.printLines(log.noticeWriter, Log.getLocalizedString(key, arg));
0N/A }
0N/A
0N/A
0N/A public interface SourceCompleter {
0N/A void complete(ClassSymbol sym)
0N/A throws CompletionFailure;
0N/A }
0N/A
0N/A /**
0N/A * A subclass of JavaFileObject for the sourcefile attribute found in a classfile.
0N/A * The attribute is only the last component of the original filename, so is unlikely
0N/A * to be valid as is, so operations other than those to access the name throw
0N/A * UnsupportedOperationException
0N/A */
0N/A private static class SourceFileObject extends BaseFileObject {
0N/A
0N/A /** The file's name.
0N/A */
0N/A private Name name;
0N/A private Name flatname;
0N/A
0N/A public SourceFileObject(Name name, Name flatname) {
0N/A super(null); // no file manager; never referenced for this file object
0N/A this.name = name;
0N/A this.flatname = flatname;
0N/A }
0N/A
0N/A public InputStream openInputStream() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A public OutputStream openOutputStream() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A public Reader openReader() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A public Writer openWriter() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A /** @deprecated see bug 6410637 */
0N/A @Deprecated
0N/A public String getName() {
0N/A return name.toString();
0N/A }
0N/A
0N/A public long getLastModified() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A public boolean delete() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
0N/A @Override
0N/A public boolean equals(Object other) {
0N/A if (!(other instanceof SourceFileObject))
0N/A return false;
0N/A SourceFileObject o = (SourceFileObject) other;
0N/A return name.equals(o.name);
0N/A }
0N/A
0N/A @Override
0N/A public int hashCode() {
0N/A return name.hashCode();
0N/A }
0N/A
0N/A public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {
0N/A return true; // fail-safe mode
0N/A }
0N/A
0N/A public URI toUri() {
0N/A try {
1417N/A return new URI(null, name.toString(), null);
0N/A } catch (URISyntaxException e) {
0N/A throw new CannotCreateUriError(name.toString(), e);
1353N/A }
1353N/A }
0N/A
0N/A @Override
1887N/A public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
0N/A throw new UnsupportedOperationException();
0N/A }
1887N/A
0N/A @Override
1887N/A protected String inferBinaryName(Iterable<? extends File> path) {
0N/A return flatname.toString();
0N/A }
0N/A }
0N/A}
0N/A