jjg@416: /*
vromero@1862: * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
jjg@416: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@416: *
jjg@416: * This code is free software; you can redistribute it and/or modify it
jjg@416: * under the terms of the GNU General Public License version 2 only, as
ohair@554: * published by the Free Software Foundation. Oracle designates this
jjg@416: * particular file as subject to the "Classpath" exception as provided
ohair@554: * by Oracle in the LICENSE file that accompanied this code.
jjg@416: *
jjg@416: * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@416: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@416: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@416: * version 2 for more details (a copy is included in the LICENSE file that
jjg@416: * accompanied this code).
jjg@416: *
jjg@416: * You should have received a copy of the GNU General Public License version
jjg@416: * 2 along with this work; if not, write to the Free Software Foundation,
jjg@416: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@416: *
ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554: * or visit www.oracle.com if you need additional information or have any
ohair@554: * questions.
jjg@416: */
jjg@416:
jjg@416: package com.sun.tools.javah;
jjg@416:
jjg@416: import java.io.File;
jjg@728: import java.io.FileNotFoundException;
jjg@416: import java.io.IOException;
jjg@416: import java.io.OutputStream;
jjg@416: import java.io.PrintWriter;
jjg@416: import java.io.Writer;
jjg@416: import java.text.MessageFormat;
jjg@416: import java.util.ArrayList;
jjg@416: import java.util.Arrays;
jjg@416: import java.util.Collections;
jjg@416: import java.util.HashMap;
jjg@416: import java.util.Iterator;
jjg@416: import java.util.LinkedHashSet;
jjg@416: import java.util.List;
jjg@416: import java.util.Locale;
jjg@416: import java.util.Map;
jjg@416: import java.util.MissingResourceException;
jjg@416: import java.util.ResourceBundle;
jjg@416: import java.util.Set;
jjg@416:
jjg@416: import javax.annotation.processing.AbstractProcessor;
jjg@416: import javax.annotation.processing.Messager;
jjg@712: import javax.annotation.processing.ProcessingEnvironment;
jjg@416: import javax.annotation.processing.RoundEnvironment;
jjg@416: import javax.annotation.processing.SupportedAnnotationTypes;
jjg@416:
jjg@416: import javax.lang.model.SourceVersion;
jjg@416: import javax.lang.model.element.ExecutableElement;
jjg@416: import javax.lang.model.element.TypeElement;
jjg@416: import javax.lang.model.element.VariableElement;
jjg@416: import javax.lang.model.type.ArrayType;
jjg@416: import javax.lang.model.type.DeclaredType;
jjg@416: import javax.lang.model.type.TypeMirror;
jjg@416: import javax.lang.model.type.TypeVisitor;
jjg@416: import javax.lang.model.util.ElementFilter;
darcy@1054: import javax.lang.model.util.SimpleTypeVisitor8;
jjg@416: import javax.lang.model.util.Types;
jjg@416:
jjg@416: import javax.tools.Diagnostic;
jjg@416: import javax.tools.DiagnosticListener;
jjg@416: import javax.tools.JavaCompiler;
jjg@416: import javax.tools.JavaCompiler.CompilationTask;
jjg@416: import javax.tools.JavaFileManager;
jjg@416: import javax.tools.JavaFileObject;
jjg@416: import javax.tools.StandardJavaFileManager;
jjg@416: import javax.tools.StandardLocation;
jjg@416: import javax.tools.ToolProvider;
jjg@712: import static javax.tools.Diagnostic.Kind.*;
jjg@712:
jjg@712: import com.sun.tools.javac.code.Symbol.CompletionFailure;
jjg@728: import com.sun.tools.javac.main.CommandLine;
jjg@416:
jjg@416: /**
jjg@416: * Javah generates support files for native methods.
jjg@1326: * Parse commandline options and invokes javadoc to execute those commands.
jjg@416: *
jjg@581: *
This is NOT part of any supported API.
jjg@416: * If you write code that depends on this, you do so at your own
jjg@416: * risk. This code and its internal interfaces are subject to change
jjg@416: * or deletion without notice.
jjg@416: *
jjg@416: * @author Sucheta Dambalkar
jjg@416: * @author Jonathan Gibbons
jjg@416: */
jjg@416: public class JavahTask implements NativeHeaderTool.NativeHeaderTask {
jjg@416: public class BadArgs extends Exception {
jjg@416: private static final long serialVersionUID = 1479361270874789045L;
jjg@416: BadArgs(String key, Object... args) {
jjg@416: super(JavahTask.this.getMessage(key, args));
jjg@416: this.key = key;
jjg@416: this.args = args;
jjg@416: }
jjg@416:
jjg@416: BadArgs showUsage(boolean b) {
jjg@416: showUsage = b;
jjg@416: return this;
jjg@416: }
jjg@416:
jjg@416: final String key;
jjg@416: final Object[] args;
jjg@416: boolean showUsage;
jjg@416: }
jjg@416:
jjg@416: static abstract class Option {
jjg@416: Option(boolean hasArg, String... aliases) {
jjg@416: this.hasArg = hasArg;
jjg@416: this.aliases = aliases;
jjg@416: }
jjg@416:
jjg@416: boolean isHidden() {
jjg@416: return false;
jjg@416: }
jjg@416:
jjg@416: boolean matches(String opt) {
jjg@416: for (String a: aliases) {
jjg@416: if (a.equals(opt))
jjg@416: return true;
jjg@416: }
jjg@416: return false;
jjg@416: }
jjg@416:
jjg@416: boolean ignoreRest() {
jjg@416: return false;
jjg@416: }
jjg@416:
jjg@416: abstract void process(JavahTask task, String opt, String arg) throws BadArgs;
jjg@416:
jjg@416: final boolean hasArg;
jjg@416: final String[] aliases;
jjg@416: }
jjg@416:
jjg@416: static abstract class HiddenOption extends Option {
jjg@416: HiddenOption(boolean hasArg, String... aliases) {
jjg@416: super(hasArg, aliases);
jjg@416: }
jjg@416:
jjg@416: @Override
jjg@416: boolean isHidden() {
jjg@416: return true;
jjg@416: }
jjg@416: }
jjg@416:
vromero@1442: static final Option[] recognizedOptions = {
jjg@416: new Option(true, "-o") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.ofile = new File(arg);
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new Option(true, "-d") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.odir = new File(arg);
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(true, "-td") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: // ignored; for backwards compatibility
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(false, "-stubs") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: // ignored; for backwards compatibility
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new Option(false, "-v", "-verbose") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.verbose = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@707: new Option(false, "-h", "-help", "--help", "-?") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.help = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(false, "-trace") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.trace = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new Option(false, "-version") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.version = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(false, "-fullversion") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.fullVersion = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new Option(false, "-jni") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.jni = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new Option(false, "-force") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.force = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(false, "-Xnew") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: // we're already using the new javah
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(false, "-llni", "-Xllni") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.llni = true;
jjg@416: }
jjg@416: },
jjg@416:
jjg@416: new HiddenOption(false, "-llnidouble") {
jjg@416: void process(JavahTask task, String opt, String arg) {
jjg@416: task.llni = true;
jjg@416: task.doubleAlign = true;
jjg@416: }
jjg@416: },
jjg@712:
jjg@712: new HiddenOption(false) {
jjg@712: boolean matches(String opt) {
jjg@712: return opt.startsWith("-XD");
jjg@712: }
jjg@712: void process(JavahTask task, String opt, String arg) {
jjg@712: task.javac_extras.add(opt);
jjg@712: }
jjg@712: },
jjg@416: };
jjg@416:
jjg@416: JavahTask() {
jjg@416: }
jjg@416:
jjg@416: JavahTask(Writer out,
jjg@416: JavaFileManager fileManager,
jjg@416: DiagnosticListener super JavaFileObject> diagnosticListener,
jjg@416: Iterable options,
jjg@416: Iterable classes) {
jjg@416: this();
jjg@416: this.log = getPrintWriterForWriter(out);
jjg@416: this.fileManager = fileManager;
jjg@416: this.diagnosticListener = diagnosticListener;
jjg@416:
jjg@416: try {
jjg@416: handleOptions(options, false);
jjg@416: } catch (BadArgs e) {
jjg@416: throw new IllegalArgumentException(e.getMessage());
jjg@416: }
jjg@416:
jjg@416: this.classes = new ArrayList();
jjg@508: if (classes != null) {
jjg@508: for (String classname: classes) {
jjg@508: classname.getClass(); // null-check
jjg@508: this.classes.add(classname);
jjg@508: }
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: public void setLocale(Locale locale) {
jjg@416: if (locale == null)
jjg@416: locale = Locale.getDefault();
jjg@416: task_locale = locale;
jjg@416: }
jjg@416:
jjg@416: public void setLog(PrintWriter log) {
jjg@416: this.log = log;
jjg@416: }
jjg@416:
jjg@416: public void setLog(OutputStream s) {
jjg@416: setLog(getPrintWriterForStream(s));
jjg@416: }
jjg@416:
jjg@416: static PrintWriter getPrintWriterForStream(OutputStream s) {
jjg@416: return new PrintWriter(s, true);
jjg@416: }
jjg@416:
jjg@416: static PrintWriter getPrintWriterForWriter(Writer w) {
jjg@416: if (w == null)
jjg@416: return getPrintWriterForStream(null);
jjg@416: else if (w instanceof PrintWriter)
jjg@416: return (PrintWriter) w;
jjg@416: else
jjg@416: return new PrintWriter(w, true);
jjg@416: }
jjg@416:
jjg@416: public void setDiagnosticListener(DiagnosticListener super JavaFileObject> dl) {
jjg@416: diagnosticListener = dl;
jjg@416: }
jjg@416:
jjg@416: public void setDiagnosticListener(OutputStream s) {
jjg@416: setDiagnosticListener(getDiagnosticListenerForStream(s));
jjg@416: }
jjg@416:
jjg@416: private DiagnosticListener getDiagnosticListenerForStream(OutputStream s) {
jjg@416: return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
jjg@416: }
jjg@416:
jjg@416: private DiagnosticListener getDiagnosticListenerForWriter(Writer w) {
jjg@416: final PrintWriter pw = getPrintWriterForWriter(w);
jjg@416: return new DiagnosticListener () {
jjg@416: public void report(Diagnostic extends JavaFileObject> diagnostic) {
jjg@416: if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
jjg@416: pw.print(getMessage("err.prefix"));
jjg@416: pw.print(" ");
jjg@416: }
jjg@416: pw.println(diagnostic.getMessage(null));
jjg@416: }
jjg@416: };
jjg@416: }
jjg@416:
jjg@416: int run(String[] args) {
jjg@416: try {
jjg@416: handleOptions(args);
jjg@416: boolean ok = run();
jjg@416: return ok ? 0 : 1;
jjg@416: } catch (BadArgs e) {
jjg@416: diagnosticListener.report(createDiagnostic(e.key, e.args));
jjg@416: return 1;
jjg@416: } catch (InternalError e) {
jjg@416: diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));
jjg@416: return 1;
jjg@712: } catch (Util.Exit e) {
jjg@712: return e.exitValue;
jjg@416: } finally {
jjg@416: log.flush();
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: public void handleOptions(String[] args) throws BadArgs {
jjg@416: handleOptions(Arrays.asList(args), true);
jjg@416: }
jjg@416:
jjg@416: private void handleOptions(Iterable args, boolean allowClasses) throws BadArgs {
jjg@416: if (log == null) {
jjg@416: log = getPrintWriterForStream(System.out);
jjg@416: if (diagnosticListener == null)
jjg@416: diagnosticListener = getDiagnosticListenerForStream(System.err);
jjg@416: } else {
jjg@416: if (diagnosticListener == null)
jjg@416: diagnosticListener = getDiagnosticListenerForWriter(log);
jjg@416: }
jjg@416:
jjg@416: if (fileManager == null)
jjg@416: fileManager = getDefaultFileManager(diagnosticListener, log);
jjg@416:
jjg@728: Iterator iter = expandAtArgs(args).iterator();
jjg@529: noArgs = !iter.hasNext();
jjg@416:
jjg@416: while (iter.hasNext()) {
jjg@416: String arg = iter.next();
jjg@416: if (arg.startsWith("-"))
jjg@416: handleOption(arg, iter);
jjg@416: else if (allowClasses) {
jjg@416: if (classes == null)
jjg@416: classes = new ArrayList();
jjg@416: classes.add(arg);
jjg@416: while (iter.hasNext())
jjg@416: classes.add(iter.next());
jjg@416: } else
jjg@416: throw new BadArgs("err.unknown.option", arg).showUsage(true);
jjg@416: }
jjg@416:
jjg@416: if ((classes == null || classes.size() == 0) &&
jjg@508: !(noArgs || help || version || fullVersion)) {
jjg@416: throw new BadArgs("err.no.classes.specified");
jjg@416: }
jjg@416:
jjg@416: if (jni && llni)
jjg@416: throw new BadArgs("jni.llni.mixed");
jjg@416:
jjg@416: if (odir != null && ofile != null)
jjg@416: throw new BadArgs("dir.file.mixed");
jjg@416: }
jjg@416:
jjg@416: private void handleOption(String name, Iterator rest) throws BadArgs {
jjg@416: for (Option o: recognizedOptions) {
jjg@416: if (o.matches(name)) {
jjg@416: if (o.hasArg) {
jjg@416: if (rest.hasNext())
jjg@416: o.process(this, name, rest.next());
jjg@416: else
jjg@416: throw new BadArgs("err.missing.arg", name).showUsage(true);
jjg@416: } else
jjg@416: o.process(this, name, null);
jjg@416:
jjg@416: if (o.ignoreRest()) {
jjg@416: while (rest.hasNext())
jjg@416: rest.next();
jjg@416: }
jjg@416: return;
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: if (fileManager.handleOption(name, rest))
jjg@416: return;
jjg@416:
jjg@416: throw new BadArgs("err.unknown.option", name).showUsage(true);
jjg@416: }
jjg@416:
jjg@728: private Iterable expandAtArgs(Iterable args) throws BadArgs {
jjg@728: try {
jjg@728: List l = new ArrayList();
jjg@728: for (String arg: args) l.add(arg);
jjg@728: return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()])));
jjg@728: } catch (FileNotFoundException e) {
jjg@728: throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage());
jjg@728: } catch (IOException e) {
jjg@728: throw new BadArgs("at.args.io.exception", e.getLocalizedMessage());
jjg@728: }
jjg@728: }
jjg@728:
jjg@416: public Boolean call() {
jjg@416: return run();
jjg@416: }
jjg@416:
jjg@416: public boolean run() throws Util.Exit {
jjg@416:
jjg@416: Util util = new Util(log, diagnosticListener);
jjg@416:
jjg@529: if (noArgs || help) {
jjg@416: showHelp();
jjg@529: return help; // treat noArgs as an error for purposes of exit code
jjg@416: }
jjg@416:
jjg@416: if (version || fullVersion) {
jjg@416: showVersion(fullVersion);
jjg@416: return true;
jjg@416: }
jjg@416:
jjg@416: util.verbose = verbose;
jjg@416:
jjg@416: Gen g;
jjg@416:
jjg@416: if (llni)
jjg@416: g = new LLNI(doubleAlign, util);
jjg@416: else {
jjg@416: // if (stubs)
jjg@416: // throw new BadArgs("jni.no.stubs");
jjg@416: g = new JNI(util);
jjg@416: }
jjg@416:
jjg@416: if (ofile != null) {
jjg@416: if (!(fileManager instanceof StandardJavaFileManager)) {
jjg@416: diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o"));
jjg@416: return false;
jjg@416: }
jjg@416: Iterable extends JavaFileObject> iter =
jjg@416: ((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile));
jjg@416: JavaFileObject fo = iter.iterator().next();
jjg@416: g.setOutFile(fo);
jjg@416: } else {
jjg@416: if (odir != null) {
jjg@416: if (!(fileManager instanceof StandardJavaFileManager)) {
jjg@416: diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d"));
jjg@416: return false;
jjg@416: }
jjg@416:
jjg@416: if (!odir.exists())
jjg@416: if (!odir.mkdirs())
jjg@416: util.error("cant.create.dir", odir.toString());
jjg@416: try {
jjg@416: ((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir));
jjg@416: } catch (IOException e) {
jjg@416: Object msg = e.getLocalizedMessage();
jjg@416: if (msg == null) {
jjg@416: msg = e;
jjg@416: }
jjg@416: diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg));
jjg@416: return false;
jjg@416: }
jjg@416: }
jjg@416: g.setFileManager(fileManager);
jjg@416: }
jjg@416:
jjg@416: /*
jjg@416: * Force set to false will turn off smarts about checking file
jjg@416: * content before writing.
jjg@416: */
jjg@416: g.setForce(force);
jjg@416:
jjg@416: if (fileManager instanceof JavahFileManager)
jjg@1377: ((JavahFileManager) fileManager).setSymbolFileEnabled(false);
jjg@416:
jjg@416: JavaCompiler c = ToolProvider.getSystemJavaCompiler();
jjg@712: List opts = new ArrayList();
jjg@712: opts.add("-proc:only");
jjg@712: opts.addAll(javac_extras);
jjh@1314: CompilationTask t = c.getTask(log, fileManager, diagnosticListener, opts, classes, null);
jjg@416: JavahProcessor p = new JavahProcessor(g);
jjg@416: t.setProcessors(Collections.singleton(p));
jjg@416:
jjg@416: boolean ok = t.call();
jjg@416: if (p.exit != null)
jjg@416: throw new Util.Exit(p.exit);
jjg@416: return ok;
jjg@416: }
jjg@416:
jjg@416: private List pathToFiles(String path) {
jjg@416: List files = new ArrayList();
jjg@416: for (String f: path.split(File.pathSeparator)) {
jjg@416: if (f.length() > 0)
jjg@416: files.add(new File(f));
jjg@416: }
jjg@416: return files;
jjg@416: }
jjg@416:
jjg@416: static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener super JavaFileObject> dl, PrintWriter log) {
jjg@416: return JavahFileManager.create(dl, log);
jjg@416: }
jjg@416:
jjg@416: private void showHelp() {
jjg@416: log.println(getMessage("main.usage", progname));
jjg@416: for (Option o: recognizedOptions) {
jjg@416: if (o.isHidden())
jjg@416: continue;
jjg@416: String name = o.aliases[0].substring(1); // there must always be at least one name
jjg@416: log.println(getMessage("main.opt." + name));
jjg@416: }
vromero@1885: String[] fmOptions = { "-classpath", "-cp", "-bootclasspath" };
jjg@416: for (String o: fmOptions) {
jjg@416: if (fileManager.isSupportedOption(o) == -1)
jjg@416: continue;
jjg@416: String name = o.substring(1);
jjg@416: log.println(getMessage("main.opt." + name));
jjg@416: }
jjg@416: log.println(getMessage("main.usage.foot"));
jjg@416: }
jjg@416:
jjg@416: private void showVersion(boolean full) {
jjg@694: log.println(version(full));
jjg@416: }
jjg@416:
jjg@416: private static final String versionRBName = "com.sun.tools.javah.resources.version";
jjg@416: private static ResourceBundle versionRB;
jjg@416:
jjg@694: private String version(boolean full) {
jjg@694: String msgKey = (full ? "javah.fullVersion" : "javah.version");
jjg@694: String versionKey = (full ? "full" : "release");
jjg@694: // versionKey=product: mm.nn.oo[-milestone]
jjg@694: // versionKey=full: mm.mm.oo[-milestone]-build
jjg@416: if (versionRB == null) {
jjg@416: try {
jjg@416: versionRB = ResourceBundle.getBundle(versionRBName);
jjg@416: } catch (MissingResourceException e) {
jjg@416: return getMessage("version.resource.missing", System.getProperty("java.version"));
jjg@416: }
jjg@416: }
jjg@416: try {
jjg@694: return getMessage(msgKey, "javah", versionRB.getString(versionKey));
jjg@416: }
jjg@416: catch (MissingResourceException e) {
jjg@416: return getMessage("version.unknown", System.getProperty("java.version"));
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: private Diagnostic createDiagnostic(final String key, final Object... args) {
jjg@416: return new Diagnostic() {
jjg@416: public Kind getKind() {
jjg@416: return Diagnostic.Kind.ERROR;
jjg@416: }
jjg@416:
jjg@416: public JavaFileObject getSource() {
jjg@416: return null;
jjg@416: }
jjg@416:
jjg@416: public long getPosition() {
jjg@416: return Diagnostic.NOPOS;
jjg@416: }
jjg@416:
jjg@416: public long getStartPosition() {
jjg@416: return Diagnostic.NOPOS;
jjg@416: }
jjg@416:
jjg@416: public long getEndPosition() {
jjg@416: return Diagnostic.NOPOS;
jjg@416: }
jjg@416:
jjg@416: public long getLineNumber() {
jjg@416: return Diagnostic.NOPOS;
jjg@416: }
jjg@416:
jjg@416: public long getColumnNumber() {
jjg@416: return Diagnostic.NOPOS;
jjg@416: }
jjg@416:
jjg@416: public String getCode() {
jjg@416: return key;
jjg@416: }
jjg@416:
jjg@416: public String getMessage(Locale locale) {
jjg@416: return JavahTask.this.getMessage(locale, key, args);
jjg@416: }
jjg@416:
jjg@416: };
jjg@728: }
jjg@416:
jjg@416: private String getMessage(String key, Object... args) {
jjg@416: return getMessage(task_locale, key, args);
jjg@416: }
jjg@416:
jjg@416: private String getMessage(Locale locale, String key, Object... args) {
jjg@416: if (bundles == null) {
jjg@416: // could make this a HashMap>
jjg@416: // and for efficiency, keep a hard reference to the bundle for the task
jjg@416: // locale
jjg@416: bundles = new HashMap();
jjg@416: }
jjg@416:
jjg@416: if (locale == null)
jjg@416: locale = Locale.getDefault();
jjg@416:
jjg@416: ResourceBundle b = bundles.get(locale);
jjg@416: if (b == null) {
jjg@416: try {
jjg@416: b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale);
jjg@416: bundles.put(locale, b);
jjg@416: } catch (MissingResourceException e) {
jjg@416: throw new InternalError("Cannot find javah resource bundle for locale " + locale, e);
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: try {
jjg@416: return MessageFormat.format(b.getString(key), args);
jjg@416: } catch (MissingResourceException e) {
jjg@416: return key;
jjg@416: //throw new InternalError(e, key);
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: File ofile;
jjg@416: File odir;
jjg@416: String bootcp;
jjg@416: String usercp;
jjg@416: List classes;
jjg@416: boolean verbose;
jjg@529: boolean noArgs;
jjg@416: boolean help;
jjg@416: boolean trace;
jjg@416: boolean version;
jjg@416: boolean fullVersion;
jjg@416: boolean jni;
jjg@416: boolean llni;
jjg@416: boolean doubleAlign;
jjg@416: boolean force;
jjg@712: Set javac_extras = new LinkedHashSet();
jjg@416:
jjg@416: PrintWriter log;
jjg@416: JavaFileManager fileManager;
jjg@416: DiagnosticListener super JavaFileObject> diagnosticListener;
jjg@416: Locale task_locale;
jjg@416: Map bundles;
jjg@416:
jjg@416: private static final String progname = "javah";
jjg@416:
jjg@416: @SupportedAnnotationTypes("*")
jjg@416: class JavahProcessor extends AbstractProcessor {
jjg@712: private Messager messager;
jjg@712:
jjg@416: JavahProcessor(Gen g) {
jjg@416: this.g = g;
jjg@416: }
jjg@416:
jjg@712: @Override
jjg@712: public SourceVersion getSupportedSourceVersion() {
jjg@712: // since this is co-bundled with javac, we can assume it supports
jjg@712: // the latest source version
jjg@712: return SourceVersion.latest();
jjg@712: }
jjg@712:
jjg@712: @Override
jjg@712: public void init(ProcessingEnvironment pEnv) {
jjg@712: super.init(pEnv);
jjg@712: messager = processingEnv.getMessager();
jjg@712: }
jjg@712:
jjg@416: public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
jjg@712: try {
jjg@712: Set classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
jjg@712: if (classes.size() > 0) {
jjg@712: checkMethodParameters(classes);
jjg@712: g.setProcessingEnvironment(processingEnv);
jjg@712: g.setClasses(classes);
jjg@712: g.run();
jjg@712: }
jjg@712: } catch (CompletionFailure cf) {
jjg@712: messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString()));
jjg@712: } catch (ClassNotFoundException cnfe) {
jjg@712: messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage()));
jjg@712: } catch (IOException ioe) {
jjg@712: messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage()));
jjg@712: } catch (Util.Exit e) {
jjg@712: exit = e;
jjg@712: }
jjg@416:
jjg@416: return true;
jjg@416: }
jjg@416:
jjg@416: private Set getAllClasses(Set extends TypeElement> classes) {
jjg@416: Set allClasses = new LinkedHashSet();
jjg@416: getAllClasses0(classes, allClasses);
jjg@416: return allClasses;
jjg@416: }
jjg@416:
jjg@416: private void getAllClasses0(Iterable extends TypeElement> classes, Set allClasses) {
jjg@416: for (TypeElement c: classes) {
jjg@416: allClasses.add(c);
jjg@416: getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses);
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: // 4942232:
jjg@416: // check that classes exist for all the parameters of native methods
jjg@416: private void checkMethodParameters(Set classes) {
jjg@416: Types types = processingEnv.getTypeUtils();
jjg@416: for (TypeElement te: classes) {
jjg@416: for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) {
jjg@416: for (VariableElement ve: ee.getParameters()) {
jjg@416: TypeMirror tm = ve.asType();
jjg@416: checkMethodParametersVisitor.visit(tm, types);
jjg@416: }
jjg@416: }
jjg@416: }
jjg@416: }
jjg@416:
jjg@416: private TypeVisitor checkMethodParametersVisitor =
darcy@1054: new SimpleTypeVisitor8() {
jjg@416: @Override
jjg@416: public Void visitArray(ArrayType t, Types types) {
jjg@416: visit(t.getComponentType(), types);
jjg@416: return null;
jjg@416: }
jjg@416: @Override
jjg@416: public Void visitDeclared(DeclaredType t, Types types) {
jjg@416: t.asElement().getKind(); // ensure class exists
jjg@416: for (TypeMirror st: types.directSupertypes(t))
jjg@416: visit(st, types);
jjg@416: return null;
jjg@416: }
jjg@416: };
jjg@416:
jjg@416: private Gen g;
jjg@416: private Util.Exit exit;
jjg@416: }
jjg@416: }