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 new DiagnosticListener<JavaFileObject> () {
 314             @DefinedBy(Api.COMPILER)
 315             public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
 316                 if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
 317                     pw.print(getMessage("err.prefix"));
 318                     pw.print(" ");
 319                 }
 320                 pw.println(diagnostic.getMessage(null));
 321             }
 322         };
 323     }
 324 
 325     int run(String[] args) {
 326         try {
 327             handleOptions(args);
 328             boolean ok = run();
 329             return ok ? 0 : 1;
 330         } catch (BadArgs e) {
 331             diagnosticListener.report(createDiagnostic(e.key, e.args));
 332             return 1;
 333         } catch (InternalError e) {
 334             diagnosticListener.report(createDiagnostic("err.internal.error", e.getMessage()));
 335             return 1;
 336         } catch (Util.Exit e) {
 337             return e.exitValue;
 338         } finally {
 339             log.flush();
 340         }
 341     }
 342 
 343     public void handleOptions(String[] args) throws BadArgs {
 344         handleOptions(Arrays.asList(args), true);
 345     }
 346 
 347     private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
 348         if (log == null) {
 349             log = getPrintWriterForStream(System.out);
 350             if (diagnosticListener == null)
 351               diagnosticListener = getDiagnosticListenerForStream(System.err);
 352         } else {
 353             if (diagnosticListener == null)
 354               diagnosticListener = getDiagnosticListenerForWriter(log);
 355         }
 356 
 357         if (fileManager == null)
 358             fileManager = getDefaultFileManager(diagnosticListener, log);
 359 
 360         Iterator<String> iter = expandAtArgs(args).iterator();
 361         noArgs = !iter.hasNext();
 362 
 363         while (iter.hasNext()) {
 364             String arg = iter.next();
 365             if (arg.startsWith("-"))
 366                 handleOption(arg, iter);
 367             else if (allowClasses) {
 368                 if (classes == null)
 369                     classes = new ArrayList<>();
 370                 classes.add(arg);
 371                 while (iter.hasNext())
 372                     classes.add(iter.next());
 373             } else
 374                 throw new BadArgs("err.unknown.option", arg).showUsage(true);
 375         }
 376 
 377         if ((classes == null || classes.size() == 0) &&
 378                 !(noArgs || help || version || fullVersion)) {
 379             throw new BadArgs("err.no.classes.specified");
 380         }
 381 
 382         if (jni && llni)
 383             throw new BadArgs("jni.llni.mixed");
 384 
 385         if (odir != null && ofile != null)
 386             throw new BadArgs("dir.file.mixed");
 387     }
 388 
 389     private void handleOption(String name, Iterator<String> rest) throws BadArgs {
 390         for (Option o: recognizedOptions) {
 391             if (o.matches(name)) {
 392                 if (o.hasArg) {
 393                     if (rest.hasNext())
 394                         o.process(this, name, rest.next());
 395                     else
 396                         throw new BadArgs("err.missing.arg", name).showUsage(true);
 397                 } else
 398                     o.process(this, name, null);
 399 
 400                 if (o.ignoreRest()) {
 401                     while (rest.hasNext())
 402                         rest.next();
 403                 }
 404                 return;
 405             }
 406         }
 407 
 408         if (fileManager.handleOption(name, rest))
 409             return;
 410 
 411         throw new BadArgs("err.unknown.option", name).showUsage(true);
 412     }
 413 
 414     private Iterable<String> expandAtArgs(Iterable<String> args) throws BadArgs {
 415         try {
 416             List<String> l = new ArrayList<>();
 417             for (String arg: args) l.add(arg);
 418             return Arrays.asList(CommandLine.parse(l.toArray(new String[l.size()])));
 419         } catch (FileNotFoundException | NoSuchFileException e) {
 420             throw new BadArgs("at.args.file.not.found", e.getLocalizedMessage());
 421         } catch (IOException e) {
 422             throw new BadArgs("at.args.io.exception", e.getLocalizedMessage());
 423         }
 424     }
 425 
 426     public Boolean call() {
 427         return run();
 428     }
 429 
 430     public boolean run() throws Util.Exit {
 431 
 432         if (!javac_extras.contains("-XDsuppress-tool-removal-message")) {
 433             log.println(getMessage("javah.misc.Deprecation"));
 434         }
 435 
 436         Util util = new Util(log, diagnosticListener);
 437 
 438         if (noArgs || help) {
 439             showHelp();
 440             return help; // treat noArgs as an error for purposes of exit code
 441         }
 442 
 443         if (version || fullVersion) {
 444             showVersion(fullVersion);
 445             return true;
 446         }
 447 
 448         util.verbose = verbose;
 449 
 450         Gen g;
 451 
 452         if (llni)
 453             g = new LLNI(doubleAlign, util);
 454         else {
 455             g = new JNI(util);
 456         }
 457 
 458         if (ofile != null) {
 459             if (!(fileManager instanceof StandardJavaFileManager)) {
 460                 diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-o"));
 461                 return false;
 462             }
 463             Iterable<? extends JavaFileObject> iter =
 464                     ((StandardJavaFileManager) fileManager).getJavaFileObjectsFromFiles(Collections.singleton(ofile));
 465             JavaFileObject fo = iter.iterator().next();
 466             g.setOutFile(fo);
 467         } else {
 468             if (odir != null) {
 469                 if (!(fileManager instanceof StandardJavaFileManager)) {
 470                     diagnosticListener.report(createDiagnostic("err.cant.use.option.for.fm", "-d"));
 471                     return false;
 472                 }
 473 
 474                 if (!odir.exists())
 475                     if (!odir.mkdirs())
 476                         util.error("cant.create.dir", odir.toString());
 477                 try {
 478                     ((StandardJavaFileManager) fileManager).setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(odir));
 479                 } catch (IOException e) {
 480                     Object msg = e.getLocalizedMessage();
 481                     if (msg == null) {
 482                         msg = e;
 483                     }
 484                     diagnosticListener.report(createDiagnostic("err.ioerror", odir, msg));
 485                     return false;
 486                 }
 487             }
 488             g.setFileManager(fileManager);
 489         }
 490 
 491         /*
 492          * Force set to false will turn off smarts about checking file
 493          * content before writing.
 494          */
 495         g.setForce(force);
 496 
 497         if (fileManager instanceof JavahFileManager)
 498             ((JavahFileManager) fileManager).setSymbolFileEnabled(false);
 499 
 500         JavaCompiler c = ToolProvider.getSystemJavaCompiler();
 501         List<String> opts = new ArrayList<>();
 502         opts.add("-proc:only");
 503         opts.addAll(javac_extras);
 504 
 505         CompilationTask t;
 506         try {
 507             t = c.getTask(log, fileManager, diagnosticListener, opts, classes, null);
 508         } catch (IllegalArgumentException e) {
 509             util.error("bad.arg", e.getMessage());
 510             return false;
 511         }
 512 
 513         JavahProcessor p = new JavahProcessor(g);
 514         t.setProcessors(Collections.singleton(p));
 515 
 516         boolean ok = t.call();
 517         if (p.exit != null)
 518             throw new Util.Exit(p.exit);
 519         return ok;
 520 
 521     }
 522 
 523     static StandardJavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
 524         return JavahFileManager.create(dl, log);
 525     }
 526 
 527     private void showHelp() {
 528         log.println(getMessage("main.usage", progname));
 529 
 530         for (Option o: recognizedOptions) {
 531             if (o.isHidden())
 532                 continue;
 533             String name = o.aliases[0].substring(1); // there must always be at least one name
 534             log.println(getMessage("main.opt." + name));
 535         }
 536 
 537         String[] fmOptions = {
 538             "--module-path", "--system",
 539             "--class-path", "-classpath", "-cp",
 540             "-bootclasspath"
 541         };
 542 
 543         for (String o: fmOptions) {
 544             if (fileManager.isSupportedOption(o) == -1)
 545                 continue;
 546             String name = o.replaceAll("^-+", "").replaceAll("-+", "_");
 547             log.println(getMessage("main.opt." + name));
 548         }
 549 
 550         log.println(getMessage("main.usage.foot"));
 551     }
 552 
 553     private void showVersion(boolean full) {
 554         log.println(version(full));
 555     }
 556 
 557     private static final String versionRBName = "com.sun.tools.javah.resources.version";
 558     private static ResourceBundle versionRB;
 559 
 560     private String version(boolean full) {
 561         String msgKey = (full ? "javah.fullVersion" : "javah.version");
 562         String versionKey = (full ? "full" : "release");
 563         // versionKey=product:  mm.nn.oo[-milestone]
 564         // versionKey=full:     mm.mm.oo[-milestone]-build
 565         if (versionRB == null) {
 566             try {
 567                 versionRB = ResourceBundle.getBundle(versionRBName);
 568             } catch (MissingResourceException e) {
 569                 return getMessage("version.resource.missing", System.getProperty("java.version"));
 570             }
 571         }
 572         try {
 573             return getMessage(msgKey, "javah", versionRB.getString(versionKey));
 574         }
 575         catch (MissingResourceException e) {
 576             return getMessage("version.unknown", System.getProperty("java.version"));
 577         }
 578     }
 579 
 580     private Diagnostic<JavaFileObject> createDiagnostic(final String key, final Object... args) {
 581         return new Diagnostic<JavaFileObject>() {
 582             @DefinedBy(Api.COMPILER)
 583             public Kind getKind() {
 584                 return Diagnostic.Kind.ERROR;
 585             }
 586 
 587             @DefinedBy(Api.COMPILER)
 588             public JavaFileObject getSource() {
 589                 return null;
 590             }
 591 
 592             @DefinedBy(Api.COMPILER)
 593             public long getPosition() {
 594                 return Diagnostic.NOPOS;
 595             }
 596 
 597             @DefinedBy(Api.COMPILER)
 598             public long getStartPosition() {
 599                 return Diagnostic.NOPOS;
 600             }
 601 
 602             @DefinedBy(Api.COMPILER)
 603             public long getEndPosition() {
 604                 return Diagnostic.NOPOS;
 605             }
 606 
 607             @DefinedBy(Api.COMPILER)
 608             public long getLineNumber() {
 609                 return Diagnostic.NOPOS;
 610             }
 611 
 612             @DefinedBy(Api.COMPILER)
 613             public long getColumnNumber() {
 614                 return Diagnostic.NOPOS;
 615             }
 616 
 617             @DefinedBy(Api.COMPILER)
 618             public String getCode() {
 619                 return key;
 620             }
 621 
 622             @DefinedBy(Api.COMPILER)
 623             public String getMessage(Locale locale) {
 624                 return JavahTask.this.getMessage(locale, key, args);
 625             }
 626 
 627         };
 628     }
 629 
 630     private String getMessage(String key, Object... args) {
 631         return getMessage(task_locale, key, args);
 632     }
 633 
 634     private String getMessage(Locale locale, String key, Object... args) {
 635         if (bundles == null) {
 636             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
 637             // and for efficiency, keep a hard reference to the bundle for the task
 638             // locale
 639             bundles = new HashMap<>();
 640         }
 641 
 642         if (locale == null)
 643             locale = Locale.getDefault();
 644 
 645         ResourceBundle b = bundles.get(locale);
 646         if (b == null) {
 647             try {
 648                 b = ResourceBundle.getBundle("com.sun.tools.javah.resources.l10n", locale);
 649                 bundles.put(locale, b);
 650             } catch (MissingResourceException e) {
 651                 throw new InternalError("Cannot find javah resource bundle for locale " + locale, e);
 652             }
 653         }
 654 
 655         try {
 656             return MessageFormat.format(b.getString(key), args);
 657         } catch (MissingResourceException e) {
 658             return key;
 659             //throw new InternalError(e, key);
 660         }
 661     }
 662 
 663     File ofile;
 664     File odir;
 665     String bootcp;
 666     String usercp;
 667     List<String> classes;
 668     boolean verbose;
 669     boolean noArgs;
 670     boolean help;
 671     boolean trace;
 672     boolean version;
 673     boolean fullVersion;
 674     boolean jni;
 675     boolean llni;
 676     boolean doubleAlign;
 677     boolean force;
 678     Set<String> javac_extras = new LinkedHashSet<>();
 679 
 680     PrintWriter log;
 681     JavaFileManager fileManager;
 682     DiagnosticListener<? super JavaFileObject> diagnosticListener;
 683     Locale task_locale;
 684     Map<Locale, ResourceBundle> bundles;
 685 
 686     private static final String progname = "javah";
 687 
 688     @SupportedAnnotationTypes("*")
 689     class JavahProcessor extends AbstractProcessor {
 690         private Messager messager;
 691 
 692         JavahProcessor(Gen g) {
 693             this.g = g;
 694         }
 695 
 696         @Override @DefinedBy(Api.ANNOTATION_PROCESSING)
 697         public SourceVersion getSupportedSourceVersion() {
 698             // since this is co-bundled with javac, we can assume it supports
 699             // the latest source version
 700             return SourceVersion.latest();
 701         }
 702 
 703         @Override @DefinedBy(Api.ANNOTATION_PROCESSING)
 704         public void init(ProcessingEnvironment pEnv) {
 705             super.init(pEnv);
 706             messager  = processingEnv.getMessager();
 707         }
 708 
 709         @DefinedBy(Api.ANNOTATION_PROCESSING)
 710         public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
 711             try {
 712                 Set<TypeElement> classes = getAllClasses(ElementFilter.typesIn(roundEnv.getRootElements()));
 713                 if (classes.size() > 0) {
 714                     checkMethodParameters(classes);
 715                     g.setProcessingEnvironment(processingEnv);
 716                     g.setClasses(classes);
 717                     g.run();
 718                 }
 719             } catch (CompletionFailure cf) {
 720                 messager.printMessage(ERROR, getMessage("class.not.found", cf.sym.getQualifiedName().toString()));
 721             } catch (ClassNotFoundException cnfe) {
 722                 messager.printMessage(ERROR, getMessage("class.not.found", cnfe.getMessage()));
 723             } catch (IOException ioe) {
 724                 messager.printMessage(ERROR, getMessage("io.exception", ioe.getMessage()));
 725             } catch (Util.Exit e) {
 726                 exit = e;
 727             }
 728 
 729             return true;
 730         }
 731 
 732         private Set<TypeElement> getAllClasses(Set<? extends TypeElement> classes) {
 733             Set<TypeElement> allClasses = new LinkedHashSet<>();
 734             getAllClasses0(classes, allClasses);
 735             return allClasses;
 736         }
 737 
 738         private void getAllClasses0(Iterable<? extends TypeElement> classes, Set<TypeElement> allClasses) {
 739             for (TypeElement c: classes) {
 740                 allClasses.add(c);
 741                 getAllClasses0(ElementFilter.typesIn(c.getEnclosedElements()), allClasses);
 742             }
 743         }
 744 
 745         // 4942232:
 746         // check that classes exist for all the parameters of native methods
 747         private void checkMethodParameters(Set<TypeElement> classes) {
 748             Types types = processingEnv.getTypeUtils();
 749             for (TypeElement te: classes) {
 750                 for (ExecutableElement ee: ElementFilter.methodsIn(te.getEnclosedElements())) {
 751                     for (VariableElement ve: ee.getParameters()) {
 752                         TypeMirror tm = ve.asType();
 753                         checkMethodParametersVisitor.visit(tm, types);
 754                     }
 755                 }
 756             }
 757         }
 758 
 759         private TypeVisitor<Void,Types> checkMethodParametersVisitor =
 760                 new SimpleTypeVisitor9<Void,Types>() {
 761             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 762             public Void visitArray(ArrayType t, Types types) {
 763                 visit(t.getComponentType(), types);
 764                 return null;
 765             }
 766             @Override @DefinedBy(Api.LANGUAGE_MODEL)
 767             public Void visitDeclared(DeclaredType t, Types types) {
 768                 t.asElement().getKind(); // ensure class exists
 769                 for (TypeMirror st: types.directSupertypes(t))
 770                     visit(st, types);
 771                 return null;
 772             }
 773         };
 774 
 775         private Gen g;
 776         private Util.Exit exit;
 777     }
 778 }