001 /* Copyright 2000, 2001, Compaq Computer Corporation */ 002 003 /* ========================================================================= 004 * ASTClassFileParser.java 005 * ========================================================================= */ 006 007 package javafe.reader; 008 009 import java.io.*; 010 import java.util.*; 011 012 //import decsrc.util.*; 013 import javafe.decsrc.ClassFileParser; 014 015 import javafe.ast.*; 016 import javafe.util.*; 017 import javafe.genericfile.GenericFile; 018 019 020 /* ------------------------------------------------------------------------- 021 * ASTClassFileParser 022 * ------------------------------------------------------------------------- */ 023 024 /** 025 * Parses the contents of a class file into an AST for the purpose of 026 * type checking. Ignores components of the class file that have no 027 * relevance to type checking (e.g. method bodies). 028 */ 029 030 class ASTClassFileParser extends ClassFileParser 031 { 032 /* -- package instance methods ------------------------------------------- */ 033 034 /** 035 * The package name of the class being parsed. 036 * Initialized by constructor (by way of set_this_class) 037 */ 038 public Name classPackage; 039 040 /** 041 * The AST of the class parsed by this parser. 042 * Initialized by constructor (by way of parse_file). 043 */ 044 //@ invariant typeDecl != null; 045 //@ invariant typeDecl.specOnly; 046 public TypeDecl typeDecl; 047 048 /** 049 * A dummy location representing the class being parsed. 050 * Initialized by constructor. 051 */ 052 //@ invariant classLocation != Location.NULL; 053 public int classLocation; 054 055 056 /** 057 * Vector of methods and fields with Synthetic attributes. 058 * Use this to weed out synthetic while constructing TypeDecl. 059 */ 060 /*@ non_null */ private Vector synthetics = new Vector(); 061 062 /** 063 * Flag indicating whether the class being parsed has the synthetic 064 * attribute. 065 */ 066 private boolean syntheticClass = false; 067 068 protected boolean includeBodies; 069 070 protected boolean omitPrivateFields = true; 071 072 /** 073 * Parse a class into a new class parser. Resulting class file is 074 * stored in <code>typeDecl</code>; this will be a "spec only" 075 * declaration. Its package is stored in <code>classPackage</code> 076 * and a location for it is stored in <code>classLocation</code>. 077 * @param inputFile the file to parse the class from 078 * @param includeBodies if true, bodies are included, if not, only a spec is produced */ 079 ASTClassFileParser(/*@ non_null */ GenericFile inputFile, boolean includeBodies) 080 throws IOException, ClassFormatError 081 { 082 super(); 083 this.includeBodies = includeBodies; 084 DataInputStream stream = null; 085 try { 086 this.inputFile = inputFile; 087 this.classLocation = Location.createWholeFileLoc(inputFile); 088 stream = new DataInputStream(inputFile.getInputStream()); 089 parse_file(stream); //@ nowarn Invariant; // "parse_file" is a helper 090 } finally { 091 if (stream != null) { 092 try { stream.close(); } 093 catch (IOException e) { } 094 } 095 } 096 removeExtraArg(); 097 } 098 099 /** Binary inner class constructors have an extra initial argument to 100 their constructors (the enclosing class). This is not present in 101 the source file. To make the AST generated by reading the binary 102 correspond to that obtained from a source file, we remove that 103 extra argument for each inner (non-static) class. Since we do this 104 at the end of parse_file, each nested class does this for its own 105 direct inner classes. - DRCok 106 */ 107 public void removeExtraArg() { 108 TypeDeclElemVec vv = typeDecl.elems; 109 for (int k=0; k<vv.size(); ++k) { 110 if (!(vv.elementAt(k) instanceof ClassDecl)) continue; 111 ClassDecl cd = (ClassDecl)vv.elementAt(k); 112 if (Modifiers.isStatic(cd.modifiers)) continue; 113 TypeDeclElemVec v = cd.elems; 114 for (int j=0; j<v.size(); ++j) { 115 if (!(v.elementAt(j) instanceof ConstructorDecl)) continue; 116 ConstructorDecl cdl = (ConstructorDecl)v.elementAt(j); 117 cdl.args.removeElementAt(0); 118 } 119 } 120 } 121 122 /* -- protected instance methods ----------------------------------------- */ 123 124 /** 125 * Add only AST nodes that are not synthetic decls to v. 126 * nodes should be an array of TypeDeclElems. 127 * A synthetic decl is one that had the synthetic attribute, 128 * or is a static method decl for an 129 * interface. 130 */ 131 protected void addNonSyntheticDecls(/*@ non_null */ TypeDeclElemVec v, 132 /*@ non_null */ TypeDeclElem elems[]) { 133 for (int i = 0; i < elems.length; i++) { 134 if (synthetics.contains(elems[i])) { //@ nowarn; 135 continue; 136 } 137 if ((modifiers & ACC_INTERFACE) != 0 && 138 elems[i] instanceof RoutineDecl) { 139 RoutineDecl rd = (RoutineDecl)elems[i]; 140 if (Modifiers.isStatic(rd.modifiers)) { 141 continue; 142 } 143 } 144 if (omitPrivateFields && elems[i] instanceof FieldDecl) { 145 if (Modifiers.isPrivate( ((FieldDecl)elems[i]).modifiers )) { 146 continue; 147 } 148 } 149 v.addElement(elems[i]); //@ nowarn Pre; 150 } 151 } 152 153 /** 154 * Parse the file and set <code>typeDecl</code>. 155 */ 156 //@ also ensures typeDecl != null; 157 protected void parse_file(DataInput stream) 158 throws ClassFormatError, IOException 159 { 160 super.parse_file(stream); 161 162 TypeNameVec interfaceVec = 163 TypeNameVec.make(interfaces); //@ nowarn Pre; 164 165 int predict = classMembers.size() + routines.length + fields.length; 166 TypeDeclElemVec elementVec = TypeDeclElemVec.make(predict); 167 168 elementVec.append(classMembers); 169 170 // only add routines and fields that are not synthetic. 171 this.addNonSyntheticDecls(elementVec, routines); 172 this.addNonSyntheticDecls(elementVec, fields); 173 174 //@ assume classIdentifier != null; 175 if ((modifiers & ACC_INTERFACE) != 0) { 176 typeDecl= (TypeDecl)InterfaceDecl.make(modifiers&~ACC_INTERFACE, 177 null, classIdentifier, 178 interfaceVec, null, elementVec, 179 classLocation, classLocation, 180 classLocation, classLocation); 181 } else { 182 typeDecl= (TypeDecl)ClassDecl.make(modifiers, 183 null, classIdentifier, 184 interfaceVec, null, elementVec, 185 classLocation, classLocation, 186 classLocation, classLocation, 187 super_class); 188 } 189 typeDecl.specOnly = true; 190 } 191 192 /** 193 * Call back from ClassFileParser. 194 */ 195 protected void set_version(int major, int minor) 196 throws ClassFormatError 197 { 198 // don't need class file version 199 } 200 201 /** 202 * Call back from ClassFileParser. 203 */ 204 protected void set_num_constants(int cnum) 205 throws ClassFormatError 206 { 207 constants = new Object[cnum]; 208 rawConstants = new Object[cnum]; 209 } 210 211 /** 212 * Call back from ClassFileParser. 213 */ 214 protected void set_const(int i, int ctype, Object value) 215 throws ClassFormatError 216 { 217 constants[i] = ctype==CONSTANT_Class ? //@ nowarn IndexTooBig; 218 DescriptorParser.parseClass((String)value) : value; 219 rawConstants[i] = value; 220 } 221 222 /** 223 * Call back from ClassFileParser. 224 */ 225 protected void set_const_ref(int i, int ctype, int class_index, 226 String field_name, String type) 227 throws ClassFormatError 228 { 229 // don't need ref constants 230 } 231 232 /** 233 * Call back from ClassFileParser. 234 */ 235 protected void set_class_attribute(String aname, 236 DataInput stream, int n) 237 throws IOException, ClassFormatError 238 { 239 if (aname.equals("Synthetic")) { 240 syntheticClass = true; 241 } else if (! aname.equals("InnerClasses")) { 242 super.set_class_attribute(aname, stream, n); 243 } else { 244 int num_classes = stream.readUnsignedShort(); 245 for (int j = 0; j < num_classes; j++) { 246 int inner = stream.readUnsignedShort(); 247 //@ assume inner < constants.length; // property of class files 248 int outer = stream.readUnsignedShort(); 249 int name = stream.readUnsignedShort(); 250 //@ assume name < constants.length; // property of class files 251 int flags = stream.readUnsignedShort(); 252 //System.out.println("PPP" + Modifiers.toString(flags)); 253 if (outer == this_class_index && name != 0) { 254 // We've found a member that needs to be parsed... 255 if (! (rawConstants[name] instanceof String)) { 256 throw new ClassFormatError("bad constant reference"); 257 } 258 //@ assume rawConstants[inner] instanceof String; // property of class files 259 String nm = (String)rawConstants[inner]; 260 int i = nm.lastIndexOf("/"); 261 String icfn = (i < 0 ? nm : nm.substring(i+1)) + ".class"; 262 GenericFile icf = inputFile.getSibling(icfn); 263 if (icf == null) { 264 throw new IOException(icfn + ": inner class not found"); 265 } 266 ASTClassFileParser parser = new ASTClassFileParser(icf,true); 267 parser.typeDecl.modifiers |= 268 (flags & ~ACC_SYNCHRONIZED & ~ACC_INTERFACE); 269 270 if (Modifiers.isPublic(parser.typeDecl.modifiers)) { 271 parser.typeDecl.modifiers &= ~ACC_PROTECTED; 272 } 273 274 // Only add classes that are not synthetic and are not anonymous inner classes, 275 // which are identified by names that start with a number. 276 if (!parser.syntheticClass && !Character.isDigit(parser.typeDecl.id.toString().charAt(0))) { 277 classMembers.addElement(parser.typeDecl); 278 } 279 } 280 } 281 } 282 } 283 284 /** 285 * Call back from ClassFileParser. 286 */ 287 protected void set_modifiers(int modifiers) 288 throws ClassFormatError 289 { 290 // The synchronized bit for classes is used for other purposes: 291 this.modifiers = modifiers & ~ACC_SYNCHRONIZED; 292 } 293 294 /** 295 * Call back from ClassFileParser. 296 */ 297 protected void set_this_class(int cindex) 298 throws ClassFormatError 299 { 300 // record the class type and synthesize a location for the class binary 301 302 TypeName typeName = (TypeName)constants[cindex]; //@ nowarn Cast, IndexTooBig; 303 //@ assume typeName != null; 304 305 Name qualifier = getNameQualifier(typeName.name); 306 Identifier terminal = getNameTerminal(typeName.name); 307 308 this_class_index = cindex; 309 //this_class = typeName; 310 classPackage = qualifier; 311 classIdentifier = terminal; 312 313 // This is not the correct location; it may be useful later, though. 314 // int location = Location.createWholeFileLoc(terminal+".java"); 315 // classLocation = location; 316 317 DescriptorParser.classLocation = classLocation; 318 } 319 320 /** 321 * Call back from ClassFileParser. 322 */ 323 protected void set_super_class(int cindex) 324 throws ClassFormatError 325 { 326 super_class = (TypeName)constants[cindex]; //@ nowarn Cast, IndexTooBig; 327 } 328 329 /** 330 * Call back from ClassFileParser. 331 */ 332 protected void set_num_interfaces(int n) 333 throws ClassFormatError 334 { 335 interfaces = new TypeName[n]; 336 } 337 338 /** 339 * Call back from ClassFileParser. 340 */ 341 protected void set_interface(int index, int cindex) 342 throws ClassFormatError 343 { 344 interfaces[index] = (TypeName)constants[cindex]; //@ nowarn Cast,IndexTooBig; 345 } 346 347 /** 348 * Call back from ClassFileParser. 349 */ 350 protected void set_num_fields(int n) 351 throws ClassFormatError 352 { 353 fields = new FieldDecl[n]; 354 } 355 356 /** 357 * Call back from ClassFileParser. 358 */ 359 protected void set_field(int i, String fname, String type, int mod) 360 throws ClassFormatError 361 { 362 fields[i] = //@ nowarn IndexTooBig; 363 FieldDecl.make(mod, null, Identifier.intern(fname), 364 DescriptorParser.parseField(type), classLocation, 365 null, classLocation); 366 } 367 368 /** 369 * Call back from ClassFileParser. 370 */ 371 protected void set_field_initializer(int i, Object value) 372 throws ClassFormatError 373 { 374 // construct a literal expression for the initializer 375 376 FieldDecl field = fields[i]; //@ nowarn IndexTooBig; 377 //@ assume field != null ; 378 379 int tag; 380 Object literal; 381 382 switch (field.type.getTag()) 383 { 384 case TagConstants.BOOLEANTYPE: 385 tag = TagConstants.BOOLEANLIT; 386 literal = Boolean.valueOf(((Integer)value).intValue() != 0); //@ nowarn Cast,Null; 387 break; 388 389 case TagConstants.INTTYPE: 390 case TagConstants.BYTETYPE: 391 case TagConstants.SHORTTYPE: 392 tag = TagConstants.INTLIT; 393 literal = (Integer)value; //@ nowarn Cast; 394 break; 395 396 case TagConstants.LONGTYPE: 397 tag = TagConstants.LONGLIT; 398 literal = (Long)value; //@ nowarn Cast; 399 break; 400 401 case TagConstants.CHARTYPE: 402 tag = TagConstants.CHARLIT; 403 literal = (Integer)value; //@ nowarn Cast; 404 break; 405 406 case TagConstants.FLOATTYPE: 407 tag = TagConstants.FLOATLIT; 408 literal = (Float)value; //@ nowarn Cast; 409 break; 410 411 case TagConstants.DOUBLETYPE: 412 tag = TagConstants.DOUBLELIT; 413 literal = (Double)value; //@ nowarn Cast; 414 break; 415 416 default: 417 tag = TagConstants.STRINGLIT; 418 literal = (String)value; //@ nowarn Cast; 419 break; 420 } 421 422 field.init = LiteralExpr.make(tag, literal, classLocation); 423 } 424 425 /** 426 * Call back from ClassFileParser. 427 */ 428 protected void set_num_methods(int n) 429 throws ClassFormatError 430 { 431 routines = new RoutineDecl[n]; 432 } 433 434 /** 435 * Call back from ClassFileParser. 436 */ 437 protected void set_method(int i, String mname, String sig, int mod) 438 throws ClassFormatError 439 { 440 MethodSignature signature = 441 DescriptorParser.parseMethod(sig); 442 FormalParaDeclVec formalVec = 443 FormalParaDeclVec.make(makeFormals(signature)); 444 BlockStmt body = null; 445 446 routines[i] = //@ nowarn IndexTooBig; 447 mname.equals("<init>") ? 448 (RoutineDecl)ConstructorDecl.make( 449 mod, null, null, formalVec, emptyTypeNameVec, body, Location.NULL, 450 classLocation, classLocation, classLocation) : 451 (RoutineDecl)MethodDecl.make( 452 mod, null, null, formalVec, emptyTypeNameVec, body, Location.NULL, 453 classLocation, classLocation, classLocation, 454 Identifier.intern(mname), signature.getReturn(), classLocation); 455 } 456 457 /** 458 * Call back from ClassFileParser. 459 */ 460 protected void set_method_body(int i, int max_stack, int max_local, 461 byte[] code, int num_handlers) 462 throws ClassFormatError 463 { 464 // put in a dummy body 465 if (!includeBodies) return; 466 routines[i].body = //@ nowarn Null, IndexTooBig; 467 BlockStmt.make(StmtVec.make(), classLocation, classLocation); 468 routines[i].locOpenBrace = classLocation; 469 } 470 471 /** 472 * Call back from ClassFileParser. 473 */ 474 protected void set_method_handler(int i, int j, int start_pc, int end_pc, 475 int handler_pc, int catch_index) 476 throws ClassFormatError 477 { 478 // don't need method handlers 479 } 480 481 /** 482 * Call back from ClassFileParser. 483 */ 484 protected void set_method_attribute(int i, String aname, 485 DataInput stream, int n) 486 throws IOException, ClassFormatError 487 { 488 // look for the Exceptions attribute and modify the appropriate method, if 489 // necessary 490 491 if (aname.equals("Exceptions")) { 492 routines[i].raises = TypeNameVec.make(parseTypeNames((DataInputStream)stream)); //@ nowarn Null, Cast, IndexTooBig; 493 } else if (aname.equals("Synthetic")) { 494 synthetics.addElement(routines[i]); //@ nowarn ; 495 } else { 496 stream.skipBytes(n); 497 } 498 } 499 500 /* -- private instance variables ----------------------------------------- */ 501 502 /** 503 * The input file being parsed. 504 */ 505 /*@ non_null */ GenericFile inputFile; 506 507 /** 508 * The constant pool of the class being parsed. 509 * Initialized by set_num_constants. 510 * Elements initialized by set_const and set_const_ref. 511 * 512 * Dynamic element types according to constant tag: 513 * UTF8 String 514 * String String 515 * Class TypeName 516 * Integer Integer 517 * Float Float 518 * Long Long 519 * Double Double 520 * FieldRef null 521 * MethodRef null 522 * InterfaceMethodRef null 523 */ 524 //@ private invariant constants != null; 525 //@ private invariant \typeof(constants) == \type(Object[]); 526 private Object[] constants; 527 528 /** 529 * The constant pool of the class being parsed. 530 * This array contains the constants as they came out of the 531 * parser (versus translated by DescriptorParser). Initialized 532 * by set_const and set_num_constants. 533 */ 534 //@ private invariant rawConstants != null; 535 //@ private invariant \typeof(rawConstants) == \type(Object[]); 536 //@ private invariant constants.length == rawConstants.length; 537 private Object[] rawConstants; 538 539 /** 540 * The modifiers of the class being parsed. 541 * Initialized by set_modifiers. 542 */ 543 private int modifiers; 544 545 /** 546 * The contant pool index of this class. 547 * Initialized by set_this_class. 548 */ 549 private int this_class_index; 550 551 /** 552 * The type name of the class being parsed. 553 * Initialized by set_this_class. 554 */ 555 //private TypeName this_class; 556 557 /** 558 * The type name of the superclass of the class being parsed. 559 * Initialized by set_super_class. 560 */ 561 private TypeName super_class; 562 563 /** 564 * The type names of the interfaces implemented by the class being parsed. 565 * Initialized by set_num_interfaces. 566 * Elements initialized by set_interface. 567 */ 568 //@ private invariant interfaces != null; 569 //@ private invariant \typeof(interfaces) == \type(TypeName[]); 570 private TypeName[] interfaces; 571 572 /** 573 * The class members of the class being parsed. 574 * Intialized by set_field, set_method, and set_class_attributes. 575 */ 576 //@ invariant classMembers != null; 577 TypeDeclElemVec classMembers = TypeDeclElemVec.make(0); 578 579 /** 580 * The fields of the class being parsed. 581 * Initialized by set_num_fields. 582 * Elements initialized by set_field. 583 */ 584 //@ invariant fields != null; 585 //@ invariant \typeof(fields) == \type(FieldDecl[]); 586 //@ spec_public 587 private FieldDecl[] fields; 588 589 /** 590 * The methods and constructors of the class being parsed. 591 * Initialized by set_num_methods. 592 * Elements initialized by set_method. 593 */ 594 //@ invariant routines != null; 595 //@ invariant \typeof(routines) == \type(RoutineDecl[]); 596 //@ spec_public 597 private RoutineDecl[] routines; 598 599 /** 600 * The identifier of the class being parsed. 601 * Initialized by set_this_class. 602 */ 603 //@ spec_public 604 private Identifier classIdentifier; 605 606 /* -- private instance methods ------------------------------------------- */ 607 608 /** 609 * Parse a sequence of type names from a given stream. 610 * @param stream the stream to parse the type names from 611 * @return an array of type names 612 * @exception ClassFormatError if the type names are not class constants 613 */ 614 //@ requires stream != null; 615 //@ ensures \nonnullelements(\result); 616 //@ ensures \typeof(\result)==\type(TypeName[]); 617 private TypeName[] parseTypeNames(DataInputStream stream) 618 throws IOException, ClassFormatError 619 { 620 int count = stream.readUnsignedShort(); 621 TypeName[] names = new TypeName[count]; 622 623 for (int i = 0; i<count; i++) 624 { 625 int index = stream.readUnsignedShort(); 626 627 if (index>=constants.length) 628 throw new ClassFormatError("unknown constant"); 629 630 Object constant = constants[index]; 631 632 if (!(constant instanceof TypeName)) 633 throw new ClassFormatError("not a class constant"); 634 635 names[i] = (TypeName)constant; 636 } 637 638 return names; 639 } 640 641 /** 642 * Construct a vector of formal parameters from a method signature. 643 * @param signature the method signature to make the formal parameters from 644 * @return the formal parameters 645 */ 646 //@ requires signature != null; 647 //@ ensures \nonnullelements(\result); 648 //@ ensures \typeof(\result) == \type(FormalParaDecl[]); 649 private FormalParaDecl[] makeFormals(MethodSignature signature) 650 { 651 int length = signature.countParameters(); 652 FormalParaDecl[] formals = new FormalParaDecl[length]; 653 654 for (int i = 0; i<length; i++) { 655 Identifier id = Identifier.intern("arg" + i); 656 formals[i] = 657 FormalParaDecl.make(0, null, id, signature.parameterAt(i), 658 classLocation); 659 } 660 661 return formals; 662 } 663 664 /* -- private class methods ---------------------------------------------- */ 665 666 /** 667 * Return the package qualifier of a given name. 668 * @param name the name to return the package qualifier of 669 * @return the package qualifier of name 670 */ 671 //@ requires name != null; 672 private static Name getNameQualifier(Name name) 673 { 674 int size = name.size(); 675 676 return size>1 ? name.prefix(size-1) : null; 677 // using null for the unnamed package ??? 678 } 679 680 /** 681 * Return the terminal identifier of a given name. 682 * @param name the name to return the terminal identifier of 683 * @return the terminal identifier of name 684 */ 685 //@ requires name != null; 686 private static Identifier getNameTerminal(Name name) 687 { 688 return name.identifierAt(name.size()-1); 689 } 690 691 /* -- private class variables -------------------------------------------- */ 692 693 /** 694 * An empty type name vector. 695 */ 696 //@ invariant emptyTypeNameVec != null; 697 //@ spec_public 698 private static final TypeNameVec emptyTypeNameVec = TypeNameVec.make(); 699 700 /** 701 * A null identifier. 702 */ 703 /* UNUSED 704 //@ invariant nullIdentifier != null; 705 private static final Identifier nullIdentifier = Identifier.intern(""); 706 */ 707 708 } 709