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             Option.TARGET.process(helper.getOptionHelper(), Option.TARGET.primaryName, arg);
 154         }
 155     },
 156 
 157     XMAXERRS("-Xmaxerrs", EXTENDED, true) {
 158         @Override
 159         public void process(Helper helper, String arg) throws InvalidValueException {
 160             Option.XMAXERRS.process(helper.getOptionHelper(), primaryName, arg);
 161         }
 162     },
 163 
 164     XMAXWARNS("-Xmaxwarns", EXTENDED, true) {
 165         @Override
 166         public void process(Helper helper, String arg) throws InvalidValueException {
 167             Option.XMAXWARNS.process(helper.getOptionHelper(), primaryName, arg);
 168         }
 169     },
 170 
 171     ADD_READS("--add-reads", EXTENDED, true) {
 172         @Override
 173         public void process(Helper helper, String arg) throws InvalidValueException {
 174             Option.ADD_READS.process(helper.getOptionHelper(), primaryName, arg);
 175         }
 176     },
 177 
 178     ADD_EXPORTS("--add-exports", EXTENDED, true) {
 179         @Override
 180         public void process(Helper helper, String arg) throws InvalidValueException {
 181             Option.ADD_EXPORTS.process(helper.getOptionHelper(), primaryName, arg);
 182         }
 183     },
 184 
 185     PATCH_MODULE("--patch-module", EXTENDED, true) {
 186         @Override
 187         public void process(Helper helper, String arg) throws InvalidValueException {
 188             Option.PATCH_MODULE.process(helper.getOptionHelper(), primaryName, arg);
 189         }
 190     },
 191 
 192     // ----- doclet options -----
 193 
 194     DOCLET("-doclet", STANDARD, true), // handled in setDocletInvoker
 195 
 196     DOCLETPATH("-docletpath", STANDARD, true), // handled in setDocletInvoker
 197 
 198     // ----- selection options -----
 199 
 200     SUBPACKAGES("-subpackages", STANDARD, true) {
 201         @Override
 202         public void process(Helper helper, String arg) {
 203             helper.addToList(this, ":", arg);
 204         }
 205     },
 206 
 207     EXCLUDE("-exclude", STANDARD, true) {
 208         @Override
 209         public void process(Helper helper, String arg) {
 210             helper.addToList(this, ":", arg);
 211         }
 212     },
 213 
 214     // ----- filtering options -----
 215 
 216     PACKAGE("-package", STANDARD) {
 217         @Override
 218         public void process(Helper helper) throws OptionException {
 219             helper.setSimpleFilter("package");
 220         }
 221     },
 222 
 223     PRIVATE("-private", STANDARD) {
 224         @Override
 225         public void process(Helper helper) throws OptionException {
 226             helper.setSimpleFilter("private");
 227         }
 228     },
 229 
 230     PROTECTED("-protected", STANDARD) {
 231         @Override
 232         public void process(Helper helper) throws OptionException {
 233             helper.setSimpleFilter("protected");
 234         }
 235     },
 236 
 237     PUBLIC("-public", STANDARD) {
 238         @Override
 239         public void process(Helper helper) throws OptionException {
 240             helper.setSimpleFilter("public");
 241         }
 242     },
 243 
 244     SHOW_MEMBERS("--show-members", STANDARD, true) {
 245         @Override
 246         public void process(Helper helper, String arg) throws OptionException {
 247             helper.setFilter(this, arg);
 248         }
 249     },
 250 
 251     SHOW_TYPES("--show-types", STANDARD, true) {
 252         @Override
 253         public void process(Helper helper, String arg) throws OptionException {
 254             helper.setFilter(this, arg);
 255         }
 256     },
 257 
 258     SHOW_PACKAGES("--show-packages", STANDARD, true) {
 259         @Override
 260         public void process(Helper helper, String arg) throws OptionException {
 261             helper.setShowPackageAccess(SHOW_PACKAGES, arg);
 262         }
 263     },
 264 
 265     SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) {
 266         @Override
 267         public void process(Helper helper, String arg) throws OptionException {
 268             helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg);
 269         }
 270     },
 271 
 272     EXPAND_REQUIRES("--expand-requires", STANDARD, true) {
 273         @Override
 274         public void process(Helper helper, String arg) throws OptionException {
 275             helper.setExpandRequires(EXPAND_REQUIRES, arg);
 276         }
 277     },
 278 
 279     // ----- output control options -----
 280 
 281     QUIET("-quiet", STANDARD) {
 282         @Override
 283         public void process(Helper helper) {
 284             helper.jdtoolOpts.put(QUIET, true);
 285         }
 286     },
 287 
 288     VERBOSE("-verbose", STANDARD) {
 289         @Override
 290         public void process(Helper helper) {
 291             helper.compOpts.put("-verbose", "");
 292         }
 293     },
 294 
 295     XWERROR("-Xwerror", HIDDEN) {
 296         @Override
 297         public void process(Helper helper) {
 298             helper.rejectWarnings = true;
 299 
 300         }
 301     },
 302 
 303     // ----- other options -----
 304 
 305     BREAKITERATOR("-breakiterator", STANDARD) {
 306         @Override
 307         public void process(Helper helper) {
 308             helper.breakiterator = true;
 309         }
 310     },
 311 
 312     LOCALE("-locale", STANDARD, true) {
 313         @Override
 314         public void process(Helper helper, String arg) {
 315             helper.docLocale = arg;
 316         }
 317     },
 318 
 319     XCLASSES("-Xclasses", HIDDEN) {
 320         @Override
 321         public void process(Helper helper) {
 322             helper.jdtoolOpts.put(XCLASSES, true);
 323         }
 324     },
 325 
 326     DUMPONERROR("--dump-on-error", HIDDEN) {
 327         @Override
 328         public void process(Helper helper) {
 329             helper.dumpOnError = true;
 330         }
 331     },
 332 
 333     IGNORE_SOURCE_ERRORS("--ignore-source-errors", HIDDEN) {
 334         @Override
 335         public void process(Helper helper) {
 336             helper.jdtoolOpts.put(IGNORE_SOURCE_ERRORS, true);
 337         }
 338     },
 339 
 340     // ----- help options -----
 341 
 342     HELP("--help -help", STANDARD) {
 343         @Override
 344         public void process(Helper helper) throws OptionException {
 345             throw new OptionException(OK, helper::usage);
 346         }
 347     },
 348 
 349     HELP_EXTRA("--help-extra -X", STANDARD) {
 350         @Override
 351         public void process(Helper helper) throws OptionException {
 352            throw new OptionException(OK, helper::Xusage);
 353         }
 354     },
 355 
 356     // This option exists only for the purpose of documenting itself.
 357     // It's actually implemented by the launcher.
 358     J("-J", STANDARD, true) {
 359         @Override
 360         public void process(Helper helper) {
 361             throw new AssertionError("the -J flag should be caught by the launcher.");
 362         }
 363     },
 364 
 365     VERSION("--version", STANDARD) {
 366         @Override
 367         public void process(Helper helper) throws OptionException {
 368             throw new OptionException(OK, helper::version);
 369         }
 370     },
 371 
 372     FULLVERSION("--full-version", HIDDEN) {
 373         @Override
 374         public void process(Helper helper) throws OptionException {
 375             throw new OptionException(OK, helper::fullVersion);
 376         }
 377     };
 378 
 379     public final String primaryName;
 380     public final List<String> names;
 381     public final OptionKind kind;
 382     public final boolean hasArg;
 383     public final boolean hasSuffix; // ex: foo:bar or -foo=bar
 384 
 385     ToolOption(String opt, OptionKind kind) {
 386         this(opt, kind, false);
 387     }
 388 
 389     ToolOption(String names, OptionKind kind, boolean hasArg) {
 390         this.names = Arrays.asList(names.split("\\s+"));
 391         this.primaryName = this.names.get(0);
 392         this.kind = kind;
 393         this.hasArg = hasArg;
 394         char lastChar = names.charAt(names.length() - 1);
 395         this.hasSuffix = lastChar == ':' || lastChar == '=';
 396     }
 397 
 398     void process(Helper helper, String arg) throws OptionException, Option.InvalidValueException { }
 399 
 400     void process(Helper helper) throws OptionException { }
 401 
 402     List<String> getNames() {
 403         return names;
 404     }
 405 
 406     String getParameters(Messager messager) {
 407         return (hasArg || primaryName.endsWith(":"))
 408                 ? messager.getText(getKey(primaryName, ".arg"))
 409                 : null;
 410     }
 411 
 412     String getDescription(Messager messager) {
 413         return messager.getText(getKey(primaryName, ".desc"));
 414     }
 415 
 416     private String getKey(String optionName, String suffix) {
 417         return "main.opt."
 418                 + optionName
 419                 .replaceAll("^-*", "")              // remove leading '-'
 420                 .replaceAll("[^A-Za-z0-9]+$", "")   // remove trailing non-alphanumeric
 421                 .replaceAll("[^A-Za-z0-9]", ".")    // replace internal non-alphanumeric
 422                 + suffix;
 423     }
 424 
 425 
 426     static ToolOption get(String name) {
 427         String oname = name;
 428         if (name.startsWith("--") && name.contains("=")) {
 429             oname = name.substring(0, name.indexOf('='));
 430         }
 431         for (ToolOption o : values()) {
 432             for (String n : o.names) {
 433                 if (oname.equals(n)) {
 434                     return o;
 435                 }
 436             }
 437         }
 438         return null;
 439     }
 440 
 441     static abstract class Helper {
 442 
 443         // File manager options
 444         final Map<Option, String> fileManagerOpts = new LinkedHashMap<>();
 445 
 446         /** javac options, set by various options. */
 447         Options compOpts; // = Options.instance(context)
 448 
 449         /** Javadoc tool options */
 450         final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class);
 451 
 452         /** dump stack traces for debugging etc.*/
 453         boolean dumpOnError = false;
 454 
 455         /** Set by -breakiterator. */
 456         boolean breakiterator = false;
 457 
 458         /** Set by -Xwerror. */
 459         boolean rejectWarnings = false;
 460 
 461         /** Set by -prompt. */
 462         boolean promptOnError;
 463 
 464         /** Set by -locale. */
 465         String docLocale = "";
 466 
 467         Helper() {
 468             populateDefaultAccessMap();
 469         }
 470 
 471         abstract void usage();
 472         abstract void Xusage();
 473 
 474         abstract void version();
 475         abstract void fullVersion();
 476 
 477         abstract String getLocalizedMessage(String msg, Object... args);
 478 
 479         abstract OptionHelper getOptionHelper();
 480 
 481         @SuppressWarnings("unchecked")
 482         void addToList(ToolOption opt, String delimiter, String str) {
 483             List<String> list = (List<String>) jdtoolOpts.computeIfAbsent(opt, v -> new ArrayList<>());
 484             list.addAll(Arrays.asList(str.split(delimiter)));
 485             jdtoolOpts.put(opt, list);
 486         }
 487 
 488         void setExpandRequires(ToolOption opt, String arg) throws OptionException {
 489             switch (arg) {
 490                 case "transitive":
 491                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
 492                     break;
 493                 case "all":
 494                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
 495                     break;
 496                 default:
 497                     String text = getLocalizedMessage("main.illegal_option_value", arg);
 498                     throw new IllegalOptionValue(this::usage, text);
 499             }
 500         }
 501 
 502         void setShowModuleContents(ToolOption opt, String arg) throws OptionException {
 503             switch (arg) {
 504                 case "api":
 505                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
 506                     break;
 507                 case "all":
 508                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
 509                     break;
 510                 default:
 511                     String text = getLocalizedMessage("main.illegal_option_value", arg);
 512                     throw new IllegalOptionValue(this::usage, text);
 513             }
 514         }
 515 
 516         void setShowPackageAccess(ToolOption opt, String arg) throws OptionException {
 517             switch (arg) {
 518                 case "exported":
 519                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
 520                     break;
 521                 case "all":
 522                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
 523                     break;
 524                 default:
 525                     String text = getLocalizedMessage("main.illegal_option_value", arg);
 526                     throw new IllegalOptionValue(this::usage, text);
 527             }
 528         }
 529 
 530 
 531         void setFilter(ToolOption opt, String arg) throws OptionException {
 532             jdtoolOpts.put(opt, getAccessValue(arg));
 533         }
 534 
 535         void setSimpleFilter(String arg) throws OptionException {
 536             handleSimpleOption(arg);
 537         }
 538 
 539         void setFileManagerOpt(Option opt, String arg) {
 540             fileManagerOpts.put(opt, arg);
 541         }
 542 
 543         void handleSimpleOption(String arg) throws OptionException {
 544             populateSimpleAccessMap(getAccessValue(arg));
 545         }
 546 
 547         /*
 548          * This method handles both the simple options -package,
 549          * -private, so on, in addition to the new ones such as
 550          * --show-types:public and so on.
 551          */
 552         private AccessKind getAccessValue(String arg) throws OptionException {
 553             int colon = arg.indexOf(':');
 554             String value = (colon > 0)
 555                     ? arg.substring(colon + 1)
 556                     : arg;
 557             switch (value) {
 558                 case "public":
 559                     return AccessKind.PUBLIC;
 560                 case "protected":
 561                     return AccessKind.PROTECTED;
 562                 case "package":
 563                     return AccessKind.PACKAGE;
 564                 case "private":
 565                     return AccessKind.PRIVATE;
 566                 default:
 567                     String text = getLocalizedMessage("main.illegal_option_value", value);
 568                     throw new IllegalOptionValue(this::usage, text);
 569             }
 570         }
 571 
 572         /*
 573          * Sets the entire kind map to PROTECTED this is the default.
 574          */
 575         private void populateDefaultAccessMap() {
 576             populateSimpleAccessMap(AccessKind.PROTECTED);
 577         }
 578 
 579         /*
 580          * This sets access to all the allowed kinds in the
 581          * access map.
 582          */
 583         void populateSimpleAccessMap(AccessKind accessValue) {
 584             for (ElementKind kind : ElementsTable.ModifierFilter.ALLOWED_KINDS) {
 585                 switch (kind) {
 586                     case METHOD:
 587                         jdtoolOpts.put(SHOW_MEMBERS, accessValue);
 588                         break;
 589                     case CLASS:
 590                         jdtoolOpts.put(SHOW_TYPES, accessValue);
 591                         break;
 592                     case PACKAGE:
 593                         jdtoolOpts.put(SHOW_PACKAGES, accessValue);
 594                         break;
 595                     case MODULE:
 596                         jdtoolOpts.put(SHOW_MODULE_CONTENTS, accessValue);
 597                         break;
 598                     default:
 599                         throw new AssertionError("unknown element kind:" + kind);
 600                 }
 601             }
 602         }
 603     }
 604 }