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