Tue, 11 Aug 2009 01:13:14 +0100
6521805: Regression: JDK5/JDK6 javac allows write access to outer class reference
Summary: javac should warn/complain about identifiers with the same name as synthetic symbol
Reviewed-by: jjg
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.io.EOFException;
29 import java.io.FileNotFoundException;
30 import java.io.FilterInputStream;
31 import java.io.InputStream;
32 import java.io.IOException;
33 import java.io.OutputStream;
34 import java.io.PrintWriter;
35 import java.io.Reader;
36 import java.io.StringWriter;
37 import java.io.Writer;
38 import java.net.URI;
39 import java.security.DigestInputStream;
40 import java.security.MessageDigest;
41 import java.security.NoSuchAlgorithmException;
42 import java.text.MessageFormat;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.EnumSet;
46 import java.util.HashMap;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Map;
51 import java.util.MissingResourceException;
52 import java.util.ResourceBundle;
54 import javax.lang.model.element.Modifier;
55 import javax.lang.model.element.NestingKind;
56 import javax.tools.Diagnostic;
57 import javax.tools.DiagnosticListener;
58 import javax.tools.JavaFileManager;
59 import javax.tools.JavaFileObject;
60 import javax.tools.StandardJavaFileManager;
61 import javax.tools.StandardLocation;
63 import com.sun.tools.classfile.*;
64 import java.net.URISyntaxException;
65 import java.net.URL;
66 import java.net.URLConnection;
68 /**
69 * "Main" class for javap, normally accessed from the command line
70 * via Main, or from JSR199 via DisassemblerTool.
71 *
72 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
73 * you write code that depends on this, you do so at your own risk.
74 * This code and its internal interfaces are subject to change or
75 * deletion without notice.</b>
76 */
77 public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
78 public class BadArgs extends Exception {
79 static final long serialVersionUID = 8765093759964640721L;
80 BadArgs(String key, Object... args) {
81 super(JavapTask.this.getMessage(key, args));
82 this.key = key;
83 this.args = args;
84 }
86 BadArgs showUsage(boolean b) {
87 showUsage = b;
88 return this;
89 }
91 final String key;
92 final Object[] args;
93 boolean showUsage;
94 }
96 static abstract class Option {
97 Option(boolean hasArg, String... aliases) {
98 this.hasArg = hasArg;
99 this.aliases = aliases;
100 }
102 boolean matches(String opt) {
103 for (String a: aliases) {
104 if (a.equals(opt))
105 return true;
106 }
107 return false;
108 }
110 boolean ignoreRest() {
111 return false;
112 }
114 abstract void process(JavapTask task, String opt, String arg) throws BadArgs;
116 final boolean hasArg;
117 final String[] aliases;
118 }
120 static Option[] recognizedOptions = {
122 new Option(false, "-help", "--help", "-?") {
123 void process(JavapTask task, String opt, String arg) {
124 task.options.help = true;
125 }
126 },
128 new Option(false, "-version") {
129 void process(JavapTask task, String opt, String arg) {
130 task.options.version = true;
131 }
132 },
134 new Option(false, "-fullversion") {
135 void process(JavapTask task, String opt, String arg) {
136 task.options.fullVersion = true;
137 }
138 },
140 new Option(false, "-v", "-verbose", "-all") {
141 void process(JavapTask task, String opt, String arg) {
142 task.options.verbose = true;
143 task.options.showFlags = true;
144 task.options.showAllAttrs = true;
145 }
146 },
148 new Option(false, "-l") {
149 void process(JavapTask task, String opt, String arg) {
150 task.options.showLineAndLocalVariableTables = true;
151 }
152 },
154 new Option(false, "-public") {
155 void process(JavapTask task, String opt, String arg) {
156 task.options.accessOptions.add(opt);
157 task.options.showAccess = AccessFlags.ACC_PUBLIC;
158 }
159 },
161 new Option(false, "-protected") {
162 void process(JavapTask task, String opt, String arg) {
163 task.options.accessOptions.add(opt);
164 task.options.showAccess = AccessFlags.ACC_PROTECTED;
165 }
166 },
168 new Option(false, "-package") {
169 void process(JavapTask task, String opt, String arg) {
170 task.options.accessOptions.add(opt);
171 task.options.showAccess = 0;
172 }
173 },
175 new Option(false, "-p", "-private") {
176 void process(JavapTask task, String opt, String arg) {
177 if (!task.options.accessOptions.contains("-p") &&
178 !task.options.accessOptions.contains("-private")) {
179 task.options.accessOptions.add(opt);
180 }
181 task.options.showAccess = AccessFlags.ACC_PRIVATE;
182 }
183 },
185 new Option(false, "-c") {
186 void process(JavapTask task, String opt, String arg) {
187 task.options.showDisassembled = true;
188 }
189 },
191 new Option(false, "-s") {
192 void process(JavapTask task, String opt, String arg) {
193 task.options.showInternalSignatures = true;
194 }
195 },
197 // new Option(false, "-all") {
198 // void process(JavapTask task, String opt, String arg) {
199 // task.options.showAllAttrs = true;
200 // }
201 // },
203 new Option(false, "-h") {
204 void process(JavapTask task, String opt, String arg) throws BadArgs {
205 throw task.new BadArgs("err.h.not.supported");
206 }
207 },
209 new Option(false, "-verify", "-verify-verbose") {
210 void process(JavapTask task, String opt, String arg) throws BadArgs {
211 throw task.new BadArgs("err.verify.not.supported");
212 }
213 },
215 new Option(false, "-sysinfo") {
216 void process(JavapTask task, String opt, String arg) {
217 task.options.sysInfo = true;
218 }
219 },
221 new Option(false, "-Xold") {
222 void process(JavapTask task, String opt, String arg) throws BadArgs {
223 task.log.println(task.getMessage("warn.Xold.not.supported"));
224 }
225 },
227 new Option(false, "-Xnew") {
228 void process(JavapTask task, String opt, String arg) throws BadArgs {
229 // ignore: this _is_ the new version
230 }
231 },
233 new Option(false, "-XDcompat") {
234 void process(JavapTask task, String opt, String arg) {
235 task.options.compat = true;
236 }
237 },
239 new Option(false, "-XDjsr277") {
240 void process(JavapTask task, String opt, String arg) {
241 task.options.jsr277 = true;
242 }
243 },
245 new Option(false, "-XDdetails") {
246 void process(JavapTask task, String opt, String arg) {
247 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
248 }
250 },
252 new Option(false, "-XDdetails:") {
253 @Override
254 boolean matches(String opt) {
255 int sep = opt.indexOf(":");
256 return sep != -1 && super.matches(opt.substring(0, sep + 1));
257 }
259 void process(JavapTask task, String opt, String arg) throws BadArgs {
260 int sep = opt.indexOf(":");
261 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
262 if (!handleArg(task, v))
263 throw task.new BadArgs("err.invalid.arg.for.option", v);
264 }
265 }
267 boolean handleArg(JavapTask task, String arg) {
268 if (arg.length() == 0)
269 return true;
271 if (arg.equals("all")) {
272 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
273 return true;
274 }
276 boolean on = true;
277 if (arg.startsWith("-")) {
278 on = false;
279 arg = arg.substring(1);
280 }
282 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
283 if (arg.equalsIgnoreCase(k.option)) {
284 if (on)
285 task.options.details.add(k);
286 else
287 task.options.details.remove(k);
288 return true;
289 }
290 }
291 return false;
292 }
293 },
295 new Option(false, "-constants") {
296 void process(JavapTask task, String opt, String arg) {
297 task.options.showConstants = true;
298 }
299 },
301 new Option(false, "-XDinner") {
302 void process(JavapTask task, String opt, String arg) {
303 task.options.showInnerClasses = true;
304 }
305 },
307 new Option(false, "-XDindent:") {
308 @Override
309 boolean matches(String opt) {
310 int sep = opt.indexOf(":");
311 return sep != -1 && super.matches(opt.substring(0, sep + 1));
312 }
314 void process(JavapTask task, String opt, String arg) throws BadArgs {
315 int sep = opt.indexOf(":");
316 try {
317 task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
318 } catch (NumberFormatException e) {
319 }
320 }
321 },
323 new Option(false, "-XDtab:") {
324 @Override
325 boolean matches(String opt) {
326 int sep = opt.indexOf(":");
327 return sep != -1 && super.matches(opt.substring(0, sep + 1));
328 }
330 void process(JavapTask task, String opt, String arg) throws BadArgs {
331 int sep = opt.indexOf(":");
332 try {
333 task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
334 } catch (NumberFormatException e) {
335 }
336 }
337 }
339 };
341 public JavapTask() {
342 context = new Context();
343 context.put(Messages.class, this);
344 options = Options.instance(context);
345 attributeFactory = new Attribute.Factory();
346 }
348 public JavapTask(Writer out,
349 JavaFileManager fileManager,
350 DiagnosticListener<? super JavaFileObject> diagnosticListener) {
351 this();
352 this.log = getPrintWriterForWriter(out);
353 this.fileManager = fileManager;
354 this.diagnosticListener = diagnosticListener;
355 }
357 public JavapTask(Writer out,
358 JavaFileManager fileManager,
359 DiagnosticListener<? super JavaFileObject> diagnosticListener,
360 Iterable<String> options,
361 Iterable<String> classes) {
362 this(out, fileManager, diagnosticListener);
364 this.classes = new ArrayList<String>();
365 for (String classname: classes) {
366 classname.getClass(); // null-check
367 this.classes.add(classname);
368 }
370 try {
371 handleOptions(options, false);
372 } catch (BadArgs e) {
373 throw new IllegalArgumentException(e.getMessage());
374 }
375 }
377 public void setLocale(Locale locale) {
378 if (locale == null)
379 locale = Locale.getDefault();
380 task_locale = locale;
381 }
383 public void setLog(PrintWriter log) {
384 this.log = log;
385 }
387 public void setLog(OutputStream s) {
388 setLog(getPrintWriterForStream(s));
389 }
391 private static PrintWriter getPrintWriterForStream(OutputStream s) {
392 return new PrintWriter(s, true);
393 }
395 private static PrintWriter getPrintWriterForWriter(Writer w) {
396 if (w == null)
397 return getPrintWriterForStream(null);
398 else if (w instanceof PrintWriter)
399 return (PrintWriter) w;
400 else
401 return new PrintWriter(w, true);
402 }
404 public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
405 diagnosticListener = dl;
406 }
408 public void setDiagnosticListener(OutputStream s) {
409 setDiagnosticListener(getDiagnosticListenerForStream(s));
410 }
412 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
413 return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
414 }
416 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
417 final PrintWriter pw = getPrintWriterForWriter(w);
418 return new DiagnosticListener<JavaFileObject> () {
419 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
420 switch (diagnostic.getKind()) {
421 case ERROR:
422 pw.print(getMessage("err.prefix"));
423 break;
424 case WARNING:
425 pw.print(getMessage("warn.prefix"));
426 break;
427 case NOTE:
428 pw.print(getMessage("note.prefix"));
429 break;
430 }
431 pw.print(" ");
432 pw.println(diagnostic.getMessage(null));
433 }
434 };
435 }
437 /** Result codes.
438 */
439 static final int
440 EXIT_OK = 0, // Compilation completed with no errors.
441 EXIT_ERROR = 1, // Completed but reported errors.
442 EXIT_CMDERR = 2, // Bad command-line arguments
443 EXIT_SYSERR = 3, // System error or resource exhaustion.
444 EXIT_ABNORMAL = 4; // Compiler terminated abnormally
446 int run(String[] args) {
447 try {
448 handleOptions(args);
450 // the following gives consistent behavior with javac
451 if (classes == null || classes.size() == 0) {
452 if (options.help || options.version || options.fullVersion)
453 return EXIT_OK;
454 else
455 return EXIT_CMDERR;
456 }
458 boolean ok = run();
459 return ok ? EXIT_OK : EXIT_ERROR;
460 } catch (BadArgs e) {
461 reportError(e.key, e.args);
462 if (e.showUsage) {
463 log.println(getMessage("main.usage.summary", progname));
464 }
465 return EXIT_CMDERR;
466 } catch (InternalError e) {
467 Object[] e_args;
468 if (e.getCause() == null)
469 e_args = e.args;
470 else {
471 e_args = new Object[e.args.length + 1];
472 e_args[0] = e.getCause();
473 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
474 }
475 reportError("err.internal.error", e_args);
476 return EXIT_ABNORMAL;
477 } finally {
478 log.flush();
479 }
480 }
482 public void handleOptions(String[] args) throws BadArgs {
483 handleOptions(Arrays.asList(args), true);
484 }
486 private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
487 if (log == null) {
488 log = getPrintWriterForStream(System.out);
489 if (diagnosticListener == null)
490 diagnosticListener = getDiagnosticListenerForStream(System.err);
491 } else {
492 if (diagnosticListener == null)
493 diagnosticListener = getDiagnosticListenerForWriter(log);
494 }
497 if (fileManager == null)
498 fileManager = getDefaultFileManager(diagnosticListener, log);
500 Iterator<String> iter = args.iterator();
501 boolean noArgs = !iter.hasNext();
503 while (iter.hasNext()) {
504 String arg = iter.next();
505 if (arg.startsWith("-"))
506 handleOption(arg, iter);
507 else if (allowClasses) {
508 if (classes == null)
509 classes = new ArrayList<String>();
510 classes.add(arg);
511 while (iter.hasNext())
512 classes.add(iter.next());
513 } else
514 throw new BadArgs("err.unknown.option", arg).showUsage(true);
515 }
517 if (!options.compat && options.accessOptions.size() > 1) {
518 StringBuilder sb = new StringBuilder();
519 for (String opt: options.accessOptions) {
520 if (sb.length() > 0)
521 sb.append(" ");
522 sb.append(opt);
523 }
524 throw new BadArgs("err.incompatible.options", sb);
525 }
527 if ((classes == null || classes.size() == 0) &&
528 !(noArgs || options.help || options.version || options.fullVersion)) {
529 throw new BadArgs("err.no.classes.specified");
530 }
532 if (noArgs || options.help)
533 showHelp();
535 if (options.version || options.fullVersion)
536 showVersion(options.fullVersion);
537 }
539 private void handleOption(String name, Iterator<String> rest) throws BadArgs {
540 for (Option o: recognizedOptions) {
541 if (o.matches(name)) {
542 if (o.hasArg) {
543 if (rest.hasNext())
544 o.process(this, name, rest.next());
545 else
546 throw new BadArgs("err.missing.arg", name).showUsage(true);
547 } else
548 o.process(this, name, null);
550 if (o.ignoreRest()) {
551 while (rest.hasNext())
552 rest.next();
553 }
554 return;
555 }
556 }
558 if (fileManager.handleOption(name, rest))
559 return;
561 throw new BadArgs("err.unknown.option", name).showUsage(true);
562 }
564 public Boolean call() {
565 return run();
566 }
568 public boolean run() {
569 if (classes == null || classes.size() == 0)
570 return false;
572 context.put(PrintWriter.class, log);
573 ClassWriter classWriter = ClassWriter.instance(context);
574 SourceWriter sourceWriter = SourceWriter.instance(context);
575 sourceWriter.setFileManager(fileManager);
577 attributeFactory.setCompat(options.compat);
578 attributeFactory.setJSR277(options.jsr277);
580 boolean ok = true;
582 for (String className: classes) {
583 JavaFileObject fo;
584 try {
585 writeClass(classWriter, className);
586 } catch (ConstantPoolException e) {
587 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
588 ok = false;
589 } catch (EOFException e) {
590 reportError("err.end.of.file", className);
591 ok = false;
592 } catch (FileNotFoundException e) {
593 reportError("err.file.not.found", e.getLocalizedMessage());
594 ok = false;
595 } catch (IOException e) {
596 //e.printStackTrace();
597 Object msg = e.getLocalizedMessage();
598 if (msg == null)
599 msg = e;
600 reportError("err.ioerror", className, msg);
601 ok = false;
602 } catch (Throwable t) {
603 StringWriter sw = new StringWriter();
604 PrintWriter pw = new PrintWriter(sw);
605 t.printStackTrace(pw);
606 pw.close();
607 reportError("err.crash", t.toString(), sw.toString());
608 ok = false;
609 }
610 }
612 return ok;
613 }
615 protected boolean writeClass(ClassWriter classWriter, String className)
616 throws IOException, ConstantPoolException {
617 JavaFileObject fo = open(className);
618 if (fo == null) {
619 reportError("err.class.not.found", className);
620 return false;
621 }
623 ClassFileInfo cfInfo = read(fo);
624 if (!className.endsWith(".class")) {
625 String cfName = cfInfo.cf.getName();
626 if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
627 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
628 }
629 write(cfInfo);
631 if (options.showInnerClasses) {
632 ClassFile cf = cfInfo.cf;
633 Attribute a = cf.getAttribute(Attribute.InnerClasses);
634 if (a instanceof InnerClasses_attribute) {
635 InnerClasses_attribute inners = (InnerClasses_attribute) a;
636 try {
637 boolean ok = true;
638 for (int i = 0; i < inners.classes.length; i++) {
639 int outerIndex = inners.classes[i].outer_class_info_index;
640 ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
641 String outerClassName = outerClassInfo.getName();
642 if (outerClassName.equals(cf.getName())) {
643 int innerIndex = inners.classes[i].inner_class_info_index;
644 ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
645 String innerClassName = innerClassInfo.getName();
646 classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
647 classWriter.println();
648 ok = ok & writeClass(classWriter, innerClassName);
649 }
650 }
651 return ok;
652 } catch (ConstantPoolException e) {
653 reportError("err.bad.innerclasses.attribute", className);
654 return false;
655 }
656 } else if (a != null) {
657 reportError("err.bad.innerclasses.attribute", className);
658 return false;
659 }
660 }
662 return true;
663 }
665 protected JavaFileObject open(String className) throws IOException {
666 // for compatibility, first see if it is a class name
667 JavaFileObject fo = getClassFileObject(className);
668 if (fo != null)
669 return fo;
671 // see if it is an inner class, by replacing dots to $, starting from the right
672 String cn = className;
673 int lastDot;
674 while ((lastDot = cn.lastIndexOf(".")) != -1) {
675 cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
676 fo = getClassFileObject(cn);
677 if (fo != null)
678 return fo;
679 }
681 if (!className.endsWith(".class"))
682 return null;
684 if (fileManager instanceof StandardJavaFileManager) {
685 StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
686 fo = sfm.getJavaFileObjects(className).iterator().next();
687 if (fo != null && fo.getLastModified() != 0) {
688 return fo;
689 }
690 }
692 // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
693 // to suit javap's needs
694 if (className.matches("^[A-Za-z]+:.*")) {
695 try {
696 final URI uri = new URI(className);
697 final URL url = uri.toURL();
698 final URLConnection conn = url.openConnection();
699 return new JavaFileObject() {
700 public Kind getKind() {
701 return JavaFileObject.Kind.CLASS;
702 }
704 public boolean isNameCompatible(String simpleName, Kind kind) {
705 throw new UnsupportedOperationException();
706 }
708 public NestingKind getNestingKind() {
709 throw new UnsupportedOperationException();
710 }
712 public Modifier getAccessLevel() {
713 throw new UnsupportedOperationException();
714 }
716 public URI toUri() {
717 return uri;
718 }
720 public String getName() {
721 return url.toString();
722 }
724 public InputStream openInputStream() throws IOException {
725 return conn.getInputStream();
726 }
728 public OutputStream openOutputStream() throws IOException {
729 throw new UnsupportedOperationException();
730 }
732 public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
733 throw new UnsupportedOperationException();
734 }
736 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
737 throw new UnsupportedOperationException();
738 }
740 public Writer openWriter() throws IOException {
741 throw new UnsupportedOperationException();
742 }
744 public long getLastModified() {
745 return conn.getLastModified();
746 }
748 public boolean delete() {
749 throw new UnsupportedOperationException();
750 }
752 };
753 } catch (URISyntaxException ignore) {
754 } catch (IOException ignore) {
755 }
756 }
758 return null;
759 }
761 public static class ClassFileInfo {
762 ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
763 this.fo = fo;
764 this.cf = cf;
765 this.digest = digest;
766 this.size = size;
767 }
768 public final JavaFileObject fo;
769 public final ClassFile cf;
770 public final byte[] digest;
771 public final int size;
772 }
774 public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
775 InputStream in = fo.openInputStream();
776 try {
777 SizeInputStream sizeIn = null;
778 MessageDigest md = null;
779 if (options.sysInfo || options.verbose) {
780 try {
781 md = MessageDigest.getInstance("MD5");
782 } catch (NoSuchAlgorithmException ignore) {
783 }
784 in = new DigestInputStream(in, md);
785 in = sizeIn = new SizeInputStream(in);
786 }
788 ClassFile cf = ClassFile.read(in, attributeFactory);
789 byte[] digest = (md == null) ? null : md.digest();
790 int size = (sizeIn == null) ? -1 : sizeIn.size();
791 return new ClassFileInfo(fo, cf, digest, size);
792 } finally {
793 in.close();
794 }
795 }
797 public void write(ClassFileInfo info) {
798 ClassWriter classWriter = ClassWriter.instance(context);
799 if (options.sysInfo || options.verbose) {
800 classWriter.setFile(info.fo.toUri());
801 classWriter.setLastModified(info.fo.getLastModified());
802 classWriter.setDigest("MD5", info.digest);
803 classWriter.setFileSize(info.size);
804 }
806 classWriter.write(info.cf);
807 }
809 protected void setClassFile(ClassFile classFile) {
810 ClassWriter classWriter = ClassWriter.instance(context);
811 classWriter.setClassFile(classFile);
812 }
814 protected void setMethod(Method enclosingMethod) {
815 ClassWriter classWriter = ClassWriter.instance(context);
816 classWriter.setMethod(enclosingMethod);
817 }
819 protected void write(Attribute value) {
820 AttributeWriter attrWriter = AttributeWriter.instance(context);
821 ClassWriter classWriter = ClassWriter.instance(context);
822 ClassFile cf = classWriter.getClassFile();
823 attrWriter.write(cf, value, cf.constant_pool);
824 }
826 protected void write(Attributes attrs) {
827 AttributeWriter attrWriter = AttributeWriter.instance(context);
828 ClassWriter classWriter = ClassWriter.instance(context);
829 ClassFile cf = classWriter.getClassFile();
830 attrWriter.write(cf, attrs, cf.constant_pool);
831 }
833 protected void write(ConstantPool constant_pool) {
834 ConstantWriter constantWriter = ConstantWriter.instance(context);
835 constantWriter.writeConstantPool(constant_pool);
836 }
838 protected void write(ConstantPool constant_pool, int value) {
839 ConstantWriter constantWriter = ConstantWriter.instance(context);
840 constantWriter.write(value);
841 }
843 protected void write(ConstantPool.CPInfo value) {
844 ConstantWriter constantWriter = ConstantWriter.instance(context);
845 constantWriter.println(value);
846 }
848 protected void write(Field value) {
849 ClassWriter classWriter = ClassWriter.instance(context);
850 classWriter.writeField(value);
851 }
853 protected void write(Method value) {
854 ClassWriter classWriter = ClassWriter.instance(context);
855 classWriter.writeMethod(value);
856 }
858 private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
859 return JavapFileManager.create(dl, log);
860 }
862 private JavaFileObject getClassFileObject(String className) throws IOException {
863 JavaFileObject fo;
864 fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
865 if (fo == null)
866 fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
867 return fo;
868 }
870 private void showHelp() {
871 log.println(getMessage("main.usage", progname));
872 for (Option o: recognizedOptions) {
873 String name = o.aliases[0].substring(1); // there must always be at least one name
874 if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
875 continue;
876 log.println(getMessage("main.opt." + name));
877 }
878 String[] fmOptions = { "-classpath", "-bootclasspath" };
879 for (String o: fmOptions) {
880 if (fileManager.isSupportedOption(o) == -1)
881 continue;
882 String name = o.substring(1);
883 log.println(getMessage("main.opt." + name));
884 }
886 }
888 private void showVersion(boolean full) {
889 log.println(version(full ? "full" : "release"));
890 }
892 private static final String versionRBName = "com.sun.tools.javap.resources.version";
893 private static ResourceBundle versionRB;
895 private String version(String key) {
896 // key=version: mm.nn.oo[-milestone]
897 // key=full: mm.mm.oo[-milestone]-build
898 if (versionRB == null) {
899 try {
900 versionRB = ResourceBundle.getBundle(versionRBName);
901 } catch (MissingResourceException e) {
902 return getMessage("version.resource.missing", System.getProperty("java.version"));
903 }
904 }
905 try {
906 return versionRB.getString(key);
907 }
908 catch (MissingResourceException e) {
909 return getMessage("version.unknown", System.getProperty("java.version"));
910 }
911 }
913 private void reportError(String key, Object... args) {
914 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
915 }
917 private void reportNote(String key, Object... args) {
918 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
919 }
921 private void reportWarning(String key, Object... args) {
922 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
923 }
925 private Diagnostic<JavaFileObject> createDiagnostic(
926 final Diagnostic.Kind kind, final String key, final Object... args) {
927 return new Diagnostic<JavaFileObject>() {
928 public Kind getKind() {
929 return kind;
930 }
932 public JavaFileObject getSource() {
933 return null;
934 }
936 public long getPosition() {
937 return Diagnostic.NOPOS;
938 }
940 public long getStartPosition() {
941 return Diagnostic.NOPOS;
942 }
944 public long getEndPosition() {
945 return Diagnostic.NOPOS;
946 }
948 public long getLineNumber() {
949 return Diagnostic.NOPOS;
950 }
952 public long getColumnNumber() {
953 return Diagnostic.NOPOS;
954 }
956 public String getCode() {
957 return key;
958 }
960 public String getMessage(Locale locale) {
961 return JavapTask.this.getMessage(locale, key, args);
962 }
964 @Override
965 public String toString() {
966 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
967 }
969 };
971 }
973 public String getMessage(String key, Object... args) {
974 return getMessage(task_locale, key, args);
975 }
977 public String getMessage(Locale locale, String key, Object... args) {
978 if (bundles == null) {
979 // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
980 // and for efficiency, keep a hard reference to the bundle for the task
981 // locale
982 bundles = new HashMap<Locale, ResourceBundle>();
983 }
985 if (locale == null)
986 locale = Locale.getDefault();
988 ResourceBundle b = bundles.get(locale);
989 if (b == null) {
990 try {
991 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
992 bundles.put(locale, b);
993 } catch (MissingResourceException e) {
994 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
995 }
996 }
998 try {
999 return MessageFormat.format(b.getString(key), args);
1000 } catch (MissingResourceException e) {
1001 throw new InternalError(e, key);
1002 }
1003 }
1005 protected Context context;
1006 JavaFileManager fileManager;
1007 PrintWriter log;
1008 DiagnosticListener<? super JavaFileObject> diagnosticListener;
1009 List<String> classes;
1010 Options options;
1011 //ResourceBundle bundle;
1012 Locale task_locale;
1013 Map<Locale, ResourceBundle> bundles;
1014 protected Attribute.Factory attributeFactory;
1016 private static final String progname = "javap";
1018 private static class SizeInputStream extends FilterInputStream {
1019 SizeInputStream(InputStream in) {
1020 super(in);
1021 }
1023 int size() {
1024 return size;
1025 }
1027 @Override
1028 public int read(byte[] buf, int offset, int length) throws IOException {
1029 int n = super.read(buf, offset, length);
1030 if (n > 0)
1031 size += n;
1032 return n;
1033 }
1035 @Override
1036 public int read() throws IOException {
1037 int b = super.read();
1038 size += 1;
1039 return b;
1040 }
1042 private int size;
1043 }
1044 }