1 /* 2 * Copyright (c) 2006, 2011, 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 com.sun.tools.javac.code.Lint; 29 import com.sun.tools.javac.code.Source; 30 import com.sun.tools.javac.code.Type; 31 import com.sun.tools.javac.jvm.Target; 32 import com.sun.tools.javac.main.JavacOption.HiddenOption; 33 import com.sun.tools.javac.main.JavacOption.Option; 34 import com.sun.tools.javac.main.JavacOption.XOption; 35 import com.sun.tools.javac.util.ListBuffer; 36 import com.sun.tools.javac.util.Options; 37 import com.sun.tools.javac.processing.JavacProcessingEnvironment; 38 import java.io.File; 39 import java.io.FileWriter; 40 import java.io.PrintWriter; 41 import java.util.EnumSet; 42 import java.util.LinkedHashMap; 43 import java.util.Map; 44 import java.util.Set; 45 import javax.lang.model.SourceVersion; 46 47 import static com.sun.tools.javac.main.OptionName.*; 48 49 /** 50 * TODO: describe com.sun.tools.javac.main.RecognizedOptions 51 * 52 * <p><b>This is NOT part of any supported API. 53 * If you write code that depends on this, you do so at your own 54 * risk. This code and its internal interfaces are subject to change 55 * or deletion without notice.</b></p> 56 */ 57 public class RecognizedOptions { 58 59 private RecognizedOptions() {} 60 61 public interface OptionHelper { 62 63 void setOut(PrintWriter out); 64 65 void error(String key, Object... args); 66 67 void printVersion(); 68 69 void printFullVersion(); 70 71 void printHelp(); 72 73 void printXhelp(); 74 75 void addFile(File f); 76 77 void addClassName(String s); 78 79 } 80 81 public static class GrumpyHelper implements OptionHelper { 82 83 public void setOut(PrintWriter out) { 84 throw new IllegalArgumentException(); 85 } 86 87 public void error(String key, Object... args) { 88 throw new IllegalArgumentException(Main.getLocalizedString(key, args)); 89 } 90 91 public void printVersion() { 92 throw new IllegalArgumentException(); 93 } 94 95 public void printFullVersion() { 96 throw new IllegalArgumentException(); 97 } 98 99 public void printHelp() { 100 throw new IllegalArgumentException(); 101 } 102 103 public void printXhelp() { 104 throw new IllegalArgumentException(); 105 } 106 107 public void addFile(File f) { 108 throw new IllegalArgumentException(f.getPath()); 109 } 110 111 public void addClassName(String s) { 112 throw new IllegalArgumentException(s); 113 } 114 115 } 116 117 static Set<OptionName> javacOptions = EnumSet.of( 118 G, 119 G_NONE, 120 G_CUSTOM, 121 XLINT, 122 XLINT_CUSTOM, 123 NOWARN, 124 VERBOSE, 125 DEPRECATION, 126 CLASSPATH, 127 CP, 128 SOURCEPATH, 129 BOOTCLASSPATH, 130 XBOOTCLASSPATH_PREPEND, 131 XBOOTCLASSPATH_APPEND, 132 XBOOTCLASSPATH, 133 EXTDIRS, 134 DJAVA_EXT_DIRS, 135 ENDORSEDDIRS, 136 DJAVA_ENDORSED_DIRS, 137 PROC, 138 PROCESSOR, 139 PROCESSORPATH, 140 D, 141 S, 142 IMPLICIT, 143 ENCODING, 144 SOURCE, 145 TARGET, 146 VERSION, 147 FULLVERSION, 148 DIAGS, 149 HELP, 150 A, 151 X, 152 J, 153 MOREINFO, 154 WERROR, 155 // COMPLEXINFERENCE, 156 PROMPT, 157 DOE, 158 PRINTSOURCE, 159 WARNUNCHECKED, 160 XMAXERRS, 161 XMAXWARNS, 162 XSTDOUT, 163 XPKGINFO, 164 XPRINT, 165 XPRINTROUNDS, 166 XPRINTPROCESSORINFO, 167 XPREFER, 168 O, 169 XJCOV, 170 XD, 171 AT, 172 SOURCEFILE); 173 174 static Set<OptionName> javacFileManagerOptions = EnumSet.of( 175 CLASSPATH, 176 CP, 177 SOURCEPATH, 178 BOOTCLASSPATH, 179 XBOOTCLASSPATH_PREPEND, 180 XBOOTCLASSPATH_APPEND, 181 XBOOTCLASSPATH, 182 EXTDIRS, 183 DJAVA_EXT_DIRS, 184 ENDORSEDDIRS, 185 DJAVA_ENDORSED_DIRS, 186 PROCESSORPATH, 187 D, 188 S, 189 ENCODING, 190 SOURCE); 191 192 static Set<OptionName> javacToolOptions = EnumSet.of( 193 G, 194 G_NONE, 195 G_CUSTOM, 196 XLINT, 197 XLINT_CUSTOM, 198 NOWARN, 199 VERBOSE, 200 DEPRECATION, 201 PROC, 202 PROCESSOR, 203 IMPLICIT, 204 SOURCE, 205 TARGET, 206 // VERSION, 207 // FULLVERSION, 208 // HELP, 209 A, 210 // X, 211 // J, 212 MOREINFO, 213 WERROR, 214 // COMPLEXINFERENCE, 215 PROMPT, 216 DOE, 217 PRINTSOURCE, 218 WARNUNCHECKED, 219 XMAXERRS, 220 XMAXWARNS, 221 // XSTDOUT, 222 XPKGINFO, 223 XPRINT, 224 XPRINTROUNDS, 225 XPRINTPROCESSORINFO, 226 XPREFER, 227 O, 228 XJCOV, 229 XD); 230 231 static Option[] getJavaCompilerOptions(OptionHelper helper) { 232 return getOptions(helper, javacOptions); 233 } 234 235 public static Option[] getJavacFileManagerOptions(OptionHelper helper) { 236 return getOptions(helper, javacFileManagerOptions); 237 } 238 239 public static Option[] getJavacToolOptions(OptionHelper helper) { 240 return getOptions(helper, javacToolOptions); 241 } 242 243 static Option[] getOptions(OptionHelper helper, Set<OptionName> desired) { 244 ListBuffer<Option> options = new ListBuffer<Option>(); 245 for (Option option : getAll(helper)) 246 if (desired.contains(option.getName())) 247 options.append(option); 248 return options.toArray(new Option[options.length()]); 249 } 250 251 /** 252 * Get all the recognized options. 253 * @param helper an {@code OptionHelper} to help when processing options 254 * @return an array of options 255 */ 256 public static Option[] getAll(final OptionHelper helper) { 257 return new Option[] { 258 new Option(G, "opt.g"), 259 new Option(G_NONE, "opt.g.none") { 260 @Override 261 public boolean process(Options options, String option) { 262 options.put("-g:", "none"); 263 return false; 264 } 265 }, 266 267 new Option(G_CUSTOM, "opt.g.lines.vars.source", 268 Option.ChoiceKind.ANYOF, "lines", "vars", "source"), 269 270 new XOption(XLINT, "opt.Xlint"), 271 new XOption(XLINT_CUSTOM, "opt.Xlint.suboptlist", 272 Option.ChoiceKind.ANYOF, getXLintChoices()), 273 274 // -nowarn is retained for command-line backward compatibility 275 new Option(NOWARN, "opt.nowarn") { 276 @Override 277 public boolean process(Options options, String option) { 278 options.put("-Xlint:none", option); 279 return false; 280 } 281 }, 282 283 new Option(VERBOSE, "opt.verbose"), 284 285 // -deprecation is retained for command-line backward compatibility 286 new Option(DEPRECATION, "opt.deprecation") { 287 @Override 288 public boolean process(Options options, String option) { 289 options.put("-Xlint:deprecation", option); 290 return false; 291 } 292 }, 293 294 new Option(CLASSPATH, "opt.arg.path", "opt.classpath"), 295 new Option(CP, "opt.arg.path", "opt.classpath") { 296 @Override 297 public boolean process(Options options, String option, String arg) { 298 return super.process(options, "-classpath", arg); 299 } 300 }, 301 new Option(SOURCEPATH, "opt.arg.path", "opt.sourcepath"), 302 new Option(BOOTCLASSPATH, "opt.arg.path", "opt.bootclasspath") { 303 @Override 304 public boolean process(Options options, String option, String arg) { 305 options.remove("-Xbootclasspath/p:"); 306 options.remove("-Xbootclasspath/a:"); 307 return super.process(options, option, arg); 308 } 309 }, 310 new XOption(XBOOTCLASSPATH_PREPEND,"opt.arg.path", "opt.Xbootclasspath.p"), 311 new XOption(XBOOTCLASSPATH_APPEND, "opt.arg.path", "opt.Xbootclasspath.a"), 312 new XOption(XBOOTCLASSPATH, "opt.arg.path", "opt.bootclasspath") { 313 @Override 314 public boolean process(Options options, String option, String arg) { 315 options.remove("-Xbootclasspath/p:"); 316 options.remove("-Xbootclasspath/a:"); 317 return super.process(options, "-bootclasspath", arg); 318 } 319 }, 320 new Option(EXTDIRS, "opt.arg.dirs", "opt.extdirs"), 321 new XOption(DJAVA_EXT_DIRS, "opt.arg.dirs", "opt.extdirs") { 322 @Override 323 public boolean process(Options options, String option, String arg) { 324 return super.process(options, "-extdirs", arg); 325 } 326 }, 327 new Option(ENDORSEDDIRS, "opt.arg.dirs", "opt.endorseddirs"), 328 new XOption(DJAVA_ENDORSED_DIRS, "opt.arg.dirs", "opt.endorseddirs") { 329 @Override 330 public boolean process(Options options, String option, String arg) { 331 return super.process(options, "-endorseddirs", arg); 332 } 333 }, 334 new Option(PROC, "opt.proc.none.only", 335 Option.ChoiceKind.ONEOF, "none", "only"), 336 new Option(PROCESSOR, "opt.arg.class.list", "opt.processor"), 337 new Option(PROCESSORPATH, "opt.arg.path", "opt.processorpath"), 338 new Option(D, "opt.arg.directory", "opt.d"), 339 new Option(S, "opt.arg.directory", "opt.sourceDest"), 340 new Option(IMPLICIT, "opt.implicit", 341 Option.ChoiceKind.ONEOF, "none", "class"), 342 new Option(ENCODING, "opt.arg.encoding", "opt.encoding"), 343 new Option(SOURCE, "opt.arg.release", "opt.source") { 344 @Override 345 public boolean process(Options options, String option, String operand) { 346 Source source = Source.lookup(operand); 347 if (source == null) { 348 helper.error("err.invalid.source", operand); 349 return true; 350 } 351 return super.process(options, option, operand); 352 } 353 }, 354 new Option(TARGET, "opt.arg.release", "opt.target") { 355 @Override 356 public boolean process(Options options, String option, String operand) { 357 Target target = Target.lookup(operand); 358 if (target == null) { 359 helper.error("err.invalid.target", operand); 360 return true; 361 } 362 return super.process(options, option, operand); 363 } 364 }, 365 new Option(VERSION, "opt.version") { 366 @Override 367 public boolean process(Options options, String option) { 368 helper.printVersion(); 369 return super.process(options, option); 370 } 371 }, 372 new HiddenOption(FULLVERSION) { 373 @Override 374 public boolean process(Options options, String option) { 375 helper.printFullVersion(); 376 return super.process(options, option); 377 } 378 }, 379 new HiddenOption(DIAGS) { 380 @Override 381 public boolean process(Options options, String option) { 382 Option xd = getOptions(helper, EnumSet.of(XD))[0]; 383 option = option.substring(option.indexOf('=') + 1); 384 String diagsOption = option.contains("%") ? 385 "-XDdiagsFormat=" : 386 "-XDdiags="; 387 diagsOption += option; 388 if (xd.matches(diagsOption)) 389 return xd.process(options, diagsOption); 390 else 391 return false; 392 } 393 }, 394 new Option(HELP, "opt.help") { 395 @Override 396 public boolean process(Options options, String option) { 397 helper.printHelp(); 398 return super.process(options, option); 399 } 400 }, 401 new Option(A, "opt.arg.key.equals.value","opt.A") { 402 @Override 403 String helpSynopsis() { 404 hasSuffix = true; 405 return super.helpSynopsis(); 406 } 407 408 @Override 409 public boolean matches(String arg) { 410 return arg.startsWith("-A"); 411 } 412 413 @Override 414 public boolean hasArg() { 415 return false; 416 } 417 // Mapping for processor options created in 418 // JavacProcessingEnvironment 419 @Override 420 public boolean process(Options options, String option) { 421 int argLength = option.length(); 422 if (argLength == 2) { 423 helper.error("err.empty.A.argument"); 424 return true; 425 } 426 int sepIndex = option.indexOf('='); 427 String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) ); 428 if (!JavacProcessingEnvironment.isValidOptionName(key)) { 429 helper.error("err.invalid.A.key", option); 430 return true; 431 } 432 return process(options, option, option); 433 } 434 }, 435 new Option(X, "opt.X") { 436 @Override 437 public boolean process(Options options, String option) { 438 helper.printXhelp(); 439 return super.process(options, option); 440 } 441 }, 442 443 // This option exists only for the purpose of documenting itself. 444 // It's actually implemented by the launcher. 445 new Option(J, "opt.arg.flag", "opt.J") { 446 @Override 447 String helpSynopsis() { 448 hasSuffix = true; 449 return super.helpSynopsis(); 450 } 451 @Override 452 public boolean process(Options options, String option) { 453 throw new AssertionError 454 ("the -J flag should be caught by the launcher."); 455 } 456 }, 457 458 // stop after parsing and attributing. 459 // new HiddenOption("-attrparseonly"), 460 461 // new Option("-moreinfo", "opt.moreinfo") { 462 new HiddenOption(MOREINFO) { 463 @Override 464 public boolean process(Options options, String option) { 465 Type.moreInfo = true; 466 return super.process(options, option); 467 } 468 }, 469 470 // treat warnings as errors 471 new Option(WERROR, "opt.Werror"), 472 473 // use complex inference from context in the position of a method call argument 474 new HiddenOption(COMPLEXINFERENCE), 475 476 // generare source stubs 477 // new HiddenOption("-stubs"), 478 479 // relax some constraints to allow compiling from stubs 480 // new HiddenOption("-relax"), 481 482 // output source after translating away inner classes 483 // new Option("-printflat", "opt.printflat"), 484 // new HiddenOption("-printflat"), 485 486 // display scope search details 487 // new Option("-printsearch", "opt.printsearch"), 488 // new HiddenOption("-printsearch"), 489 490 // prompt after each error 491 // new Option("-prompt", "opt.prompt"), 492 new HiddenOption(PROMPT), 493 494 // dump stack on error 495 new HiddenOption(DOE), 496 497 // output source after type erasure 498 // new Option("-s", "opt.s"), 499 new HiddenOption(PRINTSOURCE), 500 501 // output shrouded class files 502 // new Option("-scramble", "opt.scramble"), 503 // new Option("-scrambleall", "opt.scrambleall"), 504 505 // display warnings for generic unchecked operations 506 new HiddenOption(WARNUNCHECKED) { 507 @Override 508 public boolean process(Options options, String option) { 509 options.put("-Xlint:unchecked", option); 510 return false; 511 } 512 }, 513 514 new XOption(XMAXERRS, "opt.arg.number", "opt.maxerrs"), 515 new XOption(XMAXWARNS, "opt.arg.number", "opt.maxwarns"), 516 new XOption(XSTDOUT, "opt.arg.file", "opt.Xstdout") { 517 @Override 518 public boolean process(Options options, String option, String arg) { 519 try { 520 helper.setOut(new PrintWriter(new FileWriter(arg), true)); 521 } catch (java.io.IOException e) { 522 helper.error("err.error.writing.file", arg, e); 523 return true; 524 } 525 return super.process(options, option, arg); 526 } 527 }, 528 529 new XOption(XPRINT, "opt.print"), 530 531 new XOption(XPRINTROUNDS, "opt.printRounds"), 532 533 new XOption(XPRINTPROCESSORINFO, "opt.printProcessorInfo"), 534 535 new XOption(XPREFER, "opt.prefer", 536 Option.ChoiceKind.ONEOF, "source", "newer"), 537 538 new XOption(XPKGINFO, "opt.pkginfo", 539 Option.ChoiceKind.ONEOF, "always", "legacy", "nonempty"), 540 541 /* -O is a no-op, accepted for backward compatibility. */ 542 new HiddenOption(O), 543 544 /* -Xjcov produces tables to support the code coverage tool jcov. */ 545 new HiddenOption(XJCOV), 546 547 /* This is a back door to the compiler's option table. 548 * -XDx=y sets the option x to the value y. 549 * -XDx sets the option x to the value x. 550 */ 551 new HiddenOption(XD) { 552 String s; 553 @Override 554 public boolean matches(String s) { 555 this.s = s; 556 return s.startsWith(name.optionName); 557 } 558 @Override 559 public boolean process(Options options, String option) { 560 s = s.substring(name.optionName.length()); 561 int eq = s.indexOf('='); 562 String key = (eq < 0) ? s : s.substring(0, eq); 563 String value = (eq < 0) ? s : s.substring(eq+1); 564 options.put(key, value); 565 return false; 566 } 567 }, 568 569 // This option exists only for the purpose of documenting itself. 570 // It's actually implemented by the CommandLine class. 571 new Option(AT, "opt.arg.file", "opt.AT") { 572 @Override 573 String helpSynopsis() { 574 hasSuffix = true; 575 return super.helpSynopsis(); 576 } 577 @Override 578 public boolean process(Options options, String option) { 579 throw new AssertionError 580 ("the @ flag should be caught by CommandLine."); 581 } 582 }, 583 584 /* 585 * TODO: With apt, the matches method accepts anything if 586 * -XclassAsDecls is used; code elsewhere does the lookup to 587 * see if the class name is both legal and found. 588 * 589 * In apt, the process method adds the candidate class file 590 * name to a separate list. 591 */ 592 new HiddenOption(SOURCEFILE) { 593 String s; 594 @Override 595 public boolean matches(String s) { 596 this.s = s; 597 return s.endsWith(".java") // Java source file 598 || SourceVersion.isName(s); // Legal type name 599 } 600 @Override 601 public boolean process(Options options, String option) { 602 if (s.endsWith(".java") ) { 603 File f = new File(s); 604 if (!f.exists()) { 605 helper.error("err.file.not.found", f); 606 return true; 607 } 608 if (!f.isFile()) { 609 helper.error("err.file.not.file", f); 610 return true; 611 } 612 helper.addFile(f); 613 } 614 else 615 helper.addClassName(s); 616 return false; 617 } 618 }, 619 }; 620 } 621 622 public enum PkgInfo { 623 ALWAYS, LEGACY, NONEMPTY; 624 public static PkgInfo get(Options options) { 625 String v = options.get(XPKGINFO); 626 return (v == null 627 ? PkgInfo.LEGACY 628 : PkgInfo.valueOf(v.toUpperCase())); 629 } 630 } 631 632 private static Map<String,Boolean> getXLintChoices() { 633 Map<String,Boolean> choices = new LinkedHashMap<String,Boolean>(); 634 choices.put("all", false); 635 for (Lint.LintCategory c : Lint.LintCategory.values()) 636 choices.put(c.option, c.hidden); 637 for (Lint.LintCategory c : Lint.LintCategory.values()) 638 choices.put("-" + c.option, c.hidden); 639 choices.put("none", false); 640 return choices; 641 } 642 643 }