Option.java revision 3823:cd0a8a7a0199
1/* 2 * Copyright (c) 2006, 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 26package com.sun.tools.javac.main; 27 28import java.io.FileWriter; 29import java.io.PrintWriter; 30import java.nio.file.Files; 31import java.nio.file.Path; 32import java.nio.file.Paths; 33import java.text.Collator; 34import java.util.Arrays; 35import java.util.Collections; 36import java.util.Comparator; 37import java.util.EnumSet; 38import java.util.Iterator; 39import java.util.LinkedHashSet; 40import java.util.Locale; 41import java.util.ServiceLoader; 42import java.util.Set; 43import java.util.TreeSet; 44import java.util.regex.Pattern; 45import java.util.stream.Collectors; 46import java.util.stream.StreamSupport; 47 48import javax.lang.model.SourceVersion; 49 50import com.sun.tools.doclint.DocLint; 51import com.sun.tools.javac.code.Lint; 52import com.sun.tools.javac.code.Lint.LintCategory; 53import com.sun.tools.javac.code.Source; 54import com.sun.tools.javac.code.Type; 55import com.sun.tools.javac.jvm.Profile; 56import com.sun.tools.javac.jvm.Target; 57import com.sun.tools.javac.platform.PlatformProvider; 58import com.sun.tools.javac.processing.JavacProcessingEnvironment; 59import com.sun.tools.javac.util.Assert; 60import com.sun.tools.javac.util.JDK9Wrappers; 61import com.sun.tools.javac.util.Log; 62import com.sun.tools.javac.util.Log.PrefixKind; 63import com.sun.tools.javac.util.Log.WriterKind; 64import com.sun.tools.javac.util.Options; 65import com.sun.tools.javac.util.StringUtils; 66 67import static com.sun.tools.javac.main.Option.ChoiceKind.*; 68import static com.sun.tools.javac.main.Option.OptionGroup.*; 69import static com.sun.tools.javac.main.Option.OptionKind.*; 70 71/** 72 * Options for javac. 73 * The specific Option to handle a command-line option can be found by calling 74 * {@link #lookup}, which search some or all of the members of this enum in order, 75 * looking for the first {@link #matches match}. 76 * The action for an Option is performed {@link #handleOption}, which determines 77 * whether an argument is needed and where to find it; 78 * {@code handleOption} then calls {@link #process process} providing a suitable 79 * {@link OptionHelper} to provide access the compiler state. 80 * 81 * <p><b>This is NOT part of any supported API. 82 * If you write code that depends on this, you do so at your own 83 * risk. This code and its internal interfaces are subject to change 84 * or deletion without notice.</b></p> 85 */ 86public enum Option { 87 G("-g", "opt.g", STANDARD, BASIC), 88 89 G_NONE("-g:none", "opt.g.none", STANDARD, BASIC) { 90 @Override 91 public void process(OptionHelper helper, String option) { 92 helper.put("-g:", "none"); 93 } 94 }, 95 96 G_CUSTOM("-g:", "opt.g.lines.vars.source", 97 STANDARD, BASIC, ANYOF, "lines", "vars", "source"), 98 99 XLINT("-Xlint", "opt.Xlint", EXTENDED, BASIC), 100 101 XLINT_CUSTOM("-Xlint:", "opt.arg.Xlint", "opt.Xlint.custom", EXTENDED, BASIC, ANYOF, getXLintChoices()) { 102 private final String LINT_KEY_FORMAT = LARGE_INDENT + " %-" + 103 (DEFAULT_SYNOPSIS_WIDTH + SMALL_INDENT.length() - LARGE_INDENT.length() - 2) + "s %s"; 104 @Override 105 protected void help(Log log) { 106 super.help(log); 107 log.printRawLines(WriterKind.STDOUT, 108 String.format(LINT_KEY_FORMAT, 109 "all", 110 log.localize(PrefixKind.JAVAC, "opt.Xlint.all"))); 111 for (LintCategory lc : LintCategory.values()) { 112 log.printRawLines(WriterKind.STDOUT, 113 String.format(LINT_KEY_FORMAT, 114 lc.option, 115 log.localize(PrefixKind.JAVAC, 116 "opt.Xlint.desc." + lc.option))); 117 } 118 log.printRawLines(WriterKind.STDOUT, 119 String.format(LINT_KEY_FORMAT, 120 "none", 121 log.localize(PrefixKind.JAVAC, "opt.Xlint.none"))); 122 } 123 }, 124 125 XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC), 126 127 XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) { 128 @Override 129 public boolean matches(String option) { 130 return DocLint.isValidOption( 131 option.replace(XDOCLINT_CUSTOM.primaryName, DocLint.XMSGS_CUSTOM_PREFIX)); 132 } 133 134 @Override 135 public void process(OptionHelper helper, String option) { 136 String prev = helper.get(XDOCLINT_CUSTOM); 137 String next = (prev == null) ? option : (prev + " " + option); 138 helper.put(XDOCLINT_CUSTOM.primaryName, next); 139 } 140 }, 141 142 XDOCLINT_PACKAGE("-Xdoclint/package:", "opt.Xdoclint.package.args", "opt.Xdoclint.package.desc", EXTENDED, BASIC) { 143 @Override 144 public boolean matches(String option) { 145 return DocLint.isValidOption( 146 option.replace(XDOCLINT_PACKAGE.primaryName, DocLint.XCHECK_PACKAGE)); 147 } 148 149 @Override 150 public void process(OptionHelper helper, String option) { 151 String prev = helper.get(XDOCLINT_PACKAGE); 152 String next = (prev == null) ? option : (prev + " " + option); 153 helper.put(XDOCLINT_PACKAGE.primaryName, next); 154 } 155 }, 156 157 // -nowarn is retained for command-line backward compatibility 158 NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) { 159 @Override 160 public void process(OptionHelper helper, String option) { 161 helper.put("-Xlint:none", option); 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 void process(OptionHelper helper, String option) { 171 helper.put("-Xlint:deprecation", option); 172 } 173 }, 174 175 CLASS_PATH("--class-path -classpath -cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER), 176 177 SOURCE_PATH("--source-path -sourcepath", "opt.arg.path", "opt.sourcepath", STANDARD, FILEMANAGER), 178 179 MODULE_SOURCE_PATH("--module-source-path", "opt.arg.mspath", "opt.modulesourcepath", STANDARD, FILEMANAGER), 180 181 MODULE_PATH("--module-path -p", "opt.arg.path", "opt.modulepath", STANDARD, FILEMANAGER), 182 183 UPGRADE_MODULE_PATH("--upgrade-module-path", "opt.arg.path", "opt.upgrademodulepath", STANDARD, FILEMANAGER), 184 185 SYSTEM("--system", "opt.arg.jdk", "opt.system", STANDARD, FILEMANAGER), 186 187 PATCH_MODULE("--patch-module", "opt.arg.patch", "opt.patch", EXTENDED, FILEMANAGER) { 188 // The deferred filemanager diagnostics mechanism assumes a single value per option, 189 // but --patch-module can be used multiple times, once per module. Therefore we compose 190 // a value for the option containing the last value specified for each module, and separate 191 // the the module=path pairs by an invalid path character, NULL. 192 // The standard file manager code knows to split apart the NULL-separated components. 193 @Override 194 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 195 if (arg.isEmpty()) { 196 throw helper.newInvalidValueException("err.no.value.for.option", option); 197 } else if (getPattern().matcher(arg).matches()) { 198 String prev = helper.get(PATCH_MODULE); 199 if (prev == null) { 200 super.process(helper, option, arg); 201 } else { 202 String argModulePackage = arg.substring(0, arg.indexOf('=')); 203 boolean isRepeated = Arrays.stream(prev.split("\0")) 204 .map(s -> s.substring(0, s.indexOf('='))) 205 .collect(Collectors.toSet()) 206 .contains(argModulePackage); 207 if (isRepeated) { 208 throw helper.newInvalidValueException("err.repeated.value.for.patch.module", argModulePackage); 209 } else { 210 super.process(helper, option, prev + '\0' + arg); 211 } 212 } 213 } else { 214 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 215 } 216 } 217 218 @Override 219 public Pattern getPattern() { 220 return Pattern.compile("([^/]+)=(,*[^,].*)"); 221 } 222 }, 223 224 BOOT_CLASS_PATH("--boot-class-path -bootclasspath", "opt.arg.path", "opt.bootclasspath", STANDARD, FILEMANAGER) { 225 @Override 226 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 227 helper.remove("-Xbootclasspath/p:"); 228 helper.remove("-Xbootclasspath/a:"); 229 super.process(helper, option, arg); 230 } 231 }, 232 233 XBOOTCLASSPATH_PREPEND("-Xbootclasspath/p:", "opt.arg.path", "opt.Xbootclasspath.p", EXTENDED, FILEMANAGER), 234 235 XBOOTCLASSPATH_APPEND("-Xbootclasspath/a:", "opt.arg.path", "opt.Xbootclasspath.a", EXTENDED, FILEMANAGER), 236 237 XBOOTCLASSPATH("-Xbootclasspath:", "opt.arg.path", "opt.bootclasspath", EXTENDED, FILEMANAGER) { 238 @Override 239 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 240 helper.remove("-Xbootclasspath/p:"); 241 helper.remove("-Xbootclasspath/a:"); 242 super.process(helper, "-bootclasspath", arg); 243 } 244 }, 245 246 EXTDIRS("-extdirs", "opt.arg.dirs", "opt.extdirs", STANDARD, FILEMANAGER), 247 248 DJAVA_EXT_DIRS("-Djava.ext.dirs=", "opt.arg.dirs", "opt.extdirs", EXTENDED, FILEMANAGER) { 249 @Override 250 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 251 EXTDIRS.process(helper, "-extdirs", arg); 252 } 253 }, 254 255 ENDORSEDDIRS("-endorseddirs", "opt.arg.dirs", "opt.endorseddirs", STANDARD, FILEMANAGER), 256 257 DJAVA_ENDORSED_DIRS("-Djava.endorsed.dirs=", "opt.arg.dirs", "opt.endorseddirs", EXTENDED, FILEMANAGER) { 258 @Override 259 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 260 ENDORSEDDIRS.process(helper, "-endorseddirs", arg); 261 } 262 }, 263 264 PROC("-proc:", "opt.proc.none.only", STANDARD, BASIC, ONEOF, "none", "only"), 265 266 PROCESSOR("-processor", "opt.arg.class.list", "opt.processor", STANDARD, BASIC), 267 268 PROCESSOR_PATH("--processor-path -processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER), 269 270 PROCESSOR_MODULE_PATH("--processor-module-path", "opt.arg.path", "opt.processormodulepath", STANDARD, FILEMANAGER), 271 272 PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC), 273 274 D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER), 275 276 S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER), 277 278 H("-h", "opt.arg.directory", "opt.headerDest", STANDARD, FILEMANAGER), 279 280 IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"), 281 282 ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER), 283 284 SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) { 285 @Override 286 public void process(OptionHelper helper, String option, String operand) throws InvalidValueException { 287 Source source = Source.lookup(operand); 288 if (source == null) { 289 throw helper.newInvalidValueException("err.invalid.source", operand); 290 } 291 super.process(helper, option, operand); 292 } 293 }, 294 295 TARGET("-target", "opt.arg.release", "opt.target", STANDARD, BASIC) { 296 @Override 297 public void process(OptionHelper helper, String option, String operand) throws InvalidValueException { 298 Target target = Target.lookup(operand); 299 if (target == null) { 300 throw helper.newInvalidValueException("err.invalid.target", operand); 301 } 302 super.process(helper, option, operand); 303 } 304 }, 305 306 RELEASE("--release", "opt.arg.release", "opt.release", STANDARD, BASIC) { 307 @Override 308 protected void help(Log log) { 309 Iterable<PlatformProvider> providers = 310 ServiceLoader.load(PlatformProvider.class, Arguments.class.getClassLoader()); 311 Set<String> platforms = StreamSupport.stream(providers.spliterator(), false) 312 .flatMap(provider -> StreamSupport.stream(provider.getSupportedPlatformNames() 313 .spliterator(), 314 false)) 315 .collect(Collectors.toCollection(TreeSet :: new)); 316 317 StringBuilder targets = new StringBuilder(); 318 String delim = ""; 319 for (String platform : platforms) { 320 targets.append(delim); 321 targets.append(platform); 322 delim = ", "; 323 } 324 325 super.help(log, log.localize(PrefixKind.JAVAC, descrKey, targets.toString())); 326 } 327 }, 328 329 PROFILE("-profile", "opt.arg.profile", "opt.profile", STANDARD, BASIC) { 330 @Override 331 public void process(OptionHelper helper, String option, String operand) throws InvalidValueException { 332 Profile profile = Profile.lookup(operand); 333 if (profile == null) { 334 throw helper.newInvalidValueException("err.invalid.profile", operand); 335 } 336 super.process(helper, option, operand); 337 } 338 }, 339 340 VERSION("--version -version", "opt.version", STANDARD, INFO) { 341 @Override 342 public void process(OptionHelper helper, String option) throws InvalidValueException { 343 Log log = helper.getLog(); 344 String ownName = helper.getOwnName(); 345 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "version", ownName, JavaCompiler.version()); 346 super.process(helper, option); 347 } 348 }, 349 350 FULLVERSION("--full-version -fullversion", null, HIDDEN, INFO) { 351 @Override 352 public void process(OptionHelper helper, String option) throws InvalidValueException { 353 Log log = helper.getLog(); 354 String ownName = helper.getOwnName(); 355 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "fullVersion", ownName, JavaCompiler.fullVersion()); 356 super.process(helper, option); 357 } 358 }, 359 360 // Note: -h is already taken for "native header output directory". 361 HELP("--help -help", "opt.help", STANDARD, INFO) { 362 @Override 363 public void process(OptionHelper helper, String option) throws InvalidValueException { 364 Log log = helper.getLog(); 365 String ownName = helper.getOwnName(); 366 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.header", ownName); 367 showHelp(log, OptionKind.STANDARD); 368 log.printNewline(WriterKind.STDOUT); 369 super.process(helper, option); 370 } 371 }, 372 373 A("-A", "opt.arg.key.equals.value", "opt.A", STANDARD, BASIC, ArgKind.ADJACENT) { 374 @Override 375 public boolean matches(String arg) { 376 return arg.startsWith("-A"); 377 } 378 379 @Override 380 public boolean hasArg() { 381 return false; 382 } 383 // Mapping for processor options created in 384 // JavacProcessingEnvironment 385 @Override 386 public void process(OptionHelper helper, String option) throws InvalidValueException { 387 int argLength = option.length(); 388 if (argLength == 2) { 389 throw helper.newInvalidValueException("err.empty.A.argument"); 390 } 391 int sepIndex = option.indexOf('='); 392 String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) ); 393 if (!JavacProcessingEnvironment.isValidOptionName(key)) { 394 throw helper.newInvalidValueException("err.invalid.A.key", option); 395 } 396 helper.put(option, option); 397 } 398 }, 399 400 X("--help-extra -X", "opt.X", STANDARD, INFO) { 401 @Override 402 public void process(OptionHelper helper, String option) throws InvalidValueException { 403 Log log = helper.getLog(); 404 showHelp(log, OptionKind.EXTENDED); 405 log.printNewline(WriterKind.STDOUT); 406 log.printLines(WriterKind.STDOUT, PrefixKind.JAVAC, "msg.usage.nonstandard.footer"); 407 super.process(helper, option); 408 } 409 }, 410 411 // This option exists only for the purpose of documenting itself. 412 // It's actually implemented by the launcher. 413 J("-J", "opt.arg.flag", "opt.J", STANDARD, INFO, ArgKind.ADJACENT) { 414 @Override 415 public void process(OptionHelper helper, String option) { 416 throw new AssertionError("the -J flag should be caught by the launcher."); 417 } 418 }, 419 420 MOREINFO("-moreinfo", null, HIDDEN, BASIC) { 421 @Override 422 public void process(OptionHelper helper, String option) throws InvalidValueException { 423 Type.moreInfo = true; 424 super.process(helper, option); 425 } 426 }, 427 428 // treat warnings as errors 429 WERROR("-Werror", "opt.Werror", STANDARD, BASIC), 430 431 // prompt after each error 432 // new Option("-prompt", "opt.prompt"), 433 PROMPT("-prompt", null, HIDDEN, BASIC), 434 435 // dump stack on error 436 DOE("-doe", null, HIDDEN, BASIC), 437 438 // output source after type erasure 439 PRINTSOURCE("-printsource", null, HIDDEN, BASIC), 440 441 // display warnings for generic unchecked operations 442 WARNUNCHECKED("-warnunchecked", null, HIDDEN, BASIC) { 443 @Override 444 public void process(OptionHelper helper, String option) { 445 helper.put("-Xlint:unchecked", option); 446 } 447 }, 448 449 XMAXERRS("-Xmaxerrs", "opt.arg.number", "opt.maxerrs", EXTENDED, BASIC), 450 451 XMAXWARNS("-Xmaxwarns", "opt.arg.number", "opt.maxwarns", EXTENDED, BASIC), 452 453 XSTDOUT("-Xstdout", "opt.arg.file", "opt.Xstdout", EXTENDED, INFO) { 454 @Override 455 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 456 try { 457 Log log = helper.getLog(); 458 log.setWriters(new PrintWriter(new FileWriter(arg), true)); 459 } catch (java.io.IOException e) { 460 throw helper.newInvalidValueException("err.error.writing.file", arg, e); 461 } 462 super.process(helper, option, arg); 463 } 464 }, 465 466 XPRINT("-Xprint", "opt.print", EXTENDED, BASIC), 467 468 XPRINTROUNDS("-XprintRounds", "opt.printRounds", EXTENDED, BASIC), 469 470 XPRINTPROCESSORINFO("-XprintProcessorInfo", "opt.printProcessorInfo", EXTENDED, BASIC), 471 472 XPREFER("-Xprefer:", "opt.prefer", EXTENDED, BASIC, ONEOF, "source", "newer"), 473 474 XXUSERPATHSFIRST("-XXuserPathsFirst", "opt.userpathsfirst", HIDDEN, BASIC), 475 476 // see enum PkgInfo 477 XPKGINFO("-Xpkginfo:", "opt.pkginfo", EXTENDED, BASIC, ONEOF, "always", "legacy", "nonempty"), 478 479 /* -O is a no-op, accepted for backward compatibility. */ 480 O("-O", null, HIDDEN, BASIC), 481 482 /* -Xjcov produces tables to support the code coverage tool jcov. */ 483 XJCOV("-Xjcov", null, HIDDEN, BASIC), 484 485 PLUGIN("-Xplugin:", "opt.arg.plugin", "opt.plugin", EXTENDED, BASIC) { 486 @Override 487 public void process(OptionHelper helper, String option) { 488 String p = option.substring(option.indexOf(':') + 1).trim(); 489 String prev = helper.get(PLUGIN); 490 helper.put(PLUGIN.primaryName, (prev == null) ? p : prev + '\0' + p); 491 } 492 }, 493 494 XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"), 495 496 DEBUG("--debug:", null, HIDDEN, BASIC) { 497 @Override 498 public void process(OptionHelper helper, String option) throws InvalidValueException { 499 HiddenGroup.DEBUG.process(helper, option); 500 } 501 }, 502 503 SHOULDSTOP("--should-stop:", null, HIDDEN, BASIC) { 504 @Override 505 public void process(OptionHelper helper, String option) throws InvalidValueException { 506 HiddenGroup.SHOULDSTOP.process(helper, option); 507 } 508 }, 509 510 DIAGS("--diags:", null, HIDDEN, BASIC) { 511 @Override 512 public void process(OptionHelper helper, String option) throws InvalidValueException { 513 HiddenGroup.DIAGS.process(helper, option); 514 } 515 }, 516 517 /* This is a back door to the compiler's option table. 518 * -XDx=y sets the option x to the value y. 519 * -XDx sets the option x to the value x. 520 */ 521 XD("-XD", null, HIDDEN, BASIC) { 522 @Override 523 public boolean matches(String s) { 524 return s.startsWith(primaryName); 525 } 526 @Override 527 public void process(OptionHelper helper, String option) { 528 process(helper, option, option.substring(primaryName.length())); 529 } 530 531 @Override 532 public void process(OptionHelper helper, String option, String arg) { 533 int eq = arg.indexOf('='); 534 String key = (eq < 0) ? arg : arg.substring(0, eq); 535 String value = (eq < 0) ? arg : arg.substring(eq+1); 536 helper.put(key, value); 537 } 538 }, 539 540 ADD_EXPORTS("--add-exports", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) { 541 @Override 542 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 543 if (arg.isEmpty()) { 544 throw helper.newInvalidValueException("err.no.value.for.option", option); 545 } else if (getPattern().matcher(arg).matches()) { 546 String prev = helper.get(ADD_EXPORTS); 547 helper.put(ADD_EXPORTS.primaryName, (prev == null) ? arg : prev + '\0' + arg); 548 } else { 549 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 550 } 551 } 552 553 @Override 554 public Pattern getPattern() { 555 return Pattern.compile("([^/]+)/([^=]+)=(,*[^,].*)"); 556 } 557 }, 558 559 ADD_OPENS("--add-opens", null, null, HIDDEN, BASIC), 560 561 ADD_READS("--add-reads", "opt.arg.addReads", "opt.addReads", EXTENDED, BASIC) { 562 @Override 563 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 564 if (arg.isEmpty()) { 565 throw helper.newInvalidValueException("err.no.value.for.option", option); 566 } else if (getPattern().matcher(arg).matches()) { 567 String prev = helper.get(ADD_READS); 568 helper.put(ADD_READS.primaryName, (prev == null) ? arg : prev + '\0' + arg); 569 } else { 570 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 571 } 572 } 573 574 @Override 575 public Pattern getPattern() { 576 return Pattern.compile("([^=]+)=(,*[^,].*)"); 577 } 578 }, 579 580 XMODULE("-Xmodule:", "opt.arg.module", "opt.module", EXTENDED, BASIC) { 581 @Override 582 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 583 String prev = helper.get(XMODULE); 584 if (prev != null) { 585 throw helper.newInvalidValueException("err.option.too.many", XMODULE.primaryName); 586 } 587 helper.put(XMODULE.primaryName, arg); 588 } 589 }, 590 591 MODULE("--module -m", "opt.arg.m", "opt.m", STANDARD, BASIC), 592 593 ADD_MODULES("--add-modules", "opt.arg.addmods", "opt.addmods", STANDARD, BASIC) { 594 @Override 595 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 596 if (arg.isEmpty()) { 597 throw helper.newInvalidValueException("err.no.value.for.option", option); 598 } else if (getPattern().matcher(arg).matches()) { 599 String prev = helper.get(ADD_MODULES); 600 // since the individual values are simple names, we can simply join the 601 // values of multiple --add-modules options with ',' 602 helper.put(ADD_MODULES.primaryName, (prev == null) ? arg : prev + ',' + arg); 603 } else { 604 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 605 } 606 } 607 608 @Override 609 public Pattern getPattern() { 610 return Pattern.compile(",*[^,].*"); 611 } 612 }, 613 614 LIMIT_MODULES("--limit-modules", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC) { 615 @Override 616 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 617 if (arg.isEmpty()) { 618 throw helper.newInvalidValueException("err.no.value.for.option", option); 619 } else if (getPattern().matcher(arg).matches()) { 620 helper.put(LIMIT_MODULES.primaryName, arg); // last one wins 621 } else { 622 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 623 } 624 } 625 626 @Override 627 public Pattern getPattern() { 628 return Pattern.compile(",*[^,].*"); 629 } 630 }, 631 632 MODULE_VERSION("--module-version", "opt.arg.module.version", "opt.module.version", STANDARD, BASIC) { 633 @Override 634 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 635 if (arg.isEmpty()) { 636 throw helper.newInvalidValueException("err.no.value.for.option", option); 637 } else { 638 try { 639 Class.forName(JDK9Wrappers.ModuleDescriptor.Version.CLASSNAME); 640 // use official parser if available 641 try { 642 JDK9Wrappers.ModuleDescriptor.Version.parse(arg); 643 } catch (IllegalArgumentException e) { 644 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 645 } 646 } catch (ClassNotFoundException ex) { 647 // fall-back to simplistic rules when running on older platform 648 if (!(arg.charAt(0) >= '0' && arg.charAt(0) <= '9') || 649 arg.endsWith("-") || 650 arg.endsWith("+")) { 651 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg); 652 } 653 } 654 } 655 super.process(helper, option, arg); 656 } 657 }, 658 659 // This option exists only for the purpose of documenting itself. 660 // It's actually implemented by the CommandLine class. 661 AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, ArgKind.ADJACENT) { 662 @Override 663 public void process(OptionHelper helper, String option) { 664 throw new AssertionError("the @ flag should be caught by CommandLine."); 665 } 666 }, 667 668 // Standalone positional argument: source file or type name. 669 SOURCEFILE("sourcefile", null, HIDDEN, INFO) { 670 @Override 671 public boolean matches(String s) { 672 if (s.endsWith(".java")) // Java source file 673 return true; 674 int sep = s.indexOf('/'); 675 if (sep != -1) { 676 return SourceVersion.isName(s.substring(0, sep)) 677 && SourceVersion.isName(s.substring(sep + 1)); 678 } else { 679 return SourceVersion.isName(s); // Legal type name 680 } 681 } 682 @Override 683 public void process(OptionHelper helper, String option) throws InvalidValueException { 684 if (option.endsWith(".java") ) { 685 Path p = Paths.get(option); 686 if (!Files.exists(p)) { 687 throw helper.newInvalidValueException("err.file.not.found", p); 688 } 689 if (!Files.isRegularFile(p)) { 690 throw helper.newInvalidValueException("err.file.not.file", p); 691 } 692 helper.addFile(p); 693 } else { 694 helper.addClassName(option); 695 } 696 } 697 }, 698 699 MULTIRELEASE("--multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER), 700 701 INHERIT_RUNTIME_ENVIRONMENT("--inherit-runtime-environment", "opt.inherit_runtime_environment", 702 EXTENDED, BASIC) { 703 @Override 704 public void process(OptionHelper helper, String option) throws InvalidValueException { 705 try { 706 Class.forName(JDK9Wrappers.VMHelper.CLASSNAME); 707 String[] runtimeArgs = JDK9Wrappers.VMHelper.getRuntimeArguments(); 708 for (String arg : runtimeArgs) { 709 // Handle any supported runtime options; ignore all others. 710 // The runtime arguments always use the single token form, e.g. "--name=value". 711 for (Option o : getSupportedRuntimeOptions()) { 712 if (o.matches(arg)) { 713 switch (o) { 714 case ADD_MODULES: 715 int eq = arg.indexOf('='); 716 Assert.check(eq > 0, () -> ("invalid runtime option:" + arg)); 717 // --add-modules=ALL-DEFAULT is not supported at compile-time 718 // so remove it from list, and only process the rest 719 // if the set is non-empty. 720 // Note that --add-modules=ALL-DEFAULT is automatically added 721 // by the standard javac launcher. 722 String mods = Arrays.stream(arg.substring(eq + 1).split(",")) 723 .filter(s -> !s.isEmpty() && !s.equals("ALL-DEFAULT")) 724 .collect(Collectors.joining(",")); 725 if (!mods.isEmpty()) { 726 String updatedArg = arg.substring(0, eq + 1) + mods; 727 o.handleOption(helper, updatedArg, Collections.emptyIterator()); 728 } 729 break; 730 default: 731 o.handleOption(helper, arg, Collections.emptyIterator()); 732 break; 733 } 734 break; 735 } 736 } 737 } 738 } catch (ClassNotFoundException | SecurityException e) { 739 throw helper.newInvalidValueException("err.cannot.access.runtime.env"); 740 } 741 } 742 743 private Option[] getSupportedRuntimeOptions() { 744 Option[] supportedRuntimeOptions = { 745 ADD_EXPORTS, 746 ADD_MODULES, 747 LIMIT_MODULES, 748 MODULE_PATH, 749 UPGRADE_MODULE_PATH, 750 PATCH_MODULE 751 }; 752 return supportedRuntimeOptions; 753 } 754 }; 755 756 /** 757 * This exception is thrown when an invalid value is given for an option. 758 * The detail string gives a detailed, localized message, suitable for use 759 * in error messages reported to the user. 760 */ 761 public static class InvalidValueException extends Exception { 762 private static final long serialVersionUID = -1; 763 764 public InvalidValueException(String msg) { 765 super(msg); 766 } 767 768 public InvalidValueException(String msg, Throwable cause) { 769 super(msg, cause); 770 } 771 } 772 773 /** 774 * The kind of argument, if any, accepted by this option. The kind is augmented 775 * by characters in the name of the option. 776 */ 777 public enum ArgKind { 778 /** This option does not take any argument. */ 779 NONE, 780 781// Not currently supported 782// /** 783// * This option takes an optional argument, which may be provided directly after an '=' 784// * separator, or in the following argument position if that word does not itself appear 785// * to be the name of an option. 786// */ 787// OPTIONAL, 788 789 /** 790 * This option takes an argument. 791 * If the name of option ends with ':' or '=', the argument must be provided directly 792 * after that separator. 793 * Otherwise, it may appear after an '=' or in the following argument position. 794 */ 795 REQUIRED, 796 797 /** 798 * This option takes an argument immediately after the option name, with no separator 799 * character. 800 */ 801 ADJACENT 802 } 803 804 /** 805 * The kind of an Option. This is used by the -help and -X options. 806 */ 807 public enum OptionKind { 808 /** A standard option, documented by -help. */ 809 STANDARD, 810 /** An extended option, documented by -X. */ 811 EXTENDED, 812 /** A hidden option, not documented. */ 813 HIDDEN, 814 } 815 816 /** 817 * The group for an Option. This determines the situations in which the 818 * option is applicable. 819 */ 820 enum OptionGroup { 821 /** A basic option, available for use on the command line or via the 822 * Compiler API. */ 823 BASIC, 824 /** An option for javac's standard JavaFileManager. Other file managers 825 * may or may not support these options. */ 826 FILEMANAGER, 827 /** A command-line option that requests information, such as -help. */ 828 INFO, 829 /** A command-line "option" representing a file or class name. */ 830 OPERAND 831 } 832 833 /** 834 * The kind of choice for "choice" options. 835 */ 836 enum ChoiceKind { 837 /** The expected value is exactly one of the set of choices. */ 838 ONEOF, 839 /** The expected value is one of more of the set of choices. */ 840 ANYOF 841 } 842 843 enum HiddenGroup { 844 DIAGS("diags"), 845 DEBUG("debug"), 846 SHOULDSTOP("should-stop"); 847 848 static final Set<String> skipSet = new java.util.HashSet<>( 849 Arrays.asList("--diags:", "--debug:", "--should-stop:")); 850 851 final String text; 852 853 HiddenGroup(String text) { 854 this.text = text; 855 } 856 857 public void process(OptionHelper helper, String option) throws InvalidValueException { 858 String p = option.substring(option.indexOf(':') + 1).trim(); 859 String[] subOptions = p.split(";"); 860 for (String subOption : subOptions) { 861 subOption = text + "." + subOption.trim(); 862 XD.process(helper, subOption, subOption); 863 } 864 } 865 866 static boolean skip(String name) { 867 return skipSet.contains(name); 868 } 869 } 870 871 /** 872 * The "primary name" for this option. 873 * This is the name that is used to put values in the {@link Options} table. 874 */ 875 public final String primaryName; 876 877 /** 878 * The set of names (primary name and aliases) for this option. 879 * Note that some names may end in a separator, to indicate that an argument must immediately 880 * follow the separator (and cannot appear in the following argument position. 881 */ 882 public final String[] names; 883 884 /** Documentation key for arguments. */ 885 protected final String argsNameKey; 886 887 /** Documentation key for description. 888 */ 889 protected final String descrKey; 890 891 /** The kind of this option. */ 892 private final OptionKind kind; 893 894 /** The group for this option. */ 895 private final OptionGroup group; 896 897 /** The kind of argument for this option. */ 898 private final ArgKind argKind; 899 900 /** The kind of choices for this option, if any. */ 901 private final ChoiceKind choiceKind; 902 903 /** The choices for this option, if any. */ 904 private final Set<String> choices; 905 906 /** 907 * Looks up the first option matching the given argument in the full set of options. 908 * @param arg the argument to be matches 909 * @return the first option that matches, or null if none. 910 */ 911 public static Option lookup(String arg) { 912 return lookup(arg, EnumSet.allOf(Option.class)); 913 } 914 915 /** 916 * Looks up the first option matching the given argument within a set of options. 917 * @param arg the argument to be matched 918 * @param options the set of possible options 919 * @return the first option that matches, or null if none. 920 */ 921 public static Option lookup(String arg, Set<Option> options) { 922 for (Option option: options) { 923 if (option.matches(arg)) 924 return option; 925 } 926 return null; 927 } 928 929 /** 930 * Writes the "command line help" for given kind of option to the log. 931 * @param log the log 932 * @param kind the kind of options to select 933 */ 934 private static void showHelp(Log log, OptionKind kind) { 935 Comparator<Option> comp = new Comparator<Option>() { 936 final Collator collator = Collator.getInstance(Locale.US); 937 { collator.setStrength(Collator.PRIMARY); } 938 939 @Override 940 public int compare(Option o1, Option o2) { 941 return collator.compare(o1.primaryName, o2.primaryName); 942 } 943 }; 944 945 getJavaCompilerOptions() 946 .stream() 947 .filter(o -> o.kind == kind) 948 .sorted(comp) 949 .forEach(o -> { 950 o.help(log); 951 }); 952 } 953 954 Option(String text, String descrKey, 955 OptionKind kind, OptionGroup group) { 956 this(text, null, descrKey, kind, group, null, null, ArgKind.NONE); 957 } 958 959 Option(String text, String argsNameKey, String descrKey, 960 OptionKind kind, OptionGroup group) { 961 this(text, argsNameKey, descrKey, kind, group, null, null, ArgKind.REQUIRED); 962 } 963 964 Option(String text, String argsNameKey, String descrKey, 965 OptionKind kind, OptionGroup group, ArgKind ak) { 966 this(text, argsNameKey, descrKey, kind, group, null, null, ak); 967 } 968 969 Option(String text, String argsNameKey, String descrKey, OptionKind kind, OptionGroup group, 970 ChoiceKind choiceKind, Set<String> choices) { 971 this(text, argsNameKey, descrKey, kind, group, choiceKind, choices, ArgKind.REQUIRED); 972 } 973 974 Option(String text, String descrKey, 975 OptionKind kind, OptionGroup group, 976 ChoiceKind choiceKind, String... choices) { 977 this(text, null, descrKey, kind, group, choiceKind, 978 new LinkedHashSet<>(Arrays.asList(choices)), ArgKind.REQUIRED); 979 } 980 981 private Option(String text, String argsNameKey, String descrKey, 982 OptionKind kind, OptionGroup group, 983 ChoiceKind choiceKind, Set<String> choices, 984 ArgKind argKind) { 985 this.names = text.trim().split("\\s+"); 986 Assert.check(names.length >= 1); 987 this.primaryName = names[0]; 988 this.argsNameKey = argsNameKey; 989 this.descrKey = descrKey; 990 this.kind = kind; 991 this.group = group; 992 this.choiceKind = choiceKind; 993 this.choices = choices; 994 this.argKind = argKind; 995 } 996 997 public String getPrimaryName() { 998 return primaryName; 999 } 1000 1001 public OptionKind getKind() { 1002 return kind; 1003 } 1004 1005 public ArgKind getArgKind() { 1006 return argKind; 1007 } 1008 1009 public boolean hasArg() { 1010 return (argKind != ArgKind.NONE); 1011 } 1012 1013 public boolean matches(String option) { 1014 for (String name: names) { 1015 if (matches(option, name)) 1016 return true; 1017 } 1018 return false; 1019 } 1020 1021 private boolean matches(String option, String name) { 1022 if (name.startsWith("--") && !HiddenGroup.skip(name)) { 1023 return option.equals(name) 1024 || hasArg() && option.startsWith(name + "="); 1025 } 1026 1027 boolean hasSuffix = (argKind == ArgKind.ADJACENT) 1028 || name.endsWith(":") || name.endsWith("="); 1029 1030 if (!hasSuffix) 1031 return option.equals(name); 1032 1033 if (!option.startsWith(name)) 1034 return false; 1035 1036 if (choices != null) { 1037 String arg = option.substring(name.length()); 1038 if (choiceKind == ChoiceKind.ONEOF) 1039 return choices.contains(arg); 1040 else { 1041 for (String a: arg.split(",+")) { 1042 if (!choices.contains(a)) 1043 return false; 1044 } 1045 } 1046 } 1047 1048 return true; 1049 } 1050 1051 /** 1052 * Handles an option. 1053 * If an argument for the option is required, depending on spec of the option, it will be found 1054 * as part of the current arg (following ':' or '=') or in the following argument. 1055 * This is the recommended way to handle an option directly, instead of calling the underlying 1056 * {@link #process process} methods. 1057 * @param helper a helper to provide access to the environment 1058 * @param arg the arg string that identified this option 1059 * @param rest the remaining strings to be analysed 1060 * @throws InvalidValueException if the value of the option was invalid 1061 * @implNote The return value is the opposite of that used by {@link #process}. 1062 */ 1063 public void handleOption(OptionHelper helper, String arg, Iterator<String> rest) throws InvalidValueException { 1064 if (hasArg()) { 1065 String option; 1066 String operand; 1067 int sep = findSeparator(arg); 1068 if (getArgKind() == Option.ArgKind.ADJACENT) { 1069 option = primaryName; // aliases not supported 1070 operand = arg.substring(primaryName.length()); 1071 } else if (sep > 0) { 1072 option = arg.substring(0, sep); 1073 operand = arg.substring(sep + 1); 1074 } else { 1075 if (!rest.hasNext()) { 1076 throw helper.newInvalidValueException("err.req.arg", arg); 1077 } 1078 option = arg; 1079 operand = rest.next(); 1080 } 1081 process(helper, option, operand); 1082 } else { 1083 process(helper, arg); 1084 } 1085 } 1086 1087 /** 1088 * Processes an option that either does not need an argument, 1089 * or which contains an argument within it, following a separator. 1090 * @param helper a helper to provide access to the environment 1091 * @param option the option to be processed 1092 * @throws InvalidValueException if an error occurred 1093 */ 1094 public void process(OptionHelper helper, String option) throws InvalidValueException { 1095 if (argKind == ArgKind.NONE) { 1096 process(helper, primaryName, option); 1097 } else { 1098 int sep = findSeparator(option); 1099 process(helper, primaryName, option.substring(sep + 1)); 1100 } 1101 } 1102 1103 /** 1104 * Processes an option by updating the environment via a helper object. 1105 * @param helper a helper to provide access to the environment 1106 * @param option the option to be processed 1107 * @param arg the value to associate with the option, or a default value 1108 * to be used if the option does not otherwise take an argument. 1109 * @throws InvalidValueException if an error occurred 1110 */ 1111 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException { 1112 if (choices != null) { 1113 if (choiceKind == ChoiceKind.ONEOF) { 1114 // some clients like to see just one of option+choice set 1115 for (String s : choices) 1116 helper.remove(primaryName + s); 1117 String opt = primaryName + arg; 1118 helper.put(opt, opt); 1119 // some clients like to see option (without trailing ":") 1120 // set to arg 1121 String nm = primaryName.substring(0, primaryName.length() - 1); 1122 helper.put(nm, arg); 1123 } else { 1124 // set option+word for each word in arg 1125 for (String a: arg.split(",+")) { 1126 String opt = primaryName + a; 1127 helper.put(opt, opt); 1128 } 1129 } 1130 } 1131 helper.put(primaryName, arg); 1132 if (group == OptionGroup.FILEMANAGER) 1133 helper.handleFileManagerOption(this, arg); 1134 } 1135 1136 /** 1137 * Returns a pattern to analyze the value for an option. 1138 * @return the pattern 1139 * @throws UnsupportedOperationException if an option does not provide a pattern. 1140 */ 1141 public Pattern getPattern() { 1142 throw new UnsupportedOperationException(); 1143 } 1144 1145 /** 1146 * Scans a word to find the first separator character, either colon or equals. 1147 * @param word the word to be scanned 1148 * @return the position of the first':' or '=' character in the word, 1149 * or -1 if none found 1150 */ 1151 private static int findSeparator(String word) { 1152 for (int i = 0; i < word.length(); i++) { 1153 switch (word.charAt(i)) { 1154 case ':': case '=': 1155 return i; 1156 } 1157 } 1158 return -1; 1159 } 1160 1161 /** The indent for the option synopsis. */ 1162 private static final String SMALL_INDENT = " "; 1163 /** The automatic indent for the description. */ 1164 private static final String LARGE_INDENT = " "; 1165 /** The space allowed for the synopsis, if the description is to be shown on the same line. */ 1166 private static final int DEFAULT_SYNOPSIS_WIDTH = 28; 1167 /** The nominal maximum line length, when seeing if text will fit on a line. */ 1168 private static final int DEFAULT_MAX_LINE_LENGTH = 80; 1169 /** The format for a single-line help entry. */ 1170 private static final String COMPACT_FORMAT = SMALL_INDENT + "%-" + DEFAULT_SYNOPSIS_WIDTH + "s %s"; 1171 1172 /** 1173 * Writes help text for this option to the log. 1174 * @param log the log 1175 */ 1176 protected void help(Log log) { 1177 help(log, log.localize(PrefixKind.JAVAC, descrKey)); 1178 } 1179 1180 protected void help(Log log, String descr) { 1181 String synopses = Arrays.stream(names) 1182 .map(s -> helpSynopsis(s, log)) 1183 .collect(Collectors.joining(", ")); 1184 1185 // If option synopses and description fit on a single line of reasonable length, 1186 // display using COMPACT_FORMAT 1187 if (synopses.length() < DEFAULT_SYNOPSIS_WIDTH 1188 && !descr.contains("\n") 1189 && (SMALL_INDENT.length() + DEFAULT_SYNOPSIS_WIDTH + 1 + descr.length() <= DEFAULT_MAX_LINE_LENGTH)) { 1190 log.printRawLines(WriterKind.STDOUT, String.format(COMPACT_FORMAT, synopses, descr)); 1191 return; 1192 } 1193 1194 // If option synopses fit on a single line of reasonable length, show that; 1195 // otherwise, show 1 per line 1196 if (synopses.length() <= DEFAULT_MAX_LINE_LENGTH) { 1197 log.printRawLines(WriterKind.STDOUT, SMALL_INDENT + synopses); 1198 } else { 1199 for (String name: names) { 1200 log.printRawLines(WriterKind.STDOUT, SMALL_INDENT + helpSynopsis(name, log)); 1201 } 1202 } 1203 1204 // Finally, show the description 1205 log.printRawLines(WriterKind.STDOUT, LARGE_INDENT + descr.replace("\n", "\n" + LARGE_INDENT)); 1206 } 1207 1208 /** 1209 * Composes the initial synopsis of one of the forms for this option. 1210 * @param name the name of this form of the option 1211 * @param log the log used to localize the description of the arguments 1212 * @return the synopsis 1213 */ 1214 private String helpSynopsis(String name, Log log) { 1215 StringBuilder sb = new StringBuilder(); 1216 sb.append(name); 1217 if (argsNameKey == null) { 1218 if (choices != null) { 1219 String sep = "{"; 1220 for (String choice : choices) { 1221 sb.append(sep); 1222 sb.append(choices); 1223 sep = ","; 1224 } 1225 sb.append("}"); 1226 } 1227 } else { 1228 if (!name.matches(".*[=:]$") && argKind != ArgKind.ADJACENT) 1229 sb.append(" "); 1230 sb.append(log.localize(PrefixKind.JAVAC, argsNameKey)); 1231 } 1232 1233 return sb.toString(); 1234 } 1235 1236 // For -XpkgInfo:value 1237 public enum PkgInfo { 1238 /** 1239 * Always generate package-info.class for every package-info.java file. 1240 * The file may be empty if there annotations with a RetentionPolicy 1241 * of CLASS or RUNTIME. This option may be useful in conjunction with 1242 * build systems (such as Ant) that expect javac to generate at least 1243 * one .class file for every .java file. 1244 */ 1245 ALWAYS, 1246 /** 1247 * Generate a package-info.class file if package-info.java contains 1248 * annotations. The file may be empty if all the annotations have 1249 * a RetentionPolicy of SOURCE. 1250 * This value is just for backwards compatibility with earlier behavior. 1251 * Either of the other two values are to be preferred to using this one. 1252 */ 1253 LEGACY, 1254 /** 1255 * Generate a package-info.class file if and only if there are annotations 1256 * in package-info.java to be written into it. 1257 */ 1258 NONEMPTY; 1259 1260 public static PkgInfo get(Options options) { 1261 String v = options.get(XPKGINFO); 1262 return (v == null 1263 ? PkgInfo.LEGACY 1264 : PkgInfo.valueOf(StringUtils.toUpperCase(v))); 1265 } 1266 } 1267 1268 private static Set<String> getXLintChoices() { 1269 Set<String> choices = new LinkedHashSet<>(); 1270 choices.add("all"); 1271 for (Lint.LintCategory c : Lint.LintCategory.values()) { 1272 choices.add(c.option); 1273 choices.add("-" + c.option); 1274 } 1275 choices.add("none"); 1276 return choices; 1277 } 1278 1279 /** 1280 * Returns the set of options supported by the command line tool. 1281 * @return the set of options. 1282 */ 1283 static Set<Option> getJavaCompilerOptions() { 1284 return EnumSet.allOf(Option.class); 1285 } 1286 1287 /** 1288 * Returns the set of options supported by the built-in file manager. 1289 * @return the set of options. 1290 */ 1291 public static Set<Option> getJavacFileManagerOptions() { 1292 return getOptions(FILEMANAGER); 1293 } 1294 1295 /** 1296 * Returns the set of options supported by this implementation of 1297 * the JavaCompiler API, via {@link JavaCompiler#getTask}. 1298 * @return the set of options. 1299 */ 1300 public static Set<Option> getJavacToolOptions() { 1301 return getOptions(BASIC); 1302 } 1303 1304 private static Set<Option> getOptions(OptionGroup group) { 1305 return Arrays.stream(Option.values()) 1306 .filter(o -> o.group == group) 1307 .collect(Collectors.toCollection(() -> EnumSet.noneOf(Option.class))); 1308 } 1309 1310} 1311