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 }