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