Arguments.java revision 4171:77a2d6c1f321
1139804Simp/*
21541Srgrimes * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41541Srgrimes *
51541Srgrimes * This code is free software; you can redistribute it and/or modify it
61541Srgrimes * under the terms of the GNU General Public License version 2 only, as
71541Srgrimes * published by the Free Software Foundation.  Oracle designates this
81541Srgrimes * particular file as subject to the "Classpath" exception as provided
91541Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101541Srgrimes *
111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151541Srgrimes * accompanied this code).
161541Srgrimes *
171541Srgrimes * You should have received a copy of the GNU General Public License version
181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201541Srgrimes *
211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221541Srgrimes * or visit www.oracle.com if you need additional information or have any
231541Srgrimes * questions.
241541Srgrimes */
251541Srgrimes
261541Srgrimespackage com.sun.tools.javac.main;
271541Srgrimes
281541Srgrimesimport java.io.IOException;
291541Srgrimesimport java.nio.file.Files;
301541Srgrimesimport java.nio.file.Path;
311541Srgrimesimport java.nio.file.Paths;
32116182Sobrienimport java.util.Arrays;
33116182Sobrienimport java.util.Collection;
34116182Sobrienimport java.util.Collections;
35101007Srwatsonimport java.util.EnumSet;
3677572Sobrienimport java.util.HashSet;
37113490Ssilbyimport java.util.Iterator;
38101007Srwatsonimport java.util.LinkedHashMap;
391541Srgrimesimport java.util.LinkedHashSet;
401541Srgrimesimport java.util.Map;
4176166Smarkmimport java.util.Set;
42125296Ssilbyimport java.util.function.Predicate;
4376166Smarkmimport java.util.regex.Matcher;
44101173Srwatsonimport java.util.regex.Pattern;
4532036Sbdeimport java.util.stream.Stream;
461541Srgrimes
4723081Swollmanimport javax.lang.model.SourceVersion;
481541Srgrimesimport javax.tools.JavaFileManager;
491541Srgrimesimport javax.tools.JavaFileManager.Location;
50125296Ssilbyimport javax.tools.JavaFileObject;
5176166Smarkmimport javax.tools.JavaFileObject.Kind;
529759Sbdeimport javax.tools.StandardJavaFileManager;
539759Sbdeimport javax.tools.StandardLocation;
549759Sbde
559759Sbdeimport com.sun.tools.doclint.DocLint;
56116455Ssilbyimport com.sun.tools.javac.code.Lint.LintCategory;
57112777Ssilbyimport com.sun.tools.javac.code.Source;
58112777Ssilbyimport com.sun.tools.javac.file.BaseFileManager;
59112777Ssilbyimport com.sun.tools.javac.file.JavacFileManager;
60112777Ssilbyimport com.sun.tools.javac.jvm.Profile;
61113490Ssilbyimport com.sun.tools.javac.jvm.Target;
62113490Ssilbyimport com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
631541Srgrimesimport com.sun.tools.javac.platform.PlatformDescription;
6466475Sbmilekicimport com.sun.tools.javac.platform.PlatformUtils;
6566475Sbmilekicimport com.sun.tools.javac.resources.CompilerProperties.Errors;
6666475Sbmilekicimport com.sun.tools.javac.resources.CompilerProperties.Warnings;
6744078Sdfrimport com.sun.tools.javac.util.Context;
6823081Swollmanimport com.sun.tools.javac.util.JCDiagnostic;
6923081Swollmanimport com.sun.tools.javac.util.List;
7023081Swollmanimport com.sun.tools.javac.util.ListBuffer;
7123081Swollmanimport com.sun.tools.javac.util.Log;
7223081Swollmanimport com.sun.tools.javac.util.Log.PrefixKind;
7323081Swollmanimport com.sun.tools.javac.util.Log.WriterKind;
7423081Swollmanimport com.sun.tools.javac.util.Options;
75116455Ssilbyimport com.sun.tools.javac.util.PropagatedException;
76112777Ssilby
77112777Ssilby/**
78112777Ssilby * Shared option and argument handling for command line and API usage of javac.
79112777Ssilby */
80112777Ssilbypublic class Arguments {
81112777Ssilby
82112777Ssilby    /**
83112777Ssilby     * The context key for the arguments.
84113490Ssilby     */
85113490Ssilby    public static final Context.Key<Arguments> argsKey = new Context.Key<>();
86113490Ssilby
8775112Sbmilekic    private String ownName;
881541Srgrimes    private Set<String> classNames;
89129906Sbmilekic    private Set<Path> files;
90129906Sbmilekic    private Map<Option, String> deferredFileManagerOptions;
91141616Sphk    private Set<JavaFileObject> fileObjects;
92129906Sbmilekic    private boolean emptyAllowed;
93129906Sbmilekic    private final Options options;
94129906Sbmilekic
95129906Sbmilekic    private JavaFileManager fileManager;
96129906Sbmilekic    private final Log log;
97129906Sbmilekic    private final Context context;
98129906Sbmilekic
99129906Sbmilekic    private enum ErrorMode { ILLEGAL_ARGUMENT, ILLEGAL_STATE, LOG };
100129906Sbmilekic    private ErrorMode errorMode;
101129906Sbmilekic    private boolean errors;
102129906Sbmilekic
103129906Sbmilekic    /**
104129906Sbmilekic     * Gets the Arguments instance for this context.
105129906Sbmilekic     *
106129906Sbmilekic     * @param context the content
107129906Sbmilekic     * @return the Arguments instance for this context.
108129906Sbmilekic     */
109129906Sbmilekic    public static Arguments instance(Context context) {
110129906Sbmilekic        Arguments instance = context.get(argsKey);
111129906Sbmilekic        if (instance == null) {
112129906Sbmilekic            instance = new Arguments(context);
113129906Sbmilekic        }
114129906Sbmilekic        return instance;
115129906Sbmilekic    }
116129906Sbmilekic
117129906Sbmilekic    protected Arguments(Context context) {
118129906Sbmilekic        context.put(argsKey, this);
119129906Sbmilekic        options = Options.instance(context);
120129906Sbmilekic        log = Log.instance(context);
121129906Sbmilekic        this.context = context;
122129906Sbmilekic
123129906Sbmilekic        // Ideally, we could init this here and update/configure it as
124129906Sbmilekic        // needed, but right now, initializing a file manager triggers
125129906Sbmilekic        // initialization of other items in the context, such as Lint
126130271Smux        // and FSInfo, which should not be initialized until after
127129906Sbmilekic        // processArgs
128129906Sbmilekic        //        fileManager = context.get(JavaFileManager.class);
129129906Sbmilekic    }
130129906Sbmilekic
131129906Sbmilekic    private final OptionHelper cmdLineHelper = new OptionHelper() {
132129906Sbmilekic        @Override
133129906Sbmilekic        public String get(Option option) {
134129906Sbmilekic            return options.get(option);
135129906Sbmilekic        }
136129906Sbmilekic
137129906Sbmilekic        @Override
138129906Sbmilekic        public void put(String name, String value) {
139129906Sbmilekic            options.put(name, value);
140129906Sbmilekic        }
141129906Sbmilekic
142129906Sbmilekic        @Override
143129906Sbmilekic        public void remove(String name) {
144129906Sbmilekic            options.remove(name);
145129906Sbmilekic        }
146129906Sbmilekic
147129906Sbmilekic        @Override
148129906Sbmilekic        public boolean handleFileManagerOption(Option option, String value) {
149129906Sbmilekic            options.put(option, value);
150129906Sbmilekic            deferredFileManagerOptions.put(option, value);
151129906Sbmilekic            return true;
152129906Sbmilekic        }
153129906Sbmilekic
154129906Sbmilekic        @Override
155129906Sbmilekic        public Log getLog() {
156129906Sbmilekic            return log;
157129906Sbmilekic        }
158129906Sbmilekic
159129906Sbmilekic        @Override
160129906Sbmilekic        public String getOwnName() {
161129906Sbmilekic            return ownName;
162129906Sbmilekic        }
163129906Sbmilekic
164129906Sbmilekic        @Override
165129906Sbmilekic        public void addFile(Path p) {
166129906Sbmilekic            files.add(p);
167129906Sbmilekic        }
168129906Sbmilekic
169129906Sbmilekic        @Override
170129906Sbmilekic        public void addClassName(String s) {
171129906Sbmilekic            classNames.add(s);
172129906Sbmilekic        }
173129906Sbmilekic
174129906Sbmilekic    };
175129906Sbmilekic
176129906Sbmilekic    /**
177129906Sbmilekic     * Initializes this Args instance with a set of command line args.
178129906Sbmilekic     * The args will be processed in conjunction with the full set of
179129906Sbmilekic     * command line options, including -help, -version etc.
180129906Sbmilekic     * The args may also contain class names and filenames.
181129906Sbmilekic     * Any errors during this call, and later during validate, will be reported
182129906Sbmilekic     * to the log.
183129906Sbmilekic     * @param ownName the name of this tool; used to prefix messages
184129906Sbmilekic     * @param args the args to be processed
185129906Sbmilekic     */
186129906Sbmilekic    public void init(String ownName, String... args) {
187129906Sbmilekic        this.ownName = ownName;
188129906Sbmilekic        errorMode = ErrorMode.LOG;
189129906Sbmilekic        files = new LinkedHashSet<>();
190129906Sbmilekic        deferredFileManagerOptions = new LinkedHashMap<>();
191129906Sbmilekic        fileObjects = null;
192129906Sbmilekic        classNames = new LinkedHashSet<>();
193129906Sbmilekic        processArgs(List.from(args), Option.getJavaCompilerOptions(), cmdLineHelper, true, false);
194129906Sbmilekic        if (errors) {
195129906Sbmilekic            log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
196129906Sbmilekic        }
197129906Sbmilekic    }
198129906Sbmilekic
199129906Sbmilekic    private final OptionHelper apiHelper = new GrumpyHelper(null) {
200129906Sbmilekic        @Override
201129906Sbmilekic        public String get(Option option) {
202143188Salc            return options.get(option);
203129906Sbmilekic        }
204129906Sbmilekic
205129906Sbmilekic        @Override
206129906Sbmilekic        public void put(String name, String value) {
207129906Sbmilekic            options.put(name, value);
208129906Sbmilekic        }
209129906Sbmilekic
210129906Sbmilekic        @Override
211129906Sbmilekic        public void remove(String name) {
212129906Sbmilekic            options.remove(name);
213129906Sbmilekic        }
214129906Sbmilekic
215129906Sbmilekic        @Override
216129906Sbmilekic        public Log getLog() {
217129906Sbmilekic            return Arguments.this.log;
218129906Sbmilekic        }
219129906Sbmilekic    };
220129906Sbmilekic
221129906Sbmilekic    /**
222129906Sbmilekic     * Initializes this Args instance with the parameters for a JavacTask.
223129906Sbmilekic     * The options will be processed in conjunction with the restricted set
224130289Sbmilekic     * of tool options, which does not include -help, -version, etc,
225141668Sbmilekic     * nor does it include classes and filenames, which should be specified
226129906Sbmilekic     * separately.
227141668Sbmilekic     * File manager options are handled directly by the file manager.
228141668Sbmilekic     * Any errors found while processing individual args will be reported
229141668Sbmilekic     * via IllegalArgumentException.
230141668Sbmilekic     * Any subsequent errors during validate will be reported via IllegalStateException.
231141668Sbmilekic     * @param ownName the name of this tool; used to prefix messages
232141668Sbmilekic     * @param options the options to be processed
233130289Sbmilekic     * @param classNames the classes to be subject to annotation processing
234130289Sbmilekic     * @param files the files to be compiled
235130289Sbmilekic     */
236130289Sbmilekic    public void init(String ownName,
237130289Sbmilekic            Iterable<String> options,
238141668Sbmilekic            Iterable<String> classNames,
239143188Salc            Iterable<? extends JavaFileObject> files) {
240130289Sbmilekic        this.ownName = ownName;
241141668Sbmilekic        this.classNames = toSet(classNames);
242141668Sbmilekic        this.fileObjects = toSet(files);
243130289Sbmilekic        this.files = null;
244129906Sbmilekic        errorMode = ErrorMode.ILLEGAL_ARGUMENT;
245141668Sbmilekic        if (options != null) {
246141668Sbmilekic            processArgs(toList(options), Option.getJavacToolOptions(), apiHelper, false, true);
247141668Sbmilekic        }
248141668Sbmilekic        errorMode = ErrorMode.ILLEGAL_STATE;
249141668Sbmilekic    }
250141668Sbmilekic
251141668Sbmilekic    /**
252141668Sbmilekic     * Minimal initialization for tools, like javadoc,
253141668Sbmilekic     * to be able to process javac options for themselves,
254141668Sbmilekic     * and then call validate.
255141668Sbmilekic     * @param ownName  the name of this tool; used to prefix messages
256141668Sbmilekic     */
257141668Sbmilekic    public void init(String ownName) {
258141668Sbmilekic        this.ownName = ownName;
259141668Sbmilekic        errorMode = ErrorMode.LOG;
260141668Sbmilekic    }
261141668Sbmilekic
262143188Salc    /**
263143188Salc     * Gets the files to be compiled.
264141668Sbmilekic     * @return the files to be compiled
265141668Sbmilekic     */
266141668Sbmilekic    public Set<JavaFileObject> getFileObjects() {
267141668Sbmilekic        if (fileObjects == null) {
268141668Sbmilekic            fileObjects = new LinkedHashSet<>();
269130357Sbmilekic        }
270129906Sbmilekic        if (files != null) {
271129906Sbmilekic            JavacFileManager jfm = (JavacFileManager) getFileManager();
272129906Sbmilekic            for (JavaFileObject fo: jfm.getJavaFileObjectsFromPaths(files))
273149598Sandre                fileObjects.add(fo);
274149598Sandre        }
275149598Sandre        return fileObjects;
276149598Sandre    }
277149598Sandre
278149598Sandre    /**
279149598Sandre     * Gets the classes to be subject to annotation processing.
280149598Sandre     * @return the classes to be subject to annotation processing
281149598Sandre     */
282149598Sandre    public Set<String> getClassNames() {
283149598Sandre        return classNames;
284149598Sandre    }
285149598Sandre
286149598Sandre    /**
287149598Sandre     * Handles the {@code --release} option.
288149598Sandre     *
289149598Sandre     * @param additionalOptions a predicate to handle additional options implied by the
290149598Sandre     * {@code --release} option. The predicate should return true if all the additional
291149598Sandre     * options were processed successfully.
292149598Sandre     * @return true if successful, false otherwise
293149598Sandre     */
294149598Sandre    public boolean handleReleaseOptions(Predicate<Iterable<String>> additionalOptions) {
295149598Sandre        String platformString = options.get(Option.RELEASE);
296149598Sandre
297149599Sandre        checkOptionAllowed(platformString == null,
298149599Sandre                option -> error("err.release.bootclasspath.conflict", option.getPrimaryName()),
299149599Sandre                Option.BOOT_CLASS_PATH, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
300149599Sandre                Option.XBOOTCLASSPATH_PREPEND,
301149599Sandre                Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
302149599Sandre                Option.EXTDIRS, Option.DJAVA_EXT_DIRS,
303149599Sandre                Option.SOURCE, Option.TARGET,
304149599Sandre                Option.SYSTEM, Option.UPGRADE_MODULE_PATH);
305149599Sandre
306149599Sandre        if (platformString != null) {
307149599Sandre            PlatformDescription platformDescription = PlatformUtils.lookupPlatformDescription(platformString);
308149599Sandre
309149599Sandre            if (platformDescription == null) {
310149599Sandre                error("err.unsupported.release.version", platformString);
311149599Sandre                return false;
312149599Sandre            }
313149599Sandre
314149599Sandre            options.put(Option.SOURCE, platformDescription.getSourceVersion());
315149599Sandre            options.put(Option.TARGET, platformDescription.getTargetVersion());
316149599Sandre
317149599Sandre            context.put(PlatformDescription.class, platformDescription);
318149599Sandre
319149599Sandre            if (!additionalOptions.test(platformDescription.getAdditionalOptions()))
320149599Sandre                return false;
321149599Sandre
322149599Sandre            Collection<Path> platformCP = platformDescription.getPlatformPath();
323149599Sandre
324149599Sandre            if (platformCP != null) {
325149599Sandre                JavaFileManager fm = getFileManager();
326149599Sandre
327149599Sandre                if (!(fm instanceof StandardJavaFileManager)) {
328149599Sandre                    error("err.release.not.standard.file.manager");
329149599Sandre                    return false;
330149599Sandre                }
331149599Sandre
332149599Sandre                try {
333149599Sandre                    StandardJavaFileManager sfm = (StandardJavaFileManager) fm;
334149599Sandre
335149599Sandre                    if (Source.instance(context).allowModules()) {
336149599Sandre                        sfm.handleOption("--system", Arrays.asList("none").iterator());
337149599Sandre                        sfm.setLocationFromPaths(StandardLocation.UPGRADE_MODULE_PATH, platformCP);
338149599Sandre                    } else {
339149599Sandre                        sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
340149599Sandre                    }
341149599Sandre                } catch (IOException ex) {
342149599Sandre                    log.printLines(PrefixKind.JAVAC, "msg.io");
343149599Sandre                    ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
344149599Sandre                    return false;
345149599Sandre                }
346149599Sandre            }
347149599Sandre        }
348149599Sandre
349149599Sandre        return true;
350149599Sandre    }
351149599Sandre
352149599Sandre    /**
353149599Sandre     * Processes strings containing options and operands.
354149599Sandre     * @param args the strings to be processed
355149599Sandre     * @param allowableOpts the set of option declarations that are applicable
356149599Sandre     * @param helper a help for use by Option.process
357149599Sandre     * @param allowOperands whether or not to check for files and classes
358149599Sandre     * @param checkFileManager whether or not to check if the file manager can handle
359149599Sandre     *      options which are not recognized by any of allowableOpts
360149599Sandre     * @return true if all the strings were successfully processed; false otherwise
361149599Sandre     * @throws IllegalArgumentException if a problem occurs and errorMode is set to
362149599Sandre     *      ILLEGAL_ARGUMENT
363149599Sandre     */
364149599Sandre    private boolean processArgs(Iterable<String> args,
365149599Sandre            Set<Option> allowableOpts, OptionHelper helper,
366149599Sandre            boolean allowOperands, boolean checkFileManager) {
367149599Sandre        if (!doProcessArgs(args, allowableOpts, helper, allowOperands, checkFileManager))
368149599Sandre            return false;
369149599Sandre
370149599Sandre        if (!handleReleaseOptions(extra -> doProcessArgs(extra, allowableOpts, helper, allowOperands, checkFileManager)))
371149599Sandre            return false;
372149599Sandre
373149599Sandre        options.notifyListeners();
374149599Sandre
375149599Sandre        return true;
376149599Sandre    }
377149599Sandre
378149599Sandre    private boolean doProcessArgs(Iterable<String> args,
379149599Sandre            Set<Option> allowableOpts, OptionHelper helper,
380149599Sandre            boolean allowOperands, boolean checkFileManager) {
381149599Sandre        JavaFileManager fm = checkFileManager ? getFileManager() : null;
382149599Sandre        Iterator<String> argIter = args.iterator();
383149599Sandre        while (argIter.hasNext()) {
384149599Sandre            String arg = argIter.next();
385149599Sandre            if (arg.isEmpty()) {
386149599Sandre                error("err.invalid.flag", arg);
387149599Sandre                return false;
388149599Sandre            }
389149599Sandre
390149599Sandre            Option option = null;
391149599Sandre
392108466Ssam            // first, check the provided set of javac options
393100960Srwatson            if (arg.startsWith("-")) {
394100960Srwatson                option = Option.lookup(arg, allowableOpts);
395100960Srwatson            } else if (allowOperands && Option.SOURCEFILE.matches(arg)) {
396108466Ssam                option = Option.SOURCEFILE;
397100960Srwatson            }
398100960Srwatson
399100960Srwatson            if (option != null) {
400108466Ssam                try {
401113255Sdes                    option.handleOption(helper, arg, argIter);
402113487Srwatson                } catch (Option.InvalidValueException e) {
403108466Ssam                    error(e);
404108466Ssam                    return false;
405100960Srwatson                }
406101007Srwatson                continue;
407113487Srwatson            }
408113487Srwatson
409113487Srwatson            // check file manager option
410101007Srwatson            if (fm != null && fm.handleOption(arg, argIter)) {
411113487Srwatson                continue;
412101007Srwatson            }
413143302Ssam
414143302Ssam            // none of the above
415143302Ssam            error("err.invalid.flag", arg);
416108466Ssam            return false;
417108466Ssam        }
418108466Ssam
419108466Ssam        return true;
420108466Ssam    }
421108466Ssam
422108466Ssam    /**
423108466Ssam     * Validates the overall consistency of the options and operands
424108466Ssam     * processed by processOptions.
425108466Ssam     * @return true if all args are successfully validated; false otherwise.
426108466Ssam     * @throws IllegalStateException if a problem is found and errorMode is set to
427108466Ssam     *      ILLEGAL_STATE
428108466Ssam     */
429108466Ssam    public boolean validate() {
430108466Ssam        JavaFileManager fm = getFileManager();
431108466Ssam        if (options.isSet(Option.MODULE)) {
432108466Ssam            if (!fm.hasLocation(StandardLocation.CLASS_OUTPUT)) {
433108466Ssam                log.error(Errors.OutputDirMustBeSpecifiedWithDashMOption);
434108466Ssam            } else if (!fm.hasLocation(StandardLocation.MODULE_SOURCE_PATH)) {
435108466Ssam                log.error(Errors.ModulesourcepathMustBeSpecifiedWithDashMOption);
436108466Ssam            } else {
437108466Ssam                java.util.List<String> modules = Arrays.asList(options.get(Option.MODULE).split(","));
438113255Sdes                try {
439113487Srwatson                    for (String module : modules) {
440108466Ssam                        Location sourceLoc = fm.getLocationForModule(StandardLocation.MODULE_SOURCE_PATH, module);
441108466Ssam                        if (sourceLoc == null) {
442132488Salfred                            log.error(Errors.ModuleNotFoundInModuleSourcePath(module));
443108466Ssam                        } else {
444108466Ssam                            Location classLoc = fm.getLocationForModule(StandardLocation.CLASS_OUTPUT, module);
445113487Srwatson
446108466Ssam                            for (JavaFileObject file : fm.list(sourceLoc, "", EnumSet.of(JavaFileObject.Kind.SOURCE), true)) {
447112733Ssilby                                String className = fm.inferBinaryName(sourceLoc, file);
448112733Ssilby                                JavaFileObject classFile = fm.getJavaFileForInput(classLoc, className, Kind.CLASS);
449112733Ssilby
450100960Srwatson                                if (classFile == null || classFile.getLastModified() < file.getLastModified()) {
451108466Ssam                                    if (fileObjects == null)
452113480Srwatson                                        fileObjects = new HashSet<>();
453100960Srwatson                                    fileObjects.add(file);
454100960Srwatson                                }
455100960Srwatson                            }
4561541Srgrimes                        }
4571541Srgrimes                    }
4581541Srgrimes                } catch (IOException ex) {
4591541Srgrimes                    log.printLines(PrefixKind.JAVAC, "msg.io");
4601541Srgrimes                    ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
46172356Sbmilekic                    return false;
4621541Srgrimes                }
4631541Srgrimes            }
4641541Srgrimes        }
465117770Ssilby
466117770Ssilby        if (isEmpty()) {
467117770Ssilby            // It is allowed to compile nothing if just asking for help or version info.
468117770Ssilby            // But also note that none of these options are supported in API mode.
46972356Sbmilekic            if (options.isSet(Option.HELP)
4701541Srgrimes                    || options.isSet(Option.X)
47172356Sbmilekic                    || options.isSet(Option.VERSION)
4721541Srgrimes                    || options.isSet(Option.FULLVERSION)
473113487Srwatson                    || options.isSet(Option.MODULE)) {
474108466Ssam                return true;
4751541Srgrimes            }
4761541Srgrimes
4771541Srgrimes            if (!emptyAllowed) {
4781541Srgrimes                if (!errors) {
4791541Srgrimes                    if (JavaCompiler.explicitAnnotationProcessingRequested(options)) {
4801541Srgrimes                        error("err.no.source.files.classes");
4811541Srgrimes                    } else {
4821541Srgrimes                        error("err.no.source.files");
4831541Srgrimes                    }
4841541Srgrimes                }
4851541Srgrimes                return false;
486111119Simp            }
48754002Sarchie        }
48854002Sarchie
4891541Srgrimes        if (!checkDirectory(Option.D)) {
4901541Srgrimes            return false;
49172356Sbmilekic        }
4921541Srgrimes        if (!checkDirectory(Option.S)) {
49372356Sbmilekic            return false;
49472356Sbmilekic        }
4951541Srgrimes        if (!checkDirectory(Option.H)) {
4961541Srgrimes            return false;
4971541Srgrimes        }
49852201Salfred
49952201Salfred        // The following checks are to help avoid accidental confusion between
500132488Salfred        // directories of modules and exploded module directories.
5011541Srgrimes        if (fm instanceof StandardJavaFileManager) {
5021541Srgrimes            StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
5031541Srgrimes            if (sfm.hasLocation(StandardLocation.CLASS_OUTPUT)) {
50452201Salfred                Path outDir = sfm.getLocationAsPaths(StandardLocation.CLASS_OUTPUT).iterator().next();
5051541Srgrimes                if (sfm.hasLocation(StandardLocation.MODULE_SOURCE_PATH)) {
5061541Srgrimes                    // multi-module mode
5071541Srgrimes                    if (Files.exists(outDir.resolve("module-info.class"))) {
5081541Srgrimes                        log.error(Errors.MultiModuleOutdirCannotBeExplodedModule(outDir));
5091541Srgrimes                    }
5101541Srgrimes                } else {
5111541Srgrimes                    // single-module or legacy mode
5121541Srgrimes                    boolean lintPaths = options.isUnset(Option.XLINT_CUSTOM,
51372356Sbmilekic                            "-" + LintCategory.PATH.option);
51452201Salfred                    if (lintPaths) {
51552201Salfred                        Path outDirParent = outDir.getParent();
5161541Srgrimes                        if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) {
5171541Srgrimes                            log.warning(LintCategory.PATH, Warnings.OutdirIsInExplodedModule(outDir));
518117770Ssilby                        }
519117770Ssilby                    }
520117770Ssilby                }
521117770Ssilby            }
5221541Srgrimes        }
52372356Sbmilekic
5241541Srgrimes
5251541Srgrimes        String sourceString = options.get(Option.SOURCE);
526108466Ssam        Source source = (sourceString != null)
527108466Ssam                ? Source.lookup(sourceString)
5281541Srgrimes                : Source.DEFAULT;
5291541Srgrimes        String targetString = options.get(Option.TARGET);
5301541Srgrimes        Target target = (targetString != null)
5311541Srgrimes                ? Target.lookup(targetString)
5321541Srgrimes                : Target.DEFAULT;
5331541Srgrimes
5341541Srgrimes        // We don't check source/target consistency for CLDC, as J2ME
5351541Srgrimes        // profiles are not aligned with J2SE targets; moreover, a
5361541Srgrimes        // single CLDC target may have many profiles.  In addition,
5371541Srgrimes        // this is needed for the continued functioning of the JSR14
5381541Srgrimes        // prototype.
53964837Sdwmalone        if (Character.isDigit(target.name.charAt(0))) {
540141668Sbmilekic            if (target.compareTo(source.requiredTarget()) < 0) {
5411541Srgrimes                if (targetString != null) {
5421541Srgrimes                    if (sourceString == null) {
543103569Sbmilekic                        error("warn.target.default.source.conflict",
5441541Srgrimes                                targetString,
5451541Srgrimes                                source.requiredTarget().name);
5461541Srgrimes                    } else {
5471541Srgrimes                        error("warn.source.target.conflict",
5481541Srgrimes                                sourceString,
5491541Srgrimes                                source.requiredTarget().name);
55078592Sbmilekic                    }
55178592Sbmilekic                    return false;
55278592Sbmilekic                } else {
5531541Srgrimes                    target = source.requiredTarget();
5541541Srgrimes                    options.put("-target", target.name);
5551541Srgrimes                }
55678592Sbmilekic            }
55772356Sbmilekic        }
5581541Srgrimes
5591541Srgrimes        String profileString = options.get(Option.PROFILE);
5601541Srgrimes        if (profileString != null) {
561149602Sandre            Profile profile = Profile.lookup(profileString);
562149602Sandre            if (!profile.isValid(target)) {
563149602Sandre                error("warn.profile.target.conflict", profileString, target.name);
564149602Sandre            }
565149602Sandre
566149602Sandre            // This check is only effective in command line mode,
567149602Sandre            // where the file manager options are added to options
568149602Sandre            if (options.get(Option.BOOT_CLASS_PATH) != null) {
569149602Sandre                error("err.profile.bootclasspath.conflict");
570149602Sandre            }
571149602Sandre        }
572149602Sandre
573149602Sandre        if (options.isSet(Option.SOURCE_PATH) && options.isSet(Option.MODULE_SOURCE_PATH)) {
574149602Sandre            error("err.sourcepath.modulesourcepath.conflict");
575149602Sandre        }
576149602Sandre
577149602Sandre        boolean lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
578149602Sandre        if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) {
579149602Sandre            if (fm instanceof BaseFileManager) {
580149602Sandre                if (((BaseFileManager) fm).isDefaultBootClassPath())
581149602Sandre                    log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
582149602Sandre            }
583149602Sandre        }
584149602Sandre
585149602Sandre        boolean obsoleteOptionFound = false;
586149602Sandre
587149602Sandre        if (source.compareTo(Source.MIN) < 0) {
588149602Sandre            log.error(Errors.OptionRemovedSource(source.name, Source.MIN.name));
589149602Sandre        } else if (source == Source.MIN && lintOptions) {
590149602Sandre            log.warning(LintCategory.OPTIONS, Warnings.OptionObsoleteSource(source.name));
591149602Sandre            obsoleteOptionFound = true;
592149602Sandre        }
593149602Sandre
594149602Sandre        if (target.compareTo(Target.MIN) < 0) {
595149602Sandre            log.error(Errors.OptionRemovedTarget(target.name, Target.MIN.name));
596149602Sandre        } else if (target == Target.MIN && lintOptions) {
597149602Sandre            log.warning(LintCategory.OPTIONS, Warnings.OptionObsoleteTarget(target.name));
598149602Sandre            obsoleteOptionFound = true;
599149602Sandre        }
600149602Sandre
601149602Sandre        final Target t = target;
602149602Sandre        checkOptionAllowed(t.compareTo(Target.JDK1_8) <= 0,
603149602Sandre                option -> error("err.option.not.allowed.with.target", option.getPrimaryName(), t.name),
604149602Sandre                Option.BOOT_CLASS_PATH,
605149602Sandre                Option.XBOOTCLASSPATH_PREPEND, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
606149602Sandre                Option.ENDORSEDDIRS, Option.DJAVA_ENDORSED_DIRS,
607149602Sandre                Option.EXTDIRS, Option.DJAVA_EXT_DIRS,
608149602Sandre                Option.PROFILE);
609149602Sandre
610149602Sandre        checkOptionAllowed(t.compareTo(Target.JDK1_9) >= 0,
611149602Sandre                option -> error("err.option.not.allowed.with.target", option.getPrimaryName(), t.name),
612149602Sandre                Option.MODULE_SOURCE_PATH, Option.UPGRADE_MODULE_PATH,
613149602Sandre                Option.SYSTEM, Option.MODULE_PATH, Option.ADD_MODULES,
614149602Sandre                Option.ADD_EXPORTS, Option.ADD_OPENS, Option.ADD_READS,
615149602Sandre                Option.LIMIT_MODULES,
616149602Sandre                Option.PATCH_MODULE);
617149602Sandre
618149602Sandre        if (fm.hasLocation(StandardLocation.MODULE_SOURCE_PATH)) {
619149602Sandre            if (!options.isSet(Option.PROC, "only")
620149602Sandre                    && !fm.hasLocation(StandardLocation.CLASS_OUTPUT)) {
621149602Sandre                log.error(Errors.NoOutputDir);
622149602Sandre            }
623149602Sandre        }
624149602Sandre
625149602Sandre        if (fm.hasLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH) &&
626149602Sandre            fm.hasLocation(StandardLocation.ANNOTATION_PROCESSOR_PATH)) {
627149602Sandre            log.error(Errors.ProcessorpathNoProcessormodulepath);
628149602Sandre        }
629149602Sandre
630149602Sandre        if (obsoleteOptionFound && lintOptions) {
631149602Sandre            log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
632149602Sandre        }
633149602Sandre
634149602Sandre        SourceVersion sv = Source.toSourceVersion(source);
635149602Sandre        validateAddExports(sv);
636149602Sandre        validateAddModules(sv);
637149602Sandre        validateAddReads(sv);
638149602Sandre        validateLimitModules(sv);
639149602Sandre        validateDefaultModuleForCreatedFiles(sv);
640149602Sandre
641149602Sandre        if (lintOptions && options.isSet(Option.ADD_OPENS)) {
642149602Sandre            log.warning(LintCategory.OPTIONS, Warnings.AddopensIgnored);
643149602Sandre        }
644149602Sandre
645149602Sandre        return !errors && (log.nerrors == 0);
646149602Sandre    }
647149602Sandre
648149602Sandre    private void validateAddExports(SourceVersion sv) {
649149602Sandre        String addExports = options.get(Option.ADD_EXPORTS);
650149602Sandre        if (addExports != null) {
651149602Sandre            // Each entry must be of the form sourceModule/sourcePackage=target-list where
652149602Sandre            // target-list is a comma separated list of module or ALL-UNNAMED.
653149602Sandre            // Empty items in the target-list are ignored.
654149602Sandre            // There must be at least one item in the list; this is handled in Option.ADD_EXPORTS.
655149602Sandre            Pattern p = Option.ADD_EXPORTS.getPattern();
656149602Sandre            for (String e : addExports.split("\0")) {
657149602Sandre                Matcher m = p.matcher(e);
658149602Sandre                if (m.matches()) {
659149602Sandre                    String sourceModuleName = m.group(1);
660149602Sandre                    if (!SourceVersion.isName(sourceModuleName, sv)) {
661149602Sandre                        // syntactically invalid source name:  e.g. --add-exports m!/p1=m2
662149602Sandre                        log.warning(Warnings.BadNameForOption(Option.ADD_EXPORTS, sourceModuleName));
663149602Sandre                    }
664149602Sandre                    String sourcePackageName = m.group(2);
665149602Sandre                    if (!SourceVersion.isName(sourcePackageName, sv)) {
666149602Sandre                        // syntactically invalid source name:  e.g. --add-exports m1/p!=m2
667149602Sandre                        log.warning(Warnings.BadNameForOption(Option.ADD_EXPORTS, sourcePackageName));
668149602Sandre                    }
669149602Sandre
670149602Sandre                    String targetNames = m.group(3);
671149602Sandre                    for (String targetName : targetNames.split(",")) {
672149602Sandre                        switch (targetName) {
673149602Sandre                            case "":
674149602Sandre                            case "ALL-UNNAMED":
675149602Sandre                                break;
676149602Sandre
677149602Sandre                            default:
678149602Sandre                                if (!SourceVersion.isName(targetName, sv)) {
679149602Sandre                                    // syntactically invalid target name:  e.g. --add-exports m1/p1=m!
680149602Sandre                                    log.warning(Warnings.BadNameForOption(Option.ADD_EXPORTS, targetName));
681149602Sandre                                }
682149602Sandre                                break;
683149602Sandre                        }
684149602Sandre                    }
685149602Sandre                }
686149602Sandre            }
687149602Sandre        }
688149602Sandre    }
689149602Sandre
690149602Sandre    private void validateAddReads(SourceVersion sv) {
691149602Sandre        String addReads = options.get(Option.ADD_READS);
692149602Sandre        if (addReads != null) {
693149602Sandre            // Each entry must be of the form source=target-list where target-list is a
694149602Sandre            // comma-separated list of module or ALL-UNNAMED.
695149602Sandre            // Empty items in the target list are ignored.
696149602Sandre            // There must be at least one item in the list; this is handled in Option.ADD_READS.
697149602Sandre            Pattern p = Option.ADD_READS.getPattern();
698149602Sandre            for (String e : addReads.split("\0")) {
699149602Sandre                Matcher m = p.matcher(e);
700149602Sandre                if (m.matches()) {
701149602Sandre                    String sourceName = m.group(1);
702149602Sandre                    if (!SourceVersion.isName(sourceName, sv)) {
703149602Sandre                        // syntactically invalid source name:  e.g. --add-reads m!=m2
704149602Sandre                        log.warning(Warnings.BadNameForOption(Option.ADD_READS, sourceName));
705149602Sandre                    }
70615689Swollman
70715689Swollman                    String targetNames = m.group(2);
70854002Sarchie                    for (String targetName : targetNames.split(",", -1)) {
70954002Sarchie                        switch (targetName) {
71072750Sluigi                            case "":
71172750Sluigi                            case "ALL-UNNAMED":
71272750Sluigi                                break;
71315689Swollman
71415689Swollman                            default:
71572356Sbmilekic                                if (!SourceVersion.isName(targetName, sv)) {
71615689Swollman                                    // syntactically invalid target name:  e.g. --add-reads m1=m!
71715689Swollman                                    log.warning(Warnings.BadNameForOption(Option.ADD_READS, targetName));
71815689Swollman                                }
719132488Salfred                                break;
72015689Swollman                        }
72115689Swollman                    }
72272356Sbmilekic                }
72315689Swollman            }
72415689Swollman        }
725108466Ssam    }
726108466Ssam
72715689Swollman    private void validateAddModules(SourceVersion sv) {
72815689Swollman        String addModules = options.get(Option.ADD_MODULES);
72915689Swollman        if (addModules != null) {
73015689Swollman            // Each entry must be of the form target-list where target-list is a
73115689Swollman            // comma separated list of module names, or ALL-DEFAULT, ALL-SYSTEM,
73264837Sdwmalone            // or ALL-MODULE_PATH.
733141668Sbmilekic            // Empty items in the target list are ignored.
73415689Swollman            // There must be at least one item in the list; this is handled in Option.ADD_MODULES.
73572750Sluigi            for (String moduleName : addModules.split(",")) {
73615689Swollman                switch (moduleName) {
73715689Swollman                    case "":
73815689Swollman                    case "ALL-SYSTEM":
73915689Swollman                    case "ALL-MODULE-PATH":
74015689Swollman                        break;
74115689Swollman
74272356Sbmilekic                    default:
74315689Swollman                        if (!SourceVersion.isName(moduleName, sv)) {
74415689Swollman                            // syntactically invalid module name:  e.g. --add-modules m1,m!
74515689Swollman                            log.error(Errors.BadNameForOption(Option.ADD_MODULES, moduleName));
74615689Swollman                        }
74715689Swollman                        break;
74815689Swollman                }
74915689Swollman            }
75015689Swollman        }
75115689Swollman    }
75215689Swollman
75364837Sdwmalone    private void validateLimitModules(SourceVersion sv) {
754141668Sbmilekic        String limitModules = options.get(Option.LIMIT_MODULES);
75515689Swollman        if (limitModules != null) {
75615689Swollman            // Each entry must be of the form target-list where target-list is a
75715689Swollman            // comma separated list of module names, or ALL-DEFAULT, ALL-SYSTEM,
75815689Swollman            // or ALL-MODULE_PATH.
75915689Swollman            // Empty items in the target list are ignored.
76015689Swollman            // There must be at least one item in the list; this is handled in Option.LIMIT_EXPORTS.
76115689Swollman            for (String moduleName : limitModules.split(",")) {
76215689Swollman                switch (moduleName) {
76315689Swollman                    case "":
76478592Sbmilekic                        break;
76572356Sbmilekic
76615689Swollman                    default:
76715689Swollman                        if (!SourceVersion.isName(moduleName, sv)) {
76815689Swollman                            // syntactically invalid module name:  e.g. --limit-modules m1,m!
7691541Srgrimes                            log.error(Errors.BadNameForOption(Option.LIMIT_MODULES, moduleName));
7701541Srgrimes                        }
7711541Srgrimes                        break;
7721549Srgrimes                }
77381907Sjulian            }
7741541Srgrimes        }
775103569Sbmilekic    }
7761541Srgrimes
77752201Salfred    private void validateDefaultModuleForCreatedFiles(SourceVersion sv) {
77852201Salfred        String moduleName = options.get(Option.DEFAULT_MODULE_FOR_CREATED_FILES);
7791541Srgrimes        if (moduleName != null) {
78052201Salfred            if (!SourceVersion.isName(moduleName, sv)) {
7811541Srgrimes                // syntactically invalid module name:  e.g. --default-module-for-created-files m!
7821541Srgrimes                log.error(Errors.BadNameForOption(Option.DEFAULT_MODULE_FOR_CREATED_FILES,
7831541Srgrimes                                                  moduleName));
7841541Srgrimes            }
7851541Srgrimes        }
7861541Srgrimes    }
78752201Salfred
7881541Srgrimes    /**
7891541Srgrimes     * Returns true if there are no files or classes specified for use.
7901541Srgrimes     * @return true if there are no files or classes specified for use
7911541Srgrimes     */
7921541Srgrimes    public boolean isEmpty() {
7931541Srgrimes        return ((files == null) || files.isEmpty())
7941541Srgrimes                && ((fileObjects == null) || fileObjects.isEmpty())
7951541Srgrimes                && (classNames == null || classNames.isEmpty());
7961541Srgrimes    }
7971541Srgrimes
79854002Sarchie    public void allowEmpty() {
79954002Sarchie        this.emptyAllowed = true;
80054002Sarchie    }
80154002Sarchie
80254002Sarchie    /**
80372356Sbmilekic     * Gets the file manager options which may have been deferred
80454002Sarchie     * during processArgs.
80554002Sarchie     * @return the deferred file manager options
80654002Sarchie     */
80754002Sarchie    public Map<Option, String> getDeferredFileManagerOptions() {
808132488Salfred        return deferredFileManagerOptions;
80954002Sarchie    }
81054002Sarchie
81172356Sbmilekic    /**
812113255Sdes     * Gets any options specifying plugins to be run.
81354002Sarchie     * @return options for plugins
81454002Sarchie     */
81554002Sarchie    public Set<List<String>> getPluginOpts() {
81654002Sarchie        String plugins = options.get(Option.PLUGIN);
81754002Sarchie        if (plugins == null)
81854002Sarchie            return Collections.emptySet();
81954002Sarchie
82054002Sarchie        Set<List<String>> pluginOpts = new LinkedHashSet<>();
82154002Sarchie        for (String plugin: plugins.split("\\x00")) {
822129906Sbmilekic            pluginOpts.add(List.from(plugin.split("\\s+")));
823129906Sbmilekic        }
824129906Sbmilekic        return Collections.unmodifiableSet(pluginOpts);
825129906Sbmilekic    }
826129906Sbmilekic
827129906Sbmilekic    /**
828129906Sbmilekic     * Gets any options specifying how doclint should be run.
82954002Sarchie     * An empty list is returned if no doclint options are specified
83054002Sarchie     * or if the only doclint option is -Xdoclint:none.
831129906Sbmilekic     * @return options for doclint
832129906Sbmilekic     */
833129906Sbmilekic    public List<String> getDocLintOpts() {
834129906Sbmilekic        String xdoclint = options.get(Option.XDOCLINT);
835108466Ssam        String xdoclintCustom = options.get(Option.XDOCLINT_CUSTOM);
836129906Sbmilekic        if (xdoclint == null && xdoclintCustom == null)
83754002Sarchie            return List.nil();
83854002Sarchie
83954002Sarchie        Set<String> doclintOpts = new LinkedHashSet<>();
84054002Sarchie        if (xdoclint != null)
84154002Sarchie            doclintOpts.add(DocLint.XMSGS_OPTION);
84254002Sarchie        if (xdoclintCustom != null) {
84354002Sarchie            for (String s: xdoclintCustom.split("\\s+")) {
84454002Sarchie                if (s.isEmpty())
84554002Sarchie                    continue;
84654002Sarchie                doclintOpts.add(DocLint.XMSGS_CUSTOM_PREFIX + s);
84754002Sarchie            }
84854002Sarchie        }
84954002Sarchie
85054002Sarchie        if (doclintOpts.equals(Collections.singleton(DocLint.XMSGS_CUSTOM_PREFIX + "none")))
85154002Sarchie            return List.nil();
85254002Sarchie
85354002Sarchie        String checkPackages = options.get(Option.XDOCLINT_PACKAGE);
85454002Sarchie        if (checkPackages != null) {
85554002Sarchie            for (String s : checkPackages.split("\\s+")) {
85654002Sarchie                doclintOpts.add(DocLint.XCHECK_PACKAGE + s);
85754002Sarchie            }
85854002Sarchie        }
85954002Sarchie
86054002Sarchie        String format = options.get(Option.DOCLINT_FORMAT);
86187594Sobrien        if (format != null) {
86254002Sarchie            doclintOpts.add(DocLint.XHTML_VERSION_PREFIX + format);
86354002Sarchie        }
86454002Sarchie
86554002Sarchie        // standard doclet normally generates H1, H2,
86654002Sarchie        // so for now, allow user comments to assume that
86778592Sbmilekic        doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
86872356Sbmilekic        return List.from(doclintOpts.toArray(new String[doclintOpts.size()]));
86954002Sarchie    }
87054002Sarchie
87154002Sarchie    private boolean checkDirectory(Option option) {
8721541Srgrimes        String value = options.get(option);
8731541Srgrimes        if (value == null) {
8741541Srgrimes            return true;
8751541Srgrimes        }
8761549Srgrimes        Path file = Paths.get(value);
87772356Sbmilekic        if (Files.exists(file) && !Files.isDirectory(file)) {
8781541Srgrimes            error("err.file.not.directory", value);
8791541Srgrimes            return false;
8801541Srgrimes        }
8811541Srgrimes        return true;
8821541Srgrimes    }
8831541Srgrimes
8841541Srgrimes    private interface ErrorReporter {
8851541Srgrimes        void report(Option o);
8861541Srgrimes    }
8871541Srgrimes
8881541Srgrimes    void checkOptionAllowed(boolean allowed, ErrorReporter r, Option... opts) {
8891541Srgrimes        if (!allowed) {
8901541Srgrimes            Stream.of(opts)
8911541Srgrimes                  .filter(options :: isSet)
8921541Srgrimes                  .forEach(r :: report);
8931541Srgrimes        }
8941541Srgrimes    }
8951541Srgrimes
8961549Srgrimes    void error(JCDiagnostic.Error error) {
89772356Sbmilekic        errors = true;
8981541Srgrimes        switch (errorMode) {
89972356Sbmilekic            case ILLEGAL_ARGUMENT: {
90072356Sbmilekic                String msg = log.localize(error);
90172356Sbmilekic                throw new PropagatedException(new IllegalArgumentException(msg));
9021541Srgrimes            }
9031541Srgrimes            case ILLEGAL_STATE: {
9041541Srgrimes                String msg = log.localize(error);
9051541Srgrimes                throw new PropagatedException(new IllegalStateException(msg));
9061541Srgrimes            }
9071541Srgrimes            case LOG:
9081541Srgrimes                report(error);
9091541Srgrimes        }
9101541Srgrimes    }
9111541Srgrimes
9121541Srgrimes    void error(String key, Object... args) {
9131541Srgrimes        errors = true;
9141541Srgrimes        switch (errorMode) {
9151541Srgrimes            case ILLEGAL_ARGUMENT: {
9161541Srgrimes                String msg = log.localize(PrefixKind.JAVAC, key, args);
9171541Srgrimes                throw new PropagatedException(new IllegalArgumentException(msg));
9181541Srgrimes            }
9191541Srgrimes            case ILLEGAL_STATE: {
9201541Srgrimes                String msg = log.localize(PrefixKind.JAVAC, key, args);
9211541Srgrimes                throw new PropagatedException(new IllegalStateException(msg));
9221541Srgrimes            }
9231541Srgrimes            case LOG:
9241541Srgrimes                report(key, args);
9251541Srgrimes        }
9261541Srgrimes    }
9271541Srgrimes
9281541Srgrimes    void error(Option.InvalidValueException f) {
9291541Srgrimes        String msg = f.getMessage();
9301541Srgrimes        errors = true;
9311541Srgrimes        switch (errorMode) {
9321541Srgrimes            case ILLEGAL_ARGUMENT: {
9331541Srgrimes                throw new PropagatedException(new IllegalArgumentException(msg, f.getCause()));
9341541Srgrimes            }
9351541Srgrimes            case ILLEGAL_STATE: {
9361541Srgrimes                throw new PropagatedException(new IllegalStateException(msg, f.getCause()));
9371541Srgrimes            }
9381541Srgrimes            case LOG:
9391541Srgrimes                log.printRawLines(ownName + ": " + msg);
9401541Srgrimes        }
9411541Srgrimes    }
9421541Srgrimes
9431541Srgrimes    void warning(String key, Object... args) {
9441541Srgrimes        report(key, args);
9451541Srgrimes    }
9461541Srgrimes
9471541Srgrimes    private void report(String key, Object... args) {
9481541Srgrimes        // Would be good to have support for -XDrawDiagnostics here
9491541Srgrimes        log.printRawLines(ownName + ": " + log.localize(PrefixKind.JAVAC, key, args));
9501541Srgrimes    }
9511541Srgrimes
9521541Srgrimes    private void report(JCDiagnostic.Error error) {
9531541Srgrimes        // Would be good to have support for -XDrawDiagnostics here
9541541Srgrimes        log.printRawLines(ownName + ": " + log.localize(error));
9551541Srgrimes    }
9561541Srgrimes
9571541Srgrimes    private JavaFileManager getFileManager() {
9581541Srgrimes        if (fileManager == null)
959142350Ssam            fileManager = context.get(JavaFileManager.class);
960142350Ssam        return fileManager;
961142350Ssam    }
962142350Ssam
9631541Srgrimes    <T> ListBuffer<T> toList(Iterable<? extends T> items) {
9641541Srgrimes        ListBuffer<T> list = new ListBuffer<>();
9651541Srgrimes        if (items != null) {
9661541Srgrimes            for (T item : items) {
9671541Srgrimes                list.add(item);
9681541Srgrimes            }
9691541Srgrimes        }
9701541Srgrimes        return list;
9711541Srgrimes    }
9721541Srgrimes
9731541Srgrimes    <T> Set<T> toSet(Iterable<? extends T> items) {
9741541Srgrimes        Set<T> set = new LinkedHashSet<>();
9751541Srgrimes        if (items != null) {
9761541Srgrimes            for (T item : items) {
9771541Srgrimes                set.add(item);
9781541Srgrimes            }
97972356Sbmilekic        }
9801541Srgrimes        return set;
98172356Sbmilekic    }
98272356Sbmilekic}
9831541Srgrimes