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