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
26package jdk.javadoc.internal.tool;
27
28import java.util.ArrayList;
29import java.util.Arrays;
30import java.util.EnumMap;
31import java.util.LinkedHashMap;
32import java.util.List;
33import java.util.Map;
34
35import javax.lang.model.element.ElementKind;
36
37import com.sun.tools.javac.main.Option;
38import com.sun.tools.javac.main.Option.InvalidValueException;
39import com.sun.tools.javac.main.Option.OptionKind;
40import com.sun.tools.javac.main.OptionHelper;
41import com.sun.tools.javac.util.Options;
42
43import static com.sun.tools.javac.main.Option.OptionKind.*;
44import 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 */
54public 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 -help", 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    // This option exists only for the purpose of documenting itself.
365    // It's actually implemented ahead of the normal option decoding loop.
366    Xold("-Xold", EXTENDED) {
367        @Override
368        public void process(Helper helper) {
369            throw new AssertionError("the -Xold flag should be handled earlier.");
370        }
371    };
372
373    public final String primaryName;
374    public final List<String> names;
375    public final OptionKind kind;
376    public final boolean hasArg;
377    public final boolean hasSuffix; // ex: foo:bar or -foo=bar
378
379    ToolOption(String opt, OptionKind kind) {
380        this(opt, kind, false);
381    }
382
383    ToolOption(String names, OptionKind kind, boolean hasArg) {
384        this.names = Arrays.asList(names.split("\\s+"));
385        this.primaryName = this.names.get(0);
386        this.kind = kind;
387        this.hasArg = hasArg;
388        char lastChar = names.charAt(names.length() - 1);
389        this.hasSuffix = lastChar == ':' || lastChar == '=';
390    }
391
392    void process(Helper helper, String arg) throws OptionException, Option.InvalidValueException { }
393
394    void process(Helper helper) throws OptionException { }
395
396    List<String> getNames() {
397        return names;
398    }
399
400    String getParameters(Messager messager) {
401        return (hasArg || primaryName.endsWith(":"))
402                ? messager.getText(getKey(primaryName, ".arg"))
403                : null;
404    }
405
406    String getDescription(Messager messager) {
407        return messager.getText(getKey(primaryName, ".desc"));
408    }
409
410    private String getKey(String optionName, String suffix) {
411        return "main.opt."
412                + optionName
413                .replaceAll("^-*", "")              // remove leading '-'
414                .replaceAll("[^A-Za-z0-9]+$", "")   // remove trailing non-alphanumeric
415                .replaceAll("[^A-Za-z0-9]", ".")    // replace internal non-alphanumeric
416                + suffix;
417    }
418
419
420    static ToolOption get(String name) {
421        String oname = name;
422        if (name.startsWith("--") && name.contains("=")) {
423            oname = name.substring(0, name.indexOf('='));
424        }
425        for (ToolOption o : values()) {
426            for (String n : o.names) {
427                if (oname.equals(n)) {
428                    return o;
429                }
430            }
431        }
432        return null;
433    }
434
435    static abstract class Helper {
436
437        // File manager options
438        final Map<Option, String> fileManagerOpts = new LinkedHashMap<>();
439
440        /** javac options, set by various options. */
441        Options compOpts; // = Options.instance(context)
442
443        /** Javadoc tool options */
444        final Map<ToolOption, Object> jdtoolOpts = new EnumMap<>(ToolOption.class);
445
446        /** dump stack traces for debugging etc.*/
447        boolean dumpOnError = false;
448
449        /** Set by -breakiterator. */
450        boolean breakiterator = false;
451
452        /** Set by -Xwerror. */
453        boolean rejectWarnings = false;
454
455        /** Set by -prompt. */
456        boolean promptOnError;
457
458        /** Set by -locale. */
459        String docLocale = "";
460
461        Helper() {
462            populateDefaultAccessMap();
463        }
464
465        abstract void usage();
466        abstract void Xusage();
467
468        abstract String getLocalizedMessage(String msg, Object... args);
469
470        abstract OptionHelper getOptionHelper();
471
472        @SuppressWarnings("unchecked")
473        void addToList(ToolOption opt, String delimiter, String str) {
474            List<String> list = (List<String>) jdtoolOpts.computeIfAbsent(opt, v -> new ArrayList<>());
475            list.addAll(Arrays.asList(str.split(delimiter)));
476            jdtoolOpts.put(opt, list);
477        }
478
479        void setExpandRequires(ToolOption opt, String arg) throws OptionException {
480            switch (arg) {
481                case "transitive":
482                    jdtoolOpts.put(opt, AccessKind.PUBLIC);
483                    break;
484                case "all":
485                    jdtoolOpts.put(opt, AccessKind.PRIVATE);
486                    break;
487                default:
488                    String text = getLocalizedMessage("main.illegal_option_value", arg);
489                    throw new IllegalOptionValue(this::usage, text);
490            }
491        }
492
493        void setShowModuleContents(ToolOption opt, String arg) throws OptionException {
494            switch (arg) {
495                case "api":
496                    jdtoolOpts.put(opt, AccessKind.PUBLIC);
497                    break;
498                case "all":
499                    jdtoolOpts.put(opt, AccessKind.PRIVATE);
500                    break;
501                default:
502                    String text = getLocalizedMessage("main.illegal_option_value", arg);
503                    throw new IllegalOptionValue(this::usage, text);
504            }
505        }
506
507        void setShowPackageAccess(ToolOption opt, String arg) throws OptionException {
508            switch (arg) {
509                case "exported":
510                    jdtoolOpts.put(opt, AccessKind.PUBLIC);
511                    break;
512                case "all":
513                    jdtoolOpts.put(opt, AccessKind.PRIVATE);
514                    break;
515                default:
516                    String text = getLocalizedMessage("main.illegal_option_value", arg);
517                    throw new IllegalOptionValue(this::usage, text);
518            }
519        }
520
521
522        void setFilter(ToolOption opt, String arg) throws OptionException {
523            jdtoolOpts.put(opt, getAccessValue(arg));
524        }
525
526        void setSimpleFilter(String arg) throws OptionException {
527            handleSimpleOption(arg);
528        }
529
530        void setFileManagerOpt(Option opt, String arg) {
531            fileManagerOpts.put(opt, arg);
532        }
533
534        void handleSimpleOption(String arg) throws OptionException {
535            populateSimpleAccessMap(getAccessValue(arg));
536        }
537
538        /*
539         * This method handles both the simple options -package,
540         * -private, so on, in addition to the new ones such as
541         * --show-types:public and so on.
542         */
543        private AccessKind getAccessValue(String arg) throws OptionException {
544            int colon = arg.indexOf(':');
545            String value = (colon > 0)
546                    ? arg.substring(colon + 1)
547                    : arg;
548            switch (value) {
549                case "public":
550                    return AccessKind.PUBLIC;
551                case "protected":
552                    return AccessKind.PROTECTED;
553                case "package":
554                    return AccessKind.PACKAGE;
555                case "private":
556                    return AccessKind.PRIVATE;
557                default:
558                    String text = getLocalizedMessage("main.illegal_option_value", value);
559                    throw new IllegalOptionValue(this::usage, text);
560            }
561        }
562
563        /*
564         * Sets the entire kind map to PROTECTED this is the default.
565         */
566        private void populateDefaultAccessMap() {
567            populateSimpleAccessMap(AccessKind.PROTECTED);
568        }
569
570        /*
571         * This sets access to all the allowed kinds in the
572         * access map.
573         */
574        void populateSimpleAccessMap(AccessKind accessValue) {
575            for (ElementKind kind : ElementsTable.ModifierFilter.ALLOWED_KINDS) {
576                switch (kind) {
577                    case METHOD:
578                        jdtoolOpts.put(SHOW_MEMBERS, accessValue);
579                        break;
580                    case CLASS:
581                        jdtoolOpts.put(SHOW_TYPES, accessValue);
582                        break;
583                    case PACKAGE:
584                        jdtoolOpts.put(SHOW_PACKAGES, accessValue);
585                        break;
586                    case MODULE:
587                        jdtoolOpts.put(SHOW_MODULE_CONTENTS, accessValue);
588                        break;
589                    default:
590                        throw new AssertionError("unknown element kind:" + kind);
591                }
592            }
593        }
594    }
595}
596