1 /*
   2  * Copyright (c) 2012, 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 jdk.javadoc.internal.tool;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.EnumMap;
  31 import java.util.LinkedHashMap;
  32 import java.util.List;
  33 import java.util.Map;
  34 
  35 import javax.lang.model.element.ElementKind;
  36 
  37 import com.sun.tools.javac.main.Option;
  38 import com.sun.tools.javac.main.Option.InvalidValueException;
  39 import com.sun.tools.javac.main.Option.OptionKind;
  40 import com.sun.tools.javac.main.OptionHelper;
  41 import com.sun.tools.javac.util.Options;
  42 
  43 import static com.sun.tools.javac.main.Option.OptionKind.*;
  44 import static jdk.javadoc.internal.tool.Main.Result.*;
  45 
  46 /**
  47  * javadoc tool options.
  48  *
  49  *  <p><b>This is NOT part of any supported API.
  50  *  If you write code that depends on this, you do so at your own risk.
  51  *  This code and its internal interfaces are subject to change or
  52  *  deletion without notice.</b>
  53  */
  54 public enum ToolOption {
  55 
  56     // ----- options for underlying compiler -----
  57 
  58     BOOTCLASSPATH("-bootclasspath", STANDARD, true) {
  59         @Override
  60         public void process(Helper helper, String arg) throws InvalidValueException {
  61             Option.BOOT_CLASS_PATH.process(helper.getOptionHelper(), primaryName, arg);
  62         }
  63     },
  64 
  65     CLASS_PATH("--class-path -classpath -cp", STANDARD, true) {
  66         @Override
  67         public void process(Helper helper, String arg) throws InvalidValueException {
  68             Option.CLASS_PATH.process(helper.getOptionHelper(), primaryName, arg);
  69         }
  70     },
  71 
  72     EXTDIRS("-extdirs", STANDARD, true) {
  73         @Override
  74         public void process(Helper helper, String arg) throws InvalidValueException {
  75             Option.EXTDIRS.process(helper.getOptionHelper(), primaryName, arg);
  76         }
  77     },
  78 
  79     SOURCE_PATH("--source-path -sourcepath", STANDARD, true) {
  80         @Override
  81         public void process(Helper helper, String arg) throws InvalidValueException {
  82             Option.SOURCE_PATH.process(helper.getOptionHelper(), primaryName, arg);
  83         }
  84     },
  85 
  86     MODULE_SOURCE_PATH("--module-source-path", STANDARD, true) {
  87         @Override
  88         public void process(Helper helper, String arg) throws InvalidValueException {
  89             Option.MODULE_SOURCE_PATH.process(helper.getOptionHelper(), primaryName, arg);
  90         }
  91     },
  92 
  93     UPGRADE_MODULE_PATH("--upgrade-module-path", STANDARD, true) {
  94         @Override
  95         public void process(Helper helper, String arg) throws InvalidValueException {
  96             Option.UPGRADE_MODULE_PATH.process(helper.getOptionHelper(), primaryName, arg);
  97         }
  98     },
  99 
 100     SYSTEM("--system", STANDARD, true) {
 101         @Override
 102         public void process(Helper helper, String arg) throws InvalidValueException {
 103             Option.SYSTEM.process(helper.getOptionHelper(), primaryName, arg);
 104         }
 105     },
 106 
 107     MODULE_PATH("--module-path -p", STANDARD, true) {
 108         @Override
 109         public void process(Helper helper, String arg) throws InvalidValueException {
 110             Option.MODULE_PATH.process(helper.getOptionHelper(), primaryName, arg);
 111         }
 112     },
 113 
 114     ADD_MODULES("--add-modules", STANDARD, true) {
 115         @Override
 116         public void process(Helper helper, String arg) throws InvalidValueException {
 117             Option.ADD_MODULES.process(helper.getOptionHelper(), primaryName, arg);
 118         }
 119     },
 120 
 121     LIMIT_MODULES("--limit-modules", STANDARD, true) {
 122         @Override
 123         public void process(Helper helper, String arg) throws InvalidValueException {
 124             Option.LIMIT_MODULES.process(helper.getOptionHelper(), primaryName, arg);
 125         }
 126     },
 127 
 128     MODULE("--module", STANDARD, true) {
 129         @Override
 130         public void process(Helper helper, String arg) {
 131             helper.addToList(this, ",", arg);
 132         }
 133     },
 134 
 135     ENCODING("-encoding", STANDARD, true) {
 136         @Override
 137         public void process(Helper helper, String arg) throws InvalidValueException {
 138             Option.ENCODING.process(helper.getOptionHelper(), primaryName, arg);
 139         }
 140     },
 141 
 142     RELEASE("--release", STANDARD, true) {
 143         @Override
 144         public void process(Helper helper, String arg) throws InvalidValueException {
 145             Option.RELEASE.process(helper.getOptionHelper(), primaryName, arg);
 146         }
 147     },
 148 
 149     SOURCE("-source", STANDARD, true) {
 150         @Override
 151         public void process(Helper helper, String arg) throws InvalidValueException {
 152             Option.SOURCE.process(helper.getOptionHelper(), primaryName, arg);
 153         }
 154     },
 155 
 156     XMAXERRS("-Xmaxerrs", EXTENDED, true) {
 157         @Override
 158         public void process(Helper helper, String arg) throws InvalidValueException {
 159             Option.XMAXERRS.process(helper.getOptionHelper(), primaryName, arg);
 160         }
 161     },
 162 
 163     XMAXWARNS("-Xmaxwarns", EXTENDED, true) {
 164         @Override
 165         public void process(Helper helper, String arg) throws InvalidValueException {
 166             Option.XMAXWARNS.process(helper.getOptionHelper(), primaryName, arg);
 167         }
 168     },
 169 
 170     ADD_READS("--add-reads", EXTENDED, true) {
 171         @Override
 172         public void process(Helper helper, String arg) throws InvalidValueException {
 173             Option.ADD_READS.process(helper.getOptionHelper(), primaryName, arg);
 174         }
 175     },
 176 
 177     ADD_EXPORTS("--add-exports", EXTENDED, true) {
 178         @Override
 179         public void process(Helper helper, String arg) throws InvalidValueException {
 180             Option.ADD_EXPORTS.process(helper.getOptionHelper(), primaryName, arg);
 181         }
 182     },
 183 
 184     PATCH_MODULE("--patch-module", EXTENDED, true) {
 185         @Override
 186         public void process(Helper helper, String arg) throws InvalidValueException {
 187             Option.PATCH_MODULE.process(helper.getOptionHelper(), primaryName, arg);
 188         }
 189     },
 190 
 191     // ----- doclet options -----
 192 
 193     DOCLET("-doclet", STANDARD, true), // handled in setDocletInvoker
 194 
 195     DOCLETPATH("-docletpath", STANDARD, true), // handled in setDocletInvoker
 196 
 197     // ----- selection options -----
 198 
 199     SUBPACKAGES("-subpackages", STANDARD, true) {
 200         @Override
 201         public void process(Helper helper, String arg) {
 202             helper.addToList(this, ":", arg);
 203         }
 204     },
 205 
 206     EXCLUDE("-exclude", STANDARD, true) {
 207         @Override
 208         public void process(Helper helper, String arg) {
 209             helper.addToList(this, ":", arg);
 210         }
 211     },
 212 
 213     // ----- filtering options -----
 214 
 215     PACKAGE("-package", STANDARD) {
 216         @Override
 217         public void process(Helper helper) throws OptionException {
 218             helper.setSimpleFilter("package");
 219         }
 220     },
 221 
 222     PRIVATE("-private", STANDARD) {
 223         @Override
 224         public void process(Helper helper) throws OptionException {
 225             helper.setSimpleFilter("private");
 226         }
 227     },
 228 
 229     PROTECTED("-protected", STANDARD) {
 230         @Override
 231         public void process(Helper helper) throws OptionException {
 232             helper.setSimpleFilter("protected");
 233         }
 234     },
 235 
 236     PUBLIC("-public", STANDARD) {
 237         @Override
 238         public void process(Helper helper) throws OptionException {
 239             helper.setSimpleFilter("public");
 240         }
 241     },
 242 
 243     SHOW_MEMBERS("--show-members", STANDARD, true) {
 244         @Override
 245         public void process(Helper helper, String arg) throws OptionException {
 246             helper.setFilter(this, arg);
 247         }
 248     },
 249 
 250     SHOW_TYPES("--show-types", STANDARD, true) {
 251         @Override
 252         public void process(Helper helper, String arg) throws OptionException {
 253             helper.setFilter(this, arg);
 254         }
 255     },
 256 
 257     SHOW_PACKAGES("--show-packages", STANDARD, true) {
 258         @Override
 259         public void process(Helper helper, String arg) throws OptionException {
 260             helper.setShowPackageAccess(SHOW_PACKAGES, arg);
 261         }
 262     },
 263 
 264     SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) {
 265         @Override
 266         public void process(Helper helper, String arg) throws OptionException {
 267             helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg);
 268         }
 269     },
 270 
 271     EXPAND_REQUIRES("--expand-requires", STANDARD, true) {
 272         @Override
 273         public void process(Helper helper, String arg) throws OptionException {
 274             helper.setExpandRequires(EXPAND_REQUIRES, arg);
 275         }
 276     },
 277 
 278     // ----- output control options -----
 279 
 280     QUIET("-quiet", STANDARD) {
 281         @Override
 282         public void process(Helper helper) {
 283             helper.jdtoolOpts.put(QUIET, true);
 284         }
 285     },
 286 
 287     VERBOSE("-verbose", STANDARD) {
 288         @Override
 289         public void process(Helper helper) {
 290             helper.compOpts.put("-verbose", "");
 291         }
 292     },
 293 
 294     XWERROR("-Xwerror", HIDDEN) {
 295         @Override
 296         public void process(Helper helper) {
 297             helper.rejectWarnings = true;
 298 
 299         }
 300     },
 301 
 302     // ----- other options -----
 303 
 304     BREAKITERATOR("-breakiterator", STANDARD) {
 305         @Override
 306         public void process(Helper helper) {
 307             helper.breakiterator = true;
 308         }
 309     },
 310 
 311     LOCALE("-locale", STANDARD, true) {
 312         @Override
 313         public void process(Helper helper, String arg) {
 314             helper.docLocale = arg;
 315         }
 316     },
 317 
 318     XCLASSES("-Xclasses", HIDDEN) {
 319         @Override
 320         public void process(Helper helper) {
 321             helper.jdtoolOpts.put(XCLASSES, true);
 322         }
 323     },
 324 
 325     DUMPONERROR("--dump-on-error", HIDDEN) {
 326         @Override
 327         public void process(Helper helper) {
 328             helper.dumpOnError = true;
 329         }
 330     },
 331 
 332     IGNORE_SOURCE_ERRORS("--ignore-source-errors", HIDDEN) {
 333         @Override
 334         public void process(Helper helper) {
 335             helper.jdtoolOpts.put(IGNORE_SOURCE_ERRORS, true);
 336         }
 337     },
 338 
 339     // ----- help options -----
 340 
 341     HELP("--help -h -?", STANDARD) {
 342         @Override
 343         public void process(Helper helper) throws OptionException {
 344             throw new OptionException(OK, helper::usage);
 345         }
 346     },
 347 
 348     HELP_EXTRA("--help-extra -X", STANDARD) {
 349         @Override
 350         public void process(Helper helper) throws OptionException {
 351            throw new OptionException(OK, helper::Xusage);
 352         }
 353     },
 354 
 355     // This option exists only for the purpose of documenting itself.
 356     // It's actually implemented by the launcher.
 357     J("-J", STANDARD, true) {
 358         @Override
 359         public void process(Helper helper) {
 360             throw new AssertionError("the -J flag should be caught by the launcher.");
 361         }
 362     },
 363 
 364     VERSION("--version", STANDARD) {
 365         @Override
 366         public void process(Helper helper) throws OptionException {
 367             throw new OptionException(OK, helper::version);
 368         }
 369     },
 370 
 371     FULLVERSION("--full-version", HIDDEN) {
 372         @Override
 373         public void process(Helper helper) throws OptionException {
 374             throw new OptionException(OK, helper::fullVersion);
 375         }
 376     };
 377 
 378     public final String primaryName;
 379     public final List<String> names;
 380     public final OptionKind kind;
 381     public final boolean hasArg;
 382     public final boolean hasSuffix; // ex: foo:bar or -foo=bar
 383 
 384     ToolOption(String opt, OptionKind kind) {
 385         this(opt, kind, false);
 386     }
 387 
 388     ToolOption(String names, OptionKind kind, boolean hasArg) {
 389         this.names = Arrays.asList(names.split("\\s+"));
 390         this.primaryName = this.names.get(0);
 391         this.kind = kind;
 392         this.hasArg = hasArg;
 393         char lastChar = names.charAt(names.length() - 1);
 394         this.hasSuffix = lastChar == ':' || lastChar == '=';
 395     }
 396 
 397     void process(Helper helper, String arg) throws OptionException, Option.InvalidValueException { }
 398 
 399     void process(Helper helper) throws OptionException { }
 400 
 401     List<String> getNames() {
 402         return names;
 403     }
 404 
 405     String getParameters(Messager messager) {
 406         return (hasArg || primaryName.endsWith(":"))
 407                 ? messager.getText(getKey(primaryName, ".arg"))
 408                 : null;
 409     }
 410 
 411     String getDescription(Messager messager) {
 412         return messager.getText(getKey(primaryName, ".desc"));
 413     }
 414 
 415     private String getKey(String optionName, String suffix) {
 416         return "main.opt."
 417                 + optionName
 418                 .replaceAll("^-*", "")              // remove leading '-'
 419                 .replaceAll("[^A-Za-z0-9]+$", "")   // remove trailing non-alphanumeric
 420                 .replaceAll("[^A-Za-z0-9]", ".")    // replace internal non-alphanumeric
 421                 + suffix;
 422     }
 423 
 424 
 425     static ToolOption get(String name) {
 426         String oname = name;
 427         if (name.startsWith("--") && name.contains("=")) {
 428             oname = name.substring(0, name.indexOf('='));
 429         }
 430         for (ToolOption o : values()) {
 431             for (String n : o.names) {
 432                 if (oname.equals(n)) {
 433                     return o;
 434                 }
 435             }
 436         }
 437         return null;
 438     }
 439 
 440     static abstract class Helper {
 441 
 442         // File manager options
 443         final Map<Option, String> fileManagerOpts = new LinkedHashMap<>();
 444 
 445         /** javac options, set by various options. */
 446         Options compOpts; // = Options.instance(context)
 447 
 448         /** Javadoc tool options */
 449         final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class);
 450 
 451         /** dump stack traces for debugging etc.*/
 452         boolean dumpOnError = false;
 453 
 454         /** Set by -breakiterator. */
 455         boolean breakiterator = false;
 456 
 457         /** Set by -Xwerror. */
 458         boolean rejectWarnings = false;
 459 
 460         /** Set by -prompt. */
 461         boolean promptOnError;
 462 
 463         /** Set by -locale. */
 464         String docLocale = "";
 465 
 466         Helper() {
 467             populateDefaultAccessMap();
 468         }
 469 
 470         abstract void usage();
 471         abstract void Xusage();
 472 
 473         abstract void version();
 474         abstract void fullVersion();
 475 
 476         abstract String getLocalizedMessage(String msg, Object... args);
 477 
 478         abstract OptionHelper getOptionHelper();
 479 
 480         @SuppressWarnings("unchecked")
 481         void addToList(ToolOption opt, String delimiter, String str) {
 482             List<String> list = (List<String>) jdtoolOpts.computeIfAbsent(opt, v -> new ArrayList<>());
 483             list.addAll(Arrays.asList(str.split(delimiter)));
 484             jdtoolOpts.put(opt, list);
 485         }
 486 
 487         void setExpandRequires(ToolOption opt, String arg) throws OptionException {
 488             switch (arg) {
 489                 case "transitive":
 490                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
 491                     break;
 492                 case "all":
 493                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
 494                     break;
 495                 default:
 496                     String text = getLocalizedMessage("main.illegal_option_value", arg);
 497                     throw new IllegalOptionValue(this::usage, text);
 498             }
 499         }
 500 
 501         void setShowModuleContents(ToolOption opt, String arg) throws OptionException {
 502             switch (arg) {
 503                 case "api":
 504                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
 505                     break;
 506                 case "all":
 507                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
 508                     break;
 509                 default:
 510                     String text = getLocalizedMessage("main.illegal_option_value", arg);
 511                     throw new IllegalOptionValue(this::usage, text);
 512             }
 513         }
 514 
 515         void setShowPackageAccess(ToolOption opt, String arg) throws OptionException {
 516             switch (arg) {
 517                 case "exported":
 518                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
 519                     break;
 520                 case "all":
 521                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
 522                     break;
 523                 default:
 524                     String text = getLocalizedMessage("main.illegal_option_value", arg);
 525                     throw new IllegalOptionValue(this::usage, text);
 526             }
 527         }
 528 
 529 
 530         void setFilter(ToolOption opt, String arg) throws OptionException {
 531             jdtoolOpts.put(opt, getAccessValue(arg));
 532         }
 533 
 534         void setSimpleFilter(String arg) throws OptionException {
 535             handleSimpleOption(arg);
 536         }
 537 
 538         void setFileManagerOpt(Option opt, String arg) {
 539             fileManagerOpts.put(opt, arg);
 540         }
 541 
 542         void handleSimpleOption(String arg) throws OptionException {
 543             populateSimpleAccessMap(getAccessValue(arg));
 544         }
 545 
 546         /*
 547          * This method handles both the simple options -package,
 548          * -private, so on, in addition to the new ones such as
 549          * --show-types:public and so on.
 550          */
 551         private AccessKind getAccessValue(String arg) throws OptionException {
 552             int colon = arg.indexOf(':');
 553             String value = (colon > 0)
 554                     ? arg.substring(colon + 1)
 555                     : arg;
 556             switch (value) {
 557                 case "public":
 558                     return AccessKind.PUBLIC;
 559                 case "protected":
 560                     return AccessKind.PROTECTED;
 561                 case "package":
 562                     return AccessKind.PACKAGE;
 563                 case "private":
 564                     return AccessKind.PRIVATE;
 565                 default:
 566                     String text = getLocalizedMessage("main.illegal_option_value", value);
 567                     throw new IllegalOptionValue(this::usage, text);
 568             }
 569         }
 570 
 571         /*
 572          * Sets the entire kind map to PROTECTED this is the default.
 573          */
 574         private void populateDefaultAccessMap() {
 575             populateSimpleAccessMap(AccessKind.PROTECTED);
 576         }
 577 
 578         /*
 579          * This sets access to all the allowed kinds in the
 580          * access map.
 581          */
 582         void populateSimpleAccessMap(AccessKind accessValue) {
 583             for (ElementKind kind : ElementsTable.ModifierFilter.ALLOWED_KINDS) {
 584                 switch (kind) {
 585                     case METHOD:
 586                         jdtoolOpts.put(SHOW_MEMBERS, accessValue);
 587                         break;
 588                     case CLASS:
 589                         jdtoolOpts.put(SHOW_TYPES, accessValue);
 590                         break;
 591                     case PACKAGE:
 592                         jdtoolOpts.put(SHOW_PACKAGES, accessValue);
 593                         break;
 594                     case MODULE:
 595                         jdtoolOpts.put(SHOW_MODULE_CONTENTS, accessValue);
 596                         break;
 597                     default:
 598                         throw new AssertionError("unknown element kind:" + kind);
 599                 }
 600             }
 601         }
 602     }
 603 }