Arguments.java revision 2973:0e8fa3249327
156893Sfenner/*
256893Sfenner * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
356893Sfenner * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
456893Sfenner *
556893Sfenner * This code is free software; you can redistribute it and/or modify it
656893Sfenner * under the terms of the GNU General Public License version 2 only, as
756893Sfenner * published by the Free Software Foundation.  Oracle designates this
856893Sfenner * particular file as subject to the "Classpath" exception as provided
956893Sfenner * by Oracle in the LICENSE file that accompanied this code.
1056893Sfenner *
1156893Sfenner * This code is distributed in the hope that it will be useful, but WITHOUT
1256893Sfenner * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1356893Sfenner * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1456893Sfenner * version 2 for more details (a copy is included in the LICENSE file that
1556893Sfenner * accompanied this code).
1656893Sfenner *
1756893Sfenner * You should have received a copy of the GNU General Public License version
1856893Sfenner * 2 along with this work; if not, write to the Free Software Foundation,
1956893Sfenner * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2056893Sfenner *
2156893Sfenner * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2256893Sfenner * or visit www.oracle.com if you need additional information or have any
23127668Sbms * questions.
24214478Srpaulo */
2556893Sfennerpackage com.sun.tools.javac.main;
2656893Sfenner
2756893Sfennerimport java.io.File;
2856893Sfennerimport java.io.IOException;
2956893Sfennerimport java.nio.file.Path;
3056893Sfennerimport java.util.Collection;
3156893Sfennerimport java.util.Collections;
3256893Sfennerimport java.util.Iterator;
33127668Sbmsimport java.util.LinkedHashMap;
3456893Sfennerimport java.util.LinkedHashSet;
3556893Sfennerimport java.util.Map;
3698524Sfennerimport java.util.Optional;
3756893Sfennerimport java.util.ServiceLoader;
38147899Ssamimport java.util.Set;
39147899Ssamimport java.util.stream.Stream;
40147899Ssamimport java.util.stream.StreamSupport;
41147899Ssam
4275115Sfennerimport javax.tools.JavaFileManager;
4375115Sfennerimport javax.tools.JavaFileObject;
44127668Sbmsimport javax.tools.StandardJavaFileManager;
4556893Sfennerimport javax.tools.StandardLocation;
4675115Sfenner
4775115Sfennerimport com.sun.tools.doclint.DocLint;
4875115Sfennerimport com.sun.tools.javac.code.Lint.LintCategory;
4998524Sfennerimport com.sun.tools.javac.code.Source;
5098524Sfennerimport com.sun.tools.javac.file.BaseFileManager;
5198524Sfennerimport com.sun.tools.javac.file.JavacFileManager;
52127668Sbmsimport com.sun.tools.javac.jvm.Profile;
53127668Sbmsimport com.sun.tools.javac.jvm.Target;
54146773Ssamimport com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
55146773Ssamimport com.sun.tools.javac.platform.PlatformDescription;
56127668Sbmsimport com.sun.tools.javac.platform.PlatformProvider;
5775115Sfennerimport com.sun.tools.javac.platform.PlatformProvider.PlatformNotSupported;
58127668Sbmsimport com.sun.tools.javac.util.Context;
59127668Sbmsimport com.sun.tools.javac.util.List;
6056893Sfennerimport com.sun.tools.javac.util.ListBuffer;
6175115Sfennerimport com.sun.tools.javac.util.Log;
6275115Sfennerimport com.sun.tools.javac.util.Log.PrefixKind;
6375115Sfennerimport com.sun.tools.javac.util.Log.WriterKind;
6475115Sfennerimport com.sun.tools.javac.util.Options;
65214478Srpauloimport com.sun.tools.javac.util.PropagatedException;
66214478Srpaulo
67214478Srpaulo/**
68146773Ssam * Shared option and argument handling for command line and API usage of javac.
69146773Ssam */
70146773Ssampublic class Arguments {
71146773Ssam
72146773Ssam    /**
73146773Ssam     * The context key for the arguments.
74146773Ssam     */
75147899Ssam    protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
76147899Ssam
77147899Ssam    private String ownName;
78147899Ssam    private Set<String> classNames;
79146773Ssam    private Set<File> files;
80146773Ssam    private Map<Option, String> deferredFileManagerOptions;
81162017Ssam    private Set<JavaFileObject> fileObjects;
82146773Ssam    private final Options options;
83146773Ssam
84146773Ssam    private JavaFileManager fileManager;
85146773Ssam    private final Log log;
86147899Ssam    private final Context context;
87146773Ssam
88146773Ssam    private enum ErrorMode { ILLEGAL_ARGUMENT, ILLEGAL_STATE, LOG };
89146773Ssam    private ErrorMode errorMode;
90146773Ssam    private boolean errors;
91146773Ssam
92146773Ssam    /**
93146773Ssam     * Gets the Arguments instance for this context.
94146773Ssam     *
95146773Ssam     * @param context the content
96146773Ssam     * @return the Arguments instance for this context.
97214478Srpaulo     */
98146773Ssam    public static Arguments instance(Context context) {
99146773Ssam        Arguments instance = context.get(argsKey);
100146773Ssam        if (instance == null) {
101146773Ssam            instance = new Arguments(context);
102146773Ssam        }
103146773Ssam        return instance;
104146773Ssam    }
105146773Ssam
106146773Ssam    protected Arguments(Context context) {
107146773Ssam        context.put(argsKey, this);
108146773Ssam        options = Options.instance(context);
109146773Ssam        log = Log.instance(context);
110146773Ssam        this.context = context;
111146773Ssam
112146773Ssam        // Ideally, we could init this here and update/configure it as
113146773Ssam        // needed, but right now, initializing a file manager triggers
114146773Ssam        // initialization of other items in the context, such as Lint
115146773Ssam        // and FSInfo, which should not be initialized until after
116146773Ssam        // processArgs
117146773Ssam        //        fileManager = context.get(JavaFileManager.class);
118146773Ssam    }
119146773Ssam
120146773Ssam    private final OptionHelper cmdLineHelper = new OptionHelper() {
121146773Ssam        @Override
122146773Ssam        public String get(Option option) {
123146773Ssam            return options.get(option);
124146773Ssam        }
125146773Ssam
126146773Ssam        @Override
127146773Ssam        public void put(String name, String value) {
128146773Ssam            options.put(name, value);
129146773Ssam        }
130146773Ssam
131146773Ssam        @Override
132146773Ssam        public void remove(String name) {
133146773Ssam            options.remove(name);
134146773Ssam        }
135146773Ssam
136146773Ssam        @Override
137146773Ssam        public boolean handleFileManagerOption(Option option, String value) {
138214478Srpaulo            options.put(option.getText(), value);
139162017Ssam            deferredFileManagerOptions.put(option, value);
140146773Ssam            return true;
141146773Ssam        }
142146773Ssam
143146773Ssam        @Override
144146773Ssam        public Log getLog() {
145146773Ssam            return log;
146146773Ssam        }
147146773Ssam
148146773Ssam        @Override
149146773Ssam        public String getOwnName() {
150146773Ssam            return ownName;
151146773Ssam        }
152146773Ssam
153146773Ssam        @Override
154146773Ssam        public void error(String key, Object... args) {
155146773Ssam            Arguments.this.error(key, args);
15698524Sfenner        }
15798524Sfenner
15898524Sfenner        @Override
15998524Sfenner        public void addFile(File f) {
16098524Sfenner            files.add(f);
16198524Sfenner        }
16298524Sfenner
16398524Sfenner        @Override
16498524Sfenner        public void addClassName(String s) {
16598524Sfenner            classNames.add(s);
16698524Sfenner        }
16798524Sfenner
16898524Sfenner    };
16998524Sfenner
17098524Sfenner    /**
17198524Sfenner     * Initializes this Args instance with a set of command line args.
17298524Sfenner     * The args will be processed in conjunction with the full set of
17398524Sfenner     * command line options, including -help, -version etc.
17498524Sfenner     * The args may also contain class names and filenames.
17598524Sfenner     * Any errors during this call, and later during validate, will be reported
17698524Sfenner     * to the log.
17798524Sfenner     * @param ownName the name of this tool; used to prefix messages
17898524Sfenner     * @param args the args to be processed
17998524Sfenner     */
18098524Sfenner    public void init(String ownName, String... args) {
18198524Sfenner        this.ownName = ownName;
18298524Sfenner        errorMode = ErrorMode.LOG;
18398524Sfenner        files = new LinkedHashSet<>();
18498524Sfenner        deferredFileManagerOptions = new LinkedHashMap<>();
18598524Sfenner        fileObjects = null;
18698524Sfenner        classNames = new LinkedHashSet<>();
18798524Sfenner        processArgs(List.from(args), Option.getJavaCompilerOptions(), cmdLineHelper, true, false);
18898524Sfenner    }
18998524Sfenner
19098524Sfenner    private final OptionHelper apiHelper = new GrumpyHelper(null) {
19198524Sfenner        @Override
19298524Sfenner        public String get(Option option) {
19398524Sfenner            return options.get(option.getText());
19498524Sfenner        }
19598524Sfenner
19698524Sfenner        @Override
197127668Sbms        public void put(String name, String value) {
198127668Sbms            options.put(name, value);
199127668Sbms        }
200236192Sdelphij
201236192Sdelphij        @Override
202127668Sbms        public void remove(String name) {
203127668Sbms            options.remove(name);
204214478Srpaulo        }
205236192Sdelphij
206236192Sdelphij        @Override
207236192Sdelphij        public void error(String key, Object... args) {
208236192Sdelphij            Arguments.this.error(key, args);
209236192Sdelphij        }
210236192Sdelphij
211236192Sdelphij        @Override
212236192Sdelphij        public Log getLog() {
213236192Sdelphij            return Arguments.this.log;
214214478Srpaulo        }
215214478Srpaulo    };
216214478Srpaulo
217214478Srpaulo    /**
218214478Srpaulo     * Initializes this Args instance with the parameters for a JavacTask.
219214478Srpaulo     * The options will be processed in conjunction with the restricted set
220214478Srpaulo     * of tool options, which does not include -help, -version, etc,
221214478Srpaulo     * nor does it include classes and filenames, which should be specified
222214478Srpaulo     * separately.
223214478Srpaulo     * File manager options are handled directly by the file manager.
224214478Srpaulo     * Any errors found while processing individual args will be reported
225214478Srpaulo     * via IllegalArgumentException.
226214478Srpaulo     * Any subsequent errors during validate will be reported via IllegalStateException.
227214478Srpaulo     * @param ownName the name of this tool; used to prefix messages
228214478Srpaulo     * @param options the options to be processed
229214478Srpaulo     * @param classNames the classes to be subject to annotation processing
230214478Srpaulo     * @param files the files to be compiled
231214478Srpaulo     */
232214478Srpaulo    public void init(String ownName,
233214478Srpaulo            Iterable<String> options,
234214478Srpaulo            Iterable<String> classNames,
235214478Srpaulo            Iterable<? extends JavaFileObject> files) {
236214478Srpaulo        this.ownName = ownName;
237214478Srpaulo        this.classNames = toSet(classNames);
238214478Srpaulo        this.fileObjects = toSet(files);
239236192Sdelphij        this.files = null;
240236192Sdelphij        errorMode = ErrorMode.ILLEGAL_ARGUMENT;
241214478Srpaulo        if (options != null) {
242214478Srpaulo            processArgs(toList(options), Option.getJavacToolOptions(), apiHelper, false, true);
243214478Srpaulo        }
244236192Sdelphij        errorMode = ErrorMode.ILLEGAL_STATE;
245236192Sdelphij    }
246236192Sdelphij
247236192Sdelphij    /**
248236192Sdelphij     * Gets the files to be compiled.
249236192Sdelphij     * @return the files to be compiled
250236192Sdelphij     */
251236192Sdelphij    public Set<JavaFileObject> getFileObjects() {
252236192Sdelphij        if (fileObjects == null) {
253214478Srpaulo            if (files == null) {
254214478Srpaulo                fileObjects = Collections.emptySet();
255214478Srpaulo            } else {
256236192Sdelphij                fileObjects = new LinkedHashSet<>();
257236192Sdelphij                JavacFileManager jfm = (JavacFileManager) getFileManager();
258214478Srpaulo                for (JavaFileObject fo: jfm.getJavaFileObjectsFromFiles(files))
259214478Srpaulo                    fileObjects.add(fo);
260214478Srpaulo            }
261214478Srpaulo        }
262214478Srpaulo        return fileObjects;
263214478Srpaulo    }
264214478Srpaulo
265214478Srpaulo    /**
266214478Srpaulo     * Gets the classes to be subject to annotation processing.
267214478Srpaulo     * @return the classes to be subject to annotation processing
268214478Srpaulo     */
269214478Srpaulo    public Set<String> getClassNames() {
270214478Srpaulo        return classNames;
271214478Srpaulo    }
272214478Srpaulo
273214478Srpaulo    /**
274214478Srpaulo     * Processes strings containing options and operands.
275214478Srpaulo     * @param args the strings to be processed
276214478Srpaulo     * @param allowableOpts the set of option declarations that are applicable
277214478Srpaulo     * @param helper a help for use by Option.process
278214478Srpaulo     * @param allowOperands whether or not to check for files and classes
279214478Srpaulo     * @param checkFileManager whether or not to check if the file manager can handle
280236192Sdelphij     *      options which are not recognized by any of allowableOpts
281214478Srpaulo     * @return true if all the strings were successfully processed; false otherwise
282214478Srpaulo     * @throws IllegalArgumentException if a problem occurs and errorMode is set to
283214478Srpaulo     *      ILLEGAL_ARGUMENT
284236192Sdelphij     */
285236192Sdelphij    private boolean processArgs(Iterable<String> args,
286236192Sdelphij            Set<Option> allowableOpts, OptionHelper helper,
287236192Sdelphij            boolean allowOperands, boolean checkFileManager) {
288236192Sdelphij        if (!doProcessArgs(args, allowableOpts, helper, allowOperands, checkFileManager))
289214478Srpaulo            return false;
290236192Sdelphij
291214478Srpaulo        String platformString = options.get(Option.RELEASE);
292214478Srpaulo
293214478Srpaulo        checkOptionAllowed(platformString == null,
294214478Srpaulo                option -> error("err.release.bootclasspath.conflict", option.getText()),
295214478Srpaulo                Option.BOOTCLASSPATH, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
296214478Srpaulo                Option.XBOOTCLASSPATH_PREPEND, Option.ENDORSEDDIRS, Option.EXTDIRS, Option.SOURCE,
297214478Srpaulo                Option.TARGET);
298214478Srpaulo
299214478Srpaulo        if (platformString != null) {
300214478Srpaulo            PlatformDescription platformDescription = lookupDescription(platformString);
30156893Sfenner
302214478Srpaulo            if (platformDescription == null) {
303214478Srpaulo                error("err.unsupported.release.version", platformString);
30456893Sfenner                return false;
30575115Sfenner            }
30698524Sfenner
30798524Sfenner            options.put(Option.SOURCE, platformDescription.getSourceVersion());
30898524Sfenner            options.put(Option.TARGET, platformDescription.getTargetVersion());
30998524Sfenner
31098524Sfenner            context.put(PlatformDescription.class, platformDescription);
311127668Sbms
31256893Sfenner            if (!doProcessArgs(platformDescription.getAdditionalOptions(), allowableOpts, helper, allowOperands, checkFileManager))
31356893Sfenner                return false;
31456893Sfenner
31556893Sfenner            Collection<Path> platformCP = platformDescription.getPlatformPath();
31675115Sfenner
31756893Sfenner            if (platformCP != null) {
31856893Sfenner                JavaFileManager fm = getFileManager();
319127668Sbms
320127668Sbms                if (!(fm instanceof StandardJavaFileManager)) {
321127668Sbms                    error("err.release.not.standard.file.manager");
322236192Sdelphij                    return false;
323127668Sbms                }
324127668Sbms
325236192Sdelphij                try {
326127668Sbms                    StandardJavaFileManager sfm = (StandardJavaFileManager) fm;
327127668Sbms
328236192Sdelphij                    sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
329236192Sdelphij                } catch (IOException ex) {
330236192Sdelphij                    log.printLines(PrefixKind.JAVAC, "msg.io");
331127668Sbms                    ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
332127668Sbms                    return false;
333127668Sbms                }
334127668Sbms            }
335127668Sbms        }
336146773Ssam
337146773Ssam        options.notifyListeners();
338146773Ssam
339229244Sdim        return true;
340229244Sdim    }
341229244Sdim
342229244Sdim    private boolean doProcessArgs(Iterable<String> args,
343229244Sdim            Set<Option> allowableOpts, OptionHelper helper,
344229244Sdim            boolean allowOperands, boolean checkFileManager) {
345229244Sdim        JavaFileManager fm = checkFileManager ? getFileManager() : null;
346146773Ssam        Iterator<String> argIter = args.iterator();
347146773Ssam        while (argIter.hasNext()) {
34875115Sfenner            String arg = argIter.next();
34956893Sfenner            if (arg.isEmpty()) {
35056893Sfenner                error("err.invalid.flag", arg);
351146773Ssam                return false;
35256893Sfenner            }
353146773Ssam
354146773Ssam            Option option = null;
35556893Sfenner            if (arg.startsWith("-")) {
356146773Ssam                for (Option o : allowableOpts) {
357146773Ssam                    if (o.matches(arg)) {
358146773Ssam                        option = o;
35956893Sfenner                        break;
360146773Ssam                    }
36156893Sfenner                }
36256893Sfenner            } else if (allowOperands && Option.SOURCEFILE.matches(arg)) {
36356893Sfenner                option = Option.SOURCEFILE;
36456893Sfenner            }
36575115Sfenner
36675115Sfenner            if (option == null) {
36775115Sfenner                if (fm != null && fm.handleOption(arg, argIter)) {
36875115Sfenner                    continue;
369127668Sbms                }
37075115Sfenner                error("err.invalid.flag", arg);
37156893Sfenner                return false;
372146773Ssam            }
37356893Sfenner
37456893Sfenner            if (option.hasArg()) {
37556893Sfenner                if (!argIter.hasNext()) {
37656893Sfenner                    error("err.req.arg", arg);
377146773Ssam                    return false;
37856893Sfenner                }
37956893Sfenner                String operand = argIter.next();
38056893Sfenner                if (option.process(helper, arg, operand)) {
38156893Sfenner                    return false;
382146773Ssam                }
38356893Sfenner            } else {
38456893Sfenner                if (option.process(helper, arg)) {
38556893Sfenner                    return false;
38656893Sfenner                }
38756893Sfenner            }
38856893Sfenner        }
389146773Ssam
390146773Ssam        return true;
391146773Ssam    }
392146773Ssam
393146773Ssam    /**
39456893Sfenner     * Validates the overall consistency of the options and operands
39556893Sfenner     * processed by processOptions.
39656893Sfenner     * @return true if all args are successfully validating; false otherwise.
39756893Sfenner     * @throws IllegalStateException if a problem is found and errorMode is set to
398146773Ssam     *      ILLEGAL_STATE
39956893Sfenner     */
40056893Sfenner    public boolean validate() {
40156893Sfenner        if (isEmpty()) {
40256893Sfenner            // It is allowed to compile nothing if just asking for help or version info.
40356893Sfenner            // But also note that none of these options are supported in API mode.
404146773Ssam            if (options.isSet(Option.HELP)
40556893Sfenner                || options.isSet(Option.X)
40656893Sfenner                || options.isSet(Option.VERSION)
40756893Sfenner                || options.isSet(Option.FULLVERSION))
408146773Ssam                return true;
40956893Sfenner
41056893Sfenner            if (JavaCompiler.explicitAnnotationProcessingRequested(options)) {
411146773Ssam                error("err.no.source.files.classes");
41256893Sfenner            } else {
41356893Sfenner                error("err.no.source.files");
41456893Sfenner            }
41556893Sfenner            return false;
41656893Sfenner        }
41756893Sfenner
41856893Sfenner        if (!checkDirectory(Option.D)) {
419146773Ssam            return false;
42056893Sfenner        }
42156893Sfenner        if (!checkDirectory(Option.S)) {
422146773Ssam            return false;
42356893Sfenner        }
42456893Sfenner
425146773Ssam        String sourceString = options.get(Option.SOURCE);
42656893Sfenner        Source source = (sourceString != null)
42756893Sfenner                ? Source.lookup(sourceString)
428146773Ssam                : Source.DEFAULT;
42956893Sfenner        String targetString = options.get(Option.TARGET);
43056893Sfenner        Target target = (targetString != null)
43156893Sfenner                ? Target.lookup(targetString)
43256893Sfenner                : Target.DEFAULT;
43356893Sfenner
43456893Sfenner        // We don't check source/target consistency for CLDC, as J2ME
435127668Sbms        // profiles are not aligned with J2SE targets; moreover, a
436146773Ssam        // single CLDC target may have many profiles.  In addition,
43756893Sfenner        // this is needed for the continued functioning of the JSR14
43856893Sfenner        // prototype.
439146773Ssam        if (Character.isDigit(target.name.charAt(0))) {
440146773Ssam            if (target.compareTo(source.requiredTarget()) < 0) {
441146773Ssam                if (targetString != null) {
442146773Ssam                    if (sourceString == null) {
443146773Ssam                        error("warn.target.default.source.conflict",
444146773Ssam                                targetString,
445146773Ssam                                source.requiredTarget().name);
446146773Ssam                    } else {
44756893Sfenner                        error("warn.source.target.conflict",
44856893Sfenner                                sourceString,
44956893Sfenner                                source.requiredTarget().name);
45056893Sfenner                    }
45156893Sfenner                    return false;
45256893Sfenner                } else {
45356893Sfenner                    target = source.requiredTarget();
45456893Sfenner                    options.put("-target", target.name);
455146773Ssam                }
45656893Sfenner            }
45775115Sfenner        }
458127668Sbms
45956893Sfenner        String profileString = options.get(Option.PROFILE);
46056893Sfenner        if (profileString != null) {
46156893Sfenner            Profile profile = Profile.lookup(profileString);
462146773Ssam            if (!profile.isValid(target)) {
46356893Sfenner                error("warn.profile.target.conflict", profileString, target.name);
46456893Sfenner            }
46556893Sfenner
46656893Sfenner            // This check is only effective in command line mode,
46756893Sfenner            // where the file manager options are added to options
468146773Ssam            if (options.get(Option.BOOTCLASSPATH) != null) {
469146773Ssam                error("err.profile.bootclasspath.conflict");
470146773Ssam            }
471146773Ssam        }
472146773Ssam
473146773Ssam        boolean lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
474146773Ssam
475146773Ssam        if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) {
47698524Sfenner            JavaFileManager fm = getFileManager();
47775115Sfenner            if (fm instanceof BaseFileManager) {
478127668Sbms                if (((BaseFileManager) fm).isDefaultBootClassPath())
47956893Sfenner                    log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
48056893Sfenner            }
48156893Sfenner        }
48256893Sfenner
48356893Sfenner        boolean obsoleteOptionFound = false;
48456893Sfenner
48556893Sfenner        if (source.compareTo(Source.MIN) < 0) {
486146773Ssam            log.error("option.removed.source", source.name, Source.MIN.name);
48756893Sfenner        } else if (source == Source.MIN && lintOptions) {
48856893Sfenner            log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
48975115Sfenner            obsoleteOptionFound = true;
490127668Sbms        }
49156893Sfenner
49256893Sfenner        if (target.compareTo(Target.MIN) < 0) {
49356893Sfenner            log.error("option.removed.target", target.name, Target.MIN.name);
49456893Sfenner        } else if (target == Target.MIN && lintOptions) {
49556893Sfenner            log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
49656893Sfenner            obsoleteOptionFound = true;
49756893Sfenner        }
49856893Sfenner
49956893Sfenner        if (obsoleteOptionFound)
500146773Ssam            log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
50156893Sfenner
50275115Sfenner        return !errors;
503146773Ssam    }
504146773Ssam
505146773Ssam    private PlatformDescription lookupDescription(String platformString) {
506146773Ssam        int separator = platformString.indexOf(":");
50756893Sfenner        String platformProviderName =
50875115Sfenner                separator != (-1) ? platformString.substring(0, separator) : platformString;
509127668Sbms        String platformOptions =
51075115Sfenner                separator != (-1) ? platformString.substring(separator + 1) : "";
51156893Sfenner        Iterable<PlatformProvider> providers =
51256893Sfenner                ServiceLoader.load(PlatformProvider.class, Arguments.class.getClassLoader());
51356893Sfenner
51456893Sfenner        return StreamSupport.stream(providers.spliterator(), false)
51556893Sfenner                            .filter(provider -> StreamSupport.stream(provider.getSupportedPlatformNames()
51656893Sfenner                                                                             .spliterator(),
517146773Ssam                                                                     false)
518127668Sbms                                                             .anyMatch(platformProviderName::equals))
51975115Sfenner                            .findFirst()
52075115Sfenner                            .flatMap(provider -> {
52156893Sfenner                                try {
52256893Sfenner                                    return Optional.of(provider.getPlatform(platformProviderName, platformOptions));
52356893Sfenner                                } catch (PlatformNotSupported pns) {
524127668Sbms                                    return Optional.empty();
52556893Sfenner                                }
52656893Sfenner                            })
52775115Sfenner                            .orElse(null);
52875115Sfenner    }
52956893Sfenner
530127668Sbms    /**
53156893Sfenner     * Returns true if there are no files or classes specified for use.
53275115Sfenner     * @return true if there are no files or classes specified for use
53375115Sfenner     */
534127668Sbms    public boolean isEmpty() {
53556893Sfenner        return ((files == null) || files.isEmpty())
536146773Ssam                && ((fileObjects == null) || fileObjects.isEmpty())
537146773Ssam                && classNames.isEmpty();
538146773Ssam    }
539146773Ssam
540146773Ssam    /**
541146773Ssam     * Gets the file manager options which may have been deferred
542146773Ssam     * during processArgs.
543127668Sbms     * @return the deferred file manager options
544146773Ssam     */
545146773Ssam    public Map<Option, String> getDeferredFileManagerOptions() {
546146773Ssam        return deferredFileManagerOptions;
547127668Sbms    }
548127668Sbms
549127668Sbms    /**
550127668Sbms     * Gets any options specifying plugins to be run.
551127668Sbms     * @return options for plugins
552127668Sbms     */
553146773Ssam    public Set<List<String>> getPluginOpts() {
554127668Sbms        String plugins = options.get(Option.PLUGIN);
555127668Sbms        if (plugins == null)
556127668Sbms            return Collections.emptySet();
557127668Sbms
558127668Sbms        Set<List<String>> pluginOpts = new LinkedHashSet<>();
559127668Sbms        for (String plugin: plugins.split("\\x00")) {
560127668Sbms            pluginOpts.add(List.from(plugin.split("\\s+")));
561127668Sbms        }
562127668Sbms        return Collections.unmodifiableSet(pluginOpts);
563127668Sbms    }
564127668Sbms
565146773Ssam    /**
566127668Sbms     * Gets any options specifying how doclint should be run.
567127668Sbms     * An empty list is returned if no doclint options are specified
568127668Sbms     * or if the only doclint option is -Xdoclint:none.
569127668Sbms     * @return options for doclint
570127668Sbms     */
571127668Sbms    public List<String> getDocLintOpts() {
572127668Sbms        String xdoclint = options.get(Option.XDOCLINT);
573127668Sbms        String xdoclintCustom = options.get(Option.XDOCLINT_CUSTOM);
574127668Sbms        if (xdoclint == null && xdoclintCustom == null)
575127668Sbms            return List.nil();
576127668Sbms
577214478Srpaulo        Set<String> doclintOpts = new LinkedHashSet<>();
578214478Srpaulo        if (xdoclint != null)
579214478Srpaulo            doclintOpts.add(DocLint.XMSGS_OPTION);
58056893Sfenner        if (xdoclintCustom != null) {
581146773Ssam            for (String s: xdoclintCustom.split("\\s+")) {
582146773Ssam                if (s.isEmpty())
583146773Ssam                    continue;
584146773Ssam                doclintOpts.add(s.replace(Option.XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX));
585146773Ssam            }
586146773Ssam        }
587146773Ssam
58856893Sfenner        if (doclintOpts.equals(Collections.singleton(DocLint.XMSGS_CUSTOM_PREFIX + "none")))
58956893Sfenner            return List.nil();
59056893Sfenner
59156893Sfenner        String checkPackages = options.get(Option.XDOCLINT_PACKAGE);
59256893Sfenner
59375115Sfenner        if (checkPackages != null) {
594127668Sbms            for (String s : checkPackages.split("\\s+")) {
59575115Sfenner                doclintOpts.add(s.replace(Option.XDOCLINT_PACKAGE.text, DocLint.XCHECK_PACKAGE));
59698524Sfenner            }
59775115Sfenner        }
59875115Sfenner
59975115Sfenner        // standard doclet normally generates H1, H2,
60075115Sfenner        // so for now, allow user comments to assume that
60175115Sfenner        doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2");
602127668Sbms
603127668Sbms        return List.from(doclintOpts.toArray(new String[doclintOpts.size()]));
60475115Sfenner    }
60575115Sfenner
60675115Sfenner    private boolean checkDirectory(Option option) {
60775115Sfenner        String value = options.get(option);
608127668Sbms        if (value == null) {
60975115Sfenner            return true;
61075115Sfenner        }
61175115Sfenner        File file = new File(value);
61275115Sfenner        if (!file.exists()) {
61375115Sfenner            error("err.dir.not.found", value);
614147899Ssam            return false;
61575115Sfenner        }
61675115Sfenner        if (!file.isDirectory()) {
61775115Sfenner            error("err.file.not.directory", value);
61875115Sfenner            return false;
61975115Sfenner        }
62075115Sfenner        return true;
62175115Sfenner    }
62275115Sfenner
62375115Sfenner    private interface ErrorReporter {
62475115Sfenner        void report(Option o);
62575115Sfenner    }
62675115Sfenner
62775115Sfenner    void checkOptionAllowed(boolean allowed, ErrorReporter r, Option... opts) {
62875115Sfenner        if (!allowed) {
62975115Sfenner            Stream.of(opts)
63075115Sfenner                  .filter(options :: isSet)
63175115Sfenner                  .forEach(r :: report);
63275115Sfenner        }
633127668Sbms    }
63475115Sfenner
63575115Sfenner    void error(String key, Object... args) {
63675115Sfenner        errors = true;
63775115Sfenner        switch (errorMode) {
63875115Sfenner            case ILLEGAL_ARGUMENT: {
63975115Sfenner                String msg = log.localize(PrefixKind.JAVAC, key, args);
64075115Sfenner                throw new PropagatedException(new IllegalArgumentException(msg));
641127668Sbms            }
64275115Sfenner            case ILLEGAL_STATE: {
64375115Sfenner                String msg = log.localize(PrefixKind.JAVAC, key, args);
644127668Sbms                throw new PropagatedException(new IllegalStateException(msg));
64575115Sfenner            }
64675115Sfenner            case LOG:
64775115Sfenner                report(key, args);
64875115Sfenner                log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
64975115Sfenner        }
65075115Sfenner    }
65175115Sfenner
652127668Sbms    void warning(String key, Object... args) {
65375115Sfenner        report(key, args);
65475115Sfenner    }
65575115Sfenner
65675115Sfenner    private void report(String key, Object... args) {
65775115Sfenner        log.printRawLines(ownName + ": " + log.localize(PrefixKind.JAVAC, key, args));
65875115Sfenner    }
65975115Sfenner
66075115Sfenner    private JavaFileManager getFileManager() {
66175115Sfenner        if (fileManager == null)
66275115Sfenner            fileManager = context.get(JavaFileManager.class);
66375115Sfenner        return fileManager;
66475115Sfenner    }
66575115Sfenner
66675115Sfenner    <T> ListBuffer<T> toList(Iterable<? extends T> items) {
667127668Sbms        ListBuffer<T> list = new ListBuffer<>();
66898524Sfenner        if (items != null) {
66956893Sfenner            for (T item : items) {
67098524Sfenner                list.add(item);
67198524Sfenner            }
67298524Sfenner        }
67398524Sfenner        return list;
67498524Sfenner    }
675214478Srpaulo
67698524Sfenner    <T> Set<T> toSet(Iterable<? extends T> items) {
677127668Sbms        Set<T> set = new LinkedHashSet<>();
67898524Sfenner        if (items != null) {
67998524Sfenner            for (T item : items) {
68098524Sfenner                set.add(item);
68198524Sfenner            }
682214478Srpaulo        }
68356893Sfenner        return set;
68456893Sfenner    }
68556893Sfenner}
68698524Sfenner