src/share/classes/com/sun/tools/javac/main/Main.java

Tue, 07 Sep 2010 17:32:27 +0100

author
mcimadamore
date
Tue, 07 Sep 2010 17:32:27 +0100
changeset 674
584365f256a7
parent 663
eb7c263aab73
child 700
7b413ac1a720
permissions
-rw-r--r--

6979327: method handle invocation should use casts instead of type parameters to specify return type
Summary: infer return type for polymorphic signature calls according to updated JSR 292 draft
Reviewed-by: jjg
Contributed-by: john.r.rose@oracle.com

     1 /*
     2  * Copyright (c) 1999, 2009, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.main;
    28 import java.io.File;
    29 import java.io.IOException;
    30 import java.io.PrintWriter;
    31 import java.net.URL;
    32 import java.security.DigestInputStream;
    33 import java.security.MessageDigest;
    34 import java.util.MissingResourceException;
    36 import com.sun.tools.javac.code.Source;
    37 import com.sun.tools.javac.file.CacheFSInfo;
    38 import com.sun.tools.javac.file.JavacFileManager;
    39 import com.sun.tools.javac.jvm.Target;
    40 import com.sun.tools.javac.main.JavacOption.Option;
    41 import com.sun.tools.javac.main.RecognizedOptions.OptionHelper;
    42 import com.sun.tools.javac.util.*;
    43 import com.sun.tools.javac.processing.AnnotationProcessingError;
    44 import javax.tools.JavaFileManager;
    45 import javax.tools.JavaFileObject;
    46 import javax.annotation.processing.Processor;
    48 /** This class provides a commandline interface to the GJC compiler.
    49  *
    50  *  <p><b>This is NOT part of any supported API.
    51  *  If you write code that depends on this, you do so at your own risk.
    52  *  This code and its internal interfaces are subject to change or
    53  *  deletion without notice.</b>
    54  */
    55 public class Main {
    57     /** The name of the compiler, for use in diagnostics.
    58      */
    59     String ownName;
    61     /** The writer to use for diagnostic output.
    62      */
    63     PrintWriter out;
    65     /**
    66      * If true, any command line arg errors will cause an exception.
    67      */
    68     boolean fatalErrors;
    70     /** Result codes.
    71      */
    72     static final int
    73         EXIT_OK = 0,        // Compilation completed with no errors.
    74         EXIT_ERROR = 1,     // Completed but reported errors.
    75         EXIT_CMDERR = 2,    // Bad command-line arguments
    76         EXIT_SYSERR = 3,    // System error or resource exhaustion.
    77         EXIT_ABNORMAL = 4;  // Compiler terminated abnormally
    79     private Option[] recognizedOptions = RecognizedOptions.getJavaCompilerOptions(new OptionHelper() {
    81         public void setOut(PrintWriter out) {
    82             Main.this.out = out;
    83         }
    85         public void error(String key, Object... args) {
    86             Main.this.error(key, args);
    87         }
    89         public void printVersion() {
    90             Log.printLines(out, getLocalizedString("version", ownName,  JavaCompiler.version()));
    91         }
    93         public void printFullVersion() {
    94             Log.printLines(out, getLocalizedString("fullVersion", ownName,  JavaCompiler.fullVersion()));
    95         }
    97         public void printHelp() {
    98             help();
    99         }
   101         public void printXhelp() {
   102             xhelp();
   103         }
   105         public void addFile(File f) {
   106             if (!filenames.contains(f))
   107                 filenames.append(f);
   108         }
   110         public void addClassName(String s) {
   111             classnames.append(s);
   112         }
   114     });
   116     /**
   117      * Construct a compiler instance.
   118      */
   119     public Main(String name) {
   120         this(name, new PrintWriter(System.err, true));
   121     }
   123     /**
   124      * Construct a compiler instance.
   125      */
   126     public Main(String name, PrintWriter out) {
   127         this.ownName = name;
   128         this.out = out;
   129     }
   130     /** A table of all options that's passed to the JavaCompiler constructor.  */
   131     private Options options = null;
   133     /** The list of source files to process
   134      */
   135     public ListBuffer<File> filenames = null; // XXX sb protected
   137     /** List of class files names passed on the command line
   138      */
   139     public ListBuffer<String> classnames = null; // XXX sb protected
   141     /** Print a string that explains usage.
   142      */
   143     void help() {
   144         Log.printLines(out, getLocalizedString("msg.usage.header", ownName));
   145         for (int i=0; i<recognizedOptions.length; i++) {
   146             recognizedOptions[i].help(out);
   147         }
   148         out.println();
   149     }
   151     /** Print a string that explains usage for X options.
   152      */
   153     void xhelp() {
   154         for (int i=0; i<recognizedOptions.length; i++) {
   155             recognizedOptions[i].xhelp(out);
   156         }
   157         out.println();
   158         Log.printLines(out, getLocalizedString("msg.usage.nonstandard.footer"));
   159     }
   161     /** Report a usage error.
   162      */
   163     void error(String key, Object... args) {
   164         if (fatalErrors) {
   165             String msg = getLocalizedString(key, args);
   166             throw new PropagatedException(new IllegalStateException(msg));
   167         }
   168         warning(key, args);
   169         Log.printLines(out, getLocalizedString("msg.usage", ownName));
   170     }
   172     /** Report a warning.
   173      */
   174     void warning(String key, Object... args) {
   175         Log.printLines(out, ownName + ": "
   176                        + getLocalizedString(key, args));
   177     }
   179     public Option getOption(String flag) {
   180         for (Option option : recognizedOptions) {
   181             if (option.matches(flag))
   182                 return option;
   183         }
   184         return null;
   185     }
   187     public void setOptions(Options options) {
   188         if (options == null)
   189             throw new NullPointerException();
   190         this.options = options;
   191     }
   193     public void setFatalErrors(boolean fatalErrors) {
   194         this.fatalErrors = fatalErrors;
   195     }
   197     /** Process command line arguments: store all command line options
   198      *  in `options' table and return all source filenames.
   199      *  @param flags    The array of command line arguments.
   200      */
   201     public List<File> processArgs(String[] flags) { // XXX sb protected
   202         int ac = 0;
   203         while (ac < flags.length) {
   204             String flag = flags[ac];
   205             ac++;
   207             Option option = null;
   209             if (flag.length() > 0) {
   210                 // quick hack to speed up file processing:
   211                 // if the option does not begin with '-', there is no need to check
   212                 // most of the compiler options.
   213                 int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length-1;
   214                 for (int j=firstOptionToCheck; j<recognizedOptions.length; j++) {
   215                     if (recognizedOptions[j].matches(flag)) {
   216                         option = recognizedOptions[j];
   217                         break;
   218                     }
   219                 }
   220             }
   222             if (option == null) {
   223                 error("err.invalid.flag", flag);
   224                 return null;
   225             }
   227             if (option.hasArg()) {
   228                 if (ac == flags.length) {
   229                     error("err.req.arg", flag);
   230                     return null;
   231                 }
   232                 String operand = flags[ac];
   233                 ac++;
   234                 if (option.process(options, flag, operand))
   235                     return null;
   236             } else {
   237                 if (option.process(options, flag))
   238                     return null;
   239             }
   240         }
   242         if (!checkDirectory("-d"))
   243             return null;
   244         if (!checkDirectory("-s"))
   245             return null;
   247         String sourceString = options.get("-source");
   248         Source source = (sourceString != null)
   249             ? Source.lookup(sourceString)
   250             : Source.DEFAULT;
   251         String targetString = options.get("-target");
   252         Target target = (targetString != null)
   253             ? Target.lookup(targetString)
   254             : Target.DEFAULT;
   255         // We don't check source/target consistency for CLDC, as J2ME
   256         // profiles are not aligned with J2SE targets; moreover, a
   257         // single CLDC target may have many profiles.  In addition,
   258         // this is needed for the continued functioning of the JSR14
   259         // prototype.
   260         if (Character.isDigit(target.name.charAt(0))) {
   261             if (target.compareTo(source.requiredTarget()) < 0) {
   262                 if (targetString != null) {
   263                     if (sourceString == null) {
   264                         warning("warn.target.default.source.conflict",
   265                                 targetString,
   266                                 source.requiredTarget().name);
   267                     } else {
   268                         warning("warn.source.target.conflict",
   269                                 sourceString,
   270                                 source.requiredTarget().name);
   271                     }
   272                     return null;
   273                 } else {
   274                     target = source.requiredTarget();
   275                     options.put("-target", target.name);
   276                 }
   277             } else {
   278                 if (targetString == null && !source.allowGenerics()) {
   279                     target = Target.JDK1_4;
   280                     options.put("-target", target.name);
   281                 }
   282             }
   283         }
   285         // phase this out with JSR 292 PFD
   286         if ("no".equals(options.get("allowTransitionalJSR292"))) {
   287             options.put("allowTransitionalJSR292", null);
   288         } else if (target.hasInvokedynamic() && options.get("allowTransitionalJSR292") == null) {
   289             options.put("allowTransitionalJSR292", "allowTransitionalJSR292");
   290         }
   292         // handle this here so it works even if no other options given
   293         String showClass = options.get("showClass");
   294         if (showClass != null) {
   295             if (showClass.equals("showClass")) // no value given for option
   296                 showClass = "com.sun.tools.javac.Main";
   297             showClass(showClass);
   298         }
   300         return filenames.toList();
   301     }
   302     // where
   303         private boolean checkDirectory(String optName) {
   304             String value = options.get(optName);
   305             if (value == null)
   306                 return true;
   307             File file = new File(value);
   308             if (!file.exists()) {
   309                 error("err.dir.not.found", value);
   310                 return false;
   311             }
   312             if (!file.isDirectory()) {
   313                 error("err.file.not.directory", value);
   314                 return false;
   315             }
   316             return true;
   317         }
   319     /** Programmatic interface for main function.
   320      * @param args    The command line parameters.
   321      */
   322     public int compile(String[] args) {
   323         Context context = new Context();
   324         JavacFileManager.preRegister(context); // can't create it until Log has been set up
   325         int result = compile(args, context);
   326         if (fileManager instanceof JavacFileManager) {
   327             // A fresh context was created above, so jfm must be a JavacFileManager
   328             ((JavacFileManager)fileManager).close();
   329         }
   330         return result;
   331     }
   333     public int compile(String[] args, Context context) {
   334         return compile(args, context, List.<JavaFileObject>nil(), null);
   335     }
   337     /** Programmatic interface for main function.
   338      * @param args    The command line parameters.
   339      */
   340     public int compile(String[] args,
   341                        Context context,
   342                        List<JavaFileObject> fileObjects,
   343                        Iterable<? extends Processor> processors)
   344     {
   345         if (options == null)
   346             options = Options.instance(context); // creates a new one
   348         filenames = new ListBuffer<File>();
   349         classnames = new ListBuffer<String>();
   350         JavaCompiler comp = null;
   351         /*
   352          * TODO: Logic below about what is an acceptable command line
   353          * should be updated to take annotation processing semantics
   354          * into account.
   355          */
   356         try {
   357             if (args.length == 0 && fileObjects.isEmpty()) {
   358                 help();
   359                 return EXIT_CMDERR;
   360             }
   362             List<File> files;
   363             try {
   364                 files = processArgs(CommandLine.parse(args));
   365                 if (files == null) {
   366                     // null signals an error in options, abort
   367                     return EXIT_CMDERR;
   368                 } else if (files.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) {
   369                     // it is allowed to compile nothing if just asking for help or version info
   370                     if (options.get("-help") != null
   371                         || options.get("-X") != null
   372                         || options.get("-version") != null
   373                         || options.get("-fullversion") != null)
   374                         return EXIT_OK;
   375                     error("err.no.source.files");
   376                     return EXIT_CMDERR;
   377                 }
   378             } catch (java.io.FileNotFoundException e) {
   379                 Log.printLines(out, ownName + ": " +
   380                                getLocalizedString("err.file.not.found",
   381                                                   e.getMessage()));
   382                 return EXIT_SYSERR;
   383             }
   385             boolean forceStdOut = options.get("stdout") != null;
   386             if (forceStdOut) {
   387                 out.flush();
   388                 out = new PrintWriter(System.out, true);
   389             }
   391             context.put(Log.outKey, out);
   393             // allow System property in following line as a Mustang legacy
   394             boolean batchMode = (options.get("nonBatchMode") == null
   395                         && System.getProperty("nonBatchMode") == null);
   396             if (batchMode)
   397                 CacheFSInfo.preRegister(context);
   399             fileManager = context.get(JavaFileManager.class);
   401             comp = JavaCompiler.instance(context);
   402             if (comp == null) return EXIT_SYSERR;
   404             Log log = Log.instance(context);
   406             if (!files.isEmpty()) {
   407                 // add filenames to fileObjects
   408                 comp = JavaCompiler.instance(context);
   409                 List<JavaFileObject> otherFiles = List.nil();
   410                 JavacFileManager dfm = (JavacFileManager)fileManager;
   411                 for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files))
   412                     otherFiles = otherFiles.prepend(fo);
   413                 for (JavaFileObject fo : otherFiles)
   414                     fileObjects = fileObjects.prepend(fo);
   415             }
   416             comp.compile(fileObjects,
   417                          classnames.toList(),
   418                          processors);
   420             if (log.expectDiagKeys != null) {
   421                 if (log.expectDiagKeys.size() == 0) {
   422                     Log.printLines(log.noticeWriter, "all expected diagnostics found");
   423                     return EXIT_OK;
   424                 } else {
   425                     Log.printLines(log.noticeWriter, "expected diagnostic keys not found: " + log.expectDiagKeys);
   426                     return EXIT_ERROR;
   427                 }
   428             }
   430             if (comp.errorCount() != 0)
   431                 return EXIT_ERROR;
   432         } catch (IOException ex) {
   433             ioMessage(ex);
   434             return EXIT_SYSERR;
   435         } catch (OutOfMemoryError ex) {
   436             resourceMessage(ex);
   437             return EXIT_SYSERR;
   438         } catch (StackOverflowError ex) {
   439             resourceMessage(ex);
   440             return EXIT_SYSERR;
   441         } catch (FatalError ex) {
   442             feMessage(ex);
   443             return EXIT_SYSERR;
   444         } catch(AnnotationProcessingError ex) {
   445             apMessage(ex);
   446             return EXIT_SYSERR;
   447         } catch (ClientCodeException ex) {
   448             // as specified by javax.tools.JavaCompiler#getTask
   449             // and javax.tools.JavaCompiler.CompilationTask#call
   450             throw new RuntimeException(ex.getCause());
   451         } catch (PropagatedException ex) {
   452             throw ex.getCause();
   453         } catch (Throwable ex) {
   454             // Nasty.  If we've already reported an error, compensate
   455             // for buggy compiler error recovery by swallowing thrown
   456             // exceptions.
   457             if (comp == null || comp.errorCount() == 0 ||
   458                 options == null || options.get("dev") != null)
   459                 bugMessage(ex);
   460             return EXIT_ABNORMAL;
   461         } finally {
   462             if (comp != null) comp.close();
   463             filenames = null;
   464             options = null;
   465         }
   466         return EXIT_OK;
   467     }
   469     /** Print a message reporting an internal error.
   470      */
   471     void bugMessage(Throwable ex) {
   472         Log.printLines(out, getLocalizedString("msg.bug",
   473                                                JavaCompiler.version()));
   474         ex.printStackTrace(out);
   475     }
   477     /** Print a message reporting a fatal error.
   478      */
   479     void feMessage(Throwable ex) {
   480         Log.printLines(out, ex.getMessage());
   481         if (ex.getCause() != null && options.get("dev") != null) {
   482             ex.getCause().printStackTrace(out);
   483         }
   484     }
   486     /** Print a message reporting an input/output error.
   487      */
   488     void ioMessage(Throwable ex) {
   489         Log.printLines(out, getLocalizedString("msg.io"));
   490         ex.printStackTrace(out);
   491     }
   493     /** Print a message reporting an out-of-resources error.
   494      */
   495     void resourceMessage(Throwable ex) {
   496         Log.printLines(out, getLocalizedString("msg.resource"));
   497 //      System.out.println("(name buffer len = " + Name.names.length + " " + Name.nc);//DEBUG
   498         ex.printStackTrace(out);
   499     }
   501     /** Print a message reporting an uncaught exception from an
   502      * annotation processor.
   503      */
   504     void apMessage(AnnotationProcessingError ex) {
   505         Log.printLines(out,
   506                        getLocalizedString("msg.proc.annotation.uncaught.exception"));
   507         ex.getCause().printStackTrace();
   508     }
   510     /** Display the location and checksum of a class. */
   511     void showClass(String className) {
   512         out.println("javac: show class: " + className);
   513         URL url = getClass().getResource('/' + className.replace('.', '/') + ".class");
   514         if (url == null)
   515             out.println("  class not found");
   516         else {
   517             out.println("  " + url);
   518             try {
   519                 final String algorithm = "MD5";
   520                 byte[] digest;
   521                 MessageDigest md = MessageDigest.getInstance(algorithm);
   522                 DigestInputStream in = new DigestInputStream(url.openStream(), md);
   523                 try {
   524                     byte[] buf = new byte[8192];
   525                     int n;
   526                     do { n = in.read(buf); } while (n > 0);
   527                     digest = md.digest();
   528                 } finally {
   529                     in.close();
   530                 }
   531                 StringBuilder sb = new StringBuilder();
   532                 for (byte b: digest)
   533                     sb.append(String.format("%02x", b));
   534                 out.println("  " + algorithm + " checksum: " + sb);
   535             } catch (Exception e) {
   536                 out.println("  cannot compute digest: " + e);
   537             }
   538         }
   539     }
   541     private JavaFileManager fileManager;
   543     /* ************************************************************************
   544      * Internationalization
   545      *************************************************************************/
   547     /** Find a localized string in the resource bundle.
   548      *  @param key     The key for the localized string.
   549      */
   550     public static String getLocalizedString(String key, Object... args) { // FIXME sb private
   551         try {
   552             if (messages == null)
   553                 messages = new JavacMessages(javacBundleName);
   554             return messages.getLocalizedString("javac." + key, args);
   555         }
   556         catch (MissingResourceException e) {
   557             throw new Error("Fatal Error: Resource for javac is missing", e);
   558         }
   559     }
   561     public static void useRawMessages(boolean enable) {
   562         if (enable) {
   563             messages = new JavacMessages(javacBundleName) {
   564                     public String getLocalizedString(String key, Object... args) {
   565                         return key;
   566                     }
   567                 };
   568         } else {
   569             messages = new JavacMessages(javacBundleName);
   570         }
   571     }
   573     private static final String javacBundleName =
   574         "com.sun.tools.javac.resources.javac";
   576     private static JavacMessages messages;
   577 }

mercurial