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