0N/A/*
814N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. 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
553N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
553N/A * by Oracle 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,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
553N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
553N/A * or visit www.oracle.com if you need additional information or have any
553N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.tools.javac.jvm;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.net.URI;
399N/Aimport java.net.URISyntaxException;
0N/Aimport java.nio.CharBuffer;
427N/Aimport java.util.Arrays;
0N/Aimport java.util.EnumSet;
0N/Aimport java.util.HashMap;
775N/Aimport java.util.HashSet;
0N/Aimport java.util.Map;
0N/Aimport java.util.Set;
0N/Aimport javax.lang.model.SourceVersion;
0N/Aimport javax.tools.JavaFileObject;
0N/Aimport javax.tools.JavaFileManager;
255N/Aimport javax.tools.JavaFileManager.Location;
0N/Aimport javax.tools.StandardJavaFileManager;
0N/A
255N/Aimport static javax.tools.StandardLocation.*;
255N/A
0N/Aimport com.sun.tools.javac.comp.Annotate;
0N/Aimport com.sun.tools.javac.code.*;
775N/Aimport com.sun.tools.javac.code.Lint.LintCategory;
0N/Aimport com.sun.tools.javac.code.Type.*;
0N/Aimport com.sun.tools.javac.code.Symbol.*;
0N/Aimport com.sun.tools.javac.code.Symtab;
49N/Aimport com.sun.tools.javac.file.BaseFileObject;
0N/Aimport com.sun.tools.javac.util.*;
775N/Aimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
0N/A
0N/Aimport static com.sun.tools.javac.code.Flags.*;
0N/Aimport static com.sun.tools.javac.code.Kinds.*;
0N/Aimport static com.sun.tools.javac.code.TypeTags.*;
255N/Aimport static com.sun.tools.javac.jvm.ClassFile.*;
255N/Aimport static com.sun.tools.javac.jvm.ClassFile.Version.*;
0N/A
699N/Aimport static com.sun.tools.javac.main.OptionName.*;
699N/A
0N/A/** This class provides operations to read a classfile into an internal
0N/A * representation. The internal representation is anchored in a
0N/A * ClassSymbol which contains in its scope symbol representations
0N/A * for all other definitions in the classfile. Top-level Classes themselves
0N/A * appear as members of the scopes of PackageSymbols.
0N/A *
580N/A * <p><b>This is NOT part of any supported API.
580N/A * If you write code that depends on this, you do so at your own risk.
0N/A * This code and its internal interfaces are subject to change or
0N/A * deletion without notice.</b>
0N/A */
255N/Apublic class ClassReader implements Completer {
0N/A /** The context key for the class reader. */
0N/A protected static final Context.Key<ClassReader> classReaderKey =
0N/A new Context.Key<ClassReader>();
0N/A
803N/A public static final int INITIAL_BUFFER_SIZE = 0x0fff0;
803N/A
0N/A Annotate annotate;
0N/A
0N/A /** Switch: verbose output.
0N/A */
0N/A boolean verbose;
0N/A
0N/A /** Switch: check class file for correct minor version, unrecognized
0N/A * attributes.
0N/A */
0N/A boolean checkClassFile;
0N/A
0N/A /** Switch: read constant pool and code sections. This switch is initially
0N/A * set to false but can be turned on from outside.
0N/A */
0N/A public boolean readAllOfClassFile = false;
0N/A
0N/A /** Switch: read GJ signature information.
0N/A */
0N/A boolean allowGenerics;
0N/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
794N/A /** Switch: allow simplified varargs.
794N/A */
794N/A boolean allowSimplifiedVarargs;
794N/A
794N/A /** Lint option: warn about classfile issues
775N/A */
775N/A boolean lintClassfile;
775N/A
794N/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 */
0N/A final Log log;
0N/A
0N/A /** The symbol table. */
0N/A Symtab syms;
0N/A
0N/A Types types;
0N/A
0N/A /** The name table. */
112N/A final Names names;
0N/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
11N/A /** Factory for diagnostics
11N/A */
11N/A JCDiagnostic.Factory diagFactory;
11N/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.
0N/A */
0N/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;
0N/A
0N/A /** The class or method currently being read.
0N/A */
0N/A protected Symbol currentOwner = null;
0N/A
0N/A /** The buffer containing the currently read class file.
0N/A */
803N/A byte[] buf = new byte[INITIAL_BUFFER_SIZE];
0N/A
0N/A /** The current input pointer.
0N/A */
0N/A int bp;
0N/A
0N/A /** The objects of the constant pool.
0N/A */
0N/A Object[] poolObj;
0N/A
0N/A /** For every constant pool entry, an index into buf where the
0N/A * defining section of the entry is found.
0N/A */
0N/A int[] poolIdx;
0N/A
255N/A /** The major version number of the class file being read. */
255N/A int majorVersion;
255N/A /** The minor version number of the class file being read. */
255N/A int minorVersion;
255N/A
427N/A /** A table to hold the constant pool indices for method parameter
427N/A * names, as given in LocalVariableTable attributes.
427N/A */
427N/A int[] parameterNameIndices;
427N/A
427N/A /**
427N/A * Whether or not any parameter names have been found.
427N/A */
427N/A boolean haveParameterNameIndices;
427N/A
775N/A /**
775N/A * The set of attribute names for which warnings have been generated for the current class
775N/A */
775N/A Set<Name> warnedAttrs = new HashSet<Name>();
775N/A
0N/A /** Get the ClassReader instance for this invocation. */
0N/A public static ClassReader instance(Context context) {
0N/A ClassReader instance = context.get(classReaderKey);
0N/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) {
815N/A Assert.check(packages == null || packages == syms.packages);
0N/A packages = syms.packages;
815N/A Assert.check(classes == null || classes == syms.classes);
0N/A classes = syms.classes;
0N/A } else {
0N/A packages = new HashMap<Name, PackageSymbol>();
0N/A classes = new HashMap<Name, ClassSymbol>();
0N/A }
0N/A
0N/A packages.put(names.empty, syms.rootPackage);
0N/A syms.rootPackage.completer = this;
0N/A syms.unnamedPackage.completer = this;
0N/A }
0N/A
0N/A /** Construct a new class reader, optionally treated as the
0N/A * definitive classreader for this invocation.
0N/A */
0N/A protected ClassReader(Context context, boolean definitive) {
0N/A if (definitive) context.put(classReaderKey, this);
0N/A
112N/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");
11N/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);
699N/A verbose = options.isSet(VERBOSE);
699N/A checkClassFile = options.isSet("-checkclassfile");
0N/A Source source = Source.instance(context);
0N/A allowGenerics = source.allowGenerics();
0N/A allowVarargs = source.allowVarargs();
0N/A allowAnnotations = source.allowAnnotations();
794N/A allowSimplifiedVarargs = source.allowSimplifiedVarargs();
699N/A saveParameterNames = options.isSet("save-parameter-names");
699N/A cacheCompletionFailure = options.isUnset("dev");
0N/A preferSource = "source".equals(options.get("-Xprefer"));
0N/A
0N/A completionFailureName =
699N/A options.isSet("failcomplete")
0N/A ? names.fromString(options.get("failcomplete"))
0N/A : null;
0N/A
0N/A typevars = new Scope(syms.noSymbol);
255N/A
775N/A lintClassfile = Lint.instance(context).isEnabled(LintCategory.CLASSFILE);
775N/A
255N/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/************************************************************************
0N/A * Error Diagnoses
0N/A ***********************************************************************/
0N/A
11N/A
11N/A public class BadClassFile extends CompletionFailure {
0N/A private static final long serialVersionUID = 0;
0N/A
11N/A public BadClassFile(TypeSymbol sym, JavaFileObject file, JCDiagnostic diag) {
11N/A super(sym, createBadClassFileDiagnostic(file, diag));
0N/A }
0N/A }
11N/A // where
11N/A private JCDiagnostic createBadClassFileDiagnostic(JavaFileObject file, JCDiagnostic diag) {
11N/A String key = (file.getKind() == JavaFileObject.Kind.SOURCE
11N/A ? "bad.source.file.header" : "bad.class.file.header");
11N/A return diagFactory.fragment(key, file, diag);
11N/A }
0N/A
0N/A public BadClassFile badClassFile(String key, Object... args) {
0N/A return new BadClassFile (
0N/A currentOwner.enclClass(),
0N/A currentClassFile,
11N/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
307N/A /** Read a byte.
307N/A */
307N/A byte nextByte() {
307N/A return buf[bp++];
307N/A }
307N/A
0N/A /** Read an integer.
0N/A */
0N/A int nextInt() {
0N/A return
0N/A ((buf[bp++] & 0xFF) << 24) +
0N/A ((buf[bp++] & 0xFF) << 16) +
0N/A ((buf[bp++] & 0xFF) << 8) +
0N/A (buf[bp++] & 0xFF);
0N/A }
0N/A
0N/A /** Extract a character at position bp from buf.
0N/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) +
0N/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));
0N/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
0N/A /** Index all constant pool entries, writing their start addresses into
0N/A * poolIdx.
0N/A */
0N/A void indexPool() {
0N/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:
825N/A case CONSTANT_MethodType:
0N/A bp = bp + 2;
0N/A break;
825N/A case CONSTANT_MethodHandle:
825N/A bp = bp + 3;
825N/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:
825N/A case CONSTANT_InvokeDynamic:
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;
825N/A case CONSTANT_MethodHandle:
825N/A skipBytes(4);
825N/A break;
825N/A case CONSTANT_MethodType:
825N/A skipBytes(3);
825N/A break;
825N/A case CONSTANT_InvokeDynamic:
825N/A skipBytes(5);
825N/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;
815N/A Assert.check(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 }
0N/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;
0N/A
0N/A while (true) {
0N/A final byte c = signature[sigp++];
0N/A switch (c) {
0N/A
0N/A case ';': { // end
0N/A ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
0N/A startSbp,
0N/A sbp - startSbp));
0N/A if (outer == Type.noType)
0N/A outer = t.erasure(types);
0N/A else
0N/A outer = new ClassType(outer, List.<Type>nil(), t);
0N/A sbp = startSbp;
0N/A return outer;
0N/A }
0N/A
0N/A case '<': // generic arguments
0N/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;
255N/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 }
255N/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
255N/A protected enum AttributeKind { CLASS, MEMBER };
255N/A protected abstract class AttributeReader {
783N/A AttributeReader(Name name, ClassFile.Version version, Set<AttributeKind> kinds) {
255N/A this.name = name;
255N/A this.version = version;
255N/A this.kinds = kinds;
255N/A }
255N/A
255N/A boolean accepts(AttributeKind kind) {
775N/A if (kinds.contains(kind)) {
775N/A if (majorVersion > version.major || (majorVersion == version.major && minorVersion >= version.minor))
775N/A return true;
775N/A
775N/A if (lintClassfile && !warnedAttrs.contains(name)) {
775N/A JavaFileObject prev = log.useSource(currentClassFile);
775N/A try {
775N/A log.warning(LintCategory.CLASSFILE, (DiagnosticPosition) null, "future.attr",
775N/A name, version.major, version.minor, majorVersion, minorVersion);
775N/A } finally {
775N/A log.useSource(prev);
775N/A }
775N/A warnedAttrs.add(name);
775N/A }
775N/A }
775N/A return false;
255N/A }
255N/A
255N/A abstract void read(Symbol sym, int attrLen);
255N/A
255N/A final Name name;
783N/A final ClassFile.Version version;
255N/A final Set<AttributeKind> kinds;
255N/A }
255N/A
255N/A protected Set<AttributeKind> CLASS_ATTRIBUTE =
255N/A EnumSet.of(AttributeKind.CLASS);
255N/A protected Set<AttributeKind> MEMBER_ATTRIBUTE =
255N/A EnumSet.of(AttributeKind.MEMBER);
255N/A protected Set<AttributeKind> CLASS_OR_MEMBER_ATTRIBUTE =
255N/A EnumSet.of(AttributeKind.CLASS, AttributeKind.MEMBER);
255N/A
255N/A protected Map<Name, AttributeReader> attributeReaders = new HashMap<Name, AttributeReader>();
255N/A
775N/A private void initAttributeReaders() {
255N/A AttributeReader[] readers = {
255N/A // v45.3 attributes
255N/A
255N/A new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A if (readAllOfClassFile || saveParameterNames)
255N/A ((MethodSymbol)sym).code = readCode(sym);
255N/A else
255N/A bp = bp + attrLen;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.ConstantValue, V45_3, MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A Object v = readPool(nextChar());
255N/A // Ignore ConstantValue attribute if field not final.
255N/A if ((sym.flags() & FINAL) != 0)
255N/A ((VarSymbol) sym).setData(v);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Deprecated, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A sym.flags_field |= DEPRECATED;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Exceptions, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A int nexceptions = nextChar();
255N/A List<Type> thrown = List.nil();
255N/A for (int j = 0; j < nexceptions; j++)
255N/A thrown = thrown.prepend(readClassSymbol(nextChar()).type);
255N/A if (sym.type.getThrownTypes().isEmpty())
255N/A sym.type.asMethodType().thrown = thrown.reverse();
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.InnerClasses, V45_3, CLASS_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A ClassSymbol c = (ClassSymbol) sym;
255N/A readInnerClasses(c);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.LocalVariableTable, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A int newbp = bp + attrLen;
255N/A if (saveParameterNames) {
427N/A // Pick up parameter names from the variable table.
427N/A // Parameter names are not explicitly identified as such,
427N/A // but all parameter name entries in the LocalVariableTable
427N/A // have a start_pc of 0. Therefore, we record the name
427N/A // indicies of all slots with a start_pc of zero in the
427N/A // parameterNameIndicies array.
427N/A // Note that this implicitly honors the JVMS spec that
427N/A // there may be more than one LocalVariableTable, and that
427N/A // there is no specified ordering for the entries.
255N/A int numEntries = nextChar();
427N/A for (int i = 0; i < numEntries; i++) {
255N/A int start_pc = nextChar();
255N/A int length = nextChar();
255N/A int nameIndex = nextChar();
255N/A int sigIndex = nextChar();
255N/A int register = nextChar();
427N/A if (start_pc == 0) {
427N/A // ensure array large enough
427N/A if (register >= parameterNameIndices.length) {
427N/A int newSize = Math.max(register, parameterNameIndices.length + 8);
427N/A parameterNameIndices =
427N/A Arrays.copyOf(parameterNameIndices, newSize);
255N/A }
427N/A parameterNameIndices[register] = nameIndex;
427N/A haveParameterNameIndices = true;
255N/A }
255N/A }
255N/A }
255N/A bp = newbp;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.SourceFile, V45_3, CLASS_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A ClassSymbol c = (ClassSymbol) sym;
255N/A Name n = readName(nextChar());
255N/A c.sourcefile = new SourceFileObject(n, c.flatname);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Synthetic, V45_3, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A // bridge methods are visible when generics not enabled
255N/A if (allowGenerics || (sym.flags_field & BRIDGE) == 0)
255N/A sym.flags_field |= SYNTHETIC;
255N/A }
255N/A },
255N/A
255N/A // standard v49 attributes
255N/A
255N/A new AttributeReader(names.EnclosingMethod, V49, CLASS_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A int newbp = bp + attrLen;
255N/A readEnclosingMethodAttr(sym);
255N/A bp = newbp;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Signature, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A @Override
255N/A boolean accepts(AttributeKind kind) {
255N/A return super.accepts(kind) && allowGenerics;
255N/A }
255N/A
255N/A void read(Symbol sym, int attrLen) {
255N/A if (sym.kind == TYP) {
255N/A ClassSymbol c = (ClassSymbol) sym;
255N/A readingClassAttr = true;
255N/A try {
255N/A ClassType ct1 = (ClassType)c.type;
815N/A Assert.check(c == currentOwner);
255N/A ct1.typarams_field = readTypeParams(nextChar());
255N/A ct1.supertype_field = sigToType();
255N/A ListBuffer<Type> is = new ListBuffer<Type>();
255N/A while (sigp != siglimit) is.append(sigToType());
255N/A ct1.interfaces_field = is.toList();
255N/A } finally {
255N/A readingClassAttr = false;
255N/A }
255N/A } else {
255N/A List<Type> thrown = sym.type.getThrownTypes();
255N/A sym.type = readType(nextChar());
255N/A //- System.err.println(" # " + sym.type);
255N/A if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
255N/A sym.type.asMethodType().thrown = thrown;
255N/A
255N/A }
255N/A }
255N/A },
255N/A
255N/A // v49 annotation attributes
255N/A
255N/A new AttributeReader(names.AnnotationDefault, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A attachAnnotationDefault(sym);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.RuntimeInvisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A attachAnnotations(sym);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.RuntimeInvisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A attachParameterAnnotations(sym);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.RuntimeVisibleAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A attachAnnotations(sym);
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.RuntimeVisibleParameterAnnotations, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A attachParameterAnnotations(sym);
255N/A }
255N/A },
255N/A
255N/A // additional "legacy" v49 attributes, superceded by flags
255N/A
255N/A new AttributeReader(names.Annotation, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A if (allowAnnotations)
255N/A sym.flags_field |= ANNOTATION;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Bridge, V49, MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A sym.flags_field |= BRIDGE;
255N/A if (!allowGenerics)
255N/A sym.flags_field &= ~SYNTHETIC;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Enum, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A sym.flags_field |= ENUM;
255N/A }
255N/A },
255N/A
255N/A new AttributeReader(names.Varargs, V49, CLASS_OR_MEMBER_ATTRIBUTE) {
255N/A void read(Symbol sym, int attrLen) {
255N/A if (allowVarargs)
255N/A sym.flags_field |= VARARGS;
255N/A }
307N/A },
307N/A
255N/A // The following attributes for a Code attribute are not currently handled
255N/A // StackMapTable
255N/A // SourceDebugExtension
255N/A // LineNumberTable
255N/A // LocalVariableTypeTable
255N/A };
255N/A
255N/A for (AttributeReader r: readers)
255N/A attributeReaders.put(r.name, r);
255N/A }
255N/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
255N/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
951N/A if (c.members_field == null)
951N/A throw badClassFile("bad.enclosing.class", self, c);
951N/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;
112N/A if (self.name.isEmpty())
514N/A self.fullname = names.empty;
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) {
255N/A readAttrs(sym, AttributeKind.MEMBER);
255N/A }
255N/A
255N/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();
255N/A AttributeReader r = attributeReaders.get(attrName);
255N/A if (r != null && r.accepts(kind))
255N/A r.read(sym, attrLen);
255N/A else {
255N/A unrecognized(attrName);
255N/A bp = bp + attrLen;
255N/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.
0N/A */
0N/A void readClassAttrs(ClassSymbol c) {
255N/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();
0N/A if (proxy.type.tsym == syms.proprietaryType.tsym)
0N/A sym.flags_field |= PROPRIETARY;
0N/A else
0N/A proxies.append(proxy);
856N/A if (majorVersion >= V51.major &&
956N/A proxy.type.tsym == syms.polymorphicSignatureType.tsym) {
673N/A sym.flags_field |= POLYMORPHIC_SIGNATURE;
673N/A }
0N/A }
0N/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 }
0N/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 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); }
255N/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); }
255N/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); }
255N/A @Override
0N/A public String toString() {
775N/A StringBuilder buf = new StringBuilder();
0N/A buf.append("@");
0N/A buf.append(type.tsym.getQualifiedName());
0N/A buf.append("/*proxy*/{");
0N/A boolean first = true;
0N/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
307N/A /** A temporary proxy representing a type annotation.
307N/A */
307N/A static class TypeAnnotationProxy {
307N/A final CompoundAnnotationProxy compound;
307N/A final TypeAnnotationPosition position;
307N/A public TypeAnnotationProxy(CompoundAnnotationProxy compound,
307N/A TypeAnnotationPosition position) {
307N/A this.compound = compound;
307N/A this.position = position;
307N/A }
307N/A }
307N/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;
0N/A try {
0N/A for (Scope.Entry e = container.tsym.members().lookup(name);
0N/A e.scope != null;
0N/A e = e.next()) {
0N/A Symbol sym = e.sym;
0N/A if (sym.kind == MTH && sym.type.getParameterTypes().length() == 0)
0N/A return (MethodSymbol) sym;
0N/A }
0N/A } catch (CompletionFailure ex) {
0N/A failure = ex;
0N/A }
0N/A // The method wasn't found: emit a warning and recover
0N/A JavaFileObject prevSource = log.useSource(requestingOwner.classfile);
0N/A try {
0N/A if (failure == null) {
0N/A log.warning("annotation.method.not.found",
0N/A container,
0N/A name);
0N/A } else {
0N/A log.warning("annotation.method.not.found.reason",
0N/A container,
0N/A name,
79N/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;
0N/A a.accept(this);
0N/A return result;
0N/A } finally {
0N/A type = oldType;
0N/A }
0N/A }
0N/A
0N/A // implement Attribute.Visitor below
0N/A
0N/A public void visitConstant(Attribute.Constant value) {
0N/A // assert value.type == type;
0N/A result = value;
0N/A }
0N/A
0N/A public void visitClass(Attribute.Class clazz) {
0N/A result = clazz;
0N/A }
0N/A
0N/A public void visitEnum(Attribute.Enum e) {
0N/A throw new AssertionError(); // shouldn't happen
0N/A }
0N/A
0N/A public void visitCompound(Attribute.Compound compound) {
0N/A throw new AssertionError(); // shouldn't happen
0N/A }
0N/A
0N/A public void visitArray(Attribute.Array array) {
0N/A throw new AssertionError(); // shouldn't happen
0N/A }
0N/A
0N/A public void visitError(Attribute.Error e) {
0N/A throw new AssertionError(); // shouldn't happen
0N/A }
0N/A
0N/A public void visitEnumAttributeProxy(EnumAttributeProxy proxy) {
0N/A // type.tsym.flatName() should == proxy.enumFlatName
0N/A TypeSymbol enumTypeSym = proxy.enumType.tsym;
0N/A VarSymbol enumerator = null;
991N/A CompletionFailure failure = null;
991N/A try {
991N/A for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator);
991N/A e.scope != null;
991N/A e = e.next()) {
991N/A if (e.sym.kind == VAR) {
991N/A enumerator = (VarSymbol)e.sym;
991N/A break;
991N/A }
0N/A }
0N/A }
991N/A catch (CompletionFailure ex) {
991N/A failure = ex;
991N/A }
0N/A if (enumerator == null) {
991N/A if (failure != null) {
991N/A log.warning("unknown.enum.constant.reason",
991N/A currentClassFile, enumTypeSym, proxy.enumerator,
991N/A failure.getDiagnostic());
991N/A } else {
991N/A log.warning("unknown.enum.constant",
991N/A currentClassFile, enumTypeSym, proxy.enumerator);
991N/A }
991N/A result = new Attribute.Enum(enumTypeSym.type,
991N/A new VarSymbol(0, proxy.enumerator, syms.botType, enumTypeSym));
0N/A } else {
0N/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;
255N/A @Override
0N/A public String toString() {
0N/A return " ClassReader store default for " + sym.owner + "." + sym + " is " + value;
0N/A }
0N/A AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) {
0N/A this.sym = sym;
0N/A this.value = value;
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 sym.defaultValue = deproxy(sym.type.getReturnType(), value);
0N/A } finally {
0N/A currentClassFile = previousClassFile;
0N/A }
0N/A }
0N/A }
0N/A
0N/A class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Annotator {
0N/A final Symbol sym;
0N/A final List<CompoundAnnotationProxy> l;
0N/A final JavaFileObject classFile;
255N/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
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 }
0N/A
0N/A /** Read a method.
0N/A */
0N/A MethodSymbol readMethod() {
0N/A long flags = adjustMethodFlags(nextChar());
0N/A Name name = readName(nextChar());
0N/A Type type = readType(nextChar());
0N/A if (name == names.init && currentOwner.hasOuterInstance()) {
0N/A // Sometimes anonymous classes don't have an outer
0N/A // instance, however, there is no reliable way to tell so
0N/A // we never strip this$n
112N/A if (!currentOwner.name.isEmpty())
794N/A type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()),
0N/A type.getReturnType(),
0N/A type.getThrownTypes(),
0N/A syms.methodClass);
0N/A }
0N/A MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner);
427N/A if (saveParameterNames)
427N/A initParameterNames(m);
0N/A Symbol prevOwner = currentOwner;
0N/A currentOwner = m;
0N/A try {
0N/A readMemberAttrs(m);
0N/A } finally {
0N/A currentOwner = prevOwner;
0N/A }
427N/A if (saveParameterNames)
427N/A setParameterNames(m, type);
0N/A return m;
0N/A }
0N/A
794N/A private List<Type> adjustMethodParams(long flags, List<Type> args) {
794N/A boolean isVarargs = (flags & VARARGS) != 0;
794N/A if (isVarargs) {
794N/A Type varargsElem = args.last();
794N/A ListBuffer<Type> adjustedArgs = ListBuffer.lb();
794N/A for (Type t : args) {
794N/A adjustedArgs.append(t != varargsElem ?
794N/A t :
794N/A ((ArrayType)t).makeVarargs());
794N/A }
794N/A args = adjustedArgs.toList();
794N/A }
794N/A return args.tail;
794N/A }
794N/A
427N/A /**
427N/A * Init the parameter names array.
427N/A * Parameter names are currently inferred from the names in the
427N/A * LocalVariableTable attributes of a Code attribute.
427N/A * (Note: this means parameter names are currently not available for
427N/A * methods without a Code attribute.)
427N/A * This method initializes an array in which to store the name indexes
427N/A * of parameter names found in LocalVariableTable attributes. It is
427N/A * slightly supersized to allow for additional slots with a start_pc of 0.
427N/A */
427N/A void initParameterNames(MethodSymbol sym) {
427N/A // make allowance for synthetic parameters.
427N/A final int excessSlots = 4;
427N/A int expectedParameterSlots =
427N/A Code.width(sym.type.getParameterTypes()) + excessSlots;
427N/A if (parameterNameIndices == null
427N/A || parameterNameIndices.length < expectedParameterSlots) {
427N/A parameterNameIndices = new int[expectedParameterSlots];
427N/A } else
427N/A Arrays.fill(parameterNameIndices, 0);
427N/A haveParameterNameIndices = false;
427N/A }
427N/A
427N/A /**
427N/A * Set the parameter names for a symbol from the name index in the
427N/A * parameterNameIndicies array. The type of the symbol may have changed
427N/A * while reading the method attributes (see the Signature attribute).
427N/A * This may be because of generic information or because anonymous
427N/A * synthetic parameters were added. The original type (as read from
427N/A * the method descriptor) is used to help guess the existence of
427N/A * anonymous synthetic parameters.
427N/A * On completion, sym.savedParameter names will either be null (if
427N/A * no parameter names were found in the class file) or will be set to a
427N/A * list of names, one per entry in sym.type.getParameterTypes, with
427N/A * any missing names represented by the empty name.
427N/A */
427N/A void setParameterNames(MethodSymbol sym, Type jvmType) {
427N/A // if no names were found in the class file, there's nothing more to do
427N/A if (!haveParameterNameIndices)
427N/A return;
427N/A
427N/A int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
427N/A // the code in readMethod may have skipped the first parameter when
427N/A // setting up the MethodType. If so, we make a corresponding allowance
427N/A // here for the position of the first parameter. Note that this
427N/A // assumes the skipped parameter has a width of 1 -- i.e. it is not
427N/A // a double width type (long or double.)
427N/A if (sym.name == names.init && currentOwner.hasOuterInstance()) {
427N/A // Sometimes anonymous classes don't have an outer
427N/A // instance, however, there is no reliable way to tell so
427N/A // we never strip this$n
427N/A if (!currentOwner.name.isEmpty())
427N/A firstParam += 1;
427N/A }
427N/A
427N/A if (sym.type != jvmType) {
427N/A // reading the method attributes has caused the symbol's type to
427N/A // be changed. (i.e. the Signature attribute.) This may happen if
427N/A // there are hidden (synthetic) parameters in the descriptor, but
427N/A // not in the Signature. The position of these hidden parameters
427N/A // is unspecified; for now, assume they are at the beginning, and
427N/A // so skip over them. The primary case for this is two hidden
427N/A // parameters passed into Enum constructors.
427N/A int skip = Code.width(jvmType.getParameterTypes())
427N/A - Code.width(sym.type.getParameterTypes());
427N/A firstParam += skip;
427N/A }
427N/A List<Name> paramNames = List.nil();
427N/A int index = firstParam;
427N/A for (Type t: sym.type.getParameterTypes()) {
427N/A int nameIdx = (index < parameterNameIndices.length
427N/A ? parameterNameIndices[index] : 0);
427N/A Name name = nameIdx == 0 ? names.empty : readName(nameIdx);
427N/A paramNames = paramNames.prepend(name);
427N/A index += Code.width(t);
427N/A }
427N/A sym.savedParameterNames = paramNames.reverse();
427N/A }
427N/A
825N/A /**
825N/A * skip n bytes
825N/A */
825N/A void skipBytes(int n) {
825N/A bp = bp + n;
825N/A }
825N/A
0N/A /** Skip a field or method
0N/A */
0N/A void skipMember() {
0N/A bp = bp + 6;
0N/A char ac = nextChar();
0N/A for (int i = 0; i < ac; i++) {
0N/A bp = bp + 2;
0N/A int attrLen = nextInt();
0N/A bp = bp + attrLen;
0N/A }
0N/A }
0N/A
0N/A /** Enter type variables of this classtype and all enclosing ones in
0N/A * `typevars'.
0N/A */
0N/A protected void enterTypevars(Type t) {
0N/A if (t.getEnclosingType() != null && t.getEnclosingType().tag == CLASS)
0N/A enterTypevars(t.getEnclosingType());
0N/A for (List<Type> xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail)
0N/A typevars.enter(xs.head.tsym);
0N/A }
0N/A
0N/A protected void enterTypevars(Symbol sym) {
0N/A if (sym.owner.kind == MTH) {
0N/A enterTypevars(sym.owner);
0N/A enterTypevars(sym.owner.owner);
0N/A }
0N/A enterTypevars(sym.type);
0N/A }
0N/A
0N/A /** Read contents of a given class symbol `c'. Both external and internal
0N/A * versions of an inner class are read.
0N/A */
0N/A void readClass(ClassSymbol c) {
0N/A ClassType ct = (ClassType)c.type;
0N/A
0N/A // allocate scope for members
857N/A c.members_field = new Scope(c);
0N/A
0N/A // prepare type variable table
0N/A typevars = typevars.dup(currentOwner);
255N/A if (ct.getEnclosingType().tag == CLASS)
255N/A enterTypevars(ct.getEnclosingType());
0N/A
0N/A // read flags, or skip if this is an inner class
0N/A long flags = adjustClassFlags(nextChar());
0N/A if (c.owner.kind == PCK) c.flags_field = flags;
0N/A
0N/A // read own class name and check that it matches
0N/A ClassSymbol self = readClassSymbol(nextChar());
0N/A if (c != self)
0N/A throw badClassFile("class.file.wrong.class",
0N/A self.flatname);
0N/A
0N/A // class attributes must be read before class
0N/A // skip ahead to read class attributes
0N/A int startbp = bp;
0N/A nextChar();
0N/A char interfaceCount = nextChar();
0N/A bp += interfaceCount * 2;
0N/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
815N/A Assert.check(fieldCount == nextChar());
0N/A for (int i = 0; i < fieldCount; i++) enterMember(c, readField());
815N/A Assert.check(methodCount == nextChar());
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));
0N/A }
0N/A if (c == outer) {
0N/A member.flags_field = flags;
0N/A enterMember(c, member);
0N/A }
0N/A }
0N/A }
0N/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
255N/A minorVersion = nextChar();
255N/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 {
0N/A if (majorVersion == (maxMajor + 1))
0N/A log.warning("big.major.version",
0N/A currentClassFile,
0N/A majorVersion,
0N/A maxMajor);
0N/A else
0N/A throw badClassFile("wrong.version",
0N/A Integer.toString(majorVersion),
0N/A Integer.toString(minorVersion),
0N/A Integer.toString(maxMajor),
0N/A Integer.toString(maxMinor));
0N/A }
0N/A else if (checkClassFile &&
0N/A majorVersion == maxMajor &&
0N/A minorVersion > maxMinor)
0N/A {
0N/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) {
0N/A return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
0N/A }
0N/A
0N/A/************************************************************************
0N/A * Loading Classes
0N/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)
815N/A Assert.checkNull(classes.get(c.flatname), 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);
0N/A if (c == null) {
0N/A c = defineClass(name, owner);
0N/A classes.put(flatname, c);
0N/A } else if ((c.name != name || c.owner != owner) && owner.kind == TYP && c.owner.kind == PCK) {
0N/A // reassign fields of classes that might have been loaded with
0N/A // their flat names.
0N/A c.owner.members().remove(c);
0N/A c.name = name;
0N/A c.owner = owner;
0N/A c.fullname = ClassSymbol.formFullName(name, owner);
0N/A }
0N/A return c;
0N/A }
0N/A
0N/A /**
0N/A * Creates a new toplevel class symbol with given flat name and
0N/A * given class (or source) file.
0N/A *
0N/A * @param flatName a fully qualified binary class name
0N/A * @param classFile the class file or compilation unit defining
0N/A * the class (may be {@code null})
0N/A * @return a newly created class symbol
0N/A * @throws AssertionError if the class symbol already exists
0N/A */
0N/A public ClassSymbol enterClass(Name flatName, JavaFileObject classFile) {
0N/A ClassSymbol cs = classes.get(flatName);
0N/A if (cs != null) {
0N/A String msg = Log.format("%s: completer = %s; class file = %s; source file = %s",
0N/A cs.fullname,
0N/A cs.completer,
0N/A cs.classfile,
0N/A cs.sourcefile);
0N/A throw new AssertionError(msg);
0N/A }
0N/A Name packageName = Convert.packagePart(flatName);
0N/A PackageSymbol owner = packageName.isEmpty()
0N/A ? syms.unnamedPackage
0N/A : enterPackage(packageName);
0N/A cs = defineClass(Convert.shortName(flatName), owner);
0N/A cs.classfile = classFile;
0N/A classes.put(flatName, cs);
0N/A return cs;
0N/A }
0N/A
0N/A /** Create a new member or toplevel class symbol with given flat name
0N/A * and enter in `classes' unless already there.
0N/A */
0N/A public ClassSymbol enterClass(Name flatname) {
0N/A ClassSymbol c = classes.get(flatname);
0N/A if (c == null)
0N/A return enterClass(flatname, (JavaFileObject)null);
0N/A else
0N/A return c;
0N/A }
0N/A
0N/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) {
0N/A ClassSymbol c = (ClassSymbol)sym;
0N/A c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
255N/A boolean saveSuppressFlush = suppressFlush;
255N/A suppressFlush = true;
0N/A try {
0N/A completeOwners(c.owner);
0N/A completeEnclosing(c);
0N/A } finally {
255N/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 }
0N/A
0N/A /** complete up through the enclosing package. */
0N/A private void completeOwners(Symbol o) {
0N/A if (o.kind != PCK) completeOwners(o.owner);
0N/A o.complete();
0N/A }
0N/A
0N/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.*.
0N/A */
0N/A private void completeEnclosing(ClassSymbol c) {
0N/A if (c.owner.kind == PCK) {
0N/A Symbol owner = c.owner;
0N/A for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) {
0N/A Symbol encl = owner.members().lookup(name).sym;
0N/A if (encl == null)
0N/A encl = classes.get(TypeSymbol.formFlatName(name, owner));
0N/A if (encl != null)
0N/A encl.complete();
0N/A }
0N/A }
0N/A }
0N/A
0N/A /** We can only read a single class file at a time; this
0N/A * flag keeps track of when we are currently reading a class
0N/A * file.
0N/A */
0N/A private boolean filling = false;
0N/A
0N/A /** Fill in definition of class `c' from corresponding class or
0N/A * source file.
0N/A */
0N/A private void fillIn(ClassSymbol c) {
0N/A if (completionFailureName == c.fullname) {
0N/A throw new CompletionFailure(c, "user-selected completion failure by class name");
0N/A }
0N/A currentOwner = c;
775N/A warnedAttrs.clear();
0N/A JavaFileObject classfile = c.classfile;
0N/A if (classfile != null) {
0N/A JavaFileObject previousClassFile = currentClassFile;
0N/A try {
815N/A if (filling) {
815N/A Assert.error("Filling " + classfile.toUri() + " during " + previousClassFile);
815N/A }
0N/A currentClassFile = classfile;
0N/A if (verbose) {
908N/A log.printVerbose("loading", currentClassFile.toString());
0N/A }
0N/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;
0N/A missingTypeVariables = List.nil();
0N/A foundTypeVariables = List.nil();
0N/A filling = false;
0N/A ClassType ct = (ClassType)currentOwner.type;
0N/A ct.supertype_field =
0N/A types.subst(ct.supertype_field, missing, found);
0N/A ct.interfaces_field =
0N/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) {
0N/A throw badClassFile("unable.to.access.file", ex.getMessage());
0N/A } finally {
0N/A currentClassFile = previousClassFile;
0N/A }
0N/A } else {
11N/A JCDiagnostic diag =
11N/A diagFactory.fragment("class.file.not.found", c.flatname);
0N/A throw
11N/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 }
803N/A /*
803N/A * ensureCapacity will increase the buffer as needed, taking note that
803N/A * the new buffer will always be greater than the needed and never
803N/A * exactly equal to the needed size or bp. If equal then the read (above)
803N/A * will infinitely loop as buf.length - bp == 0.
803N/A */
0N/A private static byte[] ensureCapacity(byte[] buf, int needed) {
803N/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 */
11N/A private CompletionFailure newCompletionFailure(TypeSymbol c,
11N/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();
11N/A return new CompletionFailure(c, diag);
0N/A } else {
0N/A CompletionFailure result = cachedCompletionFailure;
0N/A result.sym = c;
11N/A result.diag = diag;
0N/A return result;
0N/A }
0N/A }
0N/A private CompletionFailure cachedCompletionFailure =
11N/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.
0N/A */
0N/A public PackageSymbol enterPackage(Name fullname) {
0N/A PackageSymbol p = packages.get(fullname);
0N/A if (p == null) {
815N/A Assert.check(!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));
0N/A }
0N/A
0N/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
0N/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;
0N/A ClassSymbol c = isPkgInfo
0N/A ? p.package_info
0N/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) {
0N/A p.package_info = c;
0N/A } else {
0N/A if (c.owner == p) // it might be an inner class
0N/A p.members_field.enter(c);
0N/A }
0N/A } else if (c.classfile != null && (c.flags_field & seen) == 0) {
0N/A // if c.classfile == null, we are currently compiling this class
0N/A // and no further action is necessary.
0N/A // if (c.flags_field & seen) != 0, we have already encountered
0N/A // a file of the same kind; again no further action is necessary.
0N/A if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0)
0N/A c.classfile = preferredFileObject(file, c.classfile);
0N/A }
0N/A c.flags_field |= seen;
0N/A }
0N/A
0N/A /** Implement policy to choose to derive information from a source
0N/A * file or a class file when both are present. May be overridden
0N/A * by subclasses.
0N/A */
0N/A protected JavaFileObject preferredFileObject(JavaFileObject a,
0N/A JavaFileObject b) {
0N/A
0N/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);
0N/A classKinds.remove(JavaFileObject.Kind.SOURCE);
0N/A boolean wantClassFiles = !classKinds.isEmpty();
0N/A
0N/A Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds);
0N/A sourceKinds.remove(JavaFileObject.Kind.CLASS);
0N/A boolean wantSourceFiles = !sourceKinds.isEmpty();
0N/A
0N/A boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH);
0N/A
0N/A if (verbose && verbosePath) {
0N/A if (fileManager instanceof StandardJavaFileManager) {
0N/A StandardJavaFileManager fm = (StandardJavaFileManager)fileManager;
0N/A if (haveSourcePath && wantSourceFiles) {
0N/A List<File> path = List.nil();
0N/A for (File file : fm.getLocation(SOURCE_PATH)) {
0N/A path = path.prepend(file);
0N/A }
908N/A log.printVerbose("sourcepath", path.reverse().toString());
0N/A } else if (wantSourceFiles) {
0N/A List<File> path = List.nil();
0N/A for (File file : fm.getLocation(CLASS_PATH)) {
0N/A path = path.prepend(file);
0N/A }
908N/A log.printVerbose("sourcepath", path.reverse().toString());
0N/A }
0N/A if (wantClassFiles) {
0N/A List<File> path = List.nil();
0N/A for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) {
0N/A path = path.prepend(file);
0N/A }
0N/A for (File file : fm.getLocation(CLASS_PATH)) {
0N/A path = path.prepend(file);
0N/A }
908N/A log.printVerbose("classpath", path.reverse().toString());
0N/A }
0N/A }
0N/A }
0N/A
0N/A if (wantSourceFiles && !haveSourcePath) {
0N/A fillIn(p, CLASS_PATH,
0N/A fileManager.list(CLASS_PATH,
0N/A packageName,
0N/A kinds,
0N/A false));
0N/A } else {
0N/A if (wantClassFiles)
0N/A fillIn(p, CLASS_PATH,
0N/A fileManager.list(CLASS_PATH,
0N/A packageName,
0N/A classKinds,
0N/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 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 "-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) {
603N/A log.printNoteLines(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;
56N/A private Name flatname;
0N/A
56N/A public SourceFileObject(Name name, Name flatname) {
56N/A super(null); // no file manager; never referenced for this file object
0N/A this.name = name;
56N/A this.flatname = flatname;
0N/A }
0N/A
414N/A @Override
414N/A public URI toUri() {
414N/A try {
414N/A return new URI(null, name.toString(), null);
414N/A } catch (URISyntaxException e) {
414N/A throw new CannotCreateUriError(name.toString(), e);
414N/A }
414N/A }
414N/A
414N/A @Override
414N/A public String getName() {
414N/A return name.toString();
414N/A }
414N/A
414N/A @Override
414N/A public String getShortName() {
414N/A return getName();
414N/A }
414N/A
414N/A @Override
414N/A public JavaFileObject.Kind getKind() {
414N/A return getKind(getName());
414N/A }
414N/A
414N/A @Override
0N/A public InputStream openInputStream() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
414N/A @Override
0N/A public OutputStream openOutputStream() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
414N/A @Override
414N/A public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
414N/A @Override
414N/A public Reader openReader(boolean ignoreEncodingErrors) {
414N/A throw new UnsupportedOperationException();
414N/A }
414N/A
414N/A @Override
0N/A public Writer openWriter() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
414N/A @Override
0N/A public long getLastModified() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
414N/A @Override
0N/A public boolean delete() {
0N/A throw new UnsupportedOperationException();
0N/A }
0N/A
414N/A @Override
414N/A protected String inferBinaryName(Iterable<? extends File> path) {
414N/A return flatname.toString();
414N/A }
414N/A
414N/A @Override
414N/A public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) {
414N/A return true; // fail-safe mode
0N/A }
0N/A
423N/A /**
423N/A * Check if two file objects are equal.
423N/A * SourceFileObjects are just placeholder objects for the value of a
423N/A * SourceFile attribute, and do not directly represent specific files.
423N/A * Two SourceFileObjects are equal if their names are equal.
423N/A */
0N/A @Override
0N/A public boolean equals(Object other) {
423N/A if (this == other)
423N/A return true;
423N/A
0N/A if (!(other instanceof SourceFileObject))
0N/A return false;
423N/A
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}