src/share/classes/com/sun/tools/javap/JavapTask.java

Tue, 11 Aug 2009 01:13:14 +0100

author
mcimadamore
date
Tue, 11 Aug 2009 01:13:14 +0100
changeset 359
8227961c64d3
parent 350
526de25e0b28
child 402
261c54b2312e
permissions
-rw-r--r--

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);
  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);
  1023         int size() {
  1024             return size;
  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;
  1035         @Override
  1036         public int read() throws IOException {
  1037             int b = super.read();
  1038             size += 1;
  1039             return b;
  1042         private int size;

mercurial