1 /*
2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package 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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)130         public void process(Helper helper, String arg) {
131             helper.addToList(this, ",", arg);
132         }
133     },
134 
135     ENCODING("-encoding", STANDARD, true) {
136         @Override
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)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
process(Helper helper, String arg)187         public void process(Helper helper, String arg) throws InvalidValueException {
188             Option.PATCH_MODULE.process(helper.getOptionHelper(), primaryName, arg);
189         }
190     },
191 
192     ADD_OPENS("--add-opens", HIDDEN, true) {
193         @Override
process(Helper helper, String arg)194         public void process(Helper helper, String arg) throws InvalidValueException {
195             Option.ADD_OPENS.process(helper.getOptionHelper(), primaryName, arg);
196         }
197     },
198 
199     ENABLE_PREVIEW("--enable-preview", STANDARD) {
200         @Override
process(Helper helper)201         public void process(Helper helper) throws InvalidValueException {
202             Option.PREVIEW.process(helper.getOptionHelper(), primaryName);
203         }
204     },
205 
206     // ----- doclet options -----
207 
208     DOCLET("-doclet", STANDARD, true), // handled in setDocletInvoker
209 
210     DOCLETPATH("-docletpath", STANDARD, true), // handled in setDocletInvoker
211 
212     // ----- selection options -----
213 
214     SUBPACKAGES("-subpackages", STANDARD, true) {
215         @Override
process(Helper helper, String arg)216         public void process(Helper helper, String arg) {
217             helper.addToList(this, ":", arg);
218         }
219     },
220 
221     EXCLUDE("-exclude", STANDARD, true) {
222         @Override
process(Helper helper, String arg)223         public void process(Helper helper, String arg) {
224             helper.addToList(this, ":", arg);
225         }
226     },
227 
228     // ----- filtering options -----
229 
230     PACKAGE("-package", STANDARD) {
231         @Override
process(Helper helper)232         public void process(Helper helper) throws OptionException {
233             helper.setSimpleFilter("package");
234         }
235     },
236 
237     PRIVATE("-private", STANDARD) {
238         @Override
process(Helper helper)239         public void process(Helper helper) throws OptionException {
240             helper.setSimpleFilter("private");
241         }
242     },
243 
244     PROTECTED("-protected", STANDARD) {
245         @Override
process(Helper helper)246         public void process(Helper helper) throws OptionException {
247             helper.setSimpleFilter("protected");
248         }
249     },
250 
251     PUBLIC("-public", STANDARD) {
252         @Override
process(Helper helper)253         public void process(Helper helper) throws OptionException {
254             helper.setSimpleFilter("public");
255         }
256     },
257 
258     SHOW_MEMBERS("--show-members", STANDARD, true) {
259         @Override
process(Helper helper, String arg)260         public void process(Helper helper, String arg) throws OptionException {
261             helper.setFilter(this, arg);
262         }
263     },
264 
265     SHOW_TYPES("--show-types", STANDARD, true) {
266         @Override
process(Helper helper, String arg)267         public void process(Helper helper, String arg) throws OptionException {
268             helper.setFilter(this, arg);
269         }
270     },
271 
272     SHOW_PACKAGES("--show-packages", STANDARD, true) {
273         @Override
process(Helper helper, String arg)274         public void process(Helper helper, String arg) throws OptionException {
275             helper.setShowPackageAccess(SHOW_PACKAGES, arg);
276         }
277     },
278 
279     SHOW_MODULE_CONTENTS("--show-module-contents", STANDARD, true) {
280         @Override
process(Helper helper, String arg)281         public void process(Helper helper, String arg) throws OptionException {
282             helper.setShowModuleContents(SHOW_MODULE_CONTENTS, arg);
283         }
284     },
285 
286     EXPAND_REQUIRES("--expand-requires", STANDARD, true) {
287         @Override
process(Helper helper, String arg)288         public void process(Helper helper, String arg) throws OptionException {
289             helper.setExpandRequires(EXPAND_REQUIRES, arg);
290         }
291     },
292 
293     // ----- output control options -----
294 
295     QUIET("-quiet", STANDARD) {
296         @Override
process(Helper helper)297         public void process(Helper helper) {
298             helper.jdtoolOpts.put(QUIET, true);
299         }
300     },
301 
302     VERBOSE("-verbose", STANDARD) {
303         @Override
process(Helper helper)304         public void process(Helper helper) {
305             helper.compOpts.put("-verbose", "");
306         }
307     },
308 
309     XWERROR("-Xwerror", HIDDEN) {
310         @Override
process(Helper helper)311         public void process(Helper helper) {
312             helper.rejectWarnings = true;
313 
314         }
315     },
316 
317     // ----- other options -----
318 
319     BREAKITERATOR("-breakiterator", STANDARD) {
320         @Override
process(Helper helper)321         public void process(Helper helper) {
322             helper.breakiterator = true;
323         }
324     },
325 
326     LOCALE("-locale", STANDARD, true) {
327         @Override
process(Helper helper, String arg)328         public void process(Helper helper, String arg) {
329             helper.docLocale = arg;
330         }
331     },
332 
333     XCLASSES("-Xclasses", HIDDEN) {
334         @Override
process(Helper helper)335         public void process(Helper helper) {
336             helper.jdtoolOpts.put(XCLASSES, true);
337         }
338     },
339 
340     DUMPONERROR("--dump-on-error", HIDDEN) {
341         @Override
process(Helper helper)342         public void process(Helper helper) {
343             helper.dumpOnError = true;
344         }
345     },
346 
347     IGNORE_SOURCE_ERRORS("--ignore-source-errors", HIDDEN) {
348         @Override
process(Helper helper)349         public void process(Helper helper) {
350             helper.jdtoolOpts.put(IGNORE_SOURCE_ERRORS, true);
351         }
352     },
353 
354     // ----- help options -----
355 
356     HELP("--help -help -? -h", STANDARD) {
357         @Override
process(Helper helper)358         public void process(Helper helper) throws OptionException {
359             throw new OptionException(OK, helper::usage);
360         }
361     },
362 
363     HELP_EXTRA("--help-extra -X", STANDARD) {
364         @Override
process(Helper helper)365         public void process(Helper helper) throws OptionException {
366            throw new OptionException(OK, helper::Xusage);
367         }
368     },
369 
370     // This option exists only for the purpose of documenting itself.
371     // It's actually implemented by the launcher.
372     J("-J", STANDARD, true) {
373         @Override
process(Helper helper)374         public void process(Helper helper) {
375             throw new AssertionError("the -J flag should be caught by the launcher.");
376         }
377     },
378 
379     VERSION("--version", STANDARD) {
380         @Override
process(Helper helper)381         public void process(Helper helper) throws OptionException {
382             throw new OptionException(OK, helper::version);
383         }
384     },
385 
386     FULLVERSION("--full-version", HIDDEN) {
387         @Override
process(Helper helper)388         public void process(Helper helper) throws OptionException {
389             throw new OptionException(OK, helper::fullVersion);
390         }
391     };
392 
393     public final String primaryName;
394     public final List<String> names;
395     public final OptionKind kind;
396     public final boolean hasArg;
397     public final boolean hasSuffix; // ex: foo:bar or -foo=bar
398 
ToolOption(String opt, OptionKind kind)399     ToolOption(String opt, OptionKind kind) {
400         this(opt, kind, false);
401     }
402 
ToolOption(String names, OptionKind kind, boolean hasArg)403     ToolOption(String names, OptionKind kind, boolean hasArg) {
404         this.names = Arrays.asList(names.split("\\s+"));
405         this.primaryName = this.names.get(0);
406         this.kind = kind;
407         this.hasArg = hasArg;
408         char lastChar = names.charAt(names.length() - 1);
409         this.hasSuffix = lastChar == ':' || lastChar == '=';
410     }
411 
process(Helper helper, String arg)412     void process(Helper helper, String arg) throws OptionException, Option.InvalidValueException { }
413 
process(Helper helper)414     void process(Helper helper) throws OptionException, Option.InvalidValueException { }
415 
getNames()416     List<String> getNames() {
417         return names;
418     }
419 
getParameters(Messager messager)420     String getParameters(Messager messager) {
421         return (hasArg || primaryName.endsWith(":"))
422                 ? messager.getText(getKey(primaryName, ".arg"))
423                 : null;
424     }
425 
getDescription(Messager messager)426     String getDescription(Messager messager) {
427         return messager.getText(getKey(primaryName, ".desc"));
428     }
429 
getKey(String optionName, String suffix)430     private String getKey(String optionName, String suffix) {
431         return "main.opt."
432                 + optionName
433                 .replaceAll("^-*", "")              // remove leading '-'
434                 .replaceAll("[^A-Za-z0-9]+$", "")   // remove trailing non-alphanumeric
435                 .replaceAll("[^A-Za-z0-9]", ".")    // replace internal non-alphanumeric
436                 + suffix;
437     }
438 
439 
get(String name)440     static ToolOption get(String name) {
441         String oname = name;
442         if (name.startsWith("--") && name.contains("=")) {
443             oname = name.substring(0, name.indexOf('='));
444         }
445         for (ToolOption o : values()) {
446             for (String n : o.names) {
447                 if (oname.equals(n)) {
448                     return o;
449                 }
450             }
451         }
452         return null;
453     }
454 
455     static abstract class Helper {
456 
457         // File manager options
458         final Map<Option, String> fileManagerOpts = new LinkedHashMap<>();
459 
460         /** javac options, set by various options. */
461         Options compOpts; // = Options.instance(context)
462 
463         /** Javadoc tool options */
464         final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class);
465 
466         /** dump stack traces for debugging etc.*/
467         boolean dumpOnError = false;
468 
469         /** Set by -breakiterator. */
470         boolean breakiterator = false;
471 
472         /** Set by -Xwerror. */
473         boolean rejectWarnings = false;
474 
475         /** Set by -prompt. */
476         boolean promptOnError;
477 
478         /** Set by -locale. */
479         String docLocale = "";
480 
Helper()481         Helper() {
482             populateDefaultAccessMap();
483         }
484 
usage()485         abstract void usage();
Xusage()486         abstract void Xusage();
487 
version()488         abstract void version();
fullVersion()489         abstract void fullVersion();
490 
getLocalizedMessage(String msg, Object... args)491         abstract String getLocalizedMessage(String msg, Object... args);
492 
getOptionHelper()493         abstract OptionHelper getOptionHelper();
494 
495         @SuppressWarnings("unchecked")
addToList(ToolOption opt, String delimiter, String str)496         void addToList(ToolOption opt, String delimiter, String str) {
497             List<String> list = (List<String>) jdtoolOpts.computeIfAbsent(opt, v -> new ArrayList<>());
498             list.addAll(Arrays.asList(str.split(delimiter)));
499             jdtoolOpts.put(opt, list);
500         }
501 
setExpandRequires(ToolOption opt, String arg)502         void setExpandRequires(ToolOption opt, String arg) throws OptionException {
503             switch (arg) {
504                 case "transitive":
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 
setShowModuleContents(ToolOption opt, String arg)516         void setShowModuleContents(ToolOption opt, String arg) throws OptionException {
517             switch (arg) {
518                 case "api":
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 
setShowPackageAccess(ToolOption opt, String arg)530         void setShowPackageAccess(ToolOption opt, String arg) throws OptionException {
531             switch (arg) {
532                 case "exported":
533                     jdtoolOpts.put(opt, AccessKind.PUBLIC);
534                     break;
535                 case "all":
536                     jdtoolOpts.put(opt, AccessKind.PRIVATE);
537                     break;
538                 default:
539                     String text = getLocalizedMessage("main.illegal_option_value", arg);
540                     throw new IllegalOptionValue(this::usage, text);
541             }
542         }
543 
544 
setFilter(ToolOption opt, String arg)545         void setFilter(ToolOption opt, String arg) throws OptionException {
546             jdtoolOpts.put(opt, getAccessValue(arg));
547         }
548 
setSimpleFilter(String arg)549         void setSimpleFilter(String arg) throws OptionException {
550             handleSimpleOption(arg);
551         }
552 
setFileManagerOpt(Option opt, String arg)553         void setFileManagerOpt(Option opt, String arg) {
554             fileManagerOpts.put(opt, arg);
555         }
556 
handleSimpleOption(String arg)557         void handleSimpleOption(String arg) throws OptionException {
558             populateSimpleAccessMap(getAccessValue(arg));
559         }
560 
561         /*
562          * This method handles both the simple options -package,
563          * -private, so on, in addition to the new ones such as
564          * --show-types:public and so on.
565          */
getAccessValue(String arg)566         private AccessKind getAccessValue(String arg) throws OptionException {
567             int colon = arg.indexOf(':');
568             String value = (colon > 0)
569                     ? arg.substring(colon + 1)
570                     : arg;
571             switch (value) {
572                 case "public":
573                     return AccessKind.PUBLIC;
574                 case "protected":
575                     return AccessKind.PROTECTED;
576                 case "package":
577                     return AccessKind.PACKAGE;
578                 case "private":
579                     return AccessKind.PRIVATE;
580                 default:
581                     String text = getLocalizedMessage("main.illegal_option_value", value);
582                     throw new IllegalOptionValue(this::usage, text);
583             }
584         }
585 
586         /*
587          * Sets the entire kind map to PROTECTED this is the default.
588          */
populateDefaultAccessMap()589         private void populateDefaultAccessMap() {
590             populateSimpleAccessMap(AccessKind.PROTECTED);
591         }
592 
593         /*
594          * This sets access to all the allowed kinds in the
595          * access map.
596          */
populateSimpleAccessMap(AccessKind accessValue)597         void populateSimpleAccessMap(AccessKind accessValue) {
598             for (ElementKind kind : ElementsTable.ModifierFilter.ALLOWED_KINDS) {
599                 switch (kind) {
600                     case METHOD:
601                         jdtoolOpts.put(SHOW_MEMBERS, accessValue);
602                         break;
603                     case CLASS:
604                         jdtoolOpts.put(SHOW_TYPES, accessValue);
605                         break;
606                     case PACKAGE:
607                         jdtoolOpts.put(SHOW_PACKAGES, accessValue);
608                         break;
609                     case MODULE:
610                         jdtoolOpts.put(SHOW_MODULE_CONTENTS, accessValue);
611                         break;
612                     default:
613                         throw new AssertionError("unknown element kind:" + kind);
614                 }
615             }
616         }
617     }
618 }
619