Option.java revision 2846:072008f47620
1/*
2 * Copyright (c) 2006, 2014, 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 com.sun.tools.javac.main;
27
28import java.io.File;
29import java.io.FileWriter;
30import java.io.PrintWriter;
31import java.util.Collections;
32import java.util.EnumSet;
33import java.util.LinkedHashMap;
34import java.util.Map;
35import java.util.Set;
36
37import javax.lang.model.SourceVersion;
38
39import com.sun.tools.doclint.DocLint;
40import com.sun.tools.javac.code.Lint;
41import com.sun.tools.javac.code.Lint.LintCategory;
42import com.sun.tools.javac.code.Source;
43import com.sun.tools.javac.code.Type;
44import com.sun.tools.javac.jvm.Profile;
45import com.sun.tools.javac.jvm.Target;
46import com.sun.tools.javac.processing.JavacProcessingEnvironment;
47import com.sun.tools.javac.util.Log;
48import com.sun.tools.javac.util.Log.PrefixKind;
49import com.sun.tools.javac.util.Log.WriterKind;
50import com.sun.tools.javac.util.Options;
51import com.sun.tools.javac.util.StringUtils;
52import static com.sun.tools.javac.main.Option.ChoiceKind.*;
53import static com.sun.tools.javac.main.Option.OptionGroup.*;
54import static com.sun.tools.javac.main.Option.OptionKind.*;
55
56/**
57 * Options for javac. The specific Option to handle a command-line option
58 * is identified by searching the members of this enum in order, looking for
59 * the first {@link #matches match}. The action for an Option is performed
60 * by calling {@link #process process}, and by providing a suitable
61 * {@link OptionHelper} to provide access the compiler state.
62 *
63 * <p><b>This is NOT part of any supported API.
64 * If you write code that depends on this, you do so at your own
65 * risk.  This code and its internal interfaces are subject to change
66 * or deletion without notice.</b></p>
67 */
68public enum Option {
69    G("-g", "opt.g", STANDARD, BASIC),
70
71    G_NONE("-g:none", "opt.g.none", STANDARD, BASIC) {
72        @Override
73        public boolean process(OptionHelper helper, String option) {
74            helper.put("-g:", "none");
75            return false;
76        }
77    },
78
79    G_CUSTOM("-g:",  "opt.g.lines.vars.source",
80            STANDARD, BASIC, ANYOF, "lines", "vars", "source"),
81
82    XLINT("-Xlint", "opt.Xlint", EXTENDED, BASIC),
83
84    XLINT_CUSTOM("-Xlint:", EXTENDED, BASIC, ANYOF, getXLintChoices()) {
85        private static final String LINT_KEY_FORMAT = "         %-19s %s";
86        @Override
87        void help(Log log, OptionKind kind) {
88            if (this.kind != kind)
89                return;
90
91            log.printRawLines(WriterKind.NOTICE,
92                              String.format(HELP_LINE_FORMAT,
93                                            log.localize(PrefixKind.JAVAC, "opt.Xlint.subopts"),
94                                            log.localize(PrefixKind.JAVAC, "opt.Xlint.suboptlist")));
95            log.printRawLines(WriterKind.NOTICE,
96                              String.format(LINT_KEY_FORMAT,
97                                            "all",
98                                            log.localize(PrefixKind.JAVAC, "opt.Xlint.all")));
99            for (LintCategory lc : LintCategory.values()) {
100                if (lc.hidden) continue;
101                log.printRawLines(WriterKind.NOTICE,
102                                  String.format(LINT_KEY_FORMAT,
103                                                lc.option,
104                                                log.localize(PrefixKind.JAVAC,
105                                                             "opt.Xlint.desc." + lc.option)));
106            }
107            log.printRawLines(WriterKind.NOTICE,
108                              String.format(LINT_KEY_FORMAT,
109                                            "none",
110                                            log.localize(PrefixKind.JAVAC, "opt.Xlint.none")));
111        }
112    },
113
114    XDOCLINT("-Xdoclint", "opt.Xdoclint", EXTENDED, BASIC),
115
116    XDOCLINT_CUSTOM("-Xdoclint:", "opt.Xdoclint.subopts", "opt.Xdoclint.custom", EXTENDED, BASIC) {
117        @Override
118        public boolean matches(String option) {
119            return DocLint.isValidOption(
120                    option.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
121        }
122
123        @Override
124        public boolean process(OptionHelper helper, String option) {
125            String prev = helper.get(XDOCLINT_CUSTOM);
126            String next = (prev == null) ? option : (prev + " " + option);
127            helper.put(XDOCLINT_CUSTOM.text, next);
128            return false;
129        }
130    },
131
132    XDOCLINT_PACKAGE("-Xdoclint/package:", "opt.Xdoclint.package.args", "opt.Xdoclint.package.desc", EXTENDED, BASIC) {
133        @Override
134        public boolean matches(String option) {
135            return DocLint.isValidOption(
136                    option.replace(XDOCLINT_PACKAGE.text, DocLint.XCHECK_PACKAGE));
137        }
138
139        @Override
140        public boolean process(OptionHelper helper, String option) {
141            String prev = helper.get(XDOCLINT_PACKAGE);
142            String next = (prev == null) ? option : (prev + " " + option);
143            helper.put(XDOCLINT_PACKAGE.text, next);
144            return false;
145        }
146    },
147
148    // -nowarn is retained for command-line backward compatibility
149    NOWARN("-nowarn", "opt.nowarn", STANDARD, BASIC) {
150        @Override
151        public boolean process(OptionHelper helper, String option) {
152            helper.put("-Xlint:none", option);
153            return false;
154        }
155    },
156
157    VERBOSE("-verbose", "opt.verbose", STANDARD, BASIC),
158
159    // -deprecation is retained for command-line backward compatibility
160    DEPRECATION("-deprecation", "opt.deprecation", STANDARD, BASIC) {
161        @Override
162        public boolean process(OptionHelper helper, String option) {
163            helper.put("-Xlint:deprecation", option);
164            return false;
165        }
166    },
167
168    CLASSPATH("-classpath", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER),
169
170    CP("-cp", "opt.arg.path", "opt.classpath", STANDARD, FILEMANAGER) {
171        @Override
172        public boolean process(OptionHelper helper, String option, String arg) {
173            return super.process(helper, "-classpath", arg);
174        }
175    },
176
177    SOURCEPATH("-sourcepath", "opt.arg.path", "opt.sourcepath", STANDARD, FILEMANAGER),
178
179    BOOTCLASSPATH("-bootclasspath", "opt.arg.path", "opt.bootclasspath", STANDARD, FILEMANAGER) {
180        @Override
181        public boolean process(OptionHelper helper, String option, String arg) {
182            helper.remove("-Xbootclasspath/p:");
183            helper.remove("-Xbootclasspath/a:");
184            return super.process(helper, option, arg);
185        }
186    },
187
188    XBOOTCLASSPATH_PREPEND("-Xbootclasspath/p:", "opt.arg.path", "opt.Xbootclasspath.p", EXTENDED, FILEMANAGER),
189
190    XBOOTCLASSPATH_APPEND("-Xbootclasspath/a:", "opt.arg.path", "opt.Xbootclasspath.a", EXTENDED, FILEMANAGER),
191
192    XBOOTCLASSPATH("-Xbootclasspath:", "opt.arg.path", "opt.bootclasspath", EXTENDED, FILEMANAGER) {
193        @Override
194        public boolean process(OptionHelper helper, String option, String arg) {
195            helper.remove("-Xbootclasspath/p:");
196            helper.remove("-Xbootclasspath/a:");
197            return super.process(helper, "-bootclasspath", arg);
198        }
199    },
200
201    EXTDIRS("-extdirs", "opt.arg.dirs", "opt.extdirs", STANDARD, FILEMANAGER),
202
203    DJAVA_EXT_DIRS("-Djava.ext.dirs=", "opt.arg.dirs", "opt.extdirs", EXTENDED, FILEMANAGER) {
204        @Override
205        public boolean process(OptionHelper helper, String option, String arg) {
206            return super.process(helper, "-extdirs", arg);
207        }
208    },
209
210    ENDORSEDDIRS("-endorseddirs", "opt.arg.dirs", "opt.endorseddirs", STANDARD, FILEMANAGER),
211
212    DJAVA_ENDORSED_DIRS("-Djava.endorsed.dirs=", "opt.arg.dirs", "opt.endorseddirs", EXTENDED, FILEMANAGER) {
213        @Override
214        public boolean process(OptionHelper helper, String option, String arg) {
215            return super.process(helper, "-endorseddirs", arg);
216        }
217    },
218
219    PROC("-proc:", "opt.proc.none.only", STANDARD, BASIC,  ONEOF, "none", "only"),
220
221    PROCESSOR("-processor", "opt.arg.class.list", "opt.processor", STANDARD, BASIC),
222
223    PROCESSORPATH("-processorpath", "opt.arg.path", "opt.processorpath", STANDARD, FILEMANAGER),
224
225    PARAMETERS("-parameters","opt.parameters", STANDARD, BASIC),
226
227    D("-d", "opt.arg.directory", "opt.d", STANDARD, FILEMANAGER),
228
229    S("-s", "opt.arg.directory", "opt.sourceDest", STANDARD, FILEMANAGER),
230
231    H("-h", "opt.arg.directory", "opt.headerDest", STANDARD, FILEMANAGER),
232
233    IMPLICIT("-implicit:", "opt.implicit", STANDARD, BASIC, ONEOF, "none", "class"),
234
235    ENCODING("-encoding", "opt.arg.encoding", "opt.encoding", STANDARD, FILEMANAGER) {
236        @Override
237        public boolean process(OptionHelper helper, String option, String operand) {
238            return super.process(helper, option, operand);
239        }
240
241    },
242
243    SOURCE("-source", "opt.arg.release", "opt.source", STANDARD, BASIC) {
244        @Override
245        public boolean process(OptionHelper helper, String option, String operand) {
246            Source source = Source.lookup(operand);
247            if (source == null) {
248                helper.error("err.invalid.source", operand);
249                return true;
250            }
251            return super.process(helper, option, operand);
252        }
253    },
254
255    TARGET("-target", "opt.arg.release", "opt.target", STANDARD, BASIC) {
256        @Override
257        public boolean process(OptionHelper helper, String option, String operand) {
258            Target target = Target.lookup(operand);
259            if (target == null) {
260                helper.error("err.invalid.target", operand);
261                return true;
262            }
263            return super.process(helper, option, operand);
264        }
265    },
266
267    PROFILE("-profile", "opt.arg.profile", "opt.profile", STANDARD, BASIC) {
268        @Override
269        public boolean process(OptionHelper helper, String option, String operand) {
270            Profile profile = Profile.lookup(operand);
271            if (profile == null) {
272                helper.error("err.invalid.profile", operand);
273                return true;
274            }
275            return super.process(helper, option, operand);
276        }
277    },
278
279    VERSION("-version", "opt.version", STANDARD, INFO) {
280        @Override
281        public boolean process(OptionHelper helper, String option) {
282            Log log = helper.getLog();
283            String ownName = helper.getOwnName();
284            log.printLines(PrefixKind.JAVAC, "version", ownName,  JavaCompiler.version());
285            return super.process(helper, option);
286        }
287    },
288
289    FULLVERSION("-fullversion", null, HIDDEN, INFO) {
290        @Override
291        public boolean process(OptionHelper helper, String option) {
292            Log log = helper.getLog();
293            String ownName = helper.getOwnName();
294            log.printLines(PrefixKind.JAVAC, "fullVersion", ownName,  JavaCompiler.fullVersion());
295            return super.process(helper, option);
296        }
297    },
298
299    DIAGS("-XDdiags=", null, HIDDEN, INFO) {
300        @Override
301        public boolean process(OptionHelper helper, String option) {
302            option = option.substring(option.indexOf('=') + 1);
303            String diagsOption = option.contains("%") ?
304                "-XDdiagsFormat=" :
305                "-XDdiags=";
306            diagsOption += option;
307            if (XD.matches(diagsOption))
308                return XD.process(helper, diagsOption);
309            else
310                return false;
311        }
312    },
313
314    HELP("-help", "opt.help", STANDARD, INFO) {
315        @Override
316        public boolean process(OptionHelper helper, String option) {
317            Log log = helper.getLog();
318            String ownName = helper.getOwnName();
319            log.printLines(PrefixKind.JAVAC, "msg.usage.header", ownName);
320            for (Option o: getJavaCompilerOptions()) {
321                o.help(log, OptionKind.STANDARD);
322            }
323            log.printNewline();
324            return super.process(helper, option);
325        }
326    },
327
328    A("-A", "opt.arg.key.equals.value", "opt.A", STANDARD, BASIC, true) {
329        @Override
330        public boolean matches(String arg) {
331            return arg.startsWith("-A");
332        }
333
334        @Override
335        public boolean hasArg() {
336            return false;
337        }
338        // Mapping for processor options created in
339        // JavacProcessingEnvironment
340        @Override
341        public boolean process(OptionHelper helper, String option) {
342            int argLength = option.length();
343            if (argLength == 2) {
344                helper.error("err.empty.A.argument");
345                return true;
346            }
347            int sepIndex = option.indexOf('=');
348            String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) );
349            if (!JavacProcessingEnvironment.isValidOptionName(key)) {
350                helper.error("err.invalid.A.key", option);
351                return true;
352            }
353            return process(helper, option, option);
354        }
355    },
356
357    X("-X", "opt.X", STANDARD, INFO) {
358        @Override
359        public boolean process(OptionHelper helper, String option) {
360            Log log = helper.getLog();
361            for (Option o: getJavaCompilerOptions()) {
362                o.help(log, OptionKind.EXTENDED);
363            }
364            log.printNewline();
365            log.printLines(PrefixKind.JAVAC, "msg.usage.nonstandard.footer");
366            return super.process(helper, option);
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", "opt.arg.flag", "opt.J", STANDARD, INFO, true) {
373        @Override
374        public boolean process(OptionHelper helper, String option) {
375            throw new AssertionError
376                ("the -J flag should be caught by the launcher.");
377        }
378    },
379
380    MOREINFO("-moreinfo", null, HIDDEN, BASIC) {
381        @Override
382        public boolean process(OptionHelper helper, String option) {
383            Type.moreInfo = true;
384            return super.process(helper, option);
385        }
386    },
387
388    // treat warnings as errors
389    WERROR("-Werror", "opt.Werror", STANDARD, BASIC),
390
391    // prompt after each error
392    // new Option("-prompt",                                        "opt.prompt"),
393    PROMPT("-prompt", null, HIDDEN, BASIC),
394
395    // dump stack on error
396    DOE("-doe", null, HIDDEN, BASIC),
397
398    // output source after type erasure
399    PRINTSOURCE("-printsource", null, HIDDEN, BASIC),
400
401    // display warnings for generic unchecked operations
402    WARNUNCHECKED("-warnunchecked", null, HIDDEN, BASIC) {
403        @Override
404        public boolean process(OptionHelper helper, String option) {
405            helper.put("-Xlint:unchecked", option);
406            return false;
407        }
408    },
409
410    XMAXERRS("-Xmaxerrs", "opt.arg.number", "opt.maxerrs", EXTENDED, BASIC),
411
412    XMAXWARNS("-Xmaxwarns", "opt.arg.number", "opt.maxwarns", EXTENDED, BASIC),
413
414    XSTDOUT("-Xstdout", "opt.arg.file", "opt.Xstdout", EXTENDED, INFO) {
415        @Override
416        public boolean process(OptionHelper helper, String option, String arg) {
417            try {
418                Log log = helper.getLog();
419                log.setWriters(new PrintWriter(new FileWriter(arg), true));
420            } catch (java.io.IOException e) {
421                helper.error("err.error.writing.file", arg, e);
422                return true;
423            }
424            return super.process(helper, option, arg);
425        }
426    },
427
428    XPRINT("-Xprint", "opt.print", EXTENDED, BASIC),
429
430    XPRINTROUNDS("-XprintRounds", "opt.printRounds", EXTENDED, BASIC),
431
432    XPRINTPROCESSORINFO("-XprintProcessorInfo", "opt.printProcessorInfo", EXTENDED, BASIC),
433
434    XPREFER("-Xprefer:", "opt.prefer", EXTENDED, BASIC, ONEOF, "source", "newer"),
435
436    XXUSERPATHSFIRST("-XXuserPathsFirst", "opt.userpathsfirst", HIDDEN, BASIC),
437
438    // see enum PkgInfo
439    XPKGINFO("-Xpkginfo:", "opt.pkginfo", EXTENDED, BASIC, ONEOF, "always", "legacy", "nonempty"),
440
441    /* -O is a no-op, accepted for backward compatibility. */
442    O("-O", null, HIDDEN, BASIC),
443
444    /* -Xjcov produces tables to support the code coverage tool jcov. */
445    XJCOV("-Xjcov", null, HIDDEN, BASIC),
446
447    PLUGIN("-Xplugin:", "opt.arg.plugin", "opt.plugin", EXTENDED, BASIC) {
448        @Override
449        public boolean process(OptionHelper helper, String option) {
450            String p = option.substring(option.indexOf(':') + 1);
451            String prev = helper.get(PLUGIN);
452            helper.put(PLUGIN.text, (prev == null) ? p : prev + '\0' + p.trim());
453            return false;
454        }
455    },
456
457    XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"),
458
459    /* This is a back door to the compiler's option table.
460     * -XDx=y sets the option x to the value y.
461     * -XDx sets the option x to the value x.
462     */
463    XD("-XD", null, HIDDEN, BASIC) {
464        @Override
465        public boolean matches(String s) {
466            return s.startsWith(text);
467        }
468        @Override
469        public boolean process(OptionHelper helper, String option) {
470            option = option.substring(text.length());
471            int eq = option.indexOf('=');
472            String key = (eq < 0) ? option : option.substring(0, eq);
473            String value = (eq < 0) ? option : option.substring(eq+1);
474            helper.put(key, value);
475            return false;
476        }
477    },
478
479    // This option exists only for the purpose of documenting itself.
480    // It's actually implemented by the CommandLine class.
481    AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, true) {
482        @Override
483        public boolean process(OptionHelper helper, String option) {
484            throw new AssertionError("the @ flag should be caught by CommandLine.");
485        }
486    },
487
488    /*
489     * TODO: With apt, the matches method accepts anything if
490     * -XclassAsDecls is used; code elsewhere does the lookup to
491     * see if the class name is both legal and found.
492     *
493     * In apt, the process method adds the candidate class file
494     * name to a separate list.
495     */
496    SOURCEFILE("sourcefile", null, HIDDEN, INFO) {
497        @Override
498        public boolean matches(String s) {
499            return s.endsWith(".java")  // Java source file
500                || SourceVersion.isName(s);   // Legal type name
501        }
502        @Override
503        public boolean process(OptionHelper helper, String option) {
504            if (option.endsWith(".java") ) {
505                File f = new File(option);
506                if (!f.exists()) {
507                    helper.error("err.file.not.found", f);
508                    return true;
509                }
510                if (!f.isFile()) {
511                    helper.error("err.file.not.file", f);
512                    return true;
513                }
514                helper.addFile(f);
515            } else {
516                helper.addClassName(option);
517            }
518            return false;
519        }
520    };
521
522    /** The kind of an Option. This is used by the -help and -X options. */
523    public enum OptionKind {
524        /** A standard option, documented by -help. */
525        STANDARD,
526        /** An extended option, documented by -X. */
527        EXTENDED,
528        /** A hidden option, not documented. */
529        HIDDEN,
530    }
531
532    /** The group for an Option. This determines the situations in which the
533     *  option is applicable. */
534    enum OptionGroup {
535        /** A basic option, available for use on the command line or via the
536         *  Compiler API. */
537        BASIC,
538        /** An option for javac's standard JavaFileManager. Other file managers
539         *  may or may not support these options. */
540        FILEMANAGER,
541        /** A command-line option that requests information, such as -help. */
542        INFO,
543        /** A command-line "option" representing a file or class name. */
544        OPERAND
545    }
546
547    /** The kind of choice for "choice" options. */
548    enum ChoiceKind {
549        /** The expected value is exactly one of the set of choices. */
550        ONEOF,
551        /** The expected value is one of more of the set of choices. */
552        ANYOF
553    }
554
555    public final String text;
556
557    final OptionKind kind;
558
559    final OptionGroup group;
560
561    /** Documentation key for arguments.
562     */
563    final String argsNameKey;
564
565    /** Documentation key for description.
566     */
567    final String descrKey;
568
569    /** Suffix option (-foo=bar or -foo:bar)
570     */
571    final boolean hasSuffix;
572
573    /** The kind of choices for this option, if any.
574     */
575    final ChoiceKind choiceKind;
576
577    /** The choices for this option, if any, and whether or not the choices
578     *  are hidden
579     */
580    final Map<String,Boolean> choices;
581
582
583    Option(String text, String descrKey,
584            OptionKind kind, OptionGroup group) {
585        this(text, null, descrKey, kind, group, null, null, false);
586    }
587
588    Option(String text, String argsNameKey, String descrKey,
589            OptionKind kind, OptionGroup group) {
590        this(text, argsNameKey, descrKey, kind, group, null, null, false);
591    }
592
593    Option(String text, String argsNameKey, String descrKey,
594            OptionKind kind, OptionGroup group, boolean doHasSuffix) {
595        this(text, argsNameKey, descrKey, kind, group, null, null, doHasSuffix);
596    }
597
598    Option(String text, OptionKind kind, OptionGroup group,
599            ChoiceKind choiceKind, Map<String,Boolean> choices) {
600        this(text, null, null, kind, group, choiceKind, choices, false);
601    }
602
603    Option(String text, String descrKey,
604            OptionKind kind, OptionGroup group,
605            ChoiceKind choiceKind, String... choices) {
606        this(text, null, descrKey, kind, group, choiceKind,
607                createChoices(choices), false);
608    }
609    // where
610        private static Map<String,Boolean> createChoices(String... choices) {
611            Map<String,Boolean> map = new LinkedHashMap<>();
612            for (String c: choices)
613                map.put(c, false);
614            return map;
615        }
616
617    private Option(String text, String argsNameKey, String descrKey,
618            OptionKind kind, OptionGroup group,
619            ChoiceKind choiceKind, Map<String,Boolean> choices,
620            boolean doHasSuffix) {
621        this.text = text;
622        this.argsNameKey = argsNameKey;
623        this.descrKey = descrKey;
624        this.kind = kind;
625        this.group = group;
626        this.choiceKind = choiceKind;
627        this.choices = choices;
628        char lastChar = text.charAt(text.length()-1);
629        this.hasSuffix = doHasSuffix || lastChar == ':' || lastChar == '=';
630    }
631
632    public String getText() {
633        return text;
634    }
635
636    public OptionKind getKind() {
637        return kind;
638    }
639
640    public boolean hasArg() {
641        return argsNameKey != null && !hasSuffix;
642    }
643
644    public boolean matches(String option) {
645        if (!hasSuffix)
646            return option.equals(text);
647
648        if (!option.startsWith(text))
649            return false;
650
651        if (choices != null) {
652            String arg = option.substring(text.length());
653            if (choiceKind == ChoiceKind.ONEOF)
654                return choices.keySet().contains(arg);
655            else {
656                for (String a: arg.split(",+")) {
657                    if (!choices.keySet().contains(a))
658                        return false;
659                }
660            }
661        }
662
663        return true;
664    }
665
666    public boolean process(OptionHelper helper, String option, String arg) {
667        if (choices != null) {
668            if (choiceKind == ChoiceKind.ONEOF) {
669                // some clients like to see just one of option+choice set
670                for (String s: choices.keySet())
671                    helper.remove(option + s);
672                String opt = option + arg;
673                helper.put(opt, opt);
674                // some clients like to see option (without trailing ":")
675                // set to arg
676                String nm = option.substring(0, option.length() - 1);
677                helper.put(nm, arg);
678            } else {
679                // set option+word for each word in arg
680                for (String a: arg.split(",+")) {
681                    String opt = option + a;
682                    helper.put(opt, opt);
683                }
684            }
685        }
686        helper.put(option, arg);
687        if (group == OptionGroup.FILEMANAGER)
688            helper.handleFileManagerOption(this, arg);
689        return false;
690    }
691
692    public boolean process(OptionHelper helper, String option) {
693        if (hasSuffix)
694            return process(helper, text, option.substring(text.length()));
695        else
696            return process(helper, option, option);
697    }
698
699    private static final String HELP_LINE_FORMAT = "  %-26s %s";
700
701    void help(Log log, OptionKind kind) {
702        if (this.kind != kind)
703            return;
704
705        log.printRawLines(WriterKind.NOTICE,
706                String.format(HELP_LINE_FORMAT,
707                    helpSynopsis(log),
708                    log.localize(PrefixKind.JAVAC, descrKey)));
709
710    }
711
712    private String helpSynopsis(Log log) {
713        StringBuilder sb = new StringBuilder();
714        sb.append(text);
715        if (argsNameKey == null) {
716            if (choices != null) {
717                String sep = "{";
718                for (Map.Entry<String,Boolean> e: choices.entrySet()) {
719                    if (!e.getValue()) {
720                        sb.append(sep);
721                        sb.append(e.getKey());
722                        sep = ",";
723                    }
724                }
725                sb.append("}");
726            }
727        } else {
728            if (!hasSuffix)
729                sb.append(" ");
730            sb.append(log.localize(PrefixKind.JAVAC, argsNameKey));
731
732        }
733
734        return sb.toString();
735    }
736
737    // For -XpkgInfo:value
738    public enum PkgInfo {
739        /**
740         * Always generate package-info.class for every package-info.java file.
741         * The file may be empty if there annotations with a RetentionPolicy
742         * of CLASS or RUNTIME.  This option may be useful in conjunction with
743         * build systems (such as Ant) that expect javac to generate at least
744         * one .class file for every .java file.
745         */
746        ALWAYS,
747        /**
748         * Generate a package-info.class file if package-info.java contains
749         * annotations. The file may be empty if all the annotations have
750         * a RetentionPolicy of SOURCE.
751         * This value is just for backwards compatibility with earlier behavior.
752         * Either of the other two values are to be preferred to using this one.
753         */
754        LEGACY,
755        /**
756         * Generate a package-info.class file if and only if there are annotations
757         * in package-info.java to be written into it.
758         */
759        NONEMPTY;
760
761        public static PkgInfo get(Options options) {
762            String v = options.get(XPKGINFO);
763            return (v == null
764                    ? PkgInfo.LEGACY
765                    : PkgInfo.valueOf(StringUtils.toUpperCase(v)));
766        }
767    }
768
769    private static Map<String,Boolean> getXLintChoices() {
770        Map<String,Boolean> choices = new LinkedHashMap<>();
771        choices.put("all", false);
772        for (Lint.LintCategory c : Lint.LintCategory.values())
773            choices.put(c.option, c.hidden);
774        for (Lint.LintCategory c : Lint.LintCategory.values())
775            choices.put("-" + c.option, c.hidden);
776        choices.put("none", false);
777        return choices;
778    }
779
780    static Set<Option> getJavaCompilerOptions() {
781        return EnumSet.allOf(Option.class);
782    }
783
784    public static Set<Option> getJavacFileManagerOptions() {
785        return getOptions(EnumSet.of(FILEMANAGER));
786    }
787
788    public static Set<Option> getJavacToolOptions() {
789        return getOptions(EnumSet.of(BASIC));
790    }
791
792    static Set<Option> getOptions(Set<OptionGroup> desired) {
793        Set<Option> options = EnumSet.noneOf(Option.class);
794        for (Option option : Option.values())
795            if (desired.contains(option.group))
796                options.add(option);
797        return Collections.unmodifiableSet(options);
798    }
799
800}
801