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(/*@non_null*/String aname,
236 /*@non_null*/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