1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,2280 @@ 1.4 +/* 1.5 + * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Sun designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Sun in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.26 + * have any questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.javac.jvm; 1.30 + 1.31 +import java.io.*; 1.32 +import java.net.URI; 1.33 +import java.nio.CharBuffer; 1.34 +import java.util.EnumSet; 1.35 +import java.util.HashMap; 1.36 +import java.util.Map; 1.37 +import java.util.Set; 1.38 +import javax.lang.model.SourceVersion; 1.39 +import javax.tools.JavaFileObject; 1.40 +import javax.tools.JavaFileManager; 1.41 +import javax.tools.StandardJavaFileManager; 1.42 + 1.43 +import com.sun.tools.javac.comp.Annotate; 1.44 +import com.sun.tools.javac.code.*; 1.45 +import com.sun.tools.javac.code.Type.*; 1.46 +import com.sun.tools.javac.code.Symbol.*; 1.47 +import com.sun.tools.javac.code.Symtab; 1.48 +import com.sun.tools.javac.util.*; 1.49 +import com.sun.tools.javac.util.List; 1.50 + 1.51 +import static com.sun.tools.javac.code.Flags.*; 1.52 +import static com.sun.tools.javac.code.Kinds.*; 1.53 +import static com.sun.tools.javac.code.TypeTags.*; 1.54 +import com.sun.tools.javac.jvm.ClassFile.NameAndType; 1.55 +import javax.tools.JavaFileManager.Location; 1.56 +import static javax.tools.StandardLocation.*; 1.57 + 1.58 +/** This class provides operations to read a classfile into an internal 1.59 + * representation. The internal representation is anchored in a 1.60 + * ClassSymbol which contains in its scope symbol representations 1.61 + * for all other definitions in the classfile. Top-level Classes themselves 1.62 + * appear as members of the scopes of PackageSymbols. 1.63 + * 1.64 + * <p><b>This is NOT part of any API supported by Sun Microsystems. If 1.65 + * you write code that depends on this, you do so at your own risk. 1.66 + * This code and its internal interfaces are subject to change or 1.67 + * deletion without notice.</b> 1.68 + */ 1.69 +public class ClassReader extends ClassFile implements Completer { 1.70 + /** The context key for the class reader. */ 1.71 + protected static final Context.Key<ClassReader> classReaderKey = 1.72 + new Context.Key<ClassReader>(); 1.73 + 1.74 + Annotate annotate; 1.75 + 1.76 + /** Switch: verbose output. 1.77 + */ 1.78 + boolean verbose; 1.79 + 1.80 + /** Switch: check class file for correct minor version, unrecognized 1.81 + * attributes. 1.82 + */ 1.83 + boolean checkClassFile; 1.84 + 1.85 + /** Switch: read constant pool and code sections. This switch is initially 1.86 + * set to false but can be turned on from outside. 1.87 + */ 1.88 + public boolean readAllOfClassFile = false; 1.89 + 1.90 + /** Switch: read GJ signature information. 1.91 + */ 1.92 + boolean allowGenerics; 1.93 + 1.94 + /** Switch: read varargs attribute. 1.95 + */ 1.96 + boolean allowVarargs; 1.97 + 1.98 + /** Switch: allow annotations. 1.99 + */ 1.100 + boolean allowAnnotations; 1.101 + 1.102 + /** Switch: preserve parameter names from the variable table. 1.103 + */ 1.104 + public boolean saveParameterNames; 1.105 + 1.106 + /** 1.107 + * Switch: cache completion failures unless -XDdev is used 1.108 + */ 1.109 + private boolean cacheCompletionFailure; 1.110 + 1.111 + /** 1.112 + * Switch: prefer source files instead of newer when both source 1.113 + * and class are available 1.114 + **/ 1.115 + public boolean preferSource; 1.116 + 1.117 + /** The log to use for verbose output 1.118 + */ 1.119 + final Log log; 1.120 + 1.121 + /** The symbol table. */ 1.122 + Symtab syms; 1.123 + 1.124 + Types types; 1.125 + 1.126 + /** The name table. */ 1.127 + final Name.Table names; 1.128 + 1.129 + /** Force a completion failure on this name 1.130 + */ 1.131 + final Name completionFailureName; 1.132 + 1.133 + /** Access to files 1.134 + */ 1.135 + private final JavaFileManager fileManager; 1.136 + 1.137 + /** Can be reassigned from outside: 1.138 + * the completer to be used for ".java" files. If this remains unassigned 1.139 + * ".java" files will not be loaded. 1.140 + */ 1.141 + public SourceCompleter sourceCompleter = null; 1.142 + 1.143 + /** A hashtable containing the encountered top-level and member classes, 1.144 + * indexed by flat names. The table does not contain local classes. 1.145 + */ 1.146 + private Map<Name,ClassSymbol> classes; 1.147 + 1.148 + /** A hashtable containing the encountered packages. 1.149 + */ 1.150 + private Map<Name, PackageSymbol> packages; 1.151 + 1.152 + /** The current scope where type variables are entered. 1.153 + */ 1.154 + protected Scope typevars; 1.155 + 1.156 + /** The path name of the class file currently being read. 1.157 + */ 1.158 + protected JavaFileObject currentClassFile = null; 1.159 + 1.160 + /** The class or method currently being read. 1.161 + */ 1.162 + protected Symbol currentOwner = null; 1.163 + 1.164 + /** The buffer containing the currently read class file. 1.165 + */ 1.166 + byte[] buf = new byte[0x0fff0]; 1.167 + 1.168 + /** The current input pointer. 1.169 + */ 1.170 + int bp; 1.171 + 1.172 + /** The objects of the constant pool. 1.173 + */ 1.174 + Object[] poolObj; 1.175 + 1.176 + /** For every constant pool entry, an index into buf where the 1.177 + * defining section of the entry is found. 1.178 + */ 1.179 + int[] poolIdx; 1.180 + 1.181 + /** Get the ClassReader instance for this invocation. */ 1.182 + public static ClassReader instance(Context context) { 1.183 + ClassReader instance = context.get(classReaderKey); 1.184 + if (instance == null) 1.185 + instance = new ClassReader(context, true); 1.186 + return instance; 1.187 + } 1.188 + 1.189 + /** Initialize classes and packages, treating this as the definitive classreader. */ 1.190 + public void init(Symtab syms) { 1.191 + init(syms, true); 1.192 + } 1.193 + 1.194 + /** Initialize classes and packages, optionally treating this as 1.195 + * the definitive classreader. 1.196 + */ 1.197 + private void init(Symtab syms, boolean definitive) { 1.198 + if (classes != null) return; 1.199 + 1.200 + if (definitive) { 1.201 + assert packages == null || packages == syms.packages; 1.202 + packages = syms.packages; 1.203 + assert classes == null || classes == syms.classes; 1.204 + classes = syms.classes; 1.205 + } else { 1.206 + packages = new HashMap<Name, PackageSymbol>(); 1.207 + classes = new HashMap<Name, ClassSymbol>(); 1.208 + } 1.209 + 1.210 + packages.put(names.empty, syms.rootPackage); 1.211 + syms.rootPackage.completer = this; 1.212 + syms.unnamedPackage.completer = this; 1.213 + } 1.214 + 1.215 + /** Construct a new class reader, optionally treated as the 1.216 + * definitive classreader for this invocation. 1.217 + */ 1.218 + protected ClassReader(Context context, boolean definitive) { 1.219 + if (definitive) context.put(classReaderKey, this); 1.220 + 1.221 + names = Name.Table.instance(context); 1.222 + syms = Symtab.instance(context); 1.223 + types = Types.instance(context); 1.224 + fileManager = context.get(JavaFileManager.class); 1.225 + if (fileManager == null) 1.226 + throw new AssertionError("FileManager initialization error"); 1.227 + 1.228 + init(syms, definitive); 1.229 + log = Log.instance(context); 1.230 + 1.231 + Options options = Options.instance(context); 1.232 + annotate = Annotate.instance(context); 1.233 + verbose = options.get("-verbose") != null; 1.234 + checkClassFile = options.get("-checkclassfile") != null; 1.235 + Source source = Source.instance(context); 1.236 + allowGenerics = source.allowGenerics(); 1.237 + allowVarargs = source.allowVarargs(); 1.238 + allowAnnotations = source.allowAnnotations(); 1.239 + saveParameterNames = options.get("save-parameter-names") != null; 1.240 + cacheCompletionFailure = options.get("dev") == null; 1.241 + preferSource = "source".equals(options.get("-Xprefer")); 1.242 + 1.243 + completionFailureName = 1.244 + (options.get("failcomplete") != null) 1.245 + ? names.fromString(options.get("failcomplete")) 1.246 + : null; 1.247 + 1.248 + typevars = new Scope(syms.noSymbol); 1.249 + } 1.250 + 1.251 + /** Add member to class unless it is synthetic. 1.252 + */ 1.253 + private void enterMember(ClassSymbol c, Symbol sym) { 1.254 + if ((sym.flags_field & (SYNTHETIC|BRIDGE)) != SYNTHETIC) 1.255 + c.members_field.enter(sym); 1.256 + } 1.257 + 1.258 +/************************************************************************ 1.259 + * Error Diagnoses 1.260 + ***********************************************************************/ 1.261 + 1.262 + public static class BadClassFile extends CompletionFailure { 1.263 + private static final long serialVersionUID = 0; 1.264 + 1.265 + /** 1.266 + * @param msg A localized message. 1.267 + */ 1.268 + public BadClassFile(ClassSymbol c, Object cname, Object msg) { 1.269 + super(c, Log.getLocalizedString("bad.class.file.header", 1.270 + cname, msg)); 1.271 + } 1.272 + } 1.273 + 1.274 + public BadClassFile badClassFile(String key, Object... args) { 1.275 + return new BadClassFile ( 1.276 + currentOwner.enclClass(), 1.277 + currentClassFile, 1.278 + Log.getLocalizedString(key, args)); 1.279 + } 1.280 + 1.281 +/************************************************************************ 1.282 + * Buffer Access 1.283 + ***********************************************************************/ 1.284 + 1.285 + /** Read a character. 1.286 + */ 1.287 + char nextChar() { 1.288 + return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF)); 1.289 + } 1.290 + 1.291 + /** Read an integer. 1.292 + */ 1.293 + int nextInt() { 1.294 + return 1.295 + ((buf[bp++] & 0xFF) << 24) + 1.296 + ((buf[bp++] & 0xFF) << 16) + 1.297 + ((buf[bp++] & 0xFF) << 8) + 1.298 + (buf[bp++] & 0xFF); 1.299 + } 1.300 + 1.301 + /** Extract a character at position bp from buf. 1.302 + */ 1.303 + char getChar(int bp) { 1.304 + return 1.305 + (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF)); 1.306 + } 1.307 + 1.308 + /** Extract an integer at position bp from buf. 1.309 + */ 1.310 + int getInt(int bp) { 1.311 + return 1.312 + ((buf[bp] & 0xFF) << 24) + 1.313 + ((buf[bp+1] & 0xFF) << 16) + 1.314 + ((buf[bp+2] & 0xFF) << 8) + 1.315 + (buf[bp+3] & 0xFF); 1.316 + } 1.317 + 1.318 + 1.319 + /** Extract a long integer at position bp from buf. 1.320 + */ 1.321 + long getLong(int bp) { 1.322 + DataInputStream bufin = 1.323 + new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); 1.324 + try { 1.325 + return bufin.readLong(); 1.326 + } catch (IOException e) { 1.327 + throw new AssertionError(e); 1.328 + } 1.329 + } 1.330 + 1.331 + /** Extract a float at position bp from buf. 1.332 + */ 1.333 + float getFloat(int bp) { 1.334 + DataInputStream bufin = 1.335 + new DataInputStream(new ByteArrayInputStream(buf, bp, 4)); 1.336 + try { 1.337 + return bufin.readFloat(); 1.338 + } catch (IOException e) { 1.339 + throw new AssertionError(e); 1.340 + } 1.341 + } 1.342 + 1.343 + /** Extract a double at position bp from buf. 1.344 + */ 1.345 + double getDouble(int bp) { 1.346 + DataInputStream bufin = 1.347 + new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); 1.348 + try { 1.349 + return bufin.readDouble(); 1.350 + } catch (IOException e) { 1.351 + throw new AssertionError(e); 1.352 + } 1.353 + } 1.354 + 1.355 +/************************************************************************ 1.356 + * Constant Pool Access 1.357 + ***********************************************************************/ 1.358 + 1.359 + /** Index all constant pool entries, writing their start addresses into 1.360 + * poolIdx. 1.361 + */ 1.362 + void indexPool() { 1.363 + poolIdx = new int[nextChar()]; 1.364 + poolObj = new Object[poolIdx.length]; 1.365 + int i = 1; 1.366 + while (i < poolIdx.length) { 1.367 + poolIdx[i++] = bp; 1.368 + byte tag = buf[bp++]; 1.369 + switch (tag) { 1.370 + case CONSTANT_Utf8: case CONSTANT_Unicode: { 1.371 + int len = nextChar(); 1.372 + bp = bp + len; 1.373 + break; 1.374 + } 1.375 + case CONSTANT_Class: 1.376 + case CONSTANT_String: 1.377 + bp = bp + 2; 1.378 + break; 1.379 + case CONSTANT_Fieldref: 1.380 + case CONSTANT_Methodref: 1.381 + case CONSTANT_InterfaceMethodref: 1.382 + case CONSTANT_NameandType: 1.383 + case CONSTANT_Integer: 1.384 + case CONSTANT_Float: 1.385 + bp = bp + 4; 1.386 + break; 1.387 + case CONSTANT_Long: 1.388 + case CONSTANT_Double: 1.389 + bp = bp + 8; 1.390 + i++; 1.391 + break; 1.392 + default: 1.393 + throw badClassFile("bad.const.pool.tag.at", 1.394 + Byte.toString(tag), 1.395 + Integer.toString(bp -1)); 1.396 + } 1.397 + } 1.398 + } 1.399 + 1.400 + /** Read constant pool entry at start address i, use pool as a cache. 1.401 + */ 1.402 + Object readPool(int i) { 1.403 + Object result = poolObj[i]; 1.404 + if (result != null) return result; 1.405 + 1.406 + int index = poolIdx[i]; 1.407 + if (index == 0) return null; 1.408 + 1.409 + byte tag = buf[index]; 1.410 + switch (tag) { 1.411 + case CONSTANT_Utf8: 1.412 + poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1)); 1.413 + break; 1.414 + case CONSTANT_Unicode: 1.415 + throw badClassFile("unicode.str.not.supported"); 1.416 + case CONSTANT_Class: 1.417 + poolObj[i] = readClassOrType(getChar(index + 1)); 1.418 + break; 1.419 + case CONSTANT_String: 1.420 + // FIXME: (footprint) do not use toString here 1.421 + poolObj[i] = readName(getChar(index + 1)).toString(); 1.422 + break; 1.423 + case CONSTANT_Fieldref: { 1.424 + ClassSymbol owner = readClassSymbol(getChar(index + 1)); 1.425 + NameAndType nt = (NameAndType)readPool(getChar(index + 3)); 1.426 + poolObj[i] = new VarSymbol(0, nt.name, nt.type, owner); 1.427 + break; 1.428 + } 1.429 + case CONSTANT_Methodref: 1.430 + case CONSTANT_InterfaceMethodref: { 1.431 + ClassSymbol owner = readClassSymbol(getChar(index + 1)); 1.432 + NameAndType nt = (NameAndType)readPool(getChar(index + 3)); 1.433 + poolObj[i] = new MethodSymbol(0, nt.name, nt.type, owner); 1.434 + break; 1.435 + } 1.436 + case CONSTANT_NameandType: 1.437 + poolObj[i] = new NameAndType( 1.438 + readName(getChar(index + 1)), 1.439 + readType(getChar(index + 3))); 1.440 + break; 1.441 + case CONSTANT_Integer: 1.442 + poolObj[i] = getInt(index + 1); 1.443 + break; 1.444 + case CONSTANT_Float: 1.445 + poolObj[i] = new Float(getFloat(index + 1)); 1.446 + break; 1.447 + case CONSTANT_Long: 1.448 + poolObj[i] = new Long(getLong(index + 1)); 1.449 + break; 1.450 + case CONSTANT_Double: 1.451 + poolObj[i] = new Double(getDouble(index + 1)); 1.452 + break; 1.453 + default: 1.454 + throw badClassFile("bad.const.pool.tag", Byte.toString(tag)); 1.455 + } 1.456 + return poolObj[i]; 1.457 + } 1.458 + 1.459 + /** Read signature and convert to type. 1.460 + */ 1.461 + Type readType(int i) { 1.462 + int index = poolIdx[i]; 1.463 + return sigToType(buf, index + 3, getChar(index + 1)); 1.464 + } 1.465 + 1.466 + /** If name is an array type or class signature, return the 1.467 + * corresponding type; otherwise return a ClassSymbol with given name. 1.468 + */ 1.469 + Object readClassOrType(int i) { 1.470 + int index = poolIdx[i]; 1.471 + int len = getChar(index + 1); 1.472 + int start = index + 3; 1.473 + assert buf[start] == '[' || buf[start + len - 1] != ';'; 1.474 + // by the above assertion, the following test can be 1.475 + // simplified to (buf[start] == '[') 1.476 + return (buf[start] == '[' || buf[start + len - 1] == ';') 1.477 + ? (Object)sigToType(buf, start, len) 1.478 + : (Object)enterClass(names.fromUtf(internalize(buf, start, 1.479 + len))); 1.480 + } 1.481 + 1.482 + /** Read signature and convert to type parameters. 1.483 + */ 1.484 + List<Type> readTypeParams(int i) { 1.485 + int index = poolIdx[i]; 1.486 + return sigToTypeParams(buf, index + 3, getChar(index + 1)); 1.487 + } 1.488 + 1.489 + /** Read class entry. 1.490 + */ 1.491 + ClassSymbol readClassSymbol(int i) { 1.492 + return (ClassSymbol) (readPool(i)); 1.493 + } 1.494 + 1.495 + /** Read name. 1.496 + */ 1.497 + Name readName(int i) { 1.498 + return (Name) (readPool(i)); 1.499 + } 1.500 + 1.501 +/************************************************************************ 1.502 + * Reading Types 1.503 + ***********************************************************************/ 1.504 + 1.505 + /** The unread portion of the currently read type is 1.506 + * signature[sigp..siglimit-1]. 1.507 + */ 1.508 + byte[] signature; 1.509 + int sigp; 1.510 + int siglimit; 1.511 + boolean sigEnterPhase = false; 1.512 + 1.513 + /** Convert signature to type, where signature is a name. 1.514 + */ 1.515 + Type sigToType(Name sig) { 1.516 + return sig == null 1.517 + ? null 1.518 + : sigToType(sig.table.names, sig.index, sig.len); 1.519 + } 1.520 + 1.521 + /** Convert signature to type, where signature is a byte array segment. 1.522 + */ 1.523 + Type sigToType(byte[] sig, int offset, int len) { 1.524 + signature = sig; 1.525 + sigp = offset; 1.526 + siglimit = offset + len; 1.527 + return sigToType(); 1.528 + } 1.529 + 1.530 + /** Convert signature to type, where signature is implicit. 1.531 + */ 1.532 + Type sigToType() { 1.533 + switch ((char) signature[sigp]) { 1.534 + case 'T': 1.535 + sigp++; 1.536 + int start = sigp; 1.537 + while (signature[sigp] != ';') sigp++; 1.538 + sigp++; 1.539 + return sigEnterPhase 1.540 + ? Type.noType 1.541 + : findTypeVar(names.fromUtf(signature, start, sigp - 1 - start)); 1.542 + case '+': { 1.543 + sigp++; 1.544 + Type t = sigToType(); 1.545 + return new WildcardType(t, BoundKind.EXTENDS, 1.546 + syms.boundClass); 1.547 + } 1.548 + case '*': 1.549 + sigp++; 1.550 + return new WildcardType(syms.objectType, BoundKind.UNBOUND, 1.551 + syms.boundClass); 1.552 + case '-': { 1.553 + sigp++; 1.554 + Type t = sigToType(); 1.555 + return new WildcardType(t, BoundKind.SUPER, 1.556 + syms.boundClass); 1.557 + } 1.558 + case 'B': 1.559 + sigp++; 1.560 + return syms.byteType; 1.561 + case 'C': 1.562 + sigp++; 1.563 + return syms.charType; 1.564 + case 'D': 1.565 + sigp++; 1.566 + return syms.doubleType; 1.567 + case 'F': 1.568 + sigp++; 1.569 + return syms.floatType; 1.570 + case 'I': 1.571 + sigp++; 1.572 + return syms.intType; 1.573 + case 'J': 1.574 + sigp++; 1.575 + return syms.longType; 1.576 + case 'L': 1.577 + { 1.578 + // int oldsigp = sigp; 1.579 + Type t = classSigToType(); 1.580 + if (sigp < siglimit && signature[sigp] == '.') 1.581 + throw badClassFile("deprecated inner class signature syntax " + 1.582 + "(please recompile from source)"); 1.583 + /* 1.584 + System.err.println(" decoded " + 1.585 + new String(signature, oldsigp, sigp-oldsigp) + 1.586 + " => " + t + " outer " + t.outer()); 1.587 + */ 1.588 + return t; 1.589 + } 1.590 + case 'S': 1.591 + sigp++; 1.592 + return syms.shortType; 1.593 + case 'V': 1.594 + sigp++; 1.595 + return syms.voidType; 1.596 + case 'Z': 1.597 + sigp++; 1.598 + return syms.booleanType; 1.599 + case '[': 1.600 + sigp++; 1.601 + return new ArrayType(sigToType(), syms.arrayClass); 1.602 + case '(': 1.603 + sigp++; 1.604 + List<Type> argtypes = sigToTypes(')'); 1.605 + Type restype = sigToType(); 1.606 + List<Type> thrown = List.nil(); 1.607 + while (signature[sigp] == '^') { 1.608 + sigp++; 1.609 + thrown = thrown.prepend(sigToType()); 1.610 + } 1.611 + return new MethodType(argtypes, 1.612 + restype, 1.613 + thrown.reverse(), 1.614 + syms.methodClass); 1.615 + case '<': 1.616 + typevars = typevars.dup(currentOwner); 1.617 + Type poly = new ForAll(sigToTypeParams(), sigToType()); 1.618 + typevars = typevars.leave(); 1.619 + return poly; 1.620 + default: 1.621 + throw badClassFile("bad.signature", 1.622 + Convert.utf2string(signature, sigp, 10)); 1.623 + } 1.624 + } 1.625 + 1.626 + byte[] signatureBuffer = new byte[0]; 1.627 + int sbp = 0; 1.628 + /** Convert class signature to type, where signature is implicit. 1.629 + */ 1.630 + Type classSigToType() { 1.631 + if (signature[sigp] != 'L') 1.632 + throw badClassFile("bad.class.signature", 1.633 + Convert.utf2string(signature, sigp, 10)); 1.634 + sigp++; 1.635 + Type outer = Type.noType; 1.636 + int startSbp = sbp; 1.637 + 1.638 + while (true) { 1.639 + final byte c = signature[sigp++]; 1.640 + switch (c) { 1.641 + 1.642 + case ';': { // end 1.643 + ClassSymbol t = enterClass(names.fromUtf(signatureBuffer, 1.644 + startSbp, 1.645 + sbp - startSbp)); 1.646 + if (outer == Type.noType) 1.647 + outer = t.erasure(types); 1.648 + else 1.649 + outer = new ClassType(outer, List.<Type>nil(), t); 1.650 + sbp = startSbp; 1.651 + return outer; 1.652 + } 1.653 + 1.654 + case '<': // generic arguments 1.655 + ClassSymbol t = enterClass(names.fromUtf(signatureBuffer, 1.656 + startSbp, 1.657 + sbp - startSbp)); 1.658 + outer = new ClassType(outer, sigToTypes('>'), t) { 1.659 + boolean completed = false; 1.660 + public Type getEnclosingType() { 1.661 + if (!completed) { 1.662 + completed = true; 1.663 + tsym.complete(); 1.664 + Type enclosingType = tsym.type.getEnclosingType(); 1.665 + if (enclosingType != Type.noType) { 1.666 + List<Type> typeArgs = 1.667 + super.getEnclosingType().allparams(); 1.668 + List<Type> typeParams = 1.669 + enclosingType.allparams(); 1.670 + if (typeParams.length() != typeArgs.length()) { 1.671 + // no "rare" types 1.672 + super.setEnclosingType(types.erasure(enclosingType)); 1.673 + } else { 1.674 + super.setEnclosingType(types.subst(enclosingType, 1.675 + typeParams, 1.676 + typeArgs)); 1.677 + } 1.678 + } else { 1.679 + super.setEnclosingType(Type.noType); 1.680 + } 1.681 + } 1.682 + return super.getEnclosingType(); 1.683 + } 1.684 + public void setEnclosingType(Type outer) { 1.685 + throw new UnsupportedOperationException(); 1.686 + } 1.687 + }; 1.688 + switch (signature[sigp++]) { 1.689 + case ';': 1.690 + if (sigp < signature.length && signature[sigp] == '.') { 1.691 + // support old-style GJC signatures 1.692 + // The signature produced was 1.693 + // Lfoo/Outer<Lfoo/X;>;.Lfoo/Outer$Inner<Lfoo/Y;>; 1.694 + // rather than say 1.695 + // Lfoo/Outer<Lfoo/X;>.Inner<Lfoo/Y;>; 1.696 + // so we skip past ".Lfoo/Outer$" 1.697 + sigp += (sbp - startSbp) + // "foo/Outer" 1.698 + 3; // ".L" and "$" 1.699 + signatureBuffer[sbp++] = (byte)'$'; 1.700 + break; 1.701 + } else { 1.702 + sbp = startSbp; 1.703 + return outer; 1.704 + } 1.705 + case '.': 1.706 + signatureBuffer[sbp++] = (byte)'$'; 1.707 + break; 1.708 + default: 1.709 + throw new AssertionError(signature[sigp-1]); 1.710 + } 1.711 + continue; 1.712 + 1.713 + case '.': 1.714 + signatureBuffer[sbp++] = (byte)'$'; 1.715 + continue; 1.716 + case '/': 1.717 + signatureBuffer[sbp++] = (byte)'.'; 1.718 + continue; 1.719 + default: 1.720 + signatureBuffer[sbp++] = c; 1.721 + continue; 1.722 + } 1.723 + } 1.724 + } 1.725 + 1.726 + /** Convert (implicit) signature to list of types 1.727 + * until `terminator' is encountered. 1.728 + */ 1.729 + List<Type> sigToTypes(char terminator) { 1.730 + List<Type> head = List.of(null); 1.731 + List<Type> tail = head; 1.732 + while (signature[sigp] != terminator) 1.733 + tail = tail.setTail(List.of(sigToType())); 1.734 + sigp++; 1.735 + return head.tail; 1.736 + } 1.737 + 1.738 + /** Convert signature to type parameters, where signature is a name. 1.739 + */ 1.740 + List<Type> sigToTypeParams(Name name) { 1.741 + return sigToTypeParams(name.table.names, name.index, name.len); 1.742 + } 1.743 + 1.744 + /** Convert signature to type parameters, where signature is a byte 1.745 + * array segment. 1.746 + */ 1.747 + List<Type> sigToTypeParams(byte[] sig, int offset, int len) { 1.748 + signature = sig; 1.749 + sigp = offset; 1.750 + siglimit = offset + len; 1.751 + return sigToTypeParams(); 1.752 + } 1.753 + 1.754 + /** Convert signature to type parameters, where signature is implicit. 1.755 + */ 1.756 + List<Type> sigToTypeParams() { 1.757 + List<Type> tvars = List.nil(); 1.758 + if (signature[sigp] == '<') { 1.759 + sigp++; 1.760 + int start = sigp; 1.761 + sigEnterPhase = true; 1.762 + while (signature[sigp] != '>') 1.763 + tvars = tvars.prepend(sigToTypeParam()); 1.764 + sigEnterPhase = false; 1.765 + sigp = start; 1.766 + while (signature[sigp] != '>') 1.767 + sigToTypeParam(); 1.768 + sigp++; 1.769 + } 1.770 + return tvars.reverse(); 1.771 + } 1.772 + 1.773 + /** Convert (implicit) signature to type parameter. 1.774 + */ 1.775 + Type sigToTypeParam() { 1.776 + int start = sigp; 1.777 + while (signature[sigp] != ':') sigp++; 1.778 + Name name = names.fromUtf(signature, start, sigp - start); 1.779 + TypeVar tvar; 1.780 + if (sigEnterPhase) { 1.781 + tvar = new TypeVar(name, currentOwner, syms.botType); 1.782 + typevars.enter(tvar.tsym); 1.783 + } else { 1.784 + tvar = (TypeVar)findTypeVar(name); 1.785 + } 1.786 + List<Type> bounds = List.nil(); 1.787 + Type st = null; 1.788 + if (signature[sigp] == ':' && signature[sigp+1] == ':') { 1.789 + sigp++; 1.790 + st = syms.objectType; 1.791 + } 1.792 + while (signature[sigp] == ':') { 1.793 + sigp++; 1.794 + bounds = bounds.prepend(sigToType()); 1.795 + } 1.796 + if (!sigEnterPhase) { 1.797 + types.setBounds(tvar, bounds.reverse(), st); 1.798 + } 1.799 + return tvar; 1.800 + } 1.801 + 1.802 + /** Find type variable with given name in `typevars' scope. 1.803 + */ 1.804 + Type findTypeVar(Name name) { 1.805 + Scope.Entry e = typevars.lookup(name); 1.806 + if (e.scope != null) { 1.807 + return e.sym.type; 1.808 + } else { 1.809 + if (readingClassAttr) { 1.810 + // While reading the class attribute, the supertypes 1.811 + // might refer to a type variable from an enclosing element 1.812 + // (method or class). 1.813 + // If the type variable is defined in the enclosing class, 1.814 + // we can actually find it in 1.815 + // currentOwner.owner.type.getTypeArguments() 1.816 + // However, until we have read the enclosing method attribute 1.817 + // we don't know for sure if this owner is correct. It could 1.818 + // be a method and there is no way to tell before reading the 1.819 + // enclosing method attribute. 1.820 + TypeVar t = new TypeVar(name, currentOwner, syms.botType); 1.821 + missingTypeVariables = missingTypeVariables.prepend(t); 1.822 + // System.err.println("Missing type var " + name); 1.823 + return t; 1.824 + } 1.825 + throw badClassFile("undecl.type.var", name); 1.826 + } 1.827 + } 1.828 + 1.829 +/************************************************************************ 1.830 + * Reading Attributes 1.831 + ***********************************************************************/ 1.832 + 1.833 + /** Report unrecognized attribute. 1.834 + */ 1.835 + void unrecognized(Name attrName) { 1.836 + if (checkClassFile) 1.837 + printCCF("ccf.unrecognized.attribute", attrName); 1.838 + } 1.839 + 1.840 + /** Read member attribute. 1.841 + */ 1.842 + void readMemberAttr(Symbol sym, Name attrName, int attrLen) { 1.843 + //- System.err.println(" z " + sym + ", " + attrName + ", " + attrLen); 1.844 + if (attrName == names.ConstantValue) { 1.845 + Object v = readPool(nextChar()); 1.846 + // Ignore ConstantValue attribute if field not final. 1.847 + if ((sym.flags() & FINAL) != 0) 1.848 + ((VarSymbol)sym).setData(v); 1.849 + } else if (attrName == names.Code) { 1.850 + if (readAllOfClassFile || saveParameterNames) 1.851 + ((MethodSymbol)sym).code = readCode(sym); 1.852 + else 1.853 + bp = bp + attrLen; 1.854 + } else if (attrName == names.Exceptions) { 1.855 + int nexceptions = nextChar(); 1.856 + List<Type> thrown = List.nil(); 1.857 + for (int j = 0; j < nexceptions; j++) 1.858 + thrown = thrown.prepend(readClassSymbol(nextChar()).type); 1.859 + if (sym.type.getThrownTypes().isEmpty()) 1.860 + sym.type.asMethodType().thrown = thrown.reverse(); 1.861 + } else if (attrName == names.Synthetic) { 1.862 + // bridge methods are visible when generics not enabled 1.863 + if (allowGenerics || (sym.flags_field & BRIDGE) == 0) 1.864 + sym.flags_field |= SYNTHETIC; 1.865 + } else if (attrName == names.Bridge) { 1.866 + sym.flags_field |= BRIDGE; 1.867 + if (!allowGenerics) 1.868 + sym.flags_field &= ~SYNTHETIC; 1.869 + } else if (attrName == names.Deprecated) { 1.870 + sym.flags_field |= DEPRECATED; 1.871 + } else if (attrName == names.Varargs) { 1.872 + if (allowVarargs) sym.flags_field |= VARARGS; 1.873 + } else if (attrName == names.Annotation) { 1.874 + if (allowAnnotations) sym.flags_field |= ANNOTATION; 1.875 + } else if (attrName == names.Enum) { 1.876 + sym.flags_field |= ENUM; 1.877 + } else if (allowGenerics && attrName == names.Signature) { 1.878 + List<Type> thrown = sym.type.getThrownTypes(); 1.879 + sym.type = readType(nextChar()); 1.880 + //- System.err.println(" # " + sym.type); 1.881 + if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty()) 1.882 + sym.type.asMethodType().thrown = thrown; 1.883 + } else if (attrName == names.RuntimeVisibleAnnotations) { 1.884 + attachAnnotations(sym); 1.885 + } else if (attrName == names.RuntimeInvisibleAnnotations) { 1.886 + attachAnnotations(sym); 1.887 + } else if (attrName == names.RuntimeVisibleParameterAnnotations) { 1.888 + attachParameterAnnotations(sym); 1.889 + } else if (attrName == names.RuntimeInvisibleParameterAnnotations) { 1.890 + attachParameterAnnotations(sym); 1.891 + } else if (attrName == names.LocalVariableTable) { 1.892 + int newbp = bp + attrLen; 1.893 + if (saveParameterNames) { 1.894 + // pick up parameter names from the variable table 1.895 + List<Name> parameterNames = List.nil(); 1.896 + int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0; 1.897 + int endParam = firstParam + Code.width(sym.type.getParameterTypes()); 1.898 + int numEntries = nextChar(); 1.899 + for (int i=0; i<numEntries; i++) { 1.900 + int start_pc = nextChar(); 1.901 + int length = nextChar(); 1.902 + int nameIndex = nextChar(); 1.903 + int sigIndex = nextChar(); 1.904 + int register = nextChar(); 1.905 + if (start_pc == 0 && 1.906 + firstParam <= register && 1.907 + register < endParam) { 1.908 + int index = firstParam; 1.909 + for (Type t : sym.type.getParameterTypes()) { 1.910 + if (index == register) { 1.911 + parameterNames = parameterNames.prepend(readName(nameIndex)); 1.912 + break; 1.913 + } 1.914 + index += Code.width(t); 1.915 + } 1.916 + } 1.917 + } 1.918 + parameterNames = parameterNames.reverse(); 1.919 + ((MethodSymbol)sym).savedParameterNames = parameterNames; 1.920 + } 1.921 + bp = newbp; 1.922 + } else if (attrName == names.AnnotationDefault) { 1.923 + attachAnnotationDefault(sym); 1.924 + } else if (attrName == names.EnclosingMethod) { 1.925 + int newbp = bp + attrLen; 1.926 + readEnclosingMethodAttr(sym); 1.927 + bp = newbp; 1.928 + } else { 1.929 + unrecognized(attrName); 1.930 + bp = bp + attrLen; 1.931 + } 1.932 + } 1.933 + 1.934 + void readEnclosingMethodAttr(Symbol sym) { 1.935 + // sym is a nested class with an "Enclosing Method" attribute 1.936 + // remove sym from it's current owners scope and place it in 1.937 + // the scope specified by the attribute 1.938 + sym.owner.members().remove(sym); 1.939 + ClassSymbol self = (ClassSymbol)sym; 1.940 + ClassSymbol c = readClassSymbol(nextChar()); 1.941 + NameAndType nt = (NameAndType)readPool(nextChar()); 1.942 + 1.943 + MethodSymbol m = findMethod(nt, c.members_field, self.flags()); 1.944 + if (nt != null && m == null) 1.945 + throw badClassFile("bad.enclosing.method", self); 1.946 + 1.947 + self.name = simpleBinaryName(self.flatname, c.flatname) ; 1.948 + self.owner = m != null ? m : c; 1.949 + if (self.name.len == 0) 1.950 + self.fullname = null; 1.951 + else 1.952 + self.fullname = ClassSymbol.formFullName(self.name, self.owner); 1.953 + 1.954 + if (m != null) { 1.955 + ((ClassType)sym.type).setEnclosingType(m.type); 1.956 + } else if ((self.flags_field & STATIC) == 0) { 1.957 + ((ClassType)sym.type).setEnclosingType(c.type); 1.958 + } else { 1.959 + ((ClassType)sym.type).setEnclosingType(Type.noType); 1.960 + } 1.961 + enterTypevars(self); 1.962 + if (!missingTypeVariables.isEmpty()) { 1.963 + ListBuffer<Type> typeVars = new ListBuffer<Type>(); 1.964 + for (Type typevar : missingTypeVariables) { 1.965 + typeVars.append(findTypeVar(typevar.tsym.name)); 1.966 + } 1.967 + foundTypeVariables = typeVars.toList(); 1.968 + } else { 1.969 + foundTypeVariables = List.nil(); 1.970 + } 1.971 + } 1.972 + 1.973 + // See java.lang.Class 1.974 + private Name simpleBinaryName(Name self, Name enclosing) { 1.975 + String simpleBinaryName = self.toString().substring(enclosing.toString().length()); 1.976 + if (simpleBinaryName.length() < 1 || simpleBinaryName.charAt(0) != '$') 1.977 + throw badClassFile("bad.enclosing.method", self); 1.978 + int index = 1; 1.979 + while (index < simpleBinaryName.length() && 1.980 + isAsciiDigit(simpleBinaryName.charAt(index))) 1.981 + index++; 1.982 + return names.fromString(simpleBinaryName.substring(index)); 1.983 + } 1.984 + 1.985 + private MethodSymbol findMethod(NameAndType nt, Scope scope, long flags) { 1.986 + if (nt == null) 1.987 + return null; 1.988 + 1.989 + MethodType type = nt.type.asMethodType(); 1.990 + 1.991 + for (Scope.Entry e = scope.lookup(nt.name); e.scope != null; e = e.next()) 1.992 + if (e.sym.kind == MTH && isSameBinaryType(e.sym.type.asMethodType(), type)) 1.993 + return (MethodSymbol)e.sym; 1.994 + 1.995 + if (nt.name != names.init) 1.996 + // not a constructor 1.997 + return null; 1.998 + if ((flags & INTERFACE) != 0) 1.999 + // no enclosing instance 1.1000 + return null; 1.1001 + if (nt.type.getParameterTypes().isEmpty()) 1.1002 + // no parameters 1.1003 + return null; 1.1004 + 1.1005 + // A constructor of an inner class. 1.1006 + // Remove the first argument (the enclosing instance) 1.1007 + nt.type = new MethodType(nt.type.getParameterTypes().tail, 1.1008 + nt.type.getReturnType(), 1.1009 + nt.type.getThrownTypes(), 1.1010 + syms.methodClass); 1.1011 + // Try searching again 1.1012 + return findMethod(nt, scope, flags); 1.1013 + } 1.1014 + 1.1015 + /** Similar to Types.isSameType but avoids completion */ 1.1016 + private boolean isSameBinaryType(MethodType mt1, MethodType mt2) { 1.1017 + List<Type> types1 = types.erasure(mt1.getParameterTypes()) 1.1018 + .prepend(types.erasure(mt1.getReturnType())); 1.1019 + List<Type> types2 = mt2.getParameterTypes().prepend(mt2.getReturnType()); 1.1020 + while (!types1.isEmpty() && !types2.isEmpty()) { 1.1021 + if (types1.head.tsym != types2.head.tsym) 1.1022 + return false; 1.1023 + types1 = types1.tail; 1.1024 + types2 = types2.tail; 1.1025 + } 1.1026 + return types1.isEmpty() && types2.isEmpty(); 1.1027 + } 1.1028 + 1.1029 + /** 1.1030 + * Character.isDigit answers <tt>true</tt> to some non-ascii 1.1031 + * digits. This one does not. <b>copied from java.lang.Class</b> 1.1032 + */ 1.1033 + private static boolean isAsciiDigit(char c) { 1.1034 + return '0' <= c && c <= '9'; 1.1035 + } 1.1036 + 1.1037 + /** Read member attributes. 1.1038 + */ 1.1039 + void readMemberAttrs(Symbol sym) { 1.1040 + char ac = nextChar(); 1.1041 + for (int i = 0; i < ac; i++) { 1.1042 + Name attrName = readName(nextChar()); 1.1043 + int attrLen = nextInt(); 1.1044 + readMemberAttr(sym, attrName, attrLen); 1.1045 + } 1.1046 + } 1.1047 + 1.1048 + /** Read class attribute. 1.1049 + */ 1.1050 + void readClassAttr(ClassSymbol c, Name attrName, int attrLen) { 1.1051 + if (attrName == names.SourceFile) { 1.1052 + Name n = readName(nextChar()); 1.1053 + c.sourcefile = new SourceFileObject(n); 1.1054 + } else if (attrName == names.InnerClasses) { 1.1055 + readInnerClasses(c); 1.1056 + } else if (allowGenerics && attrName == names.Signature) { 1.1057 + readingClassAttr = true; 1.1058 + try { 1.1059 + ClassType ct1 = (ClassType)c.type; 1.1060 + assert c == currentOwner; 1.1061 + ct1.typarams_field = readTypeParams(nextChar()); 1.1062 + ct1.supertype_field = sigToType(); 1.1063 + ListBuffer<Type> is = new ListBuffer<Type>(); 1.1064 + while (sigp != siglimit) is.append(sigToType()); 1.1065 + ct1.interfaces_field = is.toList(); 1.1066 + } finally { 1.1067 + readingClassAttr = false; 1.1068 + } 1.1069 + } else { 1.1070 + readMemberAttr(c, attrName, attrLen); 1.1071 + } 1.1072 + } 1.1073 + private boolean readingClassAttr = false; 1.1074 + private List<Type> missingTypeVariables = List.nil(); 1.1075 + private List<Type> foundTypeVariables = List.nil(); 1.1076 + 1.1077 + /** Read class attributes. 1.1078 + */ 1.1079 + void readClassAttrs(ClassSymbol c) { 1.1080 + char ac = nextChar(); 1.1081 + for (int i = 0; i < ac; i++) { 1.1082 + Name attrName = readName(nextChar()); 1.1083 + int attrLen = nextInt(); 1.1084 + readClassAttr(c, attrName, attrLen); 1.1085 + } 1.1086 + } 1.1087 + 1.1088 + /** Read code block. 1.1089 + */ 1.1090 + Code readCode(Symbol owner) { 1.1091 + nextChar(); // max_stack 1.1092 + nextChar(); // max_locals 1.1093 + final int code_length = nextInt(); 1.1094 + bp += code_length; 1.1095 + final char exception_table_length = nextChar(); 1.1096 + bp += exception_table_length * 8; 1.1097 + readMemberAttrs(owner); 1.1098 + return null; 1.1099 + } 1.1100 + 1.1101 +/************************************************************************ 1.1102 + * Reading Java-language annotations 1.1103 + ***********************************************************************/ 1.1104 + 1.1105 + /** Attach annotations. 1.1106 + */ 1.1107 + void attachAnnotations(final Symbol sym) { 1.1108 + int numAttributes = nextChar(); 1.1109 + if (numAttributes != 0) { 1.1110 + ListBuffer<CompoundAnnotationProxy> proxies = 1.1111 + new ListBuffer<CompoundAnnotationProxy>(); 1.1112 + for (int i = 0; i<numAttributes; i++) { 1.1113 + CompoundAnnotationProxy proxy = readCompoundAnnotation(); 1.1114 + if (proxy.type.tsym == syms.proprietaryType.tsym) 1.1115 + sym.flags_field |= PROPRIETARY; 1.1116 + else 1.1117 + proxies.append(proxy); 1.1118 + } 1.1119 + annotate.later(new AnnotationCompleter(sym, proxies.toList())); 1.1120 + } 1.1121 + } 1.1122 + 1.1123 + /** Attach parameter annotations. 1.1124 + */ 1.1125 + void attachParameterAnnotations(final Symbol method) { 1.1126 + final MethodSymbol meth = (MethodSymbol)method; 1.1127 + int numParameters = buf[bp++] & 0xFF; 1.1128 + List<VarSymbol> parameters = meth.params(); 1.1129 + int pnum = 0; 1.1130 + while (parameters.tail != null) { 1.1131 + attachAnnotations(parameters.head); 1.1132 + parameters = parameters.tail; 1.1133 + pnum++; 1.1134 + } 1.1135 + if (pnum != numParameters) { 1.1136 + throw badClassFile("bad.runtime.invisible.param.annotations", meth); 1.1137 + } 1.1138 + } 1.1139 + 1.1140 + /** Attach the default value for an annotation element. 1.1141 + */ 1.1142 + void attachAnnotationDefault(final Symbol sym) { 1.1143 + final MethodSymbol meth = (MethodSymbol)sym; // only on methods 1.1144 + final Attribute value = readAttributeValue(); 1.1145 + annotate.later(new AnnotationDefaultCompleter(meth, value)); 1.1146 + } 1.1147 + 1.1148 + Type readTypeOrClassSymbol(int i) { 1.1149 + // support preliminary jsr175-format class files 1.1150 + if (buf[poolIdx[i]] == CONSTANT_Class) 1.1151 + return readClassSymbol(i).type; 1.1152 + return readType(i); 1.1153 + } 1.1154 + Type readEnumType(int i) { 1.1155 + // support preliminary jsr175-format class files 1.1156 + int index = poolIdx[i]; 1.1157 + int length = getChar(index + 1); 1.1158 + if (buf[index + length + 2] != ';') 1.1159 + return enterClass(readName(i)).type; 1.1160 + return readType(i); 1.1161 + } 1.1162 + 1.1163 + CompoundAnnotationProxy readCompoundAnnotation() { 1.1164 + Type t = readTypeOrClassSymbol(nextChar()); 1.1165 + int numFields = nextChar(); 1.1166 + ListBuffer<Pair<Name,Attribute>> pairs = 1.1167 + new ListBuffer<Pair<Name,Attribute>>(); 1.1168 + for (int i=0; i<numFields; i++) { 1.1169 + Name name = readName(nextChar()); 1.1170 + Attribute value = readAttributeValue(); 1.1171 + pairs.append(new Pair<Name,Attribute>(name, value)); 1.1172 + } 1.1173 + return new CompoundAnnotationProxy(t, pairs.toList()); 1.1174 + } 1.1175 + 1.1176 + Attribute readAttributeValue() { 1.1177 + char c = (char) buf[bp++]; 1.1178 + switch (c) { 1.1179 + case 'B': 1.1180 + return new Attribute.Constant(syms.byteType, readPool(nextChar())); 1.1181 + case 'C': 1.1182 + return new Attribute.Constant(syms.charType, readPool(nextChar())); 1.1183 + case 'D': 1.1184 + return new Attribute.Constant(syms.doubleType, readPool(nextChar())); 1.1185 + case 'F': 1.1186 + return new Attribute.Constant(syms.floatType, readPool(nextChar())); 1.1187 + case 'I': 1.1188 + return new Attribute.Constant(syms.intType, readPool(nextChar())); 1.1189 + case 'J': 1.1190 + return new Attribute.Constant(syms.longType, readPool(nextChar())); 1.1191 + case 'S': 1.1192 + return new Attribute.Constant(syms.shortType, readPool(nextChar())); 1.1193 + case 'Z': 1.1194 + return new Attribute.Constant(syms.booleanType, readPool(nextChar())); 1.1195 + case 's': 1.1196 + return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString()); 1.1197 + case 'e': 1.1198 + return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar())); 1.1199 + case 'c': 1.1200 + return new Attribute.Class(types, readTypeOrClassSymbol(nextChar())); 1.1201 + case '[': { 1.1202 + int n = nextChar(); 1.1203 + ListBuffer<Attribute> l = new ListBuffer<Attribute>(); 1.1204 + for (int i=0; i<n; i++) 1.1205 + l.append(readAttributeValue()); 1.1206 + return new ArrayAttributeProxy(l.toList()); 1.1207 + } 1.1208 + case '@': 1.1209 + return readCompoundAnnotation(); 1.1210 + default: 1.1211 + throw new AssertionError("unknown annotation tag '" + c + "'"); 1.1212 + } 1.1213 + } 1.1214 + 1.1215 + interface ProxyVisitor extends Attribute.Visitor { 1.1216 + void visitEnumAttributeProxy(EnumAttributeProxy proxy); 1.1217 + void visitArrayAttributeProxy(ArrayAttributeProxy proxy); 1.1218 + void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy); 1.1219 + } 1.1220 + 1.1221 + static class EnumAttributeProxy extends Attribute { 1.1222 + Type enumType; 1.1223 + Name enumerator; 1.1224 + public EnumAttributeProxy(Type enumType, Name enumerator) { 1.1225 + super(null); 1.1226 + this.enumType = enumType; 1.1227 + this.enumerator = enumerator; 1.1228 + } 1.1229 + public void accept(Visitor v) { ((ProxyVisitor)v).visitEnumAttributeProxy(this); } 1.1230 + public String toString() { 1.1231 + return "/*proxy enum*/" + enumType + "." + enumerator; 1.1232 + } 1.1233 + } 1.1234 + 1.1235 + static class ArrayAttributeProxy extends Attribute { 1.1236 + List<Attribute> values; 1.1237 + ArrayAttributeProxy(List<Attribute> values) { 1.1238 + super(null); 1.1239 + this.values = values; 1.1240 + } 1.1241 + public void accept(Visitor v) { ((ProxyVisitor)v).visitArrayAttributeProxy(this); } 1.1242 + public String toString() { 1.1243 + return "{" + values + "}"; 1.1244 + } 1.1245 + } 1.1246 + 1.1247 + /** A temporary proxy representing a compound attribute. 1.1248 + */ 1.1249 + static class CompoundAnnotationProxy extends Attribute { 1.1250 + final List<Pair<Name,Attribute>> values; 1.1251 + public CompoundAnnotationProxy(Type type, 1.1252 + List<Pair<Name,Attribute>> values) { 1.1253 + super(type); 1.1254 + this.values = values; 1.1255 + } 1.1256 + public void accept(Visitor v) { ((ProxyVisitor)v).visitCompoundAnnotationProxy(this); } 1.1257 + public String toString() { 1.1258 + StringBuffer buf = new StringBuffer(); 1.1259 + buf.append("@"); 1.1260 + buf.append(type.tsym.getQualifiedName()); 1.1261 + buf.append("/*proxy*/{"); 1.1262 + boolean first = true; 1.1263 + for (List<Pair<Name,Attribute>> v = values; 1.1264 + v.nonEmpty(); v = v.tail) { 1.1265 + Pair<Name,Attribute> value = v.head; 1.1266 + if (!first) buf.append(","); 1.1267 + first = false; 1.1268 + buf.append(value.fst); 1.1269 + buf.append("="); 1.1270 + buf.append(value.snd); 1.1271 + } 1.1272 + buf.append("}"); 1.1273 + return buf.toString(); 1.1274 + } 1.1275 + } 1.1276 + 1.1277 + class AnnotationDeproxy implements ProxyVisitor { 1.1278 + private ClassSymbol requestingOwner = currentOwner.kind == MTH 1.1279 + ? currentOwner.enclClass() : (ClassSymbol)currentOwner; 1.1280 + 1.1281 + List<Attribute.Compound> deproxyCompoundList(List<CompoundAnnotationProxy> pl) { 1.1282 + // also must fill in types!!!! 1.1283 + ListBuffer<Attribute.Compound> buf = 1.1284 + new ListBuffer<Attribute.Compound>(); 1.1285 + for (List<CompoundAnnotationProxy> l = pl; l.nonEmpty(); l=l.tail) { 1.1286 + buf.append(deproxyCompound(l.head)); 1.1287 + } 1.1288 + return buf.toList(); 1.1289 + } 1.1290 + 1.1291 + Attribute.Compound deproxyCompound(CompoundAnnotationProxy a) { 1.1292 + ListBuffer<Pair<Symbol.MethodSymbol,Attribute>> buf = 1.1293 + new ListBuffer<Pair<Symbol.MethodSymbol,Attribute>>(); 1.1294 + for (List<Pair<Name,Attribute>> l = a.values; 1.1295 + l.nonEmpty(); 1.1296 + l = l.tail) { 1.1297 + MethodSymbol meth = findAccessMethod(a.type, l.head.fst); 1.1298 + buf.append(new Pair<Symbol.MethodSymbol,Attribute> 1.1299 + (meth, deproxy(meth.type.getReturnType(), l.head.snd))); 1.1300 + } 1.1301 + return new Attribute.Compound(a.type, buf.toList()); 1.1302 + } 1.1303 + 1.1304 + MethodSymbol findAccessMethod(Type container, Name name) { 1.1305 + CompletionFailure failure = null; 1.1306 + try { 1.1307 + for (Scope.Entry e = container.tsym.members().lookup(name); 1.1308 + e.scope != null; 1.1309 + e = e.next()) { 1.1310 + Symbol sym = e.sym; 1.1311 + if (sym.kind == MTH && sym.type.getParameterTypes().length() == 0) 1.1312 + return (MethodSymbol) sym; 1.1313 + } 1.1314 + } catch (CompletionFailure ex) { 1.1315 + failure = ex; 1.1316 + } 1.1317 + // The method wasn't found: emit a warning and recover 1.1318 + JavaFileObject prevSource = log.useSource(requestingOwner.classfile); 1.1319 + try { 1.1320 + if (failure == null) { 1.1321 + log.warning("annotation.method.not.found", 1.1322 + container, 1.1323 + name); 1.1324 + } else { 1.1325 + log.warning("annotation.method.not.found.reason", 1.1326 + container, 1.1327 + name, 1.1328 + failure.getMessage()); 1.1329 + } 1.1330 + } finally { 1.1331 + log.useSource(prevSource); 1.1332 + } 1.1333 + // Construct a new method type and symbol. Use bottom 1.1334 + // type (typeof null) as return type because this type is 1.1335 + // a subtype of all reference types and can be converted 1.1336 + // to primitive types by unboxing. 1.1337 + MethodType mt = new MethodType(List.<Type>nil(), 1.1338 + syms.botType, 1.1339 + List.<Type>nil(), 1.1340 + syms.methodClass); 1.1341 + return new MethodSymbol(PUBLIC | ABSTRACT, name, mt, container.tsym); 1.1342 + } 1.1343 + 1.1344 + Attribute result; 1.1345 + Type type; 1.1346 + Attribute deproxy(Type t, Attribute a) { 1.1347 + Type oldType = type; 1.1348 + try { 1.1349 + type = t; 1.1350 + a.accept(this); 1.1351 + return result; 1.1352 + } finally { 1.1353 + type = oldType; 1.1354 + } 1.1355 + } 1.1356 + 1.1357 + // implement Attribute.Visitor below 1.1358 + 1.1359 + public void visitConstant(Attribute.Constant value) { 1.1360 + // assert value.type == type; 1.1361 + result = value; 1.1362 + } 1.1363 + 1.1364 + public void visitClass(Attribute.Class clazz) { 1.1365 + result = clazz; 1.1366 + } 1.1367 + 1.1368 + public void visitEnum(Attribute.Enum e) { 1.1369 + throw new AssertionError(); // shouldn't happen 1.1370 + } 1.1371 + 1.1372 + public void visitCompound(Attribute.Compound compound) { 1.1373 + throw new AssertionError(); // shouldn't happen 1.1374 + } 1.1375 + 1.1376 + public void visitArray(Attribute.Array array) { 1.1377 + throw new AssertionError(); // shouldn't happen 1.1378 + } 1.1379 + 1.1380 + public void visitError(Attribute.Error e) { 1.1381 + throw new AssertionError(); // shouldn't happen 1.1382 + } 1.1383 + 1.1384 + public void visitEnumAttributeProxy(EnumAttributeProxy proxy) { 1.1385 + // type.tsym.flatName() should == proxy.enumFlatName 1.1386 + TypeSymbol enumTypeSym = proxy.enumType.tsym; 1.1387 + VarSymbol enumerator = null; 1.1388 + for (Scope.Entry e = enumTypeSym.members().lookup(proxy.enumerator); 1.1389 + e.scope != null; 1.1390 + e = e.next()) { 1.1391 + if (e.sym.kind == VAR) { 1.1392 + enumerator = (VarSymbol)e.sym; 1.1393 + break; 1.1394 + } 1.1395 + } 1.1396 + if (enumerator == null) { 1.1397 + log.error("unknown.enum.constant", 1.1398 + currentClassFile, enumTypeSym, proxy.enumerator); 1.1399 + result = new Attribute.Error(enumTypeSym.type); 1.1400 + } else { 1.1401 + result = new Attribute.Enum(enumTypeSym.type, enumerator); 1.1402 + } 1.1403 + } 1.1404 + 1.1405 + public void visitArrayAttributeProxy(ArrayAttributeProxy proxy) { 1.1406 + int length = proxy.values.length(); 1.1407 + Attribute[] ats = new Attribute[length]; 1.1408 + Type elemtype = types.elemtype(type); 1.1409 + int i = 0; 1.1410 + for (List<Attribute> p = proxy.values; p.nonEmpty(); p = p.tail) { 1.1411 + ats[i++] = deproxy(elemtype, p.head); 1.1412 + } 1.1413 + result = new Attribute.Array(type, ats); 1.1414 + } 1.1415 + 1.1416 + public void visitCompoundAnnotationProxy(CompoundAnnotationProxy proxy) { 1.1417 + result = deproxyCompound(proxy); 1.1418 + } 1.1419 + } 1.1420 + 1.1421 + class AnnotationDefaultCompleter extends AnnotationDeproxy implements Annotate.Annotator { 1.1422 + final MethodSymbol sym; 1.1423 + final Attribute value; 1.1424 + final JavaFileObject classFile = currentClassFile; 1.1425 + public String toString() { 1.1426 + return " ClassReader store default for " + sym.owner + "." + sym + " is " + value; 1.1427 + } 1.1428 + AnnotationDefaultCompleter(MethodSymbol sym, Attribute value) { 1.1429 + this.sym = sym; 1.1430 + this.value = value; 1.1431 + } 1.1432 + // implement Annotate.Annotator.enterAnnotation() 1.1433 + public void enterAnnotation() { 1.1434 + JavaFileObject previousClassFile = currentClassFile; 1.1435 + try { 1.1436 + currentClassFile = classFile; 1.1437 + sym.defaultValue = deproxy(sym.type.getReturnType(), value); 1.1438 + } finally { 1.1439 + currentClassFile = previousClassFile; 1.1440 + } 1.1441 + } 1.1442 + } 1.1443 + 1.1444 + class AnnotationCompleter extends AnnotationDeproxy implements Annotate.Annotator { 1.1445 + final Symbol sym; 1.1446 + final List<CompoundAnnotationProxy> l; 1.1447 + final JavaFileObject classFile; 1.1448 + public String toString() { 1.1449 + return " ClassReader annotate " + sym.owner + "." + sym + " with " + l; 1.1450 + } 1.1451 + AnnotationCompleter(Symbol sym, List<CompoundAnnotationProxy> l) { 1.1452 + this.sym = sym; 1.1453 + this.l = l; 1.1454 + this.classFile = currentClassFile; 1.1455 + } 1.1456 + // implement Annotate.Annotator.enterAnnotation() 1.1457 + public void enterAnnotation() { 1.1458 + JavaFileObject previousClassFile = currentClassFile; 1.1459 + try { 1.1460 + currentClassFile = classFile; 1.1461 + List<Attribute.Compound> newList = deproxyCompoundList(l); 1.1462 + sym.attributes_field = ((sym.attributes_field == null) 1.1463 + ? newList 1.1464 + : newList.prependList(sym.attributes_field)); 1.1465 + } finally { 1.1466 + currentClassFile = previousClassFile; 1.1467 + } 1.1468 + } 1.1469 + } 1.1470 + 1.1471 + 1.1472 +/************************************************************************ 1.1473 + * Reading Symbols 1.1474 + ***********************************************************************/ 1.1475 + 1.1476 + /** Read a field. 1.1477 + */ 1.1478 + VarSymbol readField() { 1.1479 + long flags = adjustFieldFlags(nextChar()); 1.1480 + Name name = readName(nextChar()); 1.1481 + Type type = readType(nextChar()); 1.1482 + VarSymbol v = new VarSymbol(flags, name, type, currentOwner); 1.1483 + readMemberAttrs(v); 1.1484 + return v; 1.1485 + } 1.1486 + 1.1487 + /** Read a method. 1.1488 + */ 1.1489 + MethodSymbol readMethod() { 1.1490 + long flags = adjustMethodFlags(nextChar()); 1.1491 + Name name = readName(nextChar()); 1.1492 + Type type = readType(nextChar()); 1.1493 + if (name == names.init && currentOwner.hasOuterInstance()) { 1.1494 + // Sometimes anonymous classes don't have an outer 1.1495 + // instance, however, there is no reliable way to tell so 1.1496 + // we never strip this$n 1.1497 + if (currentOwner.name.len != 0) 1.1498 + type = new MethodType(type.getParameterTypes().tail, 1.1499 + type.getReturnType(), 1.1500 + type.getThrownTypes(), 1.1501 + syms.methodClass); 1.1502 + } 1.1503 + MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner); 1.1504 + Symbol prevOwner = currentOwner; 1.1505 + currentOwner = m; 1.1506 + try { 1.1507 + readMemberAttrs(m); 1.1508 + } finally { 1.1509 + currentOwner = prevOwner; 1.1510 + } 1.1511 + return m; 1.1512 + } 1.1513 + 1.1514 + /** Skip a field or method 1.1515 + */ 1.1516 + void skipMember() { 1.1517 + bp = bp + 6; 1.1518 + char ac = nextChar(); 1.1519 + for (int i = 0; i < ac; i++) { 1.1520 + bp = bp + 2; 1.1521 + int attrLen = nextInt(); 1.1522 + bp = bp + attrLen; 1.1523 + } 1.1524 + } 1.1525 + 1.1526 + /** Enter type variables of this classtype and all enclosing ones in 1.1527 + * `typevars'. 1.1528 + */ 1.1529 + protected void enterTypevars(Type t) { 1.1530 + if (t.getEnclosingType() != null && t.getEnclosingType().tag == CLASS) 1.1531 + enterTypevars(t.getEnclosingType()); 1.1532 + for (List<Type> xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail) 1.1533 + typevars.enter(xs.head.tsym); 1.1534 + } 1.1535 + 1.1536 + protected void enterTypevars(Symbol sym) { 1.1537 + if (sym.owner.kind == MTH) { 1.1538 + enterTypevars(sym.owner); 1.1539 + enterTypevars(sym.owner.owner); 1.1540 + } 1.1541 + enterTypevars(sym.type); 1.1542 + } 1.1543 + 1.1544 + /** Read contents of a given class symbol `c'. Both external and internal 1.1545 + * versions of an inner class are read. 1.1546 + */ 1.1547 + void readClass(ClassSymbol c) { 1.1548 + ClassType ct = (ClassType)c.type; 1.1549 + 1.1550 + // allocate scope for members 1.1551 + c.members_field = new Scope(c); 1.1552 + 1.1553 + // prepare type variable table 1.1554 + typevars = typevars.dup(currentOwner); 1.1555 + if (ct.getEnclosingType().tag == CLASS) enterTypevars(ct.getEnclosingType()); 1.1556 + 1.1557 + // read flags, or skip if this is an inner class 1.1558 + long flags = adjustClassFlags(nextChar()); 1.1559 + if (c.owner.kind == PCK) c.flags_field = flags; 1.1560 + 1.1561 + // read own class name and check that it matches 1.1562 + ClassSymbol self = readClassSymbol(nextChar()); 1.1563 + if (c != self) 1.1564 + throw badClassFile("class.file.wrong.class", 1.1565 + self.flatname); 1.1566 + 1.1567 + // class attributes must be read before class 1.1568 + // skip ahead to read class attributes 1.1569 + int startbp = bp; 1.1570 + nextChar(); 1.1571 + char interfaceCount = nextChar(); 1.1572 + bp += interfaceCount * 2; 1.1573 + char fieldCount = nextChar(); 1.1574 + for (int i = 0; i < fieldCount; i++) skipMember(); 1.1575 + char methodCount = nextChar(); 1.1576 + for (int i = 0; i < methodCount; i++) skipMember(); 1.1577 + readClassAttrs(c); 1.1578 + 1.1579 + if (readAllOfClassFile) { 1.1580 + for (int i = 1; i < poolObj.length; i++) readPool(i); 1.1581 + c.pool = new Pool(poolObj.length, poolObj); 1.1582 + } 1.1583 + 1.1584 + // reset and read rest of classinfo 1.1585 + bp = startbp; 1.1586 + int n = nextChar(); 1.1587 + if (ct.supertype_field == null) 1.1588 + ct.supertype_field = (n == 0) 1.1589 + ? Type.noType 1.1590 + : readClassSymbol(n).erasure(types); 1.1591 + n = nextChar(); 1.1592 + List<Type> is = List.nil(); 1.1593 + for (int i = 0; i < n; i++) { 1.1594 + Type _inter = readClassSymbol(nextChar()).erasure(types); 1.1595 + is = is.prepend(_inter); 1.1596 + } 1.1597 + if (ct.interfaces_field == null) 1.1598 + ct.interfaces_field = is.reverse(); 1.1599 + 1.1600 + if (fieldCount != nextChar()) assert false; 1.1601 + for (int i = 0; i < fieldCount; i++) enterMember(c, readField()); 1.1602 + if (methodCount != nextChar()) assert false; 1.1603 + for (int i = 0; i < methodCount; i++) enterMember(c, readMethod()); 1.1604 + 1.1605 + typevars = typevars.leave(); 1.1606 + } 1.1607 + 1.1608 + /** Read inner class info. For each inner/outer pair allocate a 1.1609 + * member class. 1.1610 + */ 1.1611 + void readInnerClasses(ClassSymbol c) { 1.1612 + int n = nextChar(); 1.1613 + for (int i = 0; i < n; i++) { 1.1614 + nextChar(); // skip inner class symbol 1.1615 + ClassSymbol outer = readClassSymbol(nextChar()); 1.1616 + Name name = readName(nextChar()); 1.1617 + if (name == null) name = names.empty; 1.1618 + long flags = adjustClassFlags(nextChar()); 1.1619 + if (outer != null) { // we have a member class 1.1620 + if (name == names.empty) 1.1621 + name = names.one; 1.1622 + ClassSymbol member = enterClass(name, outer); 1.1623 + if ((flags & STATIC) == 0) { 1.1624 + ((ClassType)member.type).setEnclosingType(outer.type); 1.1625 + if (member.erasure_field != null) 1.1626 + ((ClassType)member.erasure_field).setEnclosingType(types.erasure(outer.type)); 1.1627 + } 1.1628 + if (c == outer) { 1.1629 + member.flags_field = flags; 1.1630 + enterMember(c, member); 1.1631 + } 1.1632 + } 1.1633 + } 1.1634 + } 1.1635 + 1.1636 + /** Read a class file. 1.1637 + */ 1.1638 + private void readClassFile(ClassSymbol c) throws IOException { 1.1639 + int magic = nextInt(); 1.1640 + if (magic != JAVA_MAGIC) 1.1641 + throw badClassFile("illegal.start.of.class.file"); 1.1642 + 1.1643 + int minorVersion = nextChar(); 1.1644 + int majorVersion = nextChar(); 1.1645 + int maxMajor = Target.MAX().majorVersion; 1.1646 + int maxMinor = Target.MAX().minorVersion; 1.1647 + if (majorVersion > maxMajor || 1.1648 + majorVersion * 1000 + minorVersion < 1.1649 + Target.MIN().majorVersion * 1000 + Target.MIN().minorVersion) 1.1650 + { 1.1651 + if (majorVersion == (maxMajor + 1)) 1.1652 + log.warning("big.major.version", 1.1653 + currentClassFile, 1.1654 + majorVersion, 1.1655 + maxMajor); 1.1656 + else 1.1657 + throw badClassFile("wrong.version", 1.1658 + Integer.toString(majorVersion), 1.1659 + Integer.toString(minorVersion), 1.1660 + Integer.toString(maxMajor), 1.1661 + Integer.toString(maxMinor)); 1.1662 + } 1.1663 + else if (checkClassFile && 1.1664 + majorVersion == maxMajor && 1.1665 + minorVersion > maxMinor) 1.1666 + { 1.1667 + printCCF("found.later.version", 1.1668 + Integer.toString(minorVersion)); 1.1669 + } 1.1670 + indexPool(); 1.1671 + if (signatureBuffer.length < bp) { 1.1672 + int ns = Integer.highestOneBit(bp) << 1; 1.1673 + signatureBuffer = new byte[ns]; 1.1674 + } 1.1675 + readClass(c); 1.1676 + } 1.1677 + 1.1678 +/************************************************************************ 1.1679 + * Adjusting flags 1.1680 + ***********************************************************************/ 1.1681 + 1.1682 + long adjustFieldFlags(long flags) { 1.1683 + return flags; 1.1684 + } 1.1685 + long adjustMethodFlags(long flags) { 1.1686 + if ((flags & ACC_BRIDGE) != 0) { 1.1687 + flags &= ~ACC_BRIDGE; 1.1688 + flags |= BRIDGE; 1.1689 + if (!allowGenerics) 1.1690 + flags &= ~SYNTHETIC; 1.1691 + } 1.1692 + if ((flags & ACC_VARARGS) != 0) { 1.1693 + flags &= ~ACC_VARARGS; 1.1694 + flags |= VARARGS; 1.1695 + } 1.1696 + return flags; 1.1697 + } 1.1698 + long adjustClassFlags(long flags) { 1.1699 + return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded 1.1700 + } 1.1701 + 1.1702 +/************************************************************************ 1.1703 + * Loading Classes 1.1704 + ***********************************************************************/ 1.1705 + 1.1706 + /** Define a new class given its name and owner. 1.1707 + */ 1.1708 + public ClassSymbol defineClass(Name name, Symbol owner) { 1.1709 + ClassSymbol c = new ClassSymbol(0, name, owner); 1.1710 + if (owner.kind == PCK) 1.1711 + assert classes.get(c.flatname) == null : c; 1.1712 + c.completer = this; 1.1713 + return c; 1.1714 + } 1.1715 + 1.1716 + /** Create a new toplevel or member class symbol with given name 1.1717 + * and owner and enter in `classes' unless already there. 1.1718 + */ 1.1719 + public ClassSymbol enterClass(Name name, TypeSymbol owner) { 1.1720 + Name flatname = TypeSymbol.formFlatName(name, owner); 1.1721 + ClassSymbol c = classes.get(flatname); 1.1722 + if (c == null) { 1.1723 + c = defineClass(name, owner); 1.1724 + classes.put(flatname, c); 1.1725 + } else if ((c.name != name || c.owner != owner) && owner.kind == TYP && c.owner.kind == PCK) { 1.1726 + // reassign fields of classes that might have been loaded with 1.1727 + // their flat names. 1.1728 + c.owner.members().remove(c); 1.1729 + c.name = name; 1.1730 + c.owner = owner; 1.1731 + c.fullname = ClassSymbol.formFullName(name, owner); 1.1732 + } 1.1733 + return c; 1.1734 + } 1.1735 + 1.1736 + /** 1.1737 + * Creates a new toplevel class symbol with given flat name and 1.1738 + * given class (or source) file. 1.1739 + * 1.1740 + * @param flatName a fully qualified binary class name 1.1741 + * @param classFile the class file or compilation unit defining 1.1742 + * the class (may be {@code null}) 1.1743 + * @return a newly created class symbol 1.1744 + * @throws AssertionError if the class symbol already exists 1.1745 + */ 1.1746 + public ClassSymbol enterClass(Name flatName, JavaFileObject classFile) { 1.1747 + ClassSymbol cs = classes.get(flatName); 1.1748 + if (cs != null) { 1.1749 + String msg = Log.format("%s: completer = %s; class file = %s; source file = %s", 1.1750 + cs.fullname, 1.1751 + cs.completer, 1.1752 + cs.classfile, 1.1753 + cs.sourcefile); 1.1754 + throw new AssertionError(msg); 1.1755 + } 1.1756 + Name packageName = Convert.packagePart(flatName); 1.1757 + PackageSymbol owner = packageName.isEmpty() 1.1758 + ? syms.unnamedPackage 1.1759 + : enterPackage(packageName); 1.1760 + cs = defineClass(Convert.shortName(flatName), owner); 1.1761 + cs.classfile = classFile; 1.1762 + classes.put(flatName, cs); 1.1763 + return cs; 1.1764 + } 1.1765 + 1.1766 + /** Create a new member or toplevel class symbol with given flat name 1.1767 + * and enter in `classes' unless already there. 1.1768 + */ 1.1769 + public ClassSymbol enterClass(Name flatname) { 1.1770 + ClassSymbol c = classes.get(flatname); 1.1771 + if (c == null) 1.1772 + return enterClass(flatname, (JavaFileObject)null); 1.1773 + else 1.1774 + return c; 1.1775 + } 1.1776 + 1.1777 + private boolean suppressFlush = false; 1.1778 + 1.1779 + /** Completion for classes to be loaded. Before a class is loaded 1.1780 + * we make sure its enclosing class (if any) is loaded. 1.1781 + */ 1.1782 + public void complete(Symbol sym) throws CompletionFailure { 1.1783 + if (sym.kind == TYP) { 1.1784 + ClassSymbol c = (ClassSymbol)sym; 1.1785 + c.members_field = new Scope.ErrorScope(c); // make sure it's always defined 1.1786 + boolean suppressFlush = this.suppressFlush; 1.1787 + this.suppressFlush = true; 1.1788 + try { 1.1789 + completeOwners(c.owner); 1.1790 + completeEnclosing(c); 1.1791 + } finally { 1.1792 + this.suppressFlush = suppressFlush; 1.1793 + } 1.1794 + fillIn(c); 1.1795 + } else if (sym.kind == PCK) { 1.1796 + PackageSymbol p = (PackageSymbol)sym; 1.1797 + try { 1.1798 + fillIn(p); 1.1799 + } catch (IOException ex) { 1.1800 + throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex); 1.1801 + } 1.1802 + } 1.1803 + if (!filling && !suppressFlush) 1.1804 + annotate.flush(); // finish attaching annotations 1.1805 + } 1.1806 + 1.1807 + /** complete up through the enclosing package. */ 1.1808 + private void completeOwners(Symbol o) { 1.1809 + if (o.kind != PCK) completeOwners(o.owner); 1.1810 + o.complete(); 1.1811 + } 1.1812 + 1.1813 + /** 1.1814 + * Tries to complete lexically enclosing classes if c looks like a 1.1815 + * nested class. This is similar to completeOwners but handles 1.1816 + * the situation when a nested class is accessed directly as it is 1.1817 + * possible with the Tree API or javax.lang.model.*. 1.1818 + */ 1.1819 + private void completeEnclosing(ClassSymbol c) { 1.1820 + if (c.owner.kind == PCK) { 1.1821 + Symbol owner = c.owner; 1.1822 + for (Name name : Convert.enclosingCandidates(Convert.shortName(c.name))) { 1.1823 + Symbol encl = owner.members().lookup(name).sym; 1.1824 + if (encl == null) 1.1825 + encl = classes.get(TypeSymbol.formFlatName(name, owner)); 1.1826 + if (encl != null) 1.1827 + encl.complete(); 1.1828 + } 1.1829 + } 1.1830 + } 1.1831 + 1.1832 + /** We can only read a single class file at a time; this 1.1833 + * flag keeps track of when we are currently reading a class 1.1834 + * file. 1.1835 + */ 1.1836 + private boolean filling = false; 1.1837 + 1.1838 + /** Fill in definition of class `c' from corresponding class or 1.1839 + * source file. 1.1840 + */ 1.1841 + private void fillIn(ClassSymbol c) { 1.1842 + if (completionFailureName == c.fullname) { 1.1843 + throw new CompletionFailure(c, "user-selected completion failure by class name"); 1.1844 + } 1.1845 + currentOwner = c; 1.1846 + JavaFileObject classfile = c.classfile; 1.1847 + if (classfile != null) { 1.1848 + JavaFileObject previousClassFile = currentClassFile; 1.1849 + try { 1.1850 + assert !filling : 1.1851 + "Filling " + classfile.toUri() + 1.1852 + " during " + previousClassFile; 1.1853 + currentClassFile = classfile; 1.1854 + if (verbose) { 1.1855 + printVerbose("loading", currentClassFile.toString()); 1.1856 + } 1.1857 + if (classfile.getKind() == JavaFileObject.Kind.CLASS) { 1.1858 + filling = true; 1.1859 + try { 1.1860 + bp = 0; 1.1861 + buf = readInputStream(buf, classfile.openInputStream()); 1.1862 + readClassFile(c); 1.1863 + if (!missingTypeVariables.isEmpty() && !foundTypeVariables.isEmpty()) { 1.1864 + List<Type> missing = missingTypeVariables; 1.1865 + List<Type> found = foundTypeVariables; 1.1866 + missingTypeVariables = List.nil(); 1.1867 + foundTypeVariables = List.nil(); 1.1868 + filling = false; 1.1869 + ClassType ct = (ClassType)currentOwner.type; 1.1870 + ct.supertype_field = 1.1871 + types.subst(ct.supertype_field, missing, found); 1.1872 + ct.interfaces_field = 1.1873 + types.subst(ct.interfaces_field, missing, found); 1.1874 + } else if (missingTypeVariables.isEmpty() != 1.1875 + foundTypeVariables.isEmpty()) { 1.1876 + Name name = missingTypeVariables.head.tsym.name; 1.1877 + throw badClassFile("undecl.type.var", name); 1.1878 + } 1.1879 + } finally { 1.1880 + missingTypeVariables = List.nil(); 1.1881 + foundTypeVariables = List.nil(); 1.1882 + filling = false; 1.1883 + } 1.1884 + } else { 1.1885 + if (sourceCompleter != null) { 1.1886 + sourceCompleter.complete(c); 1.1887 + } else { 1.1888 + throw new IllegalStateException("Source completer required to read " 1.1889 + + classfile.toUri()); 1.1890 + } 1.1891 + } 1.1892 + return; 1.1893 + } catch (IOException ex) { 1.1894 + throw badClassFile("unable.to.access.file", ex.getMessage()); 1.1895 + } finally { 1.1896 + currentClassFile = previousClassFile; 1.1897 + } 1.1898 + } else { 1.1899 + throw 1.1900 + newCompletionFailure(c, 1.1901 + Log.getLocalizedString("class.file.not.found", 1.1902 + c.flatname)); 1.1903 + } 1.1904 + } 1.1905 + // where 1.1906 + private static byte[] readInputStream(byte[] buf, InputStream s) throws IOException { 1.1907 + try { 1.1908 + buf = ensureCapacity(buf, s.available()); 1.1909 + int r = s.read(buf); 1.1910 + int bp = 0; 1.1911 + while (r != -1) { 1.1912 + bp += r; 1.1913 + buf = ensureCapacity(buf, bp); 1.1914 + r = s.read(buf, bp, buf.length - bp); 1.1915 + } 1.1916 + return buf; 1.1917 + } finally { 1.1918 + try { 1.1919 + s.close(); 1.1920 + } catch (IOException e) { 1.1921 + /* Ignore any errors, as this stream may have already 1.1922 + * thrown a related exception which is the one that 1.1923 + * should be reported. 1.1924 + */ 1.1925 + } 1.1926 + } 1.1927 + } 1.1928 + private static byte[] ensureCapacity(byte[] buf, int needed) { 1.1929 + if (buf.length < needed) { 1.1930 + byte[] old = buf; 1.1931 + buf = new byte[Integer.highestOneBit(needed) << 1]; 1.1932 + System.arraycopy(old, 0, buf, 0, old.length); 1.1933 + } 1.1934 + return buf; 1.1935 + } 1.1936 + /** Static factory for CompletionFailure objects. 1.1937 + * In practice, only one can be used at a time, so we share one 1.1938 + * to reduce the expense of allocating new exception objects. 1.1939 + */ 1.1940 + private CompletionFailure newCompletionFailure(ClassSymbol c, 1.1941 + String localized) { 1.1942 + if (!cacheCompletionFailure) { 1.1943 + // log.warning("proc.messager", 1.1944 + // Log.getLocalizedString("class.file.not.found", c.flatname)); 1.1945 + // c.debug.printStackTrace(); 1.1946 + return new CompletionFailure(c, localized); 1.1947 + } else { 1.1948 + CompletionFailure result = cachedCompletionFailure; 1.1949 + result.sym = c; 1.1950 + result.errmsg = localized; 1.1951 + return result; 1.1952 + } 1.1953 + } 1.1954 + private CompletionFailure cachedCompletionFailure = 1.1955 + new CompletionFailure(null, null); 1.1956 + { 1.1957 + cachedCompletionFailure.setStackTrace(new StackTraceElement[0]); 1.1958 + } 1.1959 + 1.1960 + /** Load a toplevel class with given fully qualified name 1.1961 + * The class is entered into `classes' only if load was successful. 1.1962 + */ 1.1963 + public ClassSymbol loadClass(Name flatname) throws CompletionFailure { 1.1964 + boolean absent = classes.get(flatname) == null; 1.1965 + ClassSymbol c = enterClass(flatname); 1.1966 + if (c.members_field == null && c.completer != null) { 1.1967 + try { 1.1968 + c.complete(); 1.1969 + } catch (CompletionFailure ex) { 1.1970 + if (absent) classes.remove(flatname); 1.1971 + throw ex; 1.1972 + } 1.1973 + } 1.1974 + return c; 1.1975 + } 1.1976 + 1.1977 +/************************************************************************ 1.1978 + * Loading Packages 1.1979 + ***********************************************************************/ 1.1980 + 1.1981 + /** Check to see if a package exists, given its fully qualified name. 1.1982 + */ 1.1983 + public boolean packageExists(Name fullname) { 1.1984 + return enterPackage(fullname).exists(); 1.1985 + } 1.1986 + 1.1987 + /** Make a package, given its fully qualified name. 1.1988 + */ 1.1989 + public PackageSymbol enterPackage(Name fullname) { 1.1990 + PackageSymbol p = packages.get(fullname); 1.1991 + if (p == null) { 1.1992 + assert !fullname.isEmpty() : "rootPackage missing!"; 1.1993 + p = new PackageSymbol( 1.1994 + Convert.shortName(fullname), 1.1995 + enterPackage(Convert.packagePart(fullname))); 1.1996 + p.completer = this; 1.1997 + packages.put(fullname, p); 1.1998 + } 1.1999 + return p; 1.2000 + } 1.2001 + 1.2002 + /** Make a package, given its unqualified name and enclosing package. 1.2003 + */ 1.2004 + public PackageSymbol enterPackage(Name name, PackageSymbol owner) { 1.2005 + return enterPackage(TypeSymbol.formFullName(name, owner)); 1.2006 + } 1.2007 + 1.2008 + /** Include class corresponding to given class file in package, 1.2009 + * unless (1) we already have one the same kind (.class or .java), or 1.2010 + * (2) we have one of the other kind, and the given class file 1.2011 + * is older. 1.2012 + */ 1.2013 + protected void includeClassFile(PackageSymbol p, JavaFileObject file) { 1.2014 + if ((p.flags_field & EXISTS) == 0) 1.2015 + for (Symbol q = p; q != null && q.kind == PCK; q = q.owner) 1.2016 + q.flags_field |= EXISTS; 1.2017 + JavaFileObject.Kind kind = file.getKind(); 1.2018 + int seen; 1.2019 + if (kind == JavaFileObject.Kind.CLASS) 1.2020 + seen = CLASS_SEEN; 1.2021 + else 1.2022 + seen = SOURCE_SEEN; 1.2023 + String binaryName = fileManager.inferBinaryName(currentLoc, file); 1.2024 + int lastDot = binaryName.lastIndexOf("."); 1.2025 + Name classname = names.fromString(binaryName.substring(lastDot + 1)); 1.2026 + boolean isPkgInfo = classname == names.package_info; 1.2027 + ClassSymbol c = isPkgInfo 1.2028 + ? p.package_info 1.2029 + : (ClassSymbol) p.members_field.lookup(classname).sym; 1.2030 + if (c == null) { 1.2031 + c = enterClass(classname, p); 1.2032 + if (c.classfile == null) // only update the file if's it's newly created 1.2033 + c.classfile = file; 1.2034 + if (isPkgInfo) { 1.2035 + p.package_info = c; 1.2036 + } else { 1.2037 + if (c.owner == p) // it might be an inner class 1.2038 + p.members_field.enter(c); 1.2039 + } 1.2040 + } else if (c.classfile != null && (c.flags_field & seen) == 0) { 1.2041 + // if c.classfile == null, we are currently compiling this class 1.2042 + // and no further action is necessary. 1.2043 + // if (c.flags_field & seen) != 0, we have already encountered 1.2044 + // a file of the same kind; again no further action is necessary. 1.2045 + if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0) 1.2046 + c.classfile = preferredFileObject(file, c.classfile); 1.2047 + } 1.2048 + c.flags_field |= seen; 1.2049 + } 1.2050 + 1.2051 + /** Implement policy to choose to derive information from a source 1.2052 + * file or a class file when both are present. May be overridden 1.2053 + * by subclasses. 1.2054 + */ 1.2055 + protected JavaFileObject preferredFileObject(JavaFileObject a, 1.2056 + JavaFileObject b) { 1.2057 + 1.2058 + if (preferSource) 1.2059 + return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b; 1.2060 + else { 1.2061 + long adate = a.getLastModified(); 1.2062 + long bdate = b.getLastModified(); 1.2063 + // 6449326: policy for bad lastModifiedTime in ClassReader 1.2064 + //assert adate >= 0 && bdate >= 0; 1.2065 + return (adate > bdate) ? a : b; 1.2066 + } 1.2067 + } 1.2068 + 1.2069 + /** 1.2070 + * specifies types of files to be read when filling in a package symbol 1.2071 + */ 1.2072 + protected EnumSet<JavaFileObject.Kind> getPackageFileKinds() { 1.2073 + return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE); 1.2074 + } 1.2075 + 1.2076 + /** 1.2077 + * this is used to support javadoc 1.2078 + */ 1.2079 + protected void extraFileActions(PackageSymbol pack, JavaFileObject fe) { 1.2080 + } 1.2081 + 1.2082 + protected Location currentLoc; // FIXME 1.2083 + 1.2084 + private boolean verbosePath = true; 1.2085 + 1.2086 + /** Load directory of package into members scope. 1.2087 + */ 1.2088 + private void fillIn(PackageSymbol p) throws IOException { 1.2089 + if (p.members_field == null) p.members_field = new Scope(p); 1.2090 + String packageName = p.fullname.toString(); 1.2091 + 1.2092 + Set<JavaFileObject.Kind> kinds = getPackageFileKinds(); 1.2093 + 1.2094 + fillIn(p, PLATFORM_CLASS_PATH, 1.2095 + fileManager.list(PLATFORM_CLASS_PATH, 1.2096 + packageName, 1.2097 + EnumSet.of(JavaFileObject.Kind.CLASS), 1.2098 + false)); 1.2099 + 1.2100 + Set<JavaFileObject.Kind> classKinds = EnumSet.copyOf(kinds); 1.2101 + classKinds.remove(JavaFileObject.Kind.SOURCE); 1.2102 + boolean wantClassFiles = !classKinds.isEmpty(); 1.2103 + 1.2104 + Set<JavaFileObject.Kind> sourceKinds = EnumSet.copyOf(kinds); 1.2105 + sourceKinds.remove(JavaFileObject.Kind.CLASS); 1.2106 + boolean wantSourceFiles = !sourceKinds.isEmpty(); 1.2107 + 1.2108 + boolean haveSourcePath = fileManager.hasLocation(SOURCE_PATH); 1.2109 + 1.2110 + if (verbose && verbosePath) { 1.2111 + if (fileManager instanceof StandardJavaFileManager) { 1.2112 + StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; 1.2113 + if (haveSourcePath && wantSourceFiles) { 1.2114 + List<File> path = List.nil(); 1.2115 + for (File file : fm.getLocation(SOURCE_PATH)) { 1.2116 + path = path.prepend(file); 1.2117 + } 1.2118 + printVerbose("sourcepath", path.reverse().toString()); 1.2119 + } else if (wantSourceFiles) { 1.2120 + List<File> path = List.nil(); 1.2121 + for (File file : fm.getLocation(CLASS_PATH)) { 1.2122 + path = path.prepend(file); 1.2123 + } 1.2124 + printVerbose("sourcepath", path.reverse().toString()); 1.2125 + } 1.2126 + if (wantClassFiles) { 1.2127 + List<File> path = List.nil(); 1.2128 + for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) { 1.2129 + path = path.prepend(file); 1.2130 + } 1.2131 + for (File file : fm.getLocation(CLASS_PATH)) { 1.2132 + path = path.prepend(file); 1.2133 + } 1.2134 + printVerbose("classpath", path.reverse().toString()); 1.2135 + } 1.2136 + } 1.2137 + } 1.2138 + 1.2139 + if (wantSourceFiles && !haveSourcePath) { 1.2140 + fillIn(p, CLASS_PATH, 1.2141 + fileManager.list(CLASS_PATH, 1.2142 + packageName, 1.2143 + kinds, 1.2144 + false)); 1.2145 + } else { 1.2146 + if (wantClassFiles) 1.2147 + fillIn(p, CLASS_PATH, 1.2148 + fileManager.list(CLASS_PATH, 1.2149 + packageName, 1.2150 + classKinds, 1.2151 + false)); 1.2152 + if (wantSourceFiles) 1.2153 + fillIn(p, SOURCE_PATH, 1.2154 + fileManager.list(SOURCE_PATH, 1.2155 + packageName, 1.2156 + sourceKinds, 1.2157 + false)); 1.2158 + } 1.2159 + verbosePath = false; 1.2160 + } 1.2161 + // where 1.2162 + private void fillIn(PackageSymbol p, 1.2163 + Location location, 1.2164 + Iterable<JavaFileObject> files) 1.2165 + { 1.2166 + currentLoc = location; 1.2167 + for (JavaFileObject fo : files) { 1.2168 + switch (fo.getKind()) { 1.2169 + case CLASS: 1.2170 + case SOURCE: { 1.2171 + // TODO pass binaryName to includeClassFile 1.2172 + String binaryName = fileManager.inferBinaryName(currentLoc, fo); 1.2173 + String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1); 1.2174 + if (SourceVersion.isIdentifier(simpleName) || 1.2175 + simpleName.equals("package-info")) 1.2176 + includeClassFile(p, fo); 1.2177 + break; 1.2178 + } 1.2179 + default: 1.2180 + extraFileActions(p, fo); 1.2181 + } 1.2182 + } 1.2183 + } 1.2184 + 1.2185 + /** Output for "-verbose" option. 1.2186 + * @param key The key to look up the correct internationalized string. 1.2187 + * @param arg An argument for substitution into the output string. 1.2188 + */ 1.2189 + private void printVerbose(String key, CharSequence arg) { 1.2190 + Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg)); 1.2191 + } 1.2192 + 1.2193 + /** Output for "-checkclassfile" option. 1.2194 + * @param key The key to look up the correct internationalized string. 1.2195 + * @param arg An argument for substitution into the output string. 1.2196 + */ 1.2197 + private void printCCF(String key, Object arg) { 1.2198 + Log.printLines(log.noticeWriter, Log.getLocalizedString(key, arg)); 1.2199 + } 1.2200 + 1.2201 + 1.2202 + public interface SourceCompleter { 1.2203 + void complete(ClassSymbol sym) 1.2204 + throws CompletionFailure; 1.2205 + } 1.2206 + 1.2207 + /** 1.2208 + * A subclass of JavaFileObject for the sourcefile attribute found in a classfile. 1.2209 + * The attribute is only the last component of the original filename, so is unlikely 1.2210 + * to be valid as is, so operations other than those to access the name throw 1.2211 + * UnsupportedOperationException 1.2212 + */ 1.2213 + private static class SourceFileObject extends BaseFileObject { 1.2214 + 1.2215 + /** The file's name. 1.2216 + */ 1.2217 + private Name name; 1.2218 + 1.2219 + public SourceFileObject(Name name) { 1.2220 + this.name = name; 1.2221 + } 1.2222 + 1.2223 + public InputStream openInputStream() { 1.2224 + throw new UnsupportedOperationException(); 1.2225 + } 1.2226 + 1.2227 + public OutputStream openOutputStream() { 1.2228 + throw new UnsupportedOperationException(); 1.2229 + } 1.2230 + 1.2231 + public Reader openReader() { 1.2232 + throw new UnsupportedOperationException(); 1.2233 + } 1.2234 + 1.2235 + public Writer openWriter() { 1.2236 + throw new UnsupportedOperationException(); 1.2237 + } 1.2238 + 1.2239 + /** @deprecated see bug 6410637 */ 1.2240 + @Deprecated 1.2241 + public String getName() { 1.2242 + return name.toString(); 1.2243 + } 1.2244 + 1.2245 + public long getLastModified() { 1.2246 + throw new UnsupportedOperationException(); 1.2247 + } 1.2248 + 1.2249 + public boolean delete() { 1.2250 + throw new UnsupportedOperationException(); 1.2251 + } 1.2252 + 1.2253 + public CharBuffer getCharContent(boolean ignoreEncodingErrors) { 1.2254 + throw new UnsupportedOperationException(); 1.2255 + } 1.2256 + 1.2257 + @Override 1.2258 + public boolean equals(Object other) { 1.2259 + if (!(other instanceof SourceFileObject)) 1.2260 + return false; 1.2261 + SourceFileObject o = (SourceFileObject) other; 1.2262 + return name.equals(o.name); 1.2263 + } 1.2264 + 1.2265 + @Override 1.2266 + public int hashCode() { 1.2267 + return name.hashCode(); 1.2268 + } 1.2269 + 1.2270 + public boolean isNameCompatible(String simpleName, JavaFileObject.Kind kind) { 1.2271 + return true; // fail-safe mode 1.2272 + } 1.2273 + 1.2274 + public URI toUri() { 1.2275 + return URI.create(name.toString()); 1.2276 + } 1.2277 + 1.2278 + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { 1.2279 + throw new UnsupportedOperationException(); 1.2280 + } 1.2281 + 1.2282 + } 1.2283 +}