< prev index next >

langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java

Print this page




  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.javac.main;
  27 
  28 import java.io.FileWriter;
  29 import java.io.PrintWriter;
  30 import java.nio.file.Files;
  31 import java.nio.file.Path;
  32 import java.nio.file.Paths;


  33 import java.util.Collections;

  34 import java.util.EnumSet;

  35 import java.util.LinkedHashMap;

  36 import java.util.Map;
  37 import java.util.ServiceLoader;
  38 import java.util.Set;
  39 import java.util.TreeSet;
  40 import java.util.stream.Collectors;
  41 import java.util.stream.StreamSupport;
  42 
  43 import javax.lang.model.SourceVersion;
  44 
  45 import com.sun.tools.doclint.DocLint;
  46 import com.sun.tools.javac.code.Lint;
  47 import com.sun.tools.javac.code.Lint.LintCategory;
  48 import com.sun.tools.javac.code.Source;
  49 import com.sun.tools.javac.code.Type;
  50 import com.sun.tools.javac.jvm.Profile;
  51 import com.sun.tools.javac.jvm.Target;
  52 import com.sun.tools.javac.platform.PlatformProvider;
  53 import com.sun.tools.javac.processing.JavacProcessingEnvironment;



  54 import com.sun.tools.javac.util.Log;
  55 import com.sun.tools.javac.util.Log.PrefixKind;
  56 import com.sun.tools.javac.util.Log.WriterKind;
  57 import com.sun.tools.javac.util.Options;
  58 import com.sun.tools.javac.util.StringUtils;
  59 
  60 import static com.sun.tools.javac.main.Option.ChoiceKind.*;
  61 import static com.sun.tools.javac.main.Option.OptionGroup.*;
  62 import static com.sun.tools.javac.main.Option.OptionKind.*;
  63 
  64 /**
  65  * Options for javac. The specific Option to handle a command-line option
  66  * is identified by searching the members of this enum in order, looking for
  67  * the first {@link #matches match}. The action for an Option is performed
  68  * by calling {@link #process process}, and by providing a suitable



  69  * {@link OptionHelper} to provide access the compiler state.
  70  *
  71  * <p><b>This is NOT part of any supported API.
  72  * If you write code that depends on this, you do so at your own
  73  * risk.  This code and its internal interfaces are subject to change
  74  * or deletion without notice.</b></p>
  75  */
  76 public enum Option {
  77     G("-g", "opt.g", STANDARD, BASIC),
  78 
  79     G_NONE("-g:none", "opt.g.none", STANDARD, BASIC) {
  80         @Override
  81         public boolean process(OptionHelper helper, String option) {
  82             helper.put("-g:", "none");
  83             return false;
  84         }
  85     },
  86 
  87     G_CUSTOM("-g:",  "opt.g.lines.vars.source",
  88             STANDARD, BASIC, ANYOF, "lines", "vars", "source"),
  89 
  90     XLINT("-Xlint", "opt.Xlint", EXTENDED, BASIC),
  91 
  92     XLINT_CUSTOM("-Xlint:", EXTENDED, BASIC, ANYOF, getXLintChoices()) {
  93         private static final String LINT_KEY_FORMAT = "         %-19s %s";

  94         @Override
  95         void help(Log log, OptionKind kind) {
  96             if (this.kind != kind)
  97                 return;
  98 
  99             log.printRawLines(WriterKind.STDOUT,
 100                               String.format(HELP_LINE_FORMAT,
 101                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.subopts"),
 102                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.suboptlist")));
 103             log.printRawLines(WriterKind.STDOUT,
 104                               String.format(LINT_KEY_FORMAT,
 105                                             "all",
 106                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.all")));
 107             for (LintCategory lc : LintCategory.values()) {
 108                 if (lc.hidden) continue;
 109                 log.printRawLines(WriterKind.STDOUT,
 110                                   String.format(LINT_KEY_FORMAT,
 111                                                 lc.option,
 112                                                 log.localize(PrefixKind.JAVAC,
 113                                                              "opt.Xlint.desc." + lc.option)));
 114             }
 115             log.printRawLines(WriterKind.STDOUT,
 116                               String.format(LINT_KEY_FORMAT,
 117                                             "none",
 118                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.none")));
 119         }
 120     },
 121 
 122     XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC),
 123 
 124     XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) {
 125         @Override
 126         public boolean matches(String option) {
 127             return DocLint.isValidOption(
 128                     option.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
 129         }
 130 
 131         @Override
 132         public boolean process(OptionHelper helper, String option) {
 133             String prev = helper.get(XDOCLINT_CUSTOM);
 134             String next = (prev == null) ? option : (prev + " " + option);
 135             helper.put(XDOCLINT_CUSTOM.text, next);
 136             return false;
 137         }
 138     },
 139 
 140     XDOCLINT_PACKAGE("-Xdoclint/package:", "opt.Xdoclint.package.args", "opt.Xdoclint.package.desc", EXTENDED, BASIC) {
 141         @Override
 142         public boolean matches(String option) {
 143             return DocLint.isValidOption(
 144                     option.replace(XDOCLINT_PACKAGE.text, DocLint.XCHECK_PACKAGE));
 145         }
 146 
 147         @Override
 148         public boolean process(OptionHelper helper, String option) {
 149             String prev = helper.get(XDOCLINT_PACKAGE);
 150             String next = (prev == null) ? option : (prev + " " + option);
 151             helper.put(XDOCLINT_PACKAGE.text, next);
 152             return false;
 153         }
 154     },
 155 
 156     // -nowarn is retained for command-line backward compatibility
 157     NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) {
 158         @Override
 159         public boolean process(OptionHelper helper, String option) {
 160             helper.put("-Xlint:none", option);
 161             return false;
 162         }
 163     },
 164 
 165     VERBOSE("-verbose", "opt.verbose", STANDARD, BASIC),
 166 
 167     // -deprecation is retained for command-line backward compatibility
 168     DEPRECATION("-deprecation", "opt.deprecation", STANDARD, BASIC) {
 169         @Override
 170         public boolean process(OptionHelper helper, String option) {
 171             helper.put("-Xlint:deprecation", option);
 172             return false;
 173         }
 174     },
 175 
 176     CLASSPATH("-classpath", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER),
 177 
 178     CP("-cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER) {
 179         @Override
 180         public boolean process(OptionHelper helper, String option, String arg) {
 181             return super.process(helper, "-classpath", arg);
 182         }
 183     },
 184 
 185     SOURCEPATH("-sourcepath", "opt.arg.path", "opt.sourcepath", STANDARD, FILEMANAGER),
 186 
 187     MODULESOURCEPATH("-modulesourcepath", "opt.arg.mspath", "opt.modulesourcepath", STANDARD, FILEMANAGER),
 188 
 189     MODULEPATH("-modulepath", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER),
 190 
 191     MP("-mp", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER) {







 192         @Override
 193         public boolean process(OptionHelper helper, String option, String arg) {
 194             return super.process(helper, "-modulepath", arg);

 195         }
 196     },
 197 
 198     UPGRADEMODULEPATH("-upgrademodulepath", "opt.arg.path", "opt.upgrademodulepath", STANDARD, FILEMANAGER),









 199 
 200     SYSTEM("-system", "opt.arg.jdk", "opt.system", STANDARD, FILEMANAGER),

 201 
 202     XPATCH("-Xpatch:", "opt.arg.patch", "opt.patch", EXTENDED, FILEMANAGER),








 203 
 204     BOOTCLASSPATH("-bootclasspath", "opt.arg.path", "opt.bootclasspath", STANDARD, FILEMANAGER) {
 205         @Override
 206         public boolean process(OptionHelper helper, String option, String arg) {
 207             helper.remove("-Xbootclasspath/p:");
 208             helper.remove("-Xbootclasspath/a:");
 209             return super.process(helper, option, arg);
 210         }
 211     },
 212 
 213     XBOOTCLASSPATH_PREPEND("-Xbootclasspath/p:", "opt.arg.path", "opt.Xbootclasspath.p", EXTENDED, FILEMANAGER),
 214 
 215     XBOOTCLASSPATH_APPEND("-Xbootclasspath/a:", "opt.arg.path", "opt.Xbootclasspath.a", EXTENDED, FILEMANAGER),
 216 
 217     XBOOTCLASSPATH("-Xbootclasspath:", "opt.arg.path", "opt.bootclasspath", EXTENDED, FILEMANAGER) {
 218         @Override
 219         public boolean process(OptionHelper helper, String option, String arg) {
 220             helper.remove("-Xbootclasspath/p:");
 221             helper.remove("-Xbootclasspath/a:");
 222             return super.process(helper, "-bootclasspath", arg);
 223         }
 224     },
 225 
 226     EXTDIRS("-extdirs", "opt.arg.dirs", "opt.extdirs", STANDARD, FILEMANAGER),
 227 
 228     DJAVA_EXT_DIRS("-Djava.ext.dirs=", "opt.arg.dirs", "opt.extdirs", EXTENDED, FILEMANAGER) {
 229         @Override
 230         public boolean process(OptionHelper helper, String option, String arg) {
 231             return super.process(helper, "-extdirs", arg);
 232         }
 233     },
 234 
 235     ENDORSEDDIRS("-endorseddirs", "opt.arg.dirs", "opt.endorseddirs", STANDARD, FILEMANAGER),
 236 
 237     DJAVA_ENDORSED_DIRS("-Djava.endorsed.dirs=", "opt.arg.dirs", "opt.endorseddirs", EXTENDED, FILEMANAGER) {
 238         @Override
 239         public boolean process(OptionHelper helper, String option, String arg) {
 240             return super.process(helper, "-endorseddirs", arg);
 241         }
 242     },
 243 
 244     PROC("-proc:", "opt.proc.none.only", STANDARD, BASIC,  ONEOF, "none", "only"),
 245 
 246     PROCESSOR("-processor", "opt.arg.class.list", "opt.processor", STANDARD, BASIC),
 247 
 248     PROCESSORPATH("-processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER),
 249 
 250     PROCESSORMODULEPATH("-processormodulepath", "opt.arg.path", "opt.processormodulepath", STANDARD, FILEMANAGER),
 251 
 252     PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC),
 253 
 254     D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER),
 255 
 256     S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER),
 257 
 258     H("-h", "opt.arg.directory", "opt.headerDest", STANDARD, FILEMANAGER),
 259 
 260     IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"),
 261 
 262     ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER),
 263 
 264     SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
 265         @Override
 266         public boolean process(OptionHelper helper, String option, String operand) {
 267             Source source = Source.lookup(operand);
 268             if (source == null) {
 269                 helper.error("err.invalid.source", operand);
 270                 return true;
 271             }
 272             return super.process(helper, option, operand);
 273         }
 274     },
 275 
 276     TARGET("-target", "opt.arg.release", "opt.target", STANDARD, BASIC) {
 277         @Override
 278         public boolean process(OptionHelper helper, String option, String operand) {
 279             Target target = Target.lookup(operand);
 280             if (target == null) {
 281                 helper.error("err.invalid.target", operand);
 282                 return true;
 283             }
 284             return super.process(helper, option, operand);
 285         }
 286     },
 287 
 288     RELEASE("-release", "opt.arg.release", "opt.release", STANDARD, BASIC) {
 289         @Override
 290         void help(Log log, OptionKind kind) {
 291             if (this.kind != kind)
 292                 return;
 293 
 294             Iterable<PlatformProvider> providers =
 295                     ServiceLoader.load(PlatformProvider.class, Arguments.class.getClassLoader());
 296             Set<String> platforms = StreamSupport.stream(providers.spliterator(), false)
 297                                                  .flatMap(provider -> StreamSupport.stream(provider.getSupportedPlatformNames()
 298                                                                                                    .spliterator(),
 299                                                                                            false))
 300                                                  .collect(Collectors.toCollection(TreeSet :: new));
 301 
 302             StringBuilder targets = new StringBuilder();
 303             String delim = "";
 304             for (String platform : platforms) {
 305                 targets.append(delim);
 306                 targets.append(platform);
 307                 delim = ", ";
 308             }
 309 
 310             log.printRawLines(WriterKind.STDOUT,
 311                     String.format(HELP_LINE_FORMAT,
 312                         super.helpSynopsis(log),
 313                         log.localize(PrefixKind.JAVAC, descrKey, targets.toString())));
 314         }
 315     },
 316 
 317     PROFILE("-profile", "opt.arg.profile", "opt.profile", STANDARD, BASIC) {
 318         @Override
 319         public boolean process(OptionHelper helper, String option, String operand) {
 320             Profile profile = Profile.lookup(operand);
 321             if (profile == null) {
 322                 helper.error("err.invalid.profile", operand);
 323                 return true;
 324             }
 325             return super.process(helper, option, operand);
 326         }
 327     },
 328 
 329     VERSION("-version", "opt.version", STANDARD, INFO) {
 330         @Override
 331         public boolean process(OptionHelper helper, String option) {
 332             Log log = helper.getLog();
 333             String ownName = helper.getOwnName();
 334             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "version", ownName,  JavaCompiler.version());
 335             return super.process(helper, option);
 336         }
 337     },
 338 
 339     FULLVERSION("-fullversion", null, HIDDEN, INFO) {
 340         @Override
 341         public boolean process(OptionHelper helper, String option) {
 342             Log log = helper.getLog();
 343             String ownName = helper.getOwnName();
 344             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "fullVersion", ownName,  JavaCompiler.fullVersion());
 345             return super.process(helper, option);
 346         }
 347     },
 348 
 349     HELP("-help", "opt.help", STANDARD, INFO) {

 350         @Override
 351         public boolean process(OptionHelper helper, String option) {
 352             Log log = helper.getLog();
 353             String ownName = helper.getOwnName();
 354             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.header", ownName);
 355             for (Option o: getJavaCompilerOptions()) {
 356                 o.help(log, OptionKind.STANDARD);
 357             }
 358             log.printNewline(WriterKind.STDOUT);
 359             return super.process(helper, option);
 360         }
 361     },
 362 
 363     A("-A", "opt.arg.key.equals.value", "opt.A", STANDARD, BASIC, true) {
 364         @Override
 365         public boolean matches(String arg) {
 366             return arg.startsWith("-A");
 367         }
 368 
 369         @Override
 370         public boolean hasArg() {
 371             return false;
 372         }
 373         // Mapping for processor options created in
 374         // JavacProcessingEnvironment
 375         @Override
 376         public boolean process(OptionHelper helper, String option) {
 377             int argLength = option.length();
 378             if (argLength == 2) {
 379                 helper.error("err.empty.A.argument");
 380                 return true;
 381             }
 382             int sepIndex = option.indexOf('=');
 383             String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) );
 384             if (!JavacProcessingEnvironment.isValidOptionName(key)) {
 385                 helper.error("err.invalid.A.key", option);
 386                 return true;
 387             }
 388             return process(helper, option, option);

 389         }
 390     },
 391 
 392     X("-X", "opt.X", STANDARD, INFO) {
 393         @Override
 394         public boolean process(OptionHelper helper, String option) {
 395             Log log = helper.getLog();
 396             for (Option o: getJavaCompilerOptions()) {
 397                 o.help(log, OptionKind.EXTENDED);
 398             }
 399             log.printNewline(WriterKind.STDOUT);
 400             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.nonstandard.footer");
 401             return super.process(helper, option);
 402         }
 403     },
 404 
 405     // This option exists only for the purpose of documenting itself.
 406     // It's actually implemented by the launcher.
 407     J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, true) {
 408         @Override
 409         public boolean process(OptionHelper helper, String option) {
 410             throw new AssertionError
 411                 ("the -J flag should be caught by the launcher.");
 412         }
 413     },
 414 
 415     MOREINFO("-moreinfo", null, HIDDEN, BASIC) {
 416         @Override
 417         public boolean process(OptionHelper helper, String option) {
 418             Type.moreInfo = true;
 419             return super.process(helper, option);
 420         }
 421     },
 422 
 423     // treat warnings as errors
 424     WERROR("-Werror", "opt.Werror", STANDARD, BASIC),
 425 
 426     // prompt after each error
 427     // new Option("-prompt",                                        "opt.prompt"),


 467     XPRINTPROCESSORINFO("-XprintProcessorInfo", "opt.printProcessorInfo", EXTENDED, BASIC),
 468 
 469     XPREFER("-Xprefer:", "opt.prefer", EXTENDED, BASIC, ONEOF, "source", "newer"),
 470 
 471     XXUSERPATHSFIRST("-XXuserPathsFirst", "opt.userpathsfirst", HIDDEN, BASIC),
 472 
 473     // see enum PkgInfo
 474     XPKGINFO("-Xpkginfo:", "opt.pkginfo", EXTENDED, BASIC, ONEOF, "always", "legacy", "nonempty"),
 475 
 476     /* -O is a no-op, accepted for backward compatibility. */
 477     O("-O", null, HIDDEN, BASIC),
 478 
 479     /* -Xjcov produces tables to support the code coverage tool jcov. */
 480     XJCOV("-Xjcov", null, HIDDEN, BASIC),
 481 
 482     PLUGIN("-Xplugin:", "opt.arg.plugin", "opt.plugin", EXTENDED, BASIC) {
 483         @Override
 484         public boolean process(OptionHelper helper, String option) {
 485             String p = option.substring(option.indexOf(':') + 1).trim();
 486             String prev = helper.get(PLUGIN);
 487             helper.put(PLUGIN.text, (prev == null) ? p : prev + '\0' + p);
 488             return false;
 489         }
 490     },
 491 
 492     XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"),
 493 
 494     XDEBUG("-Xdebug:", null, HIDDEN, BASIC) {
 495         @Override
 496         public boolean process(OptionHelper helper, String option) {
 497             String p = option.substring(option.indexOf(':') + 1).trim();
 498             String[] subOptions = p.split(";");
 499             for (String subOption : subOptions) {
 500                 subOption = "debug." + subOption.trim();
 501                 XD.process(helper, subOption, subOption);
 502             }
 503             return false;
 504         }
 505     },
 506 
 507     XSHOULDSTOP("-Xshouldstop:", null, HIDDEN, BASIC) {
 508         @Override
 509         public boolean process(OptionHelper helper, String option) {
 510             String p = option.substring(option.indexOf(':') + 1).trim();
 511             String[] subOptions = p.split(";");
 512             for (String subOption : subOptions) {
 513                 subOption = "shouldstop." + subOption.trim();
 514                 XD.process(helper, subOption, subOption);
 515             }
 516             return false;
 517         }
 518     },
 519 
 520     DIAGS("-diags:", null, HIDDEN, BASIC, true) {
 521         @Override
 522         public boolean process(OptionHelper helper, String option) {
 523             return HiddenGroup.DIAGS.process(helper, option);
 524         }
 525     },
 526 
 527     /* This is a back door to the compiler's option table.
 528      * -XDx=y sets the option x to the value y.
 529      * -XDx sets the option x to the value x.
 530      */
 531     XD("-XD", null, HIDDEN, BASIC) {
 532         @Override
 533         public boolean matches(String s) {
 534             return s.startsWith(text);
 535         }
 536         @Override
 537         public boolean process(OptionHelper helper, String option) {
 538             return process(helper, option, option.substring(text.length()));
 539         }
 540 
 541         @Override
 542         public boolean process(OptionHelper helper, String option, String arg) {
 543             int eq = arg.indexOf('=');
 544             String key = (eq < 0) ? arg : arg.substring(0, eq);
 545             String value = (eq < 0) ? arg : arg.substring(eq+1);
 546             helper.put(key, value);
 547             return false;
 548         }
 549     },
 550 
 551     XADDEXPORTS("-XaddExports:", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) {
 552         @Override
 553         public boolean process(OptionHelper helper, String option) {
 554             String p = option.substring(option.indexOf(':') + 1).trim();
 555             String prev = helper.get(XADDEXPORTS);
 556             helper.put(XADDEXPORTS.text, (prev == null) ? p : prev + '\0' + p);
 557             return false;
 558         }
 559     },
 560 
 561     XADDREADS("-XaddReads:", "opt.arg.addReads", "opt.addReads", EXTENDED, BASIC) {
 562         @Override
 563         public boolean process(OptionHelper helper, String option) {
 564             String p = option.substring(option.indexOf(':') + 1).trim();
 565             String prev = helper.get(XADDREADS);
 566             helper.put(XADDREADS.text, (prev == null) ? p : prev + '\0' + p);
 567             return false;
 568         }
 569     },
 570 
 571     XMODULE("-Xmodule:", "opt.arg.module", "opt.module", EXTENDED, BASIC) {
 572         @Override
 573         public boolean process(OptionHelper helper, String option) {
 574             String prev = helper.get(XMODULE);
 575             if (prev != null) {
 576                 helper.error("err.option.too.many", XMODULE.text);
 577             }
 578             String p = option.substring(option.indexOf(':') + 1);
 579             helper.put(XMODULE.text, p);
 580             return false;
 581         }
 582     },
 583 
 584     M("-m", "opt.arg.m", "opt.m", STANDARD, BASIC),
 585 
 586     ADDMODS("-addmods", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC),
 587     LIMITMODS("-limitmods", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC),

 588 
 589     // This option exists only for the purpose of documenting itself.
 590     // It's actually implemented by the CommandLine class.
 591     AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, true) {
 592         @Override
 593         public boolean process(OptionHelper helper, String option) {
 594             throw new AssertionError("the @ flag should be caught by CommandLine.");
 595         }
 596     },
 597 
 598     // Standalone positional argument: source file or type name.
 599     SOURCEFILE("sourcefile", null, HIDDEN, INFO) {
 600         @Override
 601         public boolean matches(String s) {
 602             if (s.endsWith(".java"))  // Java source file
 603                 return true;
 604             int sep = s.indexOf('/');
 605             if (sep != -1) {
 606                 return SourceVersion.isName(s.substring(0, sep))
 607                         && SourceVersion.isName(s.substring(sep + 1));
 608             } else {
 609                 return SourceVersion.isName(s);   // Legal type name
 610             }
 611         }
 612         @Override
 613         public boolean process(OptionHelper helper, String option) {
 614             if (option.endsWith(".java") ) {
 615                 Path p = Paths.get(option);
 616                 if (!Files.exists(p)) {
 617                     helper.error("err.file.not.found", p);
 618                     return true;
 619                 }
 620                 if (!Files.isRegularFile(p)) {
 621                     helper.error("err.file.not.file", p);
 622                     return true;
 623                 }
 624                 helper.addFile(p);
 625             } else {
 626                 helper.addClassName(option);
 627             }
 628             return false;
 629         }
 630     },
 631 
 632     MULTIRELEASE("-multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER);
 633 
 634     /** The kind of an Option. This is used by the -help and -X options. */





































































 635     public enum OptionKind {
 636         /** A standard option, documented by -help. */
 637         STANDARD,
 638         /** An extended option, documented by -X. */
 639         EXTENDED,
 640         /** A hidden option, not documented. */
 641         HIDDEN,
 642     }
 643 
 644     /** The group for an Option. This determines the situations in which the
 645      *  option is applicable. */


 646     enum OptionGroup {
 647         /** A basic option, available for use on the command line or via the
 648          *  Compiler API. */
 649         BASIC,
 650         /** An option for javac's standard JavaFileManager. Other file managers
 651          *  may or may not support these options. */
 652         FILEMANAGER,
 653         /** A command-line option that requests information, such as -help. */
 654         INFO,
 655         /** A command-line "option" representing a file or class name. */
 656         OPERAND
 657     }
 658 
 659     /** The kind of choice for "choice" options. */


 660     enum ChoiceKind {
 661         /** The expected value is exactly one of the set of choices. */
 662         ONEOF,
 663         /** The expected value is one of more of the set of choices. */
 664         ANYOF
 665     }
 666 
 667     enum HiddenGroup {
 668         DIAGS("diags");
 669 
 670         final String text;
 671 
 672         HiddenGroup(String text) {
 673             this.text = text;
 674         }
 675 
 676         public boolean process(OptionHelper helper, String option) {
 677             String p = option.substring(option.indexOf(':') + 1).trim();
 678             String[] subOptions = p.split(";");
 679             for (String subOption : subOptions) {
 680                 subOption = text + "." + subOption.trim();
 681                 XD.process(helper, subOption, subOption);
 682             }
 683             return false;
 684         }
 685     }
 686 
 687     public final String text;
 688 
 689     final OptionKind kind;
 690 
 691     final OptionGroup group;
 692 
 693     /** Documentation key for arguments.



 694      */
 695     final String argsNameKey;



 696 
 697     /** Documentation key for description.
 698      */
 699     final String descrKey;
 700 
 701     /** Suffix option (-foo=bar or -foo:bar)
 702      */
 703     final boolean hasSuffix;
 704 
 705     /** The kind of choices for this option, if any.
 706      */
 707     final ChoiceKind choiceKind;
 708 
 709     /** The choices for this option, if any, and whether or not the choices
 710      *  are hidden











 711      */
 712     final Map<String,Boolean> choices;


 713 












 714 
 715     Option(String text, String descrKey,
 716             OptionKind kind, OptionGroup group) {
 717         this(text, null, descrKey, kind, group, null, null, false);




















 718     }
 719 
 720     Option(String text, String descrKey,
 721             OptionKind kind, OptionGroup group,
 722             boolean doHasSuffix) {
 723         this(text, null, descrKey, kind, group, null, null, doHasSuffix);
 724     }
 725 
 726     Option(String text, String argsNameKey, String descrKey,
 727             OptionKind kind, OptionGroup group) {
 728         this(text, argsNameKey, descrKey, kind, group, null, null, false);
 729     }
 730 
 731     Option(String text, String argsNameKey, String descrKey,
 732             OptionKind kind, OptionGroup group, boolean doHasSuffix) {
 733         this(text, argsNameKey, descrKey, kind, group, null, null, doHasSuffix);
 734     }
 735 
 736     Option(String text, OptionKind kind, OptionGroup group,
 737             ChoiceKind choiceKind, Map<String,Boolean> choices) {
 738         this(text, null, null, kind, group, choiceKind, choices, false);
 739     }
 740 
 741     Option(String text, String descrKey,
 742             OptionKind kind, OptionGroup group,
 743             ChoiceKind choiceKind, String... choices) {
 744         this(text, null, descrKey, kind, group, choiceKind,
 745                 createChoices(choices), false);
 746     }
 747     // where
 748         private static Map<String,Boolean> createChoices(String... choices) {
 749             Map<String,Boolean> map = new LinkedHashMap<>();
 750             for (String c: choices)
 751                 map.put(c, false);
 752             return map;
 753         }
 754 
 755     private Option(String text, String argsNameKey, String descrKey,
 756             OptionKind kind, OptionGroup group,
 757             ChoiceKind choiceKind, Map<String,Boolean> choices,
 758             boolean doHasSuffix) {
 759         this.text = text;


 760         this.argsNameKey = argsNameKey;
 761         this.descrKey = descrKey;
 762         this.kind = kind;
 763         this.group = group;
 764         this.choiceKind = choiceKind;
 765         this.choices = choices;
 766         char lastChar = text.charAt(text.length()-1);
 767         this.hasSuffix = doHasSuffix || lastChar == ':' || lastChar == '=';
 768     }
 769 
 770     public String getText() {
 771         return text;
 772     }
 773 
 774     public OptionKind getKind() {
 775         return kind;
 776     }
 777 




 778     public boolean hasArg() {
 779         return argsNameKey != null && !hasSuffix;

 780     }
 781 
 782     public boolean matches(String option) {
















 783         if (!hasSuffix)
 784             return option.equals(text);
 785 
 786         if (!option.startsWith(text))
 787             return false;
 788 
 789         if (choices != null) {
 790             String arg = option.substring(text.length());
 791             if (choiceKind == ChoiceKind.ONEOF)
 792                 return choices.keySet().contains(arg);
 793             else {
 794                 for (String a: arg.split(",+")) {
 795                     if (!choices.keySet().contains(a))
 796                         return false;
 797                 }
 798             }
 799         }
 800 
 801         return true;
 802     }
 803 

























































 804     public boolean process(OptionHelper helper, String option, String arg) {
 805         if (choices != null) {
 806             if (choiceKind == ChoiceKind.ONEOF) {
 807                 // some clients like to see just one of option+choice set
 808                 for (String s: choices.keySet())
 809                     helper.remove(option + s);
 810                 String opt = option + arg;
 811                 helper.put(opt, opt);
 812                 // some clients like to see option (without trailing ":")
 813                 // set to arg
 814                 String nm = option.substring(0, option.length() - 1);
 815                 helper.put(nm, arg);
 816             } else {
 817                 // set option+word for each word in arg
 818                 for (String a: arg.split(",+")) {
 819                     String opt = option + a;
 820                     helper.put(opt, opt);
 821                 }
 822             }
 823         }
 824         helper.put(option, arg);
 825         if (group == OptionGroup.FILEMANAGER)
 826             helper.handleFileManagerOption(this, arg);
 827         return false;
 828     }
 829 
 830     public boolean process(OptionHelper helper, String option) {
 831         if (hasSuffix)
 832             return process(helper, text, option.substring(text.length()));
 833         else
 834             return process(helper, option, option);
 835     }




















 836 
 837     private static final String HELP_LINE_FORMAT = "  %-26s %s";






 838 
 839     void help(Log log, OptionKind kind) {
 840         if (this.kind != kind)









 841             return;

 842 
 843         log.printRawLines(WriterKind.STDOUT,
 844                 String.format(HELP_LINE_FORMAT,
 845                     helpSynopsis(log),
 846                     log.localize(PrefixKind.JAVAC, descrKey)));





 847 


 848     }
 849 
 850     private String helpSynopsis(Log log) {






 851         StringBuilder sb = new StringBuilder();
 852         sb.append(text);
 853         if (argsNameKey == null) {
 854             if (choices != null) {
 855                 String sep = "{";
 856                 for (Map.Entry<String,Boolean> e: choices.entrySet()) {
 857                     if (!e.getValue()) {
 858                         sb.append(sep);
 859                         sb.append(e.getKey());
 860                         sep = ",";
 861                     }
 862                 }
 863                 sb.append("}");
 864             }
 865         } else {
 866             if (!hasSuffix)
 867                 sb.append(" ");
 868             sb.append(log.localize(PrefixKind.JAVAC, argsNameKey));
 869 
 870         }
 871 
 872         return sb.toString();
 873     }
 874 
 875     // For -XpkgInfo:value
 876     public enum PkgInfo {
 877         /**
 878          * Always generate package-info.class for every package-info.java file.
 879          * The file may be empty if there annotations with a RetentionPolicy
 880          * of CLASS or RUNTIME.  This option may be useful in conjunction with
 881          * build systems (such as Ant) that expect javac to generate at least
 882          * one .class file for every .java file.
 883          */
 884         ALWAYS,
 885         /**
 886          * Generate a package-info.class file if package-info.java contains
 887          * annotations. The file may be empty if all the annotations have
 888          * a RetentionPolicy of SOURCE.
 889          * This value is just for backwards compatibility with earlier behavior.


 898 
 899         public static PkgInfo get(Options options) {
 900             String v = options.get(XPKGINFO);
 901             return (v == null
 902                     ? PkgInfo.LEGACY
 903                     : PkgInfo.valueOf(StringUtils.toUpperCase(v)));
 904         }
 905     }
 906 
 907     private static Map<String,Boolean> getXLintChoices() {
 908         Map<String,Boolean> choices = new LinkedHashMap<>();
 909         choices.put("all", false);
 910         for (Lint.LintCategory c : Lint.LintCategory.values())
 911             choices.put(c.option, c.hidden);
 912         for (Lint.LintCategory c : Lint.LintCategory.values())
 913             choices.put("-" + c.option, c.hidden);
 914         choices.put("none", false);
 915         return choices;
 916     }
 917 




 918     static Set<Option> getJavaCompilerOptions() {
 919         return EnumSet.allOf(Option.class);
 920     }
 921 




 922     public static Set<Option> getJavacFileManagerOptions() {
 923         return getOptions(EnumSet.of(FILEMANAGER));
 924     }
 925 





 926     public static Set<Option> getJavacToolOptions() {
 927         return getOptions(EnumSet.of(BASIC));
 928     }
 929 
 930     static Set<Option> getOptions(Set<OptionGroup> desired) {
 931         Set<Option> options = EnumSet.noneOf(Option.class);
 932         for (Option option : Option.values())
 933             if (desired.contains(option.group))
 934                 options.add(option);
 935         return Collections.unmodifiableSet(options);
 936     }
 937 
 938 }


  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.javac.main;
  27 
  28 import java.io.FileWriter;
  29 import java.io.PrintWriter;
  30 import java.nio.file.Files;
  31 import java.nio.file.Path;
  32 import java.nio.file.Paths;
  33 import java.text.Collator;
  34 import java.util.Arrays;
  35 import java.util.Collections;
  36 import java.util.Comparator;
  37 import java.util.EnumSet;
  38 import java.util.Iterator;
  39 import java.util.LinkedHashMap;
  40 import java.util.Locale;
  41 import java.util.Map;
  42 import java.util.ServiceLoader;
  43 import java.util.Set;
  44 import java.util.TreeSet;
  45 import java.util.stream.Collectors;
  46 import java.util.stream.StreamSupport;
  47 
  48 import javax.lang.model.SourceVersion;
  49 
  50 import com.sun.tools.doclint.DocLint;
  51 import com.sun.tools.javac.code.Lint;
  52 import com.sun.tools.javac.code.Lint.LintCategory;
  53 import com.sun.tools.javac.code.Source;
  54 import com.sun.tools.javac.code.Type;
  55 import com.sun.tools.javac.jvm.Profile;
  56 import com.sun.tools.javac.jvm.Target;
  57 import com.sun.tools.javac.platform.PlatformProvider;
  58 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
  59 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  60 import com.sun.tools.javac.util.Assert;
  61 import com.sun.tools.javac.util.JDK9Wrappers;
  62 import com.sun.tools.javac.util.Log;
  63 import com.sun.tools.javac.util.Log.PrefixKind;
  64 import com.sun.tools.javac.util.Log.WriterKind;
  65 import com.sun.tools.javac.util.Options;
  66 import com.sun.tools.javac.util.StringUtils;
  67 
  68 import static com.sun.tools.javac.main.Option.ChoiceKind.*;
  69 import static com.sun.tools.javac.main.Option.OptionGroup.*;
  70 import static com.sun.tools.javac.main.Option.OptionKind.*;
  71 
  72 /**
  73  * Options for javac.
  74  * The specific Option to handle a command-line option can be found by calling
  75  * {@link #lookup}, which search some or all of the members of this enum in order,
  76  * looking for the first {@link #matches match}.
  77  * The action for an Option is performed {@link #handleOption}, which determines
  78  * whether an argument is needed and where to find it;
  79  * {@code handleOption} then calls {@link #process process} providing a suitable
  80  * {@link OptionHelper} to provide access the compiler state.
  81  *
  82  * <p><b>This is NOT part of any supported API.
  83  * If you write code that depends on this, you do so at your own
  84  * risk.  This code and its internal interfaces are subject to change
  85  * or deletion without notice.</b></p>
  86  */
  87 public enum Option {
  88     G("-g", "opt.g", STANDARD, BASIC),
  89 
  90     G_NONE("-g:none", "opt.g.none", STANDARD, BASIC) {
  91         @Override
  92         public boolean process(OptionHelper helper, String option) {
  93             helper.put("-g:", "none");
  94             return false;
  95         }
  96     },
  97 
  98     G_CUSTOM("-g:",  "opt.g.lines.vars.source",
  99             STANDARD, BASIC, ANYOF, "lines", "vars", "source"),
 100 
 101     XLINT("-Xlint", "opt.Xlint", EXTENDED, BASIC),
 102 
 103     XLINT_CUSTOM("-Xlint:", "opt.arg.Xlint", "opt.Xlint.custom", EXTENDED, BASIC, ANYOF, getXLintChoices()) {
 104         private final String LINT_KEY_FORMAT = LARGE_INDENT + "  %-" +
 105                 (DEFAULT_SYNOPSIS_WIDTH + SMALL_INDENT.length() - LARGE_INDENT.length() - 2) + "s %s";
 106         @Override
 107         protected void help(Log log) {
 108             super.help(log);






 109             log.printRawLines(WriterKind.STDOUT,
 110                               String.format(LINT_KEY_FORMAT,
 111                                             "all",
 112                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.all")));
 113             for (LintCategory lc : LintCategory.values()) {
 114                 if (lc.hidden) continue;
 115                 log.printRawLines(WriterKind.STDOUT,
 116                                   String.format(LINT_KEY_FORMAT,
 117                                                 lc.option,
 118                                                 log.localize(PrefixKind.JAVAC,
 119                                                              "opt.Xlint.desc." + lc.option)));
 120             }
 121             log.printRawLines(WriterKind.STDOUT,
 122                               String.format(LINT_KEY_FORMAT,
 123                                             "none",
 124                                             log.localize(PrefixKind.JAVAC, "opt.Xlint.none")));
 125         }
 126     },
 127 
 128     XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC),
 129 
 130     XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) {
 131         @Override
 132         public boolean matches(String option) {
 133             return DocLint.isValidOption(
 134                     option.replace(XDOCLINT_CUSTOM.primaryName, DocLint.XMSGS_CUSTOM_PREFIX));
 135         }
 136 
 137         @Override
 138         public boolean process(OptionHelper helper, String option) {
 139             String prev = helper.get(XDOCLINT_CUSTOM);
 140             String next = (prev == null) ? option : (prev + " " + option);
 141             helper.put(XDOCLINT_CUSTOM.primaryName, next);
 142             return false;
 143         }
 144     },
 145 
 146     XDOCLINT_PACKAGE("-Xdoclint/package:", "opt.Xdoclint.package.args", "opt.Xdoclint.package.desc", EXTENDED, BASIC) {
 147         @Override
 148         public boolean matches(String option) {
 149             return DocLint.isValidOption(
 150                     option.replace(XDOCLINT_PACKAGE.primaryName, DocLint.XCHECK_PACKAGE));
 151         }
 152 
 153         @Override
 154         public boolean process(OptionHelper helper, String option) {
 155             String prev = helper.get(XDOCLINT_PACKAGE);
 156             String next = (prev == null) ? option : (prev + " " + option);
 157             helper.put(XDOCLINT_PACKAGE.primaryName, next);
 158             return false;
 159         }
 160     },
 161 
 162     // -nowarn is retained for command-line backward compatibility
 163     NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) {
 164         @Override
 165         public boolean process(OptionHelper helper, String option) {
 166             helper.put("-Xlint:none", option);
 167             return false;
 168         }
 169     },
 170 
 171     VERBOSE("-verbose", "opt.verbose", STANDARD, BASIC),
 172 
 173     // -deprecation is retained for command-line backward compatibility
 174     DEPRECATION("-deprecation", "opt.deprecation", STANDARD, BASIC) {
 175         @Override
 176         public boolean process(OptionHelper helper, String option) {
 177             helper.put("-Xlint:deprecation", option);
 178             return false;
 179         }
 180     },
 181 
 182     CLASS_PATH("--class-path -classpath -cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER),
 183 
 184     SOURCE_PATH("--source-path -sourcepath", "opt.arg.path", "opt.sourcepath", STANDARD, FILEMANAGER),





 185 
 186     MODULE_SOURCE_PATH("--module-source-path -modulesourcepath", "opt.arg.mspath", "opt.modulesourcepath", STANDARD, FILEMANAGER),
 187 
 188     MODULE_PATH("--module-path -p -modulepath -mp", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER),
 189 
 190     UPGRADE_MODULE_PATH("--upgrade-module-path -upgrademodulepath", "opt.arg.path", "opt.upgrademodulepath", STANDARD, FILEMANAGER),
 191 
 192     SYSTEM("--system -system", "opt.arg.jdk", "opt.system", STANDARD, FILEMANAGER),
 193 
 194     PATCH_MODULE("--patch-module -Xpatch:", "opt.arg.patch", "opt.patch", EXTENDED, FILEMANAGER) {
 195         // The deferred filemanager diagnostics mechanism assumes a single value per option,
 196         // but --patch-module can be used multiple times, once per module. Therefore we compose
 197         // a value for the option containing the last value specified for each module, and separate
 198         // the the module=path pairs by an invalid path character, NULL.
 199         // The standard file manager code knows to split apart the NULL-separated components.
 200         @Override
 201         public boolean process(OptionHelper helper, String option, String arg) {
 202             if (!arg.contains("=")) { // could be more strict regeex, e.g. "(?i)[a-z0-9_.]+=.*"
 203                 helper.error(Errors.LocnInvalidArgForXpatch(arg));
 204             }

 205 
 206             String previous = helper.get(this);
 207             if (previous == null) {
 208                 return super.process(helper, option, arg);
 209             }
 210 
 211             Map<String,String> map = new LinkedHashMap<>();
 212             for (String s : previous.split("\0")) {
 213                 int sep = s.indexOf('=');
 214                 map.put(s.substring(0, sep), s.substring(sep + 1));
 215             }
 216 
 217             int sep = arg.indexOf('=');
 218             map.put(arg.substring(0, sep), arg.substring(sep + 1));
 219 
 220             StringBuilder sb = new StringBuilder();
 221             map.forEach((m, p) -> {
 222                 if (sb.length() > 0)
 223                     sb.append('\0');
 224                 sb.append(m).append('=').append(p);
 225             });
 226             return super.process(helper, option, sb.toString());
 227         }
 228     },
 229 
 230     BOOT_CLASS_PATH("--boot-class-path -bootclasspath", "opt.arg.path", "opt.bootclasspath", STANDARD, FILEMANAGER) {
 231         @Override
 232         public boolean process(OptionHelper helper, String option, String arg) {
 233             helper.remove("-Xbootclasspath/p:");
 234             helper.remove("-Xbootclasspath/a:");
 235             return super.process(helper, option, arg);
 236         }
 237     },
 238 
 239     XBOOTCLASSPATH_PREPEND("-Xbootclasspath/p:", "opt.arg.path", "opt.Xbootclasspath.p", EXTENDED, FILEMANAGER),
 240 
 241     XBOOTCLASSPATH_APPEND("-Xbootclasspath/a:", "opt.arg.path", "opt.Xbootclasspath.a", EXTENDED, FILEMANAGER),
 242 
 243     XBOOTCLASSPATH("-Xbootclasspath:", "opt.arg.path", "opt.bootclasspath", EXTENDED, FILEMANAGER) {
 244         @Override
 245         public boolean process(OptionHelper helper, String option, String arg) {
 246             helper.remove("-Xbootclasspath/p:");
 247             helper.remove("-Xbootclasspath/a:");
 248             return super.process(helper, "-bootclasspath", arg);
 249         }
 250     },
 251 
 252     EXTDIRS("-extdirs", "opt.arg.dirs", "opt.extdirs", STANDARD, FILEMANAGER),
 253 
 254     DJAVA_EXT_DIRS("-Djava.ext.dirs=", "opt.arg.dirs", "opt.extdirs", EXTENDED, FILEMANAGER) {
 255         @Override
 256         public boolean process(OptionHelper helper, String option, String arg) {
 257             return EXTDIRS.process(helper, "-extdirs", arg);
 258         }
 259     },
 260 
 261     ENDORSEDDIRS("-endorseddirs", "opt.arg.dirs", "opt.endorseddirs", STANDARD, FILEMANAGER),
 262 
 263     DJAVA_ENDORSED_DIRS("-Djava.endorsed.dirs=", "opt.arg.dirs", "opt.endorseddirs", EXTENDED, FILEMANAGER) {
 264         @Override
 265         public boolean process(OptionHelper helper, String option, String arg) {
 266             return ENDORSEDDIRS.process(helper, "-endorseddirs", arg);
 267         }
 268     },
 269 
 270     PROC("-proc:", "opt.proc.none.only", STANDARD, BASIC,  ONEOF, "none", "only"),
 271 
 272     PROCESSOR("-processor", "opt.arg.class.list", "opt.processor", STANDARD, BASIC),
 273 
 274     PROCESSOR_PATH("--processor-path -processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER),
 275 
 276     PROCESSOR_MODULE_PATH("--processor-module-path -processormodulepath", "opt.arg.path", "opt.processormodulepath", STANDARD, FILEMANAGER),
 277 
 278     PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC),
 279 
 280     D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER),
 281 
 282     S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER),
 283 
 284     H("-h", "opt.arg.directory", "opt.headerDest", STANDARD, FILEMANAGER),
 285 
 286     IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"),
 287 
 288     ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER),
 289 
 290     SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
 291         @Override
 292         public boolean process(OptionHelper helper, String option, String operand) {
 293             Source source = Source.lookup(operand);
 294             if (source == null) {
 295                 helper.error("err.invalid.source", operand);
 296                 return true;
 297             }
 298             return super.process(helper, option, operand);
 299         }
 300     },
 301 
 302     TARGET("-target", "opt.arg.release", "opt.target", STANDARD, BASIC) {
 303         @Override
 304         public boolean process(OptionHelper helper, String option, String operand) {
 305             Target target = Target.lookup(operand);
 306             if (target == null) {
 307                 helper.error("err.invalid.target", operand);
 308                 return true;
 309             }
 310             return super.process(helper, option, operand);
 311         }
 312     },
 313 
 314     RELEASE("--release -release", "opt.arg.release", "opt.release", STANDARD, BASIC) {
 315         @Override
 316         protected void help(Log log) {



 317             Iterable<PlatformProvider> providers =
 318                     ServiceLoader.load(PlatformProvider.class, Arguments.class.getClassLoader());
 319             Set<String> platforms = StreamSupport.stream(providers.spliterator(), false)
 320                                                  .flatMap(provider -> StreamSupport.stream(provider.getSupportedPlatformNames()
 321                                                                                                    .spliterator(),
 322                                                                                            false))
 323                                                  .collect(Collectors.toCollection(TreeSet :: new));
 324 
 325             StringBuilder targets = new StringBuilder();
 326             String delim = "";
 327             for (String platform : platforms) {
 328                 targets.append(delim);
 329                 targets.append(platform);
 330                 delim = ", ";
 331             }
 332 
 333             super.help(log, log.localize(PrefixKind.JAVAC, descrKey, targets.toString()));



 334         }
 335     },
 336 
 337     PROFILE("-profile", "opt.arg.profile", "opt.profile", STANDARD, BASIC) {
 338         @Override
 339         public boolean process(OptionHelper helper, String option, String operand) {
 340             Profile profile = Profile.lookup(operand);
 341             if (profile == null) {
 342                 helper.error("err.invalid.profile", operand);
 343                 return true;
 344             }
 345             return super.process(helper, option, operand);
 346         }
 347     },
 348 
 349     VERSION("-version", "opt.version", STANDARD, INFO) {
 350         @Override
 351         public boolean process(OptionHelper helper, String option) {
 352             Log log = helper.getLog();
 353             String ownName = helper.getOwnName();
 354             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "version", ownName,  JavaCompiler.version());
 355             return super.process(helper, option);
 356         }
 357     },
 358 
 359     FULLVERSION("-fullversion", null, HIDDEN, INFO) {
 360         @Override
 361         public boolean process(OptionHelper helper, String option) {
 362             Log log = helper.getLog();
 363             String ownName = helper.getOwnName();
 364             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "fullVersion", ownName,  JavaCompiler.fullVersion());
 365             return super.process(helper, option);
 366         }
 367     },
 368 
 369     // Note: -h is already taken for "native header output directory".
 370     HELP("--help -help", "opt.help", STANDARD, INFO) {
 371         @Override
 372         public boolean process(OptionHelper helper, String option) {
 373             Log log = helper.getLog();
 374             String ownName = helper.getOwnName();
 375             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.header", ownName);
 376             showHelp(log, OptionKind.STANDARD);


 377             log.printNewline(WriterKind.STDOUT);
 378             return super.process(helper, option);
 379         }
 380     },
 381 
 382     A("-A", "opt.arg.key.equals.value", "opt.A", STANDARD, BASIC, ArgKind.ADJACENT) {
 383         @Override
 384         public boolean matches(String arg) {
 385             return arg.startsWith("-A");
 386         }
 387 
 388         @Override
 389         public boolean hasArg() {
 390             return false;
 391         }
 392         // Mapping for processor options created in
 393         // JavacProcessingEnvironment
 394         @Override
 395         public boolean process(OptionHelper helper, String option) {
 396             int argLength = option.length();
 397             if (argLength == 2) {
 398                 helper.error("err.empty.A.argument");
 399                 return true;
 400             }
 401             int sepIndex = option.indexOf('=');
 402             String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) );
 403             if (!JavacProcessingEnvironment.isValidOptionName(key)) {
 404                 helper.error("err.invalid.A.key", option);
 405                 return true;
 406             }
 407             helper.put(option, option);
 408             return false;
 409         }
 410     },
 411 
 412     X("-X", "opt.X", STANDARD, INFO) {
 413         @Override
 414         public boolean process(OptionHelper helper, String option) {
 415             Log log = helper.getLog();
 416             showHelp(log, OptionKind.EXTENDED);


 417             log.printNewline(WriterKind.STDOUT);
 418             log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.nonstandard.footer");
 419             return super.process(helper, option);
 420         }
 421     },
 422 
 423     // This option exists only for the purpose of documenting itself.
 424     // It's actually implemented by the launcher.
 425     J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, ArgKind.ADJACENT) {
 426         @Override
 427         public boolean process(OptionHelper helper, String option) {
 428             throw new AssertionError
 429                 ("the -J flag should be caught by the launcher.");
 430         }
 431     },
 432 
 433     MOREINFO("-moreinfo", null, HIDDEN, BASIC) {
 434         @Override
 435         public boolean process(OptionHelper helper, String option) {
 436             Type.moreInfo = true;
 437             return super.process(helper, option);
 438         }
 439     },
 440 
 441     // treat warnings as errors
 442     WERROR("-Werror", "opt.Werror", STANDARD, BASIC),
 443 
 444     // prompt after each error
 445     // new Option("-prompt",                                        "opt.prompt"),


 485     XPRINTPROCESSORINFO("-XprintProcessorInfo", "opt.printProcessorInfo", EXTENDED, BASIC),
 486 
 487     XPREFER("-Xprefer:", "opt.prefer", EXTENDED, BASIC, ONEOF, "source", "newer"),
 488 
 489     XXUSERPATHSFIRST("-XXuserPathsFirst", "opt.userpathsfirst", HIDDEN, BASIC),
 490 
 491     // see enum PkgInfo
 492     XPKGINFO("-Xpkginfo:", "opt.pkginfo", EXTENDED, BASIC, ONEOF, "always", "legacy", "nonempty"),
 493 
 494     /* -O is a no-op, accepted for backward compatibility. */
 495     O("-O", null, HIDDEN, BASIC),
 496 
 497     /* -Xjcov produces tables to support the code coverage tool jcov. */
 498     XJCOV("-Xjcov", null, HIDDEN, BASIC),
 499 
 500     PLUGIN("-Xplugin:", "opt.arg.plugin", "opt.plugin", EXTENDED, BASIC) {
 501         @Override
 502         public boolean process(OptionHelper helper, String option) {
 503             String p = option.substring(option.indexOf(':') + 1).trim();
 504             String prev = helper.get(PLUGIN);
 505             helper.put(PLUGIN.primaryName, (prev == null) ? p : prev + '\0' + p);
 506             return false;
 507         }
 508     },
 509 
 510     XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"),
 511 
 512     XDEBUG("-Xdebug:", null, HIDDEN, BASIC) {
 513         @Override
 514         public boolean process(OptionHelper helper, String option) {
 515             String p = option.substring(option.indexOf(':') + 1).trim();
 516             String[] subOptions = p.split(";");
 517             for (String subOption : subOptions) {
 518                 subOption = "debug." + subOption.trim();
 519                 XD.process(helper, subOption, subOption);
 520             }
 521             return false;
 522         }
 523     },
 524 
 525     XSHOULDSTOP("-Xshouldstop:", null, HIDDEN, BASIC) {
 526         @Override
 527         public boolean process(OptionHelper helper, String option) {
 528             String p = option.substring(option.indexOf(':') + 1).trim();
 529             String[] subOptions = p.split(";");
 530             for (String subOption : subOptions) {
 531                 subOption = "shouldstop." + subOption.trim();
 532                 XD.process(helper, subOption, subOption);
 533             }
 534             return false;
 535         }
 536     },
 537 
 538     DIAGS("-diags:", null, HIDDEN, BASIC) {
 539         @Override
 540         public boolean process(OptionHelper helper, String option) {
 541             return HiddenGroup.DIAGS.process(helper, option);
 542         }
 543     },
 544 
 545     /* This is a back door to the compiler's option table.
 546      * -XDx=y sets the option x to the value y.
 547      * -XDx sets the option x to the value x.
 548      */
 549     XD("-XD", null, HIDDEN, BASIC) {
 550         @Override
 551         public boolean matches(String s) {
 552             return s.startsWith(primaryName);
 553         }
 554         @Override
 555         public boolean process(OptionHelper helper, String option) {
 556             return process(helper, option, option.substring(primaryName.length()));
 557         }
 558 
 559         @Override
 560         public boolean process(OptionHelper helper, String option, String arg) {
 561             int eq = arg.indexOf('=');
 562             String key = (eq < 0) ? arg : arg.substring(0, eq);
 563             String value = (eq < 0) ? arg : arg.substring(eq+1);
 564             helper.put(key, value);
 565             return false;
 566         }
 567     },
 568 
 569     ADD_EXPORTS("--add-exports -XaddExports:", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) {
 570         @Override
 571         public boolean process(OptionHelper helper, String option, String arg) {
 572             String prev = helper.get(ADD_EXPORTS);
 573             helper.put(ADD_EXPORTS.primaryName, (prev == null) ? arg : prev + '\0' + arg);

 574             return false;
 575         }
 576     },
 577 
 578     ADD_READS("--add-reads -XaddReads:", "opt.arg.addReads", "opt.addReads", EXTENDED, BASIC) {
 579         @Override
 580         public boolean process(OptionHelper helper, String option, String arg) {
 581             String prev = helper.get(ADD_READS);
 582             helper.put(ADD_READS.primaryName, (prev == null) ? arg : prev + '\0' + arg);

 583             return false;
 584         }
 585     },
 586 
 587     XMODULE("-Xmodule:", "opt.arg.module", "opt.module", EXTENDED, BASIC) {
 588         @Override
 589         public boolean process(OptionHelper helper, String option, String arg) {
 590             String prev = helper.get(XMODULE);
 591             if (prev != null) {
 592                 helper.error("err.option.too.many", XMODULE.primaryName);
 593             }
 594             helper.put(XMODULE.primaryName, arg);

 595             return false;
 596         }
 597     },
 598 
 599     MODULE("--module -m", "opt.arg.m", "opt.m", STANDARD, BASIC),
 600 
 601     ADD_MODULES("--add-modules -addmods", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC),
 602 
 603     LIMIT_MODULES("--limit-modules -limitmods", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC),
 604 
 605     // This option exists only for the purpose of documenting itself.
 606     // It's actually implemented by the CommandLine class.
 607     AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, ArgKind.ADJACENT) {
 608         @Override
 609         public boolean process(OptionHelper helper, String option) {
 610             throw new AssertionError("the @ flag should be caught by CommandLine.");
 611         }
 612     },
 613 
 614     // Standalone positional argument: source file or type name.
 615     SOURCEFILE("sourcefile", null, HIDDEN, INFO) {
 616         @Override
 617         public boolean matches(String s) {
 618             if (s.endsWith(".java"))  // Java source file
 619                 return true;
 620             int sep = s.indexOf('/');
 621             if (sep != -1) {
 622                 return SourceVersion.isName(s.substring(0, sep))
 623                         && SourceVersion.isName(s.substring(sep + 1));
 624             } else {
 625                 return SourceVersion.isName(s);   // Legal type name
 626             }
 627         }
 628         @Override
 629         public boolean process(OptionHelper helper, String option) {
 630             if (option.endsWith(".java") ) {
 631                 Path p = Paths.get(option);
 632                 if (!Files.exists(p)) {
 633                     helper.error("err.file.not.found", p);
 634                     return true;
 635                 }
 636                 if (!Files.isRegularFile(p)) {
 637                     helper.error("err.file.not.file", p);
 638                     return true;
 639                 }
 640                 helper.addFile(p);
 641             } else {
 642                 helper.addClassName(option);
 643             }
 644             return false;
 645         }
 646     },
 647 
 648     MULTIRELEASE("--multi-release -multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER),
 649 
 650     INHERIT_RUNTIME_ENVIRONMENT("--inherit-runtime-environment", "opt.inherit_runtime_environment",
 651             EXTENDED, BASIC) {
 652         @Override
 653         public boolean process(OptionHelper helper, String option) {
 654             try {
 655                 Class.forName(JDK9Wrappers.VMHelper.VM_CLASSNAME);
 656                 String[] runtimeArgs = JDK9Wrappers.VMHelper.getRuntimeArguments();
 657                 for (String arg : runtimeArgs) {
 658                     // Handle any supported runtime options; ignore all others.
 659                     // The runtime arguments always use the single token form, e.g. "--name=value".
 660                     for (Option o : getSupportedRuntimeOptions()) {
 661                         if (o.matches(arg)) {
 662                             o.handleOption(helper, arg, Collections.emptyIterator());
 663                             break;
 664                         }
 665                     }
 666                 }
 667             } catch (ClassNotFoundException | SecurityException e) {
 668                 helper.error("err.cannot.access.runtime.env");
 669             }
 670             return false;
 671         }
 672 
 673         private Option[] getSupportedRuntimeOptions() {
 674             Option[] supportedRuntimeOptions = {
 675                 ADD_EXPORTS,
 676                 ADD_MODULES,
 677                 LIMIT_MODULES,
 678                 MODULE_PATH,
 679                 UPGRADE_MODULE_PATH,
 680                 PATCH_MODULE
 681             };
 682             return supportedRuntimeOptions;
 683         }
 684     };
 685 
 686     /**
 687      * The kind of argument, if any, accepted by this option. The kind is augmented
 688      * by characters in the name of the option.
 689      */
 690     public enum ArgKind {
 691         /** This option does not take any argument. */
 692         NONE,
 693 
 694 // Not currently supported
 695 //        /**
 696 //         * This option takes an optional argument, which may be provided directly after an '='
 697 //         * separator, or in the following argument position if that word does not itself appear
 698 //         * to be the name of an option.
 699 //         */
 700 //        OPTIONAL,
 701 
 702         /**
 703          * This option takes an argument.
 704          * If the name of option ends with ':' or '=', the argument must be provided directly
 705          * after that separator.
 706          * Otherwise, if may appear after an '=' or in the following argument position.
 707          */
 708         REQUIRED,
 709 
 710         /**
 711          * This option takes an argument immediately after the option name, with no separator
 712          * character.
 713          */
 714         ADJACENT
 715     }
 716 
 717     /**
 718      * The kind of an Option. This is used by the -help and -X options.
 719      */
 720     public enum OptionKind {
 721         /** A standard option, documented by -help. */
 722         STANDARD,
 723         /** An extended option, documented by -X. */
 724         EXTENDED,
 725         /** A hidden option, not documented. */
 726         HIDDEN,
 727     }
 728 
 729     /**
 730      * The group for an Option. This determines the situations in which the
 731      * option is applicable.
 732      */
 733     enum OptionGroup {
 734         /** A basic option, available for use on the command line or via the
 735          *  Compiler API. */
 736         BASIC,
 737         /** An option for javac's standard JavaFileManager. Other file managers
 738          *  may or may not support these options. */
 739         FILEMANAGER,
 740         /** A command-line option that requests information, such as -help. */
 741         INFO,
 742         /** A command-line "option" representing a file or class name. */
 743         OPERAND
 744     }
 745 
 746     /**
 747      * The kind of choice for "choice" options.
 748      */
 749     enum ChoiceKind {
 750         /** The expected value is exactly one of the set of choices. */
 751         ONEOF,
 752         /** The expected value is one of more of the set of choices. */
 753         ANYOF
 754     }
 755 
 756     enum HiddenGroup {
 757         DIAGS("diags");
 758 
 759         final String text;
 760 
 761         HiddenGroup(String text) {
 762             this.text = text;
 763         }
 764 
 765         public boolean process(OptionHelper helper, String option) {
 766             String p = option.substring(option.indexOf(':') + 1).trim();
 767             String[] subOptions = p.split(";");
 768             for (String subOption : subOptions) {
 769                 subOption = text + "." + subOption.trim();
 770                 XD.process(helper, subOption, subOption);
 771             }
 772             return false;
 773         }
 774     }
 775 
 776     /**
 777      * The "primary name" for this option.
 778      * This is the name that is used to put values in the {@link Options} table.
 779      */
 780     public final String primaryName;
 781 
 782     /**
 783      * The set of names (primary name and aliases) for this option.
 784      * Note that some names may end in a separator, to indicate that an argument must immediately
 785      * follow the separator (and cannot appear in the following argument position.
 786      */
 787     public final String[] names;
 788 
 789     /** Documentation key for arguments. */
 790     protected final String argsNameKey;
 791 
 792     /** Documentation key for description.
 793      */
 794     protected final String descrKey;
 795 
 796     /** The kind of this option. */
 797     private final OptionKind kind;

 798 
 799     /** The group for this option. */
 800     private final OptionGroup group;

 801 
 802     /** The kind of argument for this option. */
 803     private final ArgKind argKind;
 804 
 805     /** The kind of choices for this option, if any. */
 806     private final ChoiceKind choiceKind;
 807 
 808     /** The choices for this option, if any, and whether or not the choices are hidden. */
 809     private final Map<String,Boolean> choices;
 810 
 811     /**
 812      * Looks up the first option matching the given argument in the full set of options.
 813      * @param arg the argument to be matches
 814      * @return the first option that matches, or null if none.
 815      */
 816     public static Option lookup(String arg) {
 817         return lookup(arg, EnumSet.allOf(Option.class));
 818     }
 819 
 820     /**
 821      * Looks up the first option matching the given argument within a set of options.
 822      * @param arg the argument to be matches
 823      * @return the first option that matches, or null if none.
 824      */
 825     public static Option lookup(String arg, Set<Option> options) {
 826         for (Option option: options) {
 827             if (option.matches(arg))
 828                 return option;
 829         }
 830         return null;
 831     }
 832 
 833     /**
 834      * Writes the "command line help" for given kind of option to the log.
 835      * @param log the log
 836      * @param kind  the kind of options to select
 837      */
 838     private static void showHelp(Log log, OptionKind kind) {
 839         Comparator<Option> comp = new Comparator<Option>() {
 840             final Collator collator = Collator.getInstance(Locale.US);
 841             { collator.setStrength(Collator.PRIMARY); }
 842 
 843             @Override
 844             public int compare(Option o1, Option o2) {
 845                 return collator.compare(o1.primaryName, o2.primaryName);
 846             }
 847         };
 848 
 849         getJavaCompilerOptions()
 850                 .stream()
 851                 .filter(o -> o.kind == kind)
 852                 .sorted(comp)
 853                 .forEach(o -> {
 854                     o.help(log);
 855                 });
 856     }
 857 
 858     Option(String text, String descrKey,
 859             OptionKind kind, OptionGroup group) {
 860         this(text, null, descrKey, kind, group, null, null, ArgKind.NONE);

 861     }
 862 
 863     Option(String text, String argsNameKey, String descrKey,
 864             OptionKind kind, OptionGroup group) {
 865         this(text, argsNameKey, descrKey, kind, group, null, null, ArgKind.REQUIRED);
 866     }
 867 
 868     Option(String text, String argsNameKey, String descrKey,
 869             OptionKind kind, OptionGroup group, ArgKind ak) {
 870         this(text, argsNameKey, descrKey, kind, group, null, null, ak);
 871     }
 872 
 873     Option(String text, String argsNameKey, String descrKey, OptionKind kind, OptionGroup group,
 874             ChoiceKind choiceKind, Map<String,Boolean> choices) {
 875         this(text, argsNameKey, descrKey, kind, group, choiceKind, choices, ArgKind.REQUIRED);
 876     }
 877 
 878     Option(String text, String descrKey,
 879             OptionKind kind, OptionGroup group,
 880             ChoiceKind choiceKind, String... choices) {
 881         this(text, null, descrKey, kind, group, choiceKind,
 882                 createChoices(choices), ArgKind.REQUIRED);
 883     }
 884     // where
 885         private static Map<String,Boolean> createChoices(String... choices) {
 886             Map<String,Boolean> map = new LinkedHashMap<>();
 887             for (String c: choices)
 888                 map.put(c, false);
 889             return map;
 890         }
 891 
 892     private Option(String text, String argsNameKey, String descrKey,
 893             OptionKind kind, OptionGroup group,
 894             ChoiceKind choiceKind, Map<String,Boolean> choices,
 895             ArgKind argKind) {
 896         this.names = text.trim().split("\\s+");
 897         Assert.check(names.length >= 1);
 898         this.primaryName = names[0];
 899         this.argsNameKey = argsNameKey;
 900         this.descrKey = descrKey;
 901         this.kind = kind;
 902         this.group = group;
 903         this.choiceKind = choiceKind;
 904         this.choices = choices;
 905         this.argKind = argKind;

 906     }
 907 
 908     public String getPrimaryName() {
 909         return primaryName;
 910     }
 911 
 912     public OptionKind getKind() {
 913         return kind;
 914     }
 915 
 916     public ArgKind getArgKind() {
 917         return argKind;
 918     }
 919 
 920     public boolean hasArg() {
 921 //        return argsNameKey != null && !hasSuffix;
 922         return (argKind != ArgKind.NONE);
 923     }
 924 
 925     public boolean matches(String option) {
 926         for (String name: names) {
 927             if (matches(option, name))
 928                 return true;
 929         }
 930         return false;
 931     }
 932 
 933     private boolean matches(String option, String name) {
 934         if (name.startsWith("--")) {
 935             return option.equals(name)
 936                     || hasArg() && option.startsWith(name + "=");
 937         }
 938 
 939         boolean hasSuffix = (argKind == ArgKind.ADJACENT)
 940                 || name.endsWith(":") || name.endsWith("=");
 941 
 942         if (!hasSuffix)
 943             return option.equals(name);
 944 
 945         if (!option.startsWith(name))
 946             return false;
 947 
 948         if (choices != null) {
 949             String arg = option.substring(name.length());
 950             if (choiceKind == ChoiceKind.ONEOF)
 951                 return choices.keySet().contains(arg);
 952             else {
 953                 for (String a: arg.split(",+")) {
 954                     if (!choices.keySet().contains(a))
 955                         return false;
 956                 }
 957             }
 958         }
 959 
 960         return true;
 961     }
 962 
 963     /**
 964      * Handles an option.
 965      * If an argument for the option is required, depending on spec of the option, it will be found
 966      * as part of the current arg (following ':' or '=') or in the following argument.
 967      * This is the recommended way to handle an option directly, instead of calling the underlying
 968      * {@link #process process} methods.
 969      * @param helper a helper to provide access to the environment
 970      * @param arg the arg string that identified this option
 971      * @param rest the remaining strings to be analysed
 972      * @return true if the operation was successful, and false otherwise
 973      * @implNote The return value is the opposite of that used by {@link #process}.
 974      */
 975     public boolean handleOption(OptionHelper helper, String arg, Iterator<String> rest) {
 976         if (hasArg()) {
 977             String operand;
 978             int sep = findSeparator(arg);
 979             if (getArgKind() == Option.ArgKind.ADJACENT) {
 980                 operand = arg.substring(primaryName.length());
 981             } else if (sep > 0) {
 982                 operand = arg.substring(sep + 1);
 983             } else {
 984                 if (!rest.hasNext()) {
 985                     helper.error("err.req.arg", arg);
 986                     return false;
 987                 }
 988                 operand = rest.next();
 989             }
 990             return !process(helper, arg, operand);
 991         } else {
 992             return !process(helper, arg);
 993         }
 994     }
 995 
 996     /**
 997      * Processes an option that either does not need an argument,
 998      * or which contains an argument within it, following a separator.
 999      * @param helper a helper to provide access to the environment
1000      * @param option the option to be processed
1001      * @return true if an error occurred
1002      */
1003     public boolean process(OptionHelper helper, String option) {
1004         if (argKind == ArgKind.NONE) {
1005             return process(helper, primaryName, option);
1006         } else {
1007             int sep = findSeparator(option);
1008             return process(helper, primaryName, option.substring(sep + 1));
1009         }
1010     }
1011 
1012     /**
1013      * Processes an option by updating the environment via a helper object.
1014      * @param helper a helper to provide access to the environment
1015      * @param option the option to be processed
1016      * @param arg the value to associate with the option, or a default value
1017      *  to be used if the option does not otherwise take an argument.
1018      * @return true if an error occurred
1019      */
1020     public boolean process(OptionHelper helper, String option, String arg) {
1021         if (choices != null) {
1022             if (choiceKind == ChoiceKind.ONEOF) {
1023                 // some clients like to see just one of option+choice set
1024                 for (String s: choices.keySet())
1025                     helper.remove(primaryName + s);
1026                 String opt = primaryName + arg;
1027                 helper.put(opt, opt);
1028                 // some clients like to see option (without trailing ":")
1029                 // set to arg
1030                 String nm = primaryName.substring(0, primaryName.length() - 1);
1031                 helper.put(nm, arg);
1032             } else {
1033                 // set option+word for each word in arg
1034                 for (String a: arg.split(",+")) {
1035                     String opt = primaryName + a;
1036                     helper.put(opt, opt);
1037                 }
1038             }
1039         }
1040         helper.put(primaryName, arg);
1041         if (group == OptionGroup.FILEMANAGER)
1042             helper.handleFileManagerOption(this, arg);
1043         return false;
1044     }
1045 
1046     /**
1047      * Scans a word to find the first separator character, either colon or equals.
1048      * @param word the word to be scanned
1049      * @return the position of the first':' or '=' character in the word,
1050      *  or -1 if none found
1051      */
1052     private static int findSeparator(String word) {
1053         for (int i = 0; i < word.length(); i++) {
1054             switch (word.charAt(i)) {
1055                 case ':': case '=':
1056                     return i;
1057             }
1058         }
1059         return -1;
1060     }
1061 
1062     /** The indent for the option synopsis. */
1063     private static final String SMALL_INDENT = "  ";
1064     /** The automatic indent for the description. */
1065     private static final String LARGE_INDENT = "        ";
1066     /** The space allowed for the synopsis, if the description is to be shown on the same line. */
1067     private static final int DEFAULT_SYNOPSIS_WIDTH = 28;
1068     /** The nominal maximum line length, when seeing if text will fit on a line. */
1069     private static final int DEFAULT_MAX_LINE_LENGTH = 80;
1070     /** The format for a single-line help entry. */
1071     private static final String COMPACT_FORMAT = SMALL_INDENT + "%-" + DEFAULT_SYNOPSIS_WIDTH + "s %s";
1072 
1073     /**
1074      * Writes help text for this option to the log.
1075      * @param log the log
1076      */
1077     protected void help(Log log) {
1078         help(log, log.localize(PrefixKind.JAVAC, descrKey));
1079     }
1080 
1081     protected void help(Log log, String descr) {
1082         String synopses = Arrays.stream(names)
1083                 .map(s -> helpSynopsis(s, log))
1084                 .collect(Collectors.joining(", "));
1085 
1086         // If option synopses and description fit on a single line of reasonable length,
1087         // display using COMPACT_FORMAT
1088         if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH
1089                 && !descr.contains("\n")
1090                 && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + descr.length() <= DEFAULT_MAX_LINE_LENGTH)) {
1091             log.printRawLines(WriterKind.STDOUT, String.format(COMPACT_FORMAT, synopses, descr));
1092             return;
1093         }
1094 
1095         // If option synopses fit on a single line of reasonable length, show that;
1096         // otherwise, show 1 per line
1097         if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) {
1098             log.printRawLines(WriterKind.STDOUT, SMALL_INDENT + synopses);
1099         } else {
1100             for (String name: names) {
1101                 log.printRawLines(WriterKind.STDOUT, SMALL_INDENT + helpSynopsis(name, log));
1102             }
1103         }
1104 
1105         // Finally, show the description
1106         log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT));
1107     }
1108 
1109     /**
1110      * Composes the initial synopsis of one of the forms for this option.
1111      * @param name the name of this form of the option
1112      * @param log the log used to localize the description of the arguments
1113      * @return  the synopsis
1114      */
1115     private String helpSynopsis(String name, Log log) {
1116         StringBuilder sb = new StringBuilder();
1117         sb.append(name);
1118         if (argsNameKey == null) {
1119             if (choices != null) {
1120                 String sep = "{";
1121                 for (Map.Entry<String,Boolean> e: choices.entrySet()) {
1122                     if (!e.getValue()) {
1123                         sb.append(sep);
1124                         sb.append(e.getKey());
1125                         sep = ",";
1126                     }
1127                 }
1128                 sb.append("}");
1129             }
1130         } else {
1131             if (!name.matches(".*[=:]$") && argKind != ArgKind.ADJACENT)
1132                 sb.append(" ");
1133             sb.append(log.localize(PrefixKind.JAVAC, argsNameKey));

1134         }
1135 
1136         return sb.toString();
1137     }
1138 
1139     // For -XpkgInfo:value
1140     public enum PkgInfo {
1141         /**
1142          * Always generate package-info.class for every package-info.java file.
1143          * The file may be empty if there annotations with a RetentionPolicy
1144          * of CLASS or RUNTIME.  This option may be useful in conjunction with
1145          * build systems (such as Ant) that expect javac to generate at least
1146          * one .class file for every .java file.
1147          */
1148         ALWAYS,
1149         /**
1150          * Generate a package-info.class file if package-info.java contains
1151          * annotations. The file may be empty if all the annotations have
1152          * a RetentionPolicy of SOURCE.
1153          * This value is just for backwards compatibility with earlier behavior.


1162 
1163         public static PkgInfo get(Options options) {
1164             String v = options.get(XPKGINFO);
1165             return (v == null
1166                     ? PkgInfo.LEGACY
1167                     : PkgInfo.valueOf(StringUtils.toUpperCase(v)));
1168         }
1169     }
1170 
1171     private static Map<String,Boolean> getXLintChoices() {
1172         Map<String,Boolean> choices = new LinkedHashMap<>();
1173         choices.put("all", false);
1174         for (Lint.LintCategory c : Lint.LintCategory.values())
1175             choices.put(c.option, c.hidden);
1176         for (Lint.LintCategory c : Lint.LintCategory.values())
1177             choices.put("-" + c.option, c.hidden);
1178         choices.put("none", false);
1179         return choices;
1180     }
1181 
1182     /**
1183      * Returns the set of options supported by the command line tool.
1184      * @return the set of options.
1185      */
1186     static Set<Option> getJavaCompilerOptions() {
1187         return EnumSet.allOf(Option.class);
1188     }
1189 
1190     /**
1191      * Returns the set of options supported by the built-in file manager.
1192      * @return the set of options.
1193      */
1194     public static Set<Option> getJavacFileManagerOptions() {
1195         return getOptions(FILEMANAGER);
1196     }
1197 
1198     /**
1199      * Returns the set of options supported by this implementation of
1200      * the JavaCompiler API, via {@link JavaCompiler#getTask}.
1201      * @return the set of options.
1202      */
1203     public static Set<Option> getJavacToolOptions() {
1204         return getOptions(BASIC);
1205     }
1206 
1207     private static Set<Option> getOptions(OptionGroup group) {
1208         return Arrays.stream(Option.values())
1209                 .filter(o -> o.group == group)
1210                 .collect(Collectors.toCollection(() -> EnumSet.noneOf(Option.class)));


1211     }
1212 
1213 }
< prev index next >