Tue, 08 Jul 2008 17:14:22 -0700
6715757: javap does not print "extends java.lang.Object"
Reviewed-by: ksrini
1 /*
2 * Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javap;
28 import java.util.Collection;
29 import java.util.List;
31 import com.sun.tools.classfile.AccessFlags;
32 import com.sun.tools.classfile.Attribute;
33 import com.sun.tools.classfile.Attributes;
34 import com.sun.tools.classfile.ClassFile;
35 import com.sun.tools.classfile.Code_attribute;
36 import com.sun.tools.classfile.ConstantPool;
37 import com.sun.tools.classfile.ConstantPoolException;
38 import com.sun.tools.classfile.Descriptor;
39 import com.sun.tools.classfile.DescriptorException;
40 import com.sun.tools.classfile.Exceptions_attribute;
41 import com.sun.tools.classfile.Field;
42 import com.sun.tools.classfile.Method;
43 import com.sun.tools.classfile.Signature;
44 import com.sun.tools.classfile.Signature_attribute;
45 import com.sun.tools.classfile.SourceFile_attribute;
46 import com.sun.tools.classfile.Type;
48 import static com.sun.tools.classfile.AccessFlags.*;
50 /*
51 * The main javap class to write the contents of a class file as text.
52 *
53 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
54 * you write code that depends on this, you do so at your own risk.
55 * This code and its internal interfaces are subject to change or
56 * deletion without notice.</b>
57 */
58 public class ClassWriter extends BasicWriter {
59 static ClassWriter instance(Context context) {
60 ClassWriter instance = context.get(ClassWriter.class);
61 if (instance == null)
62 instance = new ClassWriter(context);
63 return instance;
64 }
66 protected ClassWriter(Context context) {
67 super(context);
68 context.put(ClassWriter.class, this);
69 options = Options.instance(context);
70 attrWriter = AttributeWriter.instance(context);
71 codeWriter = CodeWriter.instance(context);
72 constantWriter = ConstantWriter.instance(context);
73 }
75 ClassFile getClassFile() {
76 return classFile;
77 }
79 Method getMethod() {
80 return method;
81 }
83 public void write(ClassFile cf) {
84 classFile = cf;
85 constant_pool = classFile.constant_pool;
87 Attribute sfa = cf.getAttribute(Attribute.SourceFile);
88 if (sfa instanceof SourceFile_attribute) {
89 println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
90 }
92 String name = getJavaName(classFile);
93 AccessFlags flags = cf.access_flags;
95 writeModifiers(flags.getClassModifiers());
97 if (classFile.isClass())
98 print("class ");
99 else if (classFile.isInterface())
100 print("interface ");
102 print(name);
104 Signature_attribute sigAttr = getSignature(cf.attributes);
105 if (sigAttr == null) {
106 // use info from class file header
107 if (classFile.isClass() && classFile.super_class != 0 ) {
108 String sn = getJavaSuperclassName(cf);
109 print(" extends ");
110 print(sn);
111 }
112 for (int i = 0; i < classFile.interfaces.length; i++) {
113 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
114 print(getJavaInterfaceName(classFile, i));
115 }
116 } else {
117 try {
118 Type t = sigAttr.getParsedSignature().getType(constant_pool);
119 // The signature parser cannot disambiguate between a
120 // FieldType and a ClassSignatureType that only contains a superclass type.
121 if (t instanceof Type.ClassSigType)
122 print(t);
123 else {
124 print(" extends ");
125 print(t);
126 }
127 } catch (ConstantPoolException e) {
128 print(report(e));
129 }
130 }
132 if (options.verbose) {
133 println();
134 attrWriter.write(cf, cf.attributes, constant_pool);
135 println(" minor version: " + cf.minor_version);
136 println(" major version: " + cf.major_version);
137 if (!options.compat)
138 writeList(" flags: ", flags.getClassFlags(), NEWLINE);
139 constantWriter.writeConstantPool();
140 println();
141 } else {
142 if (!options.compat)
143 print(" ");
144 }
146 println("{");
147 writeFields();
148 writeMethods();
149 println("}");
150 println();
151 }
153 void writeFields() {
154 for (Field f: classFile.fields) {
155 writeField(f);
156 }
157 }
159 void writeField(Field f) {
160 if (!options.checkAccess(f.access_flags))
161 return;
163 if (!(options.showLineAndLocalVariableTables
164 || options.showDisassembled
165 || options.verbose
166 || options.showInternalSignatures
167 || options.showAllAttrs)) {
168 print(" ");
169 }
171 AccessFlags flags = f.access_flags;
172 writeModifiers(flags.getFieldModifiers());
173 Signature_attribute sigAttr = getSignature(f.attributes);
174 if (sigAttr == null)
175 print(getFieldType(f.descriptor));
176 else {
177 try {
178 Type t = sigAttr.getParsedSignature().getType(constant_pool);
179 print(t);
180 } catch (ConstantPoolException e) {
181 // report error?
182 // fall back on non-generic descriptor
183 print(getFieldType(f.descriptor));
184 }
185 }
186 print(" ");
187 print(getFieldName(f));
188 print(";");
189 println();
191 if (options.showInternalSignatures)
192 println(" Signature: " + getValue(f.descriptor));
194 if (options.verbose && !options.compat)
195 writeList(" flags: ", flags.getFieldFlags(), NEWLINE);
197 if (options.showAllAttrs) {
198 for (Attribute attr: f.attributes)
199 attrWriter.write(f, attr, constant_pool);
200 println();
201 }
203 if (options.showDisassembled || options.showLineAndLocalVariableTables)
204 println();
205 }
207 void writeMethods() {
208 for (Method m: classFile.methods)
209 writeMethod(m);
210 }
212 void writeMethod(Method m) {
213 if (!options.checkAccess(m.access_flags))
214 return;
216 method = m;
218 if (!(options.showLineAndLocalVariableTables
219 || options.showDisassembled
220 || options.verbose
221 || options.showInternalSignatures
222 || options.showAllAttrs)) {
223 print(" ");
224 }
226 AccessFlags flags = m.access_flags;
228 Descriptor d;
229 Type.MethodType methodType;
230 List<? extends Type> methodExceptions;
232 Signature_attribute sigAttr = getSignature(m.attributes);
233 if (sigAttr == null) {
234 d = m.descriptor;
235 methodType = null;
236 methodExceptions = null;
237 } else {
238 Signature methodSig = sigAttr.getParsedSignature();
239 d = methodSig;
240 try {
241 methodType = (Type.MethodType) methodSig.getType(constant_pool);
242 methodExceptions = methodType.throwsTypes;
243 if (methodExceptions != null && methodExceptions.size() == 0)
244 methodExceptions = null;
245 } catch (ConstantPoolException e) {
246 // report error?
247 // fall back on standard descriptor
248 methodType = null;
249 methodExceptions = null;
250 }
251 }
253 writeModifiers(flags.getMethodModifiers());
254 if (methodType != null) {
255 writeListIfNotEmpty("<", methodType.typeArgTypes, "> ");
256 }
257 if (getName(m).equals("<init>")) {
258 print(getJavaName(classFile));
259 print(getParameterTypes(d, flags));
260 } else if (getName(m).equals("<clinit>")) {
261 print("{}");
262 } else {
263 print(getReturnType(d));
264 print(" ");
265 print(getName(m));
266 print(getParameterTypes(d, flags));
267 }
269 Attribute e_attr = m.attributes.get(Attribute.Exceptions);
270 if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
271 if (e_attr instanceof Exceptions_attribute) {
272 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
273 if (options.compat) { // Bug XXXXXXX whitespace
274 if (!(options.showLineAndLocalVariableTables
275 || options.showDisassembled
276 || options.verbose
277 || options.showInternalSignatures
278 || options.showAllAttrs)) {
279 print(" ");
280 }
281 print(" ");
282 }
283 print(" throws ");
284 if (methodExceptions != null) { // use generic list if available
285 writeList("", methodExceptions, "");
286 } else {
287 for (int i = 0; i < exceptions.number_of_exceptions; i++) {
288 if (i > 0)
289 print(", ");
290 print(getJavaException(exceptions, i));
291 }
292 }
293 } else {
294 report("Unexpected or invalid value for Exceptions attribute");
295 }
296 }
298 print(";");
299 println();
301 if (options.showInternalSignatures)
302 println(" Signature: " + getValue(m.descriptor));
304 if (options.verbose && !options.compat)
305 writeList(" flags: ", flags.getMethodFlags(), NEWLINE);
307 Code_attribute code = null;
308 Attribute c_attr = m.attributes.get(Attribute.Code);
309 if (c_attr != null) {
310 if (c_attr instanceof Code_attribute)
311 code = (Code_attribute) c_attr;
312 else
313 report("Unexpected or invalid value for Code attribute");
314 }
316 if (options.showDisassembled && !options.showAllAttrs) {
317 if (code != null) {
318 println(" Code:");
319 codeWriter.writeInstrs(code);
320 codeWriter.writeExceptionTable(code);
321 }
322 println();
323 }
325 if (options.showLineAndLocalVariableTables) {
326 if (code != null)
327 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
328 println();
329 if (code != null)
330 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
331 println();
332 println();
333 }
335 if (options.showAllAttrs) {
336 Attribute[] attrs = m.attributes.attrs;
337 for (Attribute attr: attrs)
338 attrWriter.write(m, attr, constant_pool);
340 // // the following condition is to mimic old javap
341 // if (!(attrs.length > 0 &&
342 // attrs[attrs.length - 1] instanceof Exceptions_attribute))
343 println();
344 }
345 }
347 void writeModifiers(Collection<String> items) {
348 for (Object item: items) {
349 print(item);
350 print(" ");
351 }
352 }
354 void writeList(String prefix, Collection<?> items, String suffix) {
355 print(prefix);
356 String sep = "";
357 for (Object item: items) {
358 print(sep);
359 print(item);
360 sep = ", ";
361 }
362 print(suffix);
363 }
365 void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
366 if (items != null && items.size() > 0)
367 writeList(prefix, items, suffix);
368 }
370 Signature_attribute getSignature(Attributes attributes) {
371 if (options.compat) // javap does not recognize recent attributes
372 return null;
373 return (Signature_attribute) attributes.get(Attribute.Signature);
374 }
376 String adjustVarargs(AccessFlags flags, String params) {
377 if (flags.is(ACC_VARARGS) && !options.compat) {
378 int i = params.lastIndexOf("[]");
379 if (i > 0)
380 return params.substring(0, i) + "..." + params.substring(i+2);
381 }
383 return params;
384 }
386 String getJavaName(ClassFile cf) {
387 try {
388 return getJavaName(cf.getName());
389 } catch (ConstantPoolException e) {
390 return report(e);
391 }
392 }
394 String getJavaSuperclassName(ClassFile cf) {
395 try {
396 return getJavaName(cf.getSuperclassName());
397 } catch (ConstantPoolException e) {
398 return report(e);
399 }
400 }
402 String getJavaInterfaceName(ClassFile cf, int index) {
403 try {
404 return getJavaName(cf.getInterfaceName(index));
405 } catch (ConstantPoolException e) {
406 return report(e);
407 }
408 }
410 String getFieldType(Descriptor d) {
411 try {
412 return d.getFieldType(constant_pool);
413 } catch (ConstantPoolException e) {
414 return report(e);
415 } catch (DescriptorException e) {
416 return report(e);
417 }
418 }
420 String getReturnType(Descriptor d) {
421 try {
422 return d.getReturnType(constant_pool);
423 } catch (ConstantPoolException e) {
424 return report(e);
425 } catch (DescriptorException e) {
426 return report(e);
427 }
428 }
430 String getParameterTypes(Descriptor d, AccessFlags flags) {
431 try {
432 return adjustVarargs(flags, d.getParameterTypes(constant_pool));
433 } catch (ConstantPoolException e) {
434 return report(e);
435 } catch (DescriptorException e) {
436 return report(e);
437 }
438 }
440 String getJavaException(Exceptions_attribute attr, int index) {
441 try {
442 return getJavaName(attr.getException(index, constant_pool));
443 } catch (ConstantPoolException e) {
444 return report(e);
445 }
446 }
448 String getValue(Descriptor d) {
449 try {
450 return d.getValue(constant_pool);
451 } catch (ConstantPoolException e) {
452 return report(e);
453 }
454 }
456 String getFieldName(Field f) {
457 try {
458 return f.getName(constant_pool);
459 } catch (ConstantPoolException e) {
460 return report(e);
461 }
462 }
464 String getName(Method m) {
465 try {
466 return m.getName(constant_pool);
467 } catch (ConstantPoolException e) {
468 return report(e);
469 }
470 }
472 static String getJavaName(String name) {
473 return name.replace('/', '.');
474 }
476 String getSourceFile(SourceFile_attribute attr) {
477 try {
478 return attr.getSourceFile(constant_pool);
479 } catch (ConstantPoolException e) {
480 return report(e);
481 }
482 }
484 private Options options;
485 private AttributeWriter attrWriter;
486 private CodeWriter codeWriter;
487 private ConstantWriter constantWriter;
488 private ClassFile classFile;
489 private ConstantPool constant_pool;
490 private Method method;
491 private static final String NEWLINE = System.getProperty("line.separator", "\n");
492 }