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