src/jdk.compiler/share/classes/com/sun/tools/javah/JavahTask.java
branchhttp-client-branch
changeset 55982 b6ff245c0db6
parent 55981 907bddce488c
parent 48332 651a95f30dfb
child 55983 e4a1f0c9d4c6
equal deleted inserted replaced
55981:907bddce488c 55982:b6ff245c0db6
     1 /*
       
     2  * Copyright (c) 2002, 2016, 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  */
       
    25 
       
    26 package com.sun.tools.javah;
       
    27 
       
    28 import java.io.File;
       
    29 import java.io.FileNotFoundException;
       
    30 import java.io.IOException;
       
    31 import java.io.OutputStream;
       
    32 import java.io.PrintWriter;
       
    33 import java.io.Writer;
       
    34 import java.nio.file.NoSuchFileException;
       
    35 import java.text.MessageFormat;
       
    36 import java.util.ArrayList;
       
    37 import java.util.Arrays;
       
    38 import java.util.Collections;
       
    39 import java.util.HashMap;
       
    40 import java.util.Iterator;
       
    41 import java.util.LinkedHashSet;
       
    42 import java.util.List;
       
    43 import java.util.Locale;
       
    44 import java.util.Map;
       
    45 import java.util.MissingResourceException;
       
    46 import java.util.Objects;
       
    47 import java.util.ResourceBundle;
       
    48 import java.util.Set;
       
    49 
       
    50 import javax.annotation.processing.AbstractProcessor;
       
    51 import javax.annotation.processing.Messager;
       
    52 import javax.annotation.processing.ProcessingEnvironment;
       
    53 import javax.annotation.processing.RoundEnvironment;
       
    54 import javax.annotation.processing.SupportedAnnotationTypes;
       
    55 import javax.lang.model.SourceVersion;
       
    56 import javax.lang.model.element.ExecutableElement;
       
    57 import javax.lang.model.element.TypeElement;
       
    58 import javax.lang.model.element.VariableElement;
       
    59 import javax.lang.model.type.ArrayType;
       
    60 import javax.lang.model.type.DeclaredType;
       
    61 import javax.lang.model.type.TypeMirror;
       
    62 import javax.lang.model.type.TypeVisitor;
       
    63 import javax.lang.model.util.ElementFilter;
       
    64 import javax.lang.model.util.SimpleTypeVisitor9;
       
    65 import javax.lang.model.util.Types;
       
    66 import javax.tools.Diagnostic;
       
    67 import javax.tools.DiagnosticListener;
       
    68 import javax.tools.JavaCompiler;
       
    69 import javax.tools.JavaCompiler.CompilationTask;
       
    70 import javax.tools.JavaFileManager;
       
    71 import javax.tools.JavaFileObject;
       
    72 import javax.tools.StandardJavaFileManager;
       
    73 import javax.tools.StandardLocation;
       
    74 import javax.tools.ToolProvider;
       
    75 
       
    76 import com.sun.tools.javac.code.Symbol.CompletionFailure;
       
    77 import com.sun.tools.javac.main.CommandLine;
       
    78 import com.sun.tools.javac.util.DefinedBy;
       
    79 import com.sun.tools.javac.util.DefinedBy.Api;
       
    80 
       
    81 import static javax.tools.Diagnostic.Kind.*;
       
    82 
       
    83 
       
    84 /**
       
    85  * Javah generates support files for native methods.
       
    86  * Parse commandline options and invokes javadoc to execute those commands.
       
    87  *
       
    88  * <p><b>This is NOT part of any supported API.
       
    89  * If you write code that depends on this, you do so at your own
       
    90  * risk.  This code and its internal interfaces are subject to change
       
    91  * or deletion without notice.</b></p>
       
    92  *
       
    93  * @author Sucheta Dambalkar
       
    94  * @author Jonathan Gibbons
       
    95  */
       
    96 public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
       
    97     public class BadArgs extends Exception {
       
    98         private static final long serialVersionUID = 1479361270874789045L;
       
    99         BadArgs(String key, Object... args) {
       
   100             super(JavahTask.this.getMessage(key, args));
       
   101             this.key = key;
       
   102             this.args = args;
       
   103         }
       
   104 
       
   105         BadArgs showUsage(boolean b) {
       
   106             showUsage = b;
       
   107             return this;
       
   108         }
       
   109 
       
   110         final String key;
       
   111         final Object[] args;
       
   112         boolean showUsage;
       
   113     }
       
   114 
       
   115     static abstract class Option {
       
   116         Option(boolean hasArg, String... aliases) {
       
   117             this.hasArg = hasArg;
       
   118             this.aliases = aliases;
       
   119         }
       
   120 
       
   121         boolean isHidden() {
       
   122             return false;
       
   123         }
       
   124 
       
   125         boolean matches(String opt) {
       
   126             for (String a: aliases) {
       
   127                 if (a.equals(opt))
       
   128                     return true;
       
   129             }
       
   130             return false;
       
   131         }
       
   132 
       
   133         boolean ignoreRest() {
       
   134             return false;
       
   135         }
       
   136 
       
   137         abstract void process(JavahTask task, String opt, String arg) throws BadArgs;
       
   138 
       
   139         final boolean hasArg;
       
   140         final String[] aliases;
       
   141     }
       
   142 
       
   143     static abstract class HiddenOption extends Option {
       
   144         HiddenOption(boolean hasArg, String... aliases) {
       
   145             super(hasArg, aliases);
       
   146         }
       
   147 
       
   148         @Override
       
   149         boolean isHidden() {
       
   150             return true;
       
   151         }
       
   152     }
       
   153 
       
   154     static final Option[] recognizedOptions = {
       
   155         new Option(true, "-o") {
       
   156             void process(JavahTask task, String opt, String arg) {
       
   157                 task.ofile = new File(arg);
       
   158             }
       
   159         },
       
   160 
       
   161         new Option(true, "-d") {
       
   162             void process(JavahTask task, String opt, String arg) {
       
   163                 task.odir = new File(arg);
       
   164             }
       
   165         },
       
   166 
       
   167         new HiddenOption(true, "-td") {
       
   168             void process(JavahTask task, String opt, String arg) {
       
   169                  // ignored; for backwards compatibility
       
   170             }
       
   171         },
       
   172 
       
   173         new Option(false, "-v", "-verbose") {
       
   174             void process(JavahTask task, String opt, String arg) {
       
   175                 task.verbose = true;
       
   176             }
       
   177         },
       
   178 
       
   179         new Option(false, "-h", "-help", "--help", "-?") {
       
   180             void process(JavahTask task, String opt, String arg) {
       
   181                 task.help = true;
       
   182             }
       
   183         },
       
   184 
       
   185         new HiddenOption(false, "-trace") {
       
   186             void process(JavahTask task, String opt, String arg) {
       
   187                 task.trace = true;
       
   188             }
       
   189         },
       
   190 
       
   191         new Option(false, "-version") {
       
   192             void process(JavahTask task, String opt, String arg) {
       
   193                 task.version = true;
       
   194             }
       
   195         },
       
   196 
       
   197         new HiddenOption(false, "-fullversion") {
       
   198             void process(JavahTask task, String opt, String arg) {
       
   199                 task.fullVersion = true;
       
   200             }
       
   201         },
       
   202 
       
   203         new Option(false, "-jni") {
       
   204             void process(JavahTask task, String opt, String arg) {
       
   205                 task.jni = true;
       
   206             }
       
   207         },
       
   208 
       
   209         new Option(false, "-force") {
       
   210             void process(JavahTask task, String opt, String arg) {
       
   211                 task.force = true;
       
   212             }
       
   213         },
       
   214 
       
   215         new HiddenOption(false, "-Xnew") {
       
   216             void process(JavahTask task, String opt, String arg) {
       
   217                 // we're already using the new javah
       
   218             }
       
   219         },
       
   220 
       
   221         new HiddenOption(false, "-llni", "-Xllni") {
       
   222             void process(JavahTask task, String opt, String arg) {
       
   223                 task.llni = true;
       
   224             }
       
   225         },
       
   226 
       
   227         new HiddenOption(false, "-llnidouble") {
       
   228             void process(JavahTask task, String opt, String arg) {
       
   229                 task.llni = true;
       
   230                 task.doubleAlign = true;
       
   231             }
       
   232         },
       
   233 
       
   234         new HiddenOption(false) {
       
   235             boolean matches(String opt) {
       
   236                 return opt.startsWith("-XD");
       
   237             }
       
   238             void process(JavahTask task, String opt, String arg) {
       
   239                 task.javac_extras.add(opt);
       
   240             }
       
   241         },
       
   242     };
       
   243 
       
   244     JavahTask() {
       
   245     }
       
   246 
       
   247     JavahTask(Writer out,
       
   248             JavaFileManager fileManager,
       
   249             DiagnosticListener<? super JavaFileObject> diagnosticListener,
       
   250             Iterable<String> options,
       
   251             Iterable<String> classes) {
       
   252         this();
       
   253         this.log = getPrintWriterForWriter(out);
       
   254         this.fileManager = fileManager;
       
   255         this.diagnosticListener = diagnosticListener;
       
   256 
       
   257         try {
       
   258             handleOptions(options, false);
       
   259         } catch (BadArgs e) {
       
   260             throw new IllegalArgumentException(e.getMessage());
       
   261         }
       
   262 
       
   263         this.classes = new ArrayList<>();
       
   264         if (classes != null) {
       
   265             for (String classname: classes) {
       
   266                 Objects.requireNonNull(classname);
       
   267                 this.classes.add(classname);
       
   268             }
       
   269         }
       
   270     }
       
   271 
       
   272     public void setLocale(Locale locale) {
       
   273         if (locale == null)
       
   274             locale = Locale.getDefault();
       
   275         task_locale = locale;
       
   276     }
       
   277 
       
   278     public void setLog(PrintWriter log) {
       
   279         this.log = log;
       
   280     }
       
   281 
       
   282     public void setLog(OutputStream s) {
       
   283         setLog(getPrintWriterForStream(s));
       
   284     }
       
   285 
       
   286     static PrintWriter getPrintWriterForStream(OutputStream s) {
       
   287         return new PrintWriter(s, true);
       
   288     }
       
   289 
       
   290     static PrintWriter getPrintWriterForWriter(Writer w) {
       
   291         if (w == null)
       
   292             return getPrintWriterForStream(null);
       
   293         else if (w instanceof PrintWriter)
       
   294             return (PrintWriter) w;
       
   295         else
       
   296             return new PrintWriter(w, true);
       
   297     }
       
   298 
       
   299     public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
       
   300         diagnosticListener = dl;
       
   301     }
       
   302 
       
   303     public void setDiagnosticListener(OutputStream s) {
       
   304         setDiagnosticListener(getDiagnosticListenerForStream(s));
       
   305     }
       
   306 
       
   307     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
       
   308         return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
       
   309     }
       
   310 
       
   311     private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
       
   312         final PrintWriter pw = getPrintWriterForWriter(w);
       
   313         return diagnostic -> {
       
   314             if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
       
   315                 pw.print(getMessage("err.prefix"));
       
   316                 pw.print(" ");
       
   317             }
       
   318             pw.println(diagnostic.getMessage(null));
       
   319         };
       
   320     }
       
   321 
       
   322     int run(String[] args) {
       
   323         try {
       
   324             handleOptions(args);
       
   325             boolean ok = run();
       
   326             return ok ? 0 : 1;
       
   327         } catch (BadArgs e) {
       
   328             diagnosticListener.report(createDiagnostic(e.key, e.args));
       
   329             return 1;
       
   330         } catch (InternalError e) {
       
   331             diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));
       
   332             return 1;
       
   333         } catch (Util.Exit e) {
       
   334             return e.exitValue;
       
   335         } finally {
       
   336             log.flush();
       
   337         }
       
   338     }
       
   339 
       
   340     public void handleOptions(String[] args) throws BadArgs {
       
   341         handleOptions(Arrays.asList(args), true);
       
   342     }
       
   343 
       
   344     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
       
   345         if (log == null) {
       
   346             log = getPrintWriterForStream(System.out);
       
   347             if (diagnosticListener == null)
       
   348               diagnosticListener = getDiagnosticListenerForStream(System.err);
       
   349         } else {
       
   350             if (diagnosticListener == null)
       
   351               diagnosticListener = getDiagnosticListenerForWriter(log);
       
   352         }
       
   353 
       
   354         if (fileManager == null)
       
   355             fileManager = getDefaultFileManager(diagnosticListener, log);
       
   356 
       
   357         Iterator<String> iter = expandAtArgs(args).iterator();
       
   358         noArgs = !iter.hasNext();
       
   359 
       
   360         while (iter.hasNext()) {
       
   361             String arg = iter.next();
       
   362             if (arg.startsWith("-"))
       
   363                 handleOption(arg, iter);
       
   364             else if (allowClasses) {
       
   365                 if (classes == null)
       
   366                     classes = new ArrayList<>();
       
   367                 classes.add(arg);
       
   368                 while (iter.hasNext())
       
   369                     classes.add(iter.next());
       
   370             } else
       
   371                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
       
   372         }
       
   373 
       
   374         if ((classes == null || classes.size() == 0) &&
       
   375                 !(noArgs || help || version || fullVersion)) {
       
   376             throw new BadArgs("err.no.classes.specified");
       
   377         }
       
   378 
       
   379         if (jni && llni)
       
   380             throw new BadArgs("jni.llni.mixed");
       
   381 
       
   382         if (odir != null && ofile != null)
       
   383             throw new BadArgs("dir.file.mixed");
       
   384     }
       
   385 
       
   386     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
       
   387         for (Option o: recognizedOptions) {
       
   388             if (o.matches(name)) {
       
   389                 if (o.hasArg) {
       
   390                     if (rest.hasNext())
       
   391                         o.process(this, name, rest.next());
       
   392                     else
       
   393                         throw new BadArgs("err.missing.arg", name).showUsage(true);
       
   394                 } else
       
   395                     o.process(this, name, null);
       
   396 
       
   397                 if (o.ignoreRest()) {
       
   398                     while (rest.hasNext())
       
   399                         rest.next();
       
   400                 }
       
   401                 return;
       
   402             }
       
   403         }
       
   404 
       
   405         if (fileManager.handleOption(name, rest))
       
   406             return;
       
   407 
       
   408         throw new BadArgs("err.unknown.option", name).showUsage(true);
       
   409     }
       
   410 
       
   411     private Iterable<String> expandAtArgs(Iterable<String> args) throws BadArgs {
       
   412         try {
       
   413             List<String> l = new ArrayList<>();
       
   414             for (String arg: args) l.add(arg);
       
   415             return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()])));
       
   416         } catch (FileNotFoundException | NoSuchFileException e) {
       
   417             throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage());
       
   418         } catch (IOException e) {
       
   419             throw new BadArgs("at.args.io.exception", e.getLocalizedMessage());
       
   420         }
       
   421     }
       
   422 
       
   423     public Boolean call() {
       
   424         return run();
       
   425     }
       
   426 
       
   427     public boolean run() throws Util.Exit {
       
   428 
       
   429         if (!javac_extras.contains("-XDsuppress-tool-removal-message")) {
       
   430             log.println(getMessage("javah.misc.Deprecation"));
       
   431         }
       
   432 
       
   433         Util util = new Util(log, diagnosticListener);
       
   434 
       
   435         if (noArgs || help) {
       
   436             showHelp();
       
   437             return help; // treat noArgs as an error for purposes of exit code
       
   438         }
       
   439 
       
   440         if (version || fullVersion) {
       
   441             showVersion(fullVersion);
       
   442             return true;
       
   443         }
       
   444 
       
   445         util.verbose = verbose;
       
   446 
       
   447         Gen g;
       
   448 
       
   449         if (llni)
       
   450             g = new LLNI(doubleAlign, util);
       
   451         else {
       
   452             g = new JNI(util);
       
   453         }
       
   454 
       
   455         if (ofile != null) {
       
   456             if (!(fileManager instanceof StandardJavaFileManager)) {
       
   457                 diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o"));
       
   458                 return false;
       
   459             }
       
   460             Iterable<? extends JavaFileObject> iter =
       
   461                     ((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile));
       
   462             JavaFileObject fo = iter.iterator().next();
       
   463             g.setOutFile(fo);
       
   464         } else {
       
   465             if (odir != null) {
       
   466                 if (!(fileManager instanceof StandardJavaFileManager)) {
       
   467                     diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d"));
       
   468                     return false;
       
   469                 }
       
   470 
       
   471                 if (!odir.exists())
       
   472                     if (!odir.mkdirs())
       
   473                         util.error("cant.create.dir", odir.toString());
       
   474                 try {
       
   475                     ((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir));
       
   476                 } catch (IOException e) {
       
   477                     Object msg = e.getLocalizedMessage();
       
   478                     if (msg == null) {
       
   479                         msg = e;
       
   480                     }
       
   481                     diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg));
       
   482                     return false;
       
   483                 }
       
   484             }
       
   485             g.setFileManager(fileManager);
       
   486         }
       
   487 
       
   488         /*
       
   489          * Force set to false will turn off smarts about checking file
       
   490          * content before writing.
       
   491          */
       
   492         g.setForce(force);
       
   493 
       
   494         if (fileManager instanceof JavahFileManager)
       
   495             ((JavahFileManager) fileManager).setSymbolFileEnabled(false);
       
   496 
       
   497         JavaCompiler c = ToolProvider.getSystemJavaCompiler();
       
   498         List<String> opts = new ArrayList<>();
       
   499         opts.add("-proc:only");
       
   500         opts.addAll(javac_extras);
       
   501 
       
   502         CompilationTask t;
       
   503         try {
       
   504             t = c.getTask(log, fileManager, diagnosticListener, opts, classes, null);
       
   505         } catch (IllegalArgumentException e) {
       
   506             util.error("bad.arg", e.getMessage());
       
   507             return false;
       
   508         }
       
   509 
       
   510         JavahProcessor p = new JavahProcessor(g);
       
   511         t.setProcessors(Collections.singleton(p));
       
   512 
       
   513         boolean ok = t.call();
       
   514         if (p.exit != null)
       
   515             throw new Util.Exit(p.exit);
       
   516         return ok;
       
   517 
       
   518     }
       
   519 
       
   520     static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
       
   521         return JavahFileManager.create(dl, log);
       
   522     }
       
   523 
       
   524     private void showHelp() {
       
   525         log.println(getMessage("main.usage", progname));
       
   526 
       
   527         for (Option o: recognizedOptions) {
       
   528             if (o.isHidden())
       
   529                 continue;
       
   530             String name = o.aliases[0].substring(1); // there must always be at least one name
       
   531             log.println(getMessage("main.opt." + name));
       
   532         }
       
   533 
       
   534         String[] fmOptions = {
       
   535             "--module-path", "--system",
       
   536             "--class-path", "-classpath", "-cp",
       
   537             "-bootclasspath"
       
   538         };
       
   539 
       
   540         for (String o: fmOptions) {
       
   541             if (fileManager.isSupportedOption(o) == -1)
       
   542                 continue;
       
   543             String name = o.replaceAll("^-+", "").replaceAll("-+", "_");
       
   544             log.println(getMessage("main.opt." + name));
       
   545         }
       
   546 
       
   547         log.println(getMessage("main.usage.foot"));
       
   548     }
       
   549 
       
   550     private void showVersion(boolean full) {
       
   551         log.println(version(full));
       
   552     }
       
   553 
       
   554     private static final String versionRBName = "com.sun.tools.javah.resources.version";
       
   555     private static ResourceBundle versionRB;
       
   556 
       
   557     private String version(boolean full) {
       
   558         String msgKey = (full ? "javah.fullVersion" : "javah.version");
       
   559         String versionKey = (full ? "full" : "release");
       
   560         // versionKey=product:  mm.nn.oo[-milestone]
       
   561         // versionKey=full:     mm.mm.oo[-milestone]-build
       
   562         if (versionRB == null) {
       
   563             try {
       
   564                 versionRB = ResourceBundle.getBundle(versionRBName);
       
   565             } catch (MissingResourceException e) {
       
   566                 return getMessage("version.resource.missing", System.getProperty("java.version"));
       
   567             }
       
   568         }
       
   569         try {
       
   570             return getMessage(msgKey, "javah", versionRB.getString(versionKey));
       
   571         }
       
   572         catch (MissingResourceException e) {
       
   573             return getMessage("version.unknown", System.getProperty("java.version"));
       
   574         }
       
   575     }
       
   576 
       
   577     private Diagnostic<JavaFileObject> createDiagnostic(final String key, final Object... args) {
       
   578         return new Diagnostic<JavaFileObject>() {
       
   579             @DefinedBy(Api.COMPILER)
       
   580             public Kind getKind() {
       
   581                 return Diagnostic.Kind.ERROR;
       
   582             }
       
   583 
       
   584             @DefinedBy(Api.COMPILER)
       
   585             public JavaFileObject getSource() {
       
   586                 return null;
       
   587             }
       
   588 
       
   589             @DefinedBy(Api.COMPILER)
       
   590             public long getPosition() {
       
   591                 return Diagnostic.NOPOS;
       
   592             }
       
   593 
       
   594             @DefinedBy(Api.COMPILER)
       
   595             public long getStartPosition() {
       
   596                 return Diagnostic.NOPOS;
       
   597             }
       
   598 
       
   599             @DefinedBy(Api.COMPILER)
       
   600             public long getEndPosition() {
       
   601                 return Diagnostic.NOPOS;
       
   602             }
       
   603 
       
   604             @DefinedBy(Api.COMPILER)
       
   605             public long getLineNumber() {
       
   606                 return Diagnostic.NOPOS;
       
   607             }
       
   608 
       
   609             @DefinedBy(Api.COMPILER)
       
   610             public long getColumnNumber() {
       
   611                 return Diagnostic.NOPOS;
       
   612             }
       
   613 
       
   614             @DefinedBy(Api.COMPILER)
       
   615             public String getCode() {
       
   616                 return key;
       
   617             }
       
   618 
       
   619             @DefinedBy(Api.COMPILER)
       
   620             public String getMessage(Locale locale) {
       
   621                 return JavahTask.this.getMessage(locale, key, args);
       
   622             }
       
   623 
       
   624         };
       
   625     }
       
   626 
       
   627     private String getMessage(String key, Object... args) {
       
   628         return getMessage(task_locale, key, args);
       
   629     }
       
   630 
       
   631     private String getMessage(Locale locale, String key, Object... args) {
       
   632         if (bundles == null) {
       
   633             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
       
   634             // and for efficiency, keep a hard reference to the bundle for the task
       
   635             // locale
       
   636             bundles = new HashMap<>();
       
   637         }
       
   638 
       
   639         if (locale == null)
       
   640             locale = Locale.getDefault();
       
   641 
       
   642         ResourceBundle b = bundles.get(locale);
       
   643         if (b == null) {
       
   644             try {
       
   645                 b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale);
       
   646                 bundles.put(locale, b);
       
   647             } catch (MissingResourceException e) {
       
   648                 throw new InternalError("Cannot find javah resource bundle for locale " + locale, e);
       
   649             }
       
   650         }
       
   651 
       
   652         try {
       
   653             return MessageFormat.format(b.getString(key), args);
       
   654         } catch (MissingResourceException e) {
       
   655             return key;
       
   656             //throw new InternalError(e, key);
       
   657         }
       
   658     }
       
   659 
       
   660     File ofile;
       
   661     File odir;
       
   662     String bootcp;
       
   663     String usercp;
       
   664     List<String> classes;
       
   665     boolean verbose;
       
   666     boolean noArgs;
       
   667     boolean help;
       
   668     boolean trace;
       
   669     boolean version;
       
   670     boolean fullVersion;
       
   671     boolean jni;
       
   672     boolean llni;
       
   673     boolean doubleAlign;
       
   674     boolean force;
       
   675     Set<String> javac_extras = new LinkedHashSet<>();
       
   676 
       
   677     PrintWriter log;
       
   678     JavaFileManager fileManager;
       
   679     DiagnosticListener<? super JavaFileObject> diagnosticListener;
       
   680     Locale task_locale;
       
   681     Map<Locale, ResourceBundle> bundles;
       
   682 
       
   683     private static final String progname = "javah";
       
   684 
       
   685     @SupportedAnnotationTypes("*")
       
   686     class JavahProcessor extends AbstractProcessor {
       
   687         private Messager messager;
       
   688 
       
   689         JavahProcessor(Gen g) {
       
   690             this.g = g;
       
   691         }
       
   692 
       
   693         @Override @DefinedBy(Api.ANNOTATION_PROCESSING)
       
   694         public SourceVersion getSupportedSourceVersion() {
       
   695             // since this is co-bundled with javac, we can assume it supports
       
   696             // the latest source version
       
   697             return SourceVersion.latest();
       
   698         }
       
   699 
       
   700         @Override @DefinedBy(Api.ANNOTATION_PROCESSING)
       
   701         public void init(ProcessingEnvironment pEnv) {
       
   702             super.init(pEnv);
       
   703             messager  = processingEnv.getMessager();
       
   704         }
       
   705 
       
   706         @DefinedBy(Api.ANNOTATION_PROCESSING)
       
   707         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
       
   708             try {
       
   709                 Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
       
   710                 if (classes.size() > 0) {
       
   711                     checkMethodParameters(classes);
       
   712                     g.setProcessingEnvironment(processingEnv);
       
   713                     g.setClasses(classes);
       
   714                     g.run();
       
   715                 }
       
   716             } catch (CompletionFailure cf) {
       
   717                 messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString()));
       
   718             } catch (ClassNotFoundException cnfe) {
       
   719                 messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage()));
       
   720             } catch (IOException ioe) {
       
   721                 messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage()));
       
   722             } catch (Util.Exit e) {
       
   723                 exit = e;
       
   724             }
       
   725 
       
   726             return true;
       
   727         }
       
   728 
       
   729         private Set<TypeElement> getAllClasses(Set<? extends TypeElement> classes) {
       
   730             Set<TypeElement> allClasses = new LinkedHashSet<>();
       
   731             getAllClasses0(classes, allClasses);
       
   732             return allClasses;
       
   733         }
       
   734 
       
   735         private void getAllClasses0(Iterable<? extends TypeElement> classes, Set<TypeElement> allClasses) {
       
   736             for (TypeElement c: classes) {
       
   737                 allClasses.add(c);
       
   738                 getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses);
       
   739             }
       
   740         }
       
   741 
       
   742         // 4942232:
       
   743         // check that classes exist for all the parameters of native methods
       
   744         private void checkMethodParameters(Set<TypeElement> classes) {
       
   745             Types types = processingEnv.getTypeUtils();
       
   746             for (TypeElement te: classes) {
       
   747                 for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) {
       
   748                     for (VariableElement ve: ee.getParameters()) {
       
   749                         TypeMirror tm = ve.asType();
       
   750                         checkMethodParametersVisitor.visit(tm, types);
       
   751                     }
       
   752                 }
       
   753             }
       
   754         }
       
   755 
       
   756         private TypeVisitor<Void,Types> checkMethodParametersVisitor =
       
   757                 new SimpleTypeVisitor9<Void,Types>() {
       
   758             @Override @DefinedBy(Api.LANGUAGE_MODEL)
       
   759             public Void visitArray(ArrayType t, Types types) {
       
   760                 visit(t.getComponentType(), types);
       
   761                 return null;
       
   762             }
       
   763             @Override @DefinedBy(Api.LANGUAGE_MODEL)
       
   764             public Void visitDeclared(DeclaredType t, Types types) {
       
   765                 t.asElement().getKind(); // ensure class exists
       
   766                 for (TypeMirror st: types.directSupertypes(t))
       
   767                     visit(st, types);
       
   768                 return null;
       
   769             }
       
   770         };
       
   771 
       
   772         private Gen g;
       
   773         private Util.Exit exit;
       
   774     }
       
   775 }