001    /*
002     * Copyright 2006-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javac.main;
027    
028    import com.sun.tools.javac.code.Lint;
029    import com.sun.tools.javac.code.Source;
030    import com.sun.tools.javac.code.Type;
031    import com.sun.tools.javac.jvm.Target;
032    import com.sun.tools.javac.main.JavacOption.HiddenOption;
033    import com.sun.tools.javac.main.JavacOption.Option;
034    import com.sun.tools.javac.main.JavacOption.XOption;
035    import com.sun.tools.javac.util.ListBuffer;
036    import com.sun.tools.javac.util.Options;
037    import com.sun.tools.javac.processing.JavacProcessingEnvironment;
038    import java.io.File;
039    import java.io.FileWriter;
040    import java.io.PrintWriter;
041    import java.util.Collection;
042    import java.util.EnumSet;
043    import java.util.LinkedHashSet;
044    import java.util.Set;
045    import javax.lang.model.SourceVersion;
046    
047    import static com.sun.tools.javac.main.OptionName.*;
048    
049    /**
050     * TODO: describe com.sun.tools.javac.main.RecognizedOptions
051     *
052     * <p><b>This is NOT part of any API supported by Sun Microsystems.
053     * If you write code that depends on this, you do so at your own
054     * risk.  This code and its internal interfaces are subject to change
055     * or deletion without notice.</b></p>
056     */
057    public class RecognizedOptions {
058    
059        private RecognizedOptions() {}
060    
061        public interface OptionHelper {
062    
063            void setOut(PrintWriter out);
064    
065            void error(String key, Object... args);
066    
067            void printVersion();
068    
069            void printFullVersion();
070    
071            void printHelp();
072    
073            void printXhelp();
074    
075            void addFile(File f);
076    
077            void addClassName(String s);
078    
079        }
080    
081        public static class GrumpyHelper implements OptionHelper {
082    
083            public void setOut(PrintWriter out) {
084                throw new IllegalArgumentException();
085            }
086    
087            public void error(String key, Object... args) {
088                throw new IllegalArgumentException(Main.getLocalizedString(key, args));
089            }
090    
091            public void printVersion() {
092                throw new IllegalArgumentException();
093            }
094    
095            public void printFullVersion() {
096                throw new IllegalArgumentException();
097            }
098    
099            public void printHelp() {
100                throw new IllegalArgumentException();
101            }
102    
103            public void printXhelp() {
104                throw new IllegalArgumentException();
105            }
106    
107            public void addFile(File f) {
108                throw new IllegalArgumentException(f.getPath());
109            }
110    
111            public void addClassName(String s) {
112                throw new IllegalArgumentException(s);
113            }
114    
115        }
116    
117        static Set<OptionName> javacOptions = EnumSet.of(
118            G,
119            G_NONE,
120            G_CUSTOM,
121            XLINT,
122            XLINT_CUSTOM,
123            NOWARN,
124            VERBOSE,
125            DEPRECATION,
126            CLASSPATH,
127            CP,
128            SOURCEPATH,
129            BOOTCLASSPATH,
130            XBOOTCLASSPATH_PREPEND,
131            XBOOTCLASSPATH_APPEND,
132            XBOOTCLASSPATH,
133            EXTDIRS,
134            DJAVA_EXT_DIRS,
135            ENDORSEDDIRS,
136            DJAVA_ENDORSED_DIRS,
137            PROC,
138            PROCESSOR,
139            PROCESSORPATH,
140            D,
141            S,
142            IMPLICIT,
143            ENCODING,
144            SOURCE,
145            TARGET,
146            VERSION,
147            FULLVERSION,
148            HELP,
149            A,
150            X,
151            J,
152            MOREINFO,
153            WERROR,
154            // COMPLEXINFERENCE,
155            PROMPT,
156            DOE,
157            PRINTSOURCE,
158            WARNUNCHECKED,
159            XMAXERRS,
160            XMAXWARNS,
161            XSTDOUT,
162            XPRINT,
163            XPRINTROUNDS,
164            XPRINTPROCESSORINFO,
165            XPREFER,
166            O,
167            XJCOV,
168            XD,
169            SOURCEFILE);
170    
171        static Set<OptionName> javacFileManagerOptions = EnumSet.of(
172            CLASSPATH,
173            CP,
174            SOURCEPATH,
175            BOOTCLASSPATH,
176            XBOOTCLASSPATH_PREPEND,
177            XBOOTCLASSPATH_APPEND,
178            XBOOTCLASSPATH,
179            EXTDIRS,
180            DJAVA_EXT_DIRS,
181            ENDORSEDDIRS,
182            DJAVA_ENDORSED_DIRS,
183            PROCESSORPATH,
184            D,
185            S,
186            ENCODING,
187            SOURCE);
188    
189        static Set<OptionName> javacToolOptions = EnumSet.of(
190            G,
191            G_NONE,
192            G_CUSTOM,
193            XLINT,
194            XLINT_CUSTOM,
195            NOWARN,
196            VERBOSE,
197            DEPRECATION,
198            PROC,
199            PROCESSOR,
200            IMPLICIT,
201            SOURCE,
202            TARGET,
203            // VERSION,
204            // FULLVERSION,
205            // HELP,
206            A,
207            // X,
208            // J,
209            MOREINFO,
210            WERROR,
211            // COMPLEXINFERENCE,
212            PROMPT,
213            DOE,
214            PRINTSOURCE,
215            WARNUNCHECKED,
216            XMAXERRS,
217            XMAXWARNS,
218            // XSTDOUT,
219            XPRINT,
220            XPRINTROUNDS,
221            XPRINTPROCESSORINFO,
222            XPREFER,
223            O,
224            XJCOV,
225            XD);
226    
227        static Option[] getJavaCompilerOptions(OptionHelper helper) {
228            return getOptions(helper, javacOptions);
229        }
230    
231        public static Option[] getJavacFileManagerOptions(OptionHelper helper) {
232            return getOptions(helper, javacFileManagerOptions);
233        }
234    
235        public static Option[] getJavacToolOptions(OptionHelper helper) {
236            return getOptions(helper, javacToolOptions);
237        }
238    
239        static Option[] getOptions(OptionHelper helper, Set<OptionName> desired) {
240            ListBuffer<Option> options = new ListBuffer<Option>();
241            for (Option option : getAll(helper))
242                if (desired.contains(option.getName()))
243                    options.append(option);
244            return options.toArray(new Option[options.length()]);
245        }
246    
247        /**
248         * Get all the recognized options.
249         * @param helper an {@code OptionHelper} to help when processing options
250         * @return an array of options
251         */
252        public static Option[] getAll(final OptionHelper helper) {
253            return new Option[] {
254            new Option(G,                                           "opt.g"),
255            new Option(G_NONE,                                      "opt.g.none") {
256                @Override
257                public boolean process(Options options, String option) {
258                    options.put("-g:", "none");
259                    return false;
260                }
261            },
262    
263            new Option(G_CUSTOM,                                    "opt.g.lines.vars.source",
264                    Option.ChoiceKind.ANYOF, "lines", "vars", "source"),
265    
266            new XOption(XLINT,                                      "opt.Xlint"),
267            new XOption(XLINT_CUSTOM,                               "opt.Xlint.suboptlist",
268                    Option.ChoiceKind.ANYOF, getXLintChoices()),
269    
270            // -nowarn is retained for command-line backward compatibility
271            new Option(NOWARN,                                      "opt.nowarn") {
272                @Override
273                public boolean process(Options options, String option) {
274                    options.put("-Xlint:none", option);
275                    return false;
276                }
277            },
278    
279            new Option(VERBOSE,                                     "opt.verbose"),
280    
281            // -deprecation is retained for command-line backward compatibility
282            new Option(DEPRECATION,                                 "opt.deprecation") {
283                @Override
284                public boolean process(Options options, String option) {
285                    options.put("-Xlint:deprecation", option);
286                    return false;
287                }
288            },
289    
290            new Option(CLASSPATH,              "opt.arg.path",      "opt.classpath"),
291            new Option(CP,                     "opt.arg.path",      "opt.classpath") {
292                @Override
293                public boolean process(Options options, String option, String arg) {
294                    return super.process(options, "-classpath", arg);
295                }
296            },
297            new Option(SOURCEPATH,             "opt.arg.path",      "opt.sourcepath"),
298            new Option(BOOTCLASSPATH,          "opt.arg.path",      "opt.bootclasspath") {
299                @Override
300                public boolean process(Options options, String option, String arg) {
301                    options.remove("-Xbootclasspath/p:");
302                    options.remove("-Xbootclasspath/a:");
303                    return super.process(options, option, arg);
304                }
305            },
306            new XOption(XBOOTCLASSPATH_PREPEND,"opt.arg.path", "opt.Xbootclasspath.p"),
307            new XOption(XBOOTCLASSPATH_APPEND, "opt.arg.path", "opt.Xbootclasspath.a"),
308            new XOption(XBOOTCLASSPATH,        "opt.arg.path", "opt.bootclasspath") {
309                @Override
310                public boolean process(Options options, String option, String arg) {
311                    options.remove("-Xbootclasspath/p:");
312                    options.remove("-Xbootclasspath/a:");
313                    return super.process(options, "-bootclasspath", arg);
314                }
315            },
316            new Option(EXTDIRS,                "opt.arg.dirs",      "opt.extdirs"),
317            new XOption(DJAVA_EXT_DIRS,        "opt.arg.dirs",      "opt.extdirs") {
318                @Override
319                public boolean process(Options options, String option, String arg) {
320                    return super.process(options, "-extdirs", arg);
321                }
322            },
323            new Option(ENDORSEDDIRS,            "opt.arg.dirs",     "opt.endorseddirs"),
324            new XOption(DJAVA_ENDORSED_DIRS,    "opt.arg.dirs",     "opt.endorseddirs") {
325                @Override
326                public boolean process(Options options, String option, String arg) {
327                    return super.process(options, "-endorseddirs", arg);
328                }
329            },
330            new Option(PROC,                                 "opt.proc.none.only",
331                    Option.ChoiceKind.ONEOF, "none", "only"),
332            new Option(PROCESSOR,           "opt.arg.class.list",   "opt.processor"),
333            new Option(PROCESSORPATH,       "opt.arg.path",         "opt.processorpath"),
334            new Option(D,                   "opt.arg.directory",    "opt.d"),
335            new Option(S,                   "opt.arg.directory",    "opt.sourceDest"),
336            new Option(IMPLICIT,                                    "opt.implicit",
337                    Option.ChoiceKind.ONEOF, "none", "class"),
338            new Option(ENCODING,            "opt.arg.encoding",     "opt.encoding"),
339            new Option(SOURCE,              "opt.arg.release",      "opt.source") {
340                @Override
341                public boolean process(Options options, String option, String operand) {
342                    Source source = Source.lookup(operand);
343                    if (source == null) {
344                        helper.error("err.invalid.source", operand);
345                        return true;
346                    }
347                    return super.process(options, option, operand);
348                }
349            },
350            new Option(TARGET,              "opt.arg.release",      "opt.target") {
351                @Override
352                public boolean process(Options options, String option, String operand) {
353                    Target target = Target.lookup(operand);
354                    if (target == null) {
355                        helper.error("err.invalid.target", operand);
356                        return true;
357                    }
358                    return super.process(options, option, operand);
359                }
360            },
361            new Option(VERSION,                                     "opt.version") {
362                @Override
363                public boolean process(Options options, String option) {
364                    helper.printVersion();
365                    return super.process(options, option);
366                }
367            },
368            new HiddenOption(FULLVERSION) {
369                @Override
370                public boolean process(Options options, String option) {
371                    helper.printFullVersion();
372                    return super.process(options, option);
373                }
374            },
375            new Option(HELP,                                        "opt.help") {
376                @Override
377                public boolean process(Options options, String option) {
378                    helper.printHelp();
379                    return super.process(options, option);
380                }
381            },
382            new Option(A,                "opt.arg.key.equals.value","opt.A") {
383                @Override
384                String helpSynopsis() {
385                    hasSuffix = true;
386                    return super.helpSynopsis();
387                }
388    
389                @Override
390                public boolean matches(String arg) {
391                    return arg.startsWith("-A");
392                }
393    
394                @Override
395                public boolean hasArg() {
396                    return false;
397                }
398                // Mapping for processor options created in
399                // JavacProcessingEnvironment
400                @Override
401                public boolean process(Options options, String option) {
402                    int argLength = option.length();
403                    if (argLength == 2) {
404                        helper.error("err.empty.A.argument");
405                        return true;
406                    }
407                    int sepIndex = option.indexOf('=');
408                    String key = option.substring(2, (sepIndex != -1 ? sepIndex : argLength) );
409                    if (!JavacProcessingEnvironment.isValidOptionName(key)) {
410                        helper.error("err.invalid.A.key", option);
411                        return true;
412                    }
413                    return process(options, option, option);
414                }
415            },
416            new Option(X,                                           "opt.X") {
417                @Override
418                public boolean process(Options options, String option) {
419                    helper.printXhelp();
420                    return super.process(options, option);
421                }
422            },
423    
424            // This option exists only for the purpose of documenting itself.
425            // It's actually implemented by the launcher.
426            new Option(J,                   "opt.arg.flag",         "opt.J") {
427                @Override
428                String helpSynopsis() {
429                    hasSuffix = true;
430                    return super.helpSynopsis();
431                }
432                @Override
433                public boolean process(Options options, String option) {
434                    throw new AssertionError
435                        ("the -J flag should be caught by the launcher.");
436                }
437            },
438    
439            // stop after parsing and attributing.
440            // new HiddenOption("-attrparseonly"),
441    
442            // new Option("-moreinfo",                                      "opt.moreinfo") {
443            new HiddenOption(MOREINFO) {
444                @Override
445                public boolean process(Options options, String option) {
446                    Type.moreInfo = true;
447                    return super.process(options, option);
448                }
449            },
450    
451            // treat warnings as errors
452            new HiddenOption(WERROR),
453    
454            // use complex inference from context in the position of a method call argument
455            new HiddenOption(COMPLEXINFERENCE),
456    
457            // generare source stubs
458            // new HiddenOption("-stubs"),
459    
460            // relax some constraints to allow compiling from stubs
461            // new HiddenOption("-relax"),
462    
463            // output source after translating away inner classes
464            // new Option("-printflat",                             "opt.printflat"),
465            // new HiddenOption("-printflat"),
466    
467            // display scope search details
468            // new Option("-printsearch",                           "opt.printsearch"),
469            // new HiddenOption("-printsearch"),
470    
471            // prompt after each error
472            // new Option("-prompt",                                        "opt.prompt"),
473            new HiddenOption(PROMPT),
474    
475            // dump stack on error
476            new HiddenOption(DOE),
477    
478            // output source after type erasure
479            // new Option("-s",                                     "opt.s"),
480            new HiddenOption(PRINTSOURCE),
481    
482            // output shrouded class files
483            // new Option("-scramble",                              "opt.scramble"),
484            // new Option("-scrambleall",                           "opt.scrambleall"),
485    
486            // display warnings for generic unchecked operations
487            new HiddenOption(WARNUNCHECKED) {
488                @Override
489                public boolean process(Options options, String option) {
490                    options.put("-Xlint:unchecked", option);
491                    return false;
492                }
493            },
494    
495            new XOption(XMAXERRS,           "opt.arg.number",       "opt.maxerrs"),
496            new XOption(XMAXWARNS,          "opt.arg.number",       "opt.maxwarns"),
497            new XOption(XSTDOUT,            "opt.arg.file",         "opt.Xstdout") {
498                @Override
499                public boolean process(Options options, String option, String arg) {
500                    try {
501                        helper.setOut(new PrintWriter(new FileWriter(arg), true));
502                    } catch (java.io.IOException e) {
503                        helper.error("err.error.writing.file", arg, e);
504                        return true;
505                    }
506                    return super.process(options, option, arg);
507                }
508            },
509    
510            new XOption(XPRINT,                                     "opt.print"),
511    
512            new XOption(XPRINTROUNDS,                               "opt.printRounds"),
513    
514            new XOption(XPRINTPROCESSORINFO,                        "opt.printProcessorInfo"),
515    
516            new XOption(XPREFER,                                    "opt.prefer",
517                    Option.ChoiceKind.ONEOF, "source", "newer"),
518    
519            /* -O is a no-op, accepted for backward compatibility. */
520            new HiddenOption(O),
521    
522            /* -Xjcov produces tables to support the code coverage tool jcov. */
523            new HiddenOption(XJCOV),
524    
525            /* This is a back door to the compiler's option table.
526             * -XDx=y sets the option x to the value y.
527             * -XDx sets the option x to the value x.
528             */
529            new HiddenOption(XD) {
530                String s;
531                @Override
532                public boolean matches(String s) {
533                    this.s = s;
534                    return s.startsWith(name.optionName);
535                }
536                @Override
537                public boolean process(Options options, String option) {
538                    s = s.substring(name.optionName.length());
539                    int eq = s.indexOf('=');
540                    String key = (eq < 0) ? s : s.substring(0, eq);
541                    String value = (eq < 0) ? s : s.substring(eq+1);
542                    options.put(key, value);
543                    return false;
544                }
545            },
546    
547            /*
548             * TODO: With apt, the matches method accepts anything if
549             * -XclassAsDecls is used; code elsewhere does the lookup to
550             * see if the class name is both legal and found.
551             *
552             * In apt, the process method adds the candiate class file
553             * name to a separate list.
554             */
555            new HiddenOption(SOURCEFILE) {
556                String s;
557                @Override
558                public boolean matches(String s) {
559                    this.s = s;
560                    return s.endsWith(".java")  // Java source file
561                        || SourceVersion.isName(s);   // Legal type name
562                }
563                @Override
564                public boolean process(Options options, String option) {
565                    if (s.endsWith(".java") ) {
566                        File f = new File(s);
567                        if (!f.exists()) {
568                            helper.error("err.file.not.found", f);
569                            return true;
570                        }
571                        if (!f.isFile()) {
572                            helper.error("err.file.not.file", f);
573                            return true;
574                        }
575                        helper.addFile(f);
576                    }
577                    else
578                        helper.addClassName(s);
579                    return false;
580                }
581            },
582        };
583        }
584    
585        private static Collection<String> getXLintChoices() {
586            Collection<String> choices = new LinkedHashSet<String>();
587            choices.add("all");
588            for (Lint.LintCategory c : Lint.LintCategory.values())
589                choices.add(c.option);
590            for (Lint.LintCategory c : Lint.LintCategory.values())
591                choices.add("-" + c.option);
592            choices.add("none");
593            return choices;
594        }
595    
596    }