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