8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.tools.javac.main;
26
27 import java.io.File;
28 import java.util.Collections;
29 import java.util.Iterator;
30 import java.util.LinkedHashMap;
31 import java.util.LinkedHashSet;
32 import java.util.Map;
33 import java.util.Set;
34
35 import javax.tools.JavaFileManager;
36 import javax.tools.JavaFileObject;
37
38 import com.sun.tools.doclint.DocLint;
39 import com.sun.tools.javac.code.Lint.LintCategory;
40 import com.sun.tools.javac.code.Source;
41 import com.sun.tools.javac.file.JavacFileManager;
42 import com.sun.tools.javac.jvm.Profile;
43 import com.sun.tools.javac.jvm.Target;
44 import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
45 import com.sun.tools.javac.file.BaseFileManager;
46 import com.sun.tools.javac.util.Context;
47 import com.sun.tools.javac.util.List;
48 import com.sun.tools.javac.util.ListBuffer;
49 import com.sun.tools.javac.util.Log;
50 import com.sun.tools.javac.util.Log.PrefixKind;
51 import com.sun.tools.javac.util.Options;
52 import com.sun.tools.javac.util.PropagatedException;
53
54 /**
55 * Shared option and argument handling for command line and API usage of javac.
56 */
57 public class Arguments {
58
59 /**
60 * The context key for the arguments.
61 */
62 protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
63
64 private String ownName;
65 private Set<String> classNames;
66 private Set<File> files;
67 private Map<Option, String> deferredFileManagerOptions;
68 private Set<JavaFileObject> fileObjects;
69 private final Options options;
70
255 */
256 public Set<String> getClassNames() {
257 return classNames;
258 }
259
260 /**
261 * Processes strings containing options and operands.
262 * @param args the strings to be processed
263 * @param allowableOpts the set of option declarations that are applicable
264 * @param helper a help for use by Option.process
265 * @param allowOperands whether or not to check for files and classes
266 * @param checkFileManager whether or not to check if the file manager can handle
267 * options which are not recognized by any of allowableOpts
268 * @return true if all the strings were successfully processed; false otherwise
269 * @throws IllegalArgumentException if a problem occurs and errorMode is set to
270 * ILLEGAL_ARGUMENT
271 */
272 private boolean processArgs(Iterable<String> args,
273 Set<Option> allowableOpts, OptionHelper helper,
274 boolean allowOperands, boolean checkFileManager) {
275 JavaFileManager fm = checkFileManager ? getFileManager() : null;
276 Iterator<String> argIter = args.iterator();
277 while (argIter.hasNext()) {
278 String arg = argIter.next();
279 if (arg.isEmpty()) {
280 error("err.invalid.flag", arg);
281 return false;
282 }
283
284 Option option = null;
285 if (arg.startsWith("-")) {
286 for (Option o : allowableOpts) {
287 if (o.matches(arg)) {
288 option = o;
289 break;
290 }
291 }
292 } else if (allowOperands && Option.SOURCEFILE.matches(arg)) {
293 option = Option.SOURCEFILE;
294 }
298 continue;
299 }
300 error("err.invalid.flag", arg);
301 return false;
302 }
303
304 if (option.hasArg()) {
305 if (!argIter.hasNext()) {
306 error("err.req.arg", arg);
307 return false;
308 }
309 String operand = argIter.next();
310 if (option.process(helper, arg, operand)) {
311 return false;
312 }
313 } else {
314 if (option.process(helper, arg)) {
315 return false;
316 }
317 }
318
319 }
320
321 options.notifyListeners();
322
323 return true;
324 }
325
326 /**
327 * Validates the overall consistency of the options and operands
328 * processed by processOptions.
329 * @return true if all args are successfully validating; false otherwise.
330 * @throws IllegalStateException if a problem is found and errorMode is set to
331 * ILLEGAL_STATE
332 */
333 public boolean validate() {
334 if (isEmpty()) {
335 // It is allowed to compile nothing if just asking for help or version info.
336 // But also note that none of these options are supported in API mode.
337 if (options.isSet(Option.HELP)
338 || options.isSet(Option.X)
339 || options.isSet(Option.VERSION)
340 || options.isSet(Option.FULLVERSION))
341 return true;
342
388 }
389 }
390 }
391
392 String profileString = options.get(Option.PROFILE);
393 if (profileString != null) {
394 Profile profile = Profile.lookup(profileString);
395 if (!profile.isValid(target)) {
396 error("warn.profile.target.conflict", profileString, target.name);
397 }
398
399 // This check is only effective in command line mode,
400 // where the file manager options are added to options
401 if (options.get(Option.BOOTCLASSPATH) != null) {
402 error("err.profile.bootclasspath.conflict");
403 }
404 }
405
406 boolean lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
407
408 if (lintOptions && source.compareTo(Source.DEFAULT) < 0) {
409 JavaFileManager fm = getFileManager();
410 if (fm instanceof BaseFileManager) {
411 if (((BaseFileManager) fm).isDefaultBootClassPath())
412 log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
413 }
414 }
415
416 boolean obsoleteOptionFound = false;
417
418 if (source.compareTo(Source.MIN) < 0) {
419 log.error("option.removed.source", source.name, Source.MIN.name);
420 } else if (source == Source.MIN && lintOptions) {
421 log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
422 obsoleteOptionFound = true;
423 }
424
425 if (target.compareTo(Target.MIN) < 0) {
426 log.error("option.removed.target", target.name, Target.MIN.name);
427 } else if (target == Target.MIN && lintOptions) {
428 log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
429 obsoleteOptionFound = true;
430 }
431
432 if (obsoleteOptionFound)
433 log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
434
435 return !errors;
436 }
437
438 /**
439 * Returns true if there are no files or classes specified for use.
440 * @return true if there are no files or classes specified for use
441 */
442 public boolean isEmpty() {
443 return ((files == null) || files.isEmpty())
444 && ((fileObjects == null) || fileObjects.isEmpty())
445 && classNames.isEmpty();
446 }
447
448 /**
449 * Gets the file manager options which may have been deferred
450 * during processArgs.
451 * @return the deferred file manager options
452 */
453 public Map<Option, String> getDeferredFileManagerOptions() {
454 return deferredFileManagerOptions;
455 }
456
457 /**
511 return List.from(doclintOpts.toArray(new String[doclintOpts.size()]));
512 }
513
514 private boolean checkDirectory(Option option) {
515 String value = options.get(option);
516 if (value == null) {
517 return true;
518 }
519 File file = new File(value);
520 if (!file.exists()) {
521 error("err.dir.not.found", value);
522 return false;
523 }
524 if (!file.isDirectory()) {
525 error("err.file.not.directory", value);
526 return false;
527 }
528 return true;
529 }
530
531 void error(String key, Object... args) {
532 errors = true;
533 switch (errorMode) {
534 case ILLEGAL_ARGUMENT: {
535 String msg = log.localize(PrefixKind.JAVAC, key, args);
536 throw new PropagatedException(new IllegalArgumentException(msg));
537 }
538 case ILLEGAL_STATE: {
539 String msg = log.localize(PrefixKind.JAVAC, key, args);
540 throw new PropagatedException(new IllegalStateException(msg));
541 }
542 case LOG:
543 report(key, args);
544 log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
545 }
546 }
547
548 void warning(String key, Object... args) {
549 report(key, args);
550 }
|
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package com.sun.tools.javac.main;
26
27 import java.io.File;
28 import java.io.IOException;
29 import java.nio.file.Path;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.Iterator;
33 import java.util.LinkedHashMap;
34 import java.util.LinkedHashSet;
35 import java.util.Map;
36 import java.util.Optional;
37 import java.util.ServiceLoader;
38 import java.util.Set;
39 import java.util.stream.Stream;
40 import java.util.stream.StreamSupport;
41
42 import javax.tools.JavaFileManager;
43 import javax.tools.JavaFileObject;
44 import javax.tools.StandardJavaFileManager;
45 import javax.tools.StandardLocation;
46
47 import com.sun.tools.doclint.DocLint;
48 import com.sun.tools.javac.code.Lint.LintCategory;
49 import com.sun.tools.javac.code.Source;
50 import com.sun.tools.javac.file.BaseFileManager;
51 import com.sun.tools.javac.file.JavacFileManager;
52 import com.sun.tools.javac.jvm.Profile;
53 import com.sun.tools.javac.jvm.Target;
54 import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
55 import com.sun.tools.javac.platform.PlatformDescription;
56 import com.sun.tools.javac.platform.PlatformProvider;
57 import com.sun.tools.javac.platform.PlatformProvider.PlatformNotSupported;
58 import com.sun.tools.javac.util.Context;
59 import com.sun.tools.javac.util.List;
60 import com.sun.tools.javac.util.ListBuffer;
61 import com.sun.tools.javac.util.Log;
62 import com.sun.tools.javac.util.Log.PrefixKind;
63 import com.sun.tools.javac.util.Log.WriterKind;
64 import com.sun.tools.javac.util.Options;
65 import com.sun.tools.javac.util.PropagatedException;
66
67 /**
68 * Shared option and argument handling for command line and API usage of javac.
69 */
70 public class Arguments {
71
72 /**
73 * The context key for the arguments.
74 */
75 protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
76
77 private String ownName;
78 private Set<String> classNames;
79 private Set<File> files;
80 private Map<Option, String> deferredFileManagerOptions;
81 private Set<JavaFileObject> fileObjects;
82 private final Options options;
83
268 */
269 public Set<String> getClassNames() {
270 return classNames;
271 }
272
273 /**
274 * Processes strings containing options and operands.
275 * @param args the strings to be processed
276 * @param allowableOpts the set of option declarations that are applicable
277 * @param helper a help for use by Option.process
278 * @param allowOperands whether or not to check for files and classes
279 * @param checkFileManager whether or not to check if the file manager can handle
280 * options which are not recognized by any of allowableOpts
281 * @return true if all the strings were successfully processed; false otherwise
282 * @throws IllegalArgumentException if a problem occurs and errorMode is set to
283 * ILLEGAL_ARGUMENT
284 */
285 private boolean processArgs(Iterable<String> args,
286 Set<Option> allowableOpts, OptionHelper helper,
287 boolean allowOperands, boolean checkFileManager) {
288 if (!doProcessArgs(args, allowableOpts, helper, allowOperands, checkFileManager))
289 return false;
290
291 String platformString = options.get(Option.RELEASE);
292
293 checkOptionAllowed(platformString == null,
294 option -> error("err.release.bootclasspath.conflict", option.getText()),
295 Option.BOOTCLASSPATH, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
296 Option.XBOOTCLASSPATH_PREPEND, Option.ENDORSEDDIRS, Option.EXTDIRS, Option.SOURCE,
297 Option.TARGET);
298
299 if (platformString != null) {
300 PlatformDescription platformDescription = lookupDescription(platformString);
301
302 if (platformDescription == null) {
303 error("err.unsupported.release.version", platformString);
304 return false;
305 }
306
307 options.put(Option.SOURCE, platformDescription.getSourceVersion());
308 options.put(Option.TARGET, platformDescription.getTargetVersion());
309
310 context.put(PlatformDescription.class, platformDescription);
311
312 if (!doProcessArgs(platformDescription.getAdditionalOptions(), allowableOpts, helper, allowOperands, checkFileManager))
313 return false;
314
315 Collection<Path> platformCP = platformDescription.getPlatformPath();
316
317 if (platformCP != null) {
318 JavaFileManager fm = getFileManager();
319
320 if (!(fm instanceof StandardJavaFileManager)) {
321 error("err.release.not.standard.file.manager");
322 return false;
323 }
324
325 try {
326 StandardJavaFileManager sfm = (StandardJavaFileManager) fm;
327
328 sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
329 } catch (IOException ex) {
330 log.printLines(PrefixKind.JAVAC, "msg.io");
331 ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
332 return false;
333 }
334 }
335 }
336
337 options.notifyListeners();
338
339 return true;
340 }
341
342 private boolean doProcessArgs(Iterable<String> args,
343 Set<Option> allowableOpts, OptionHelper helper,
344 boolean allowOperands, boolean checkFileManager) {
345 JavaFileManager fm = checkFileManager ? getFileManager() : null;
346 Iterator<String> argIter = args.iterator();
347 while (argIter.hasNext()) {
348 String arg = argIter.next();
349 if (arg.isEmpty()) {
350 error("err.invalid.flag", arg);
351 return false;
352 }
353
354 Option option = null;
355 if (arg.startsWith("-")) {
356 for (Option o : allowableOpts) {
357 if (o.matches(arg)) {
358 option = o;
359 break;
360 }
361 }
362 } else if (allowOperands && Option.SOURCEFILE.matches(arg)) {
363 option = Option.SOURCEFILE;
364 }
368 continue;
369 }
370 error("err.invalid.flag", arg);
371 return false;
372 }
373
374 if (option.hasArg()) {
375 if (!argIter.hasNext()) {
376 error("err.req.arg", arg);
377 return false;
378 }
379 String operand = argIter.next();
380 if (option.process(helper, arg, operand)) {
381 return false;
382 }
383 } else {
384 if (option.process(helper, arg)) {
385 return false;
386 }
387 }
388 }
389
390 return true;
391 }
392
393 /**
394 * Validates the overall consistency of the options and operands
395 * processed by processOptions.
396 * @return true if all args are successfully validating; false otherwise.
397 * @throws IllegalStateException if a problem is found and errorMode is set to
398 * ILLEGAL_STATE
399 */
400 public boolean validate() {
401 if (isEmpty()) {
402 // It is allowed to compile nothing if just asking for help or version info.
403 // But also note that none of these options are supported in API mode.
404 if (options.isSet(Option.HELP)
405 || options.isSet(Option.X)
406 || options.isSet(Option.VERSION)
407 || options.isSet(Option.FULLVERSION))
408 return true;
409
455 }
456 }
457 }
458
459 String profileString = options.get(Option.PROFILE);
460 if (profileString != null) {
461 Profile profile = Profile.lookup(profileString);
462 if (!profile.isValid(target)) {
463 error("warn.profile.target.conflict", profileString, target.name);
464 }
465
466 // This check is only effective in command line mode,
467 // where the file manager options are added to options
468 if (options.get(Option.BOOTCLASSPATH) != null) {
469 error("err.profile.bootclasspath.conflict");
470 }
471 }
472
473 boolean lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
474
475 if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) {
476 JavaFileManager fm = getFileManager();
477 if (fm instanceof BaseFileManager) {
478 if (((BaseFileManager) fm).isDefaultBootClassPath())
479 log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
480 }
481 }
482
483 boolean obsoleteOptionFound = false;
484
485 if (source.compareTo(Source.MIN) < 0) {
486 log.error("option.removed.source", source.name, Source.MIN.name);
487 } else if (source == Source.MIN && lintOptions) {
488 log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
489 obsoleteOptionFound = true;
490 }
491
492 if (target.compareTo(Target.MIN) < 0) {
493 log.error("option.removed.target", target.name, Target.MIN.name);
494 } else if (target == Target.MIN && lintOptions) {
495 log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
496 obsoleteOptionFound = true;
497 }
498
499 if (obsoleteOptionFound)
500 log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
501
502 return !errors;
503 }
504
505 private PlatformDescription lookupDescription(String platformString) {
506 int separator = platformString.indexOf(":");
507 String platformProviderName =
508 separator != (-1) ? platformString.substring(0, separator) : platformString;
509 String platformOptions =
510 separator != (-1) ? platformString.substring(separator + 1) : "";
511 Iterable<PlatformProvider> providers =
512 ServiceLoader.load(PlatformProvider.class, Arguments.class.getClassLoader());
513
514 return StreamSupport.stream(providers.spliterator(), false)
515 .filter(provider -> StreamSupport.stream(provider.getSupportedPlatformNames()
516 .spliterator(),
517 false)
518 .anyMatch(platformProviderName::equals))
519 .findFirst()
520 .flatMap(provider -> {
521 try {
522 return Optional.of(provider.getPlatform(platformProviderName, platformOptions));
523 } catch (PlatformNotSupported pns) {
524 return Optional.empty();
525 }
526 })
527 .orElse(null);
528 }
529
530 /**
531 * Returns true if there are no files or classes specified for use.
532 * @return true if there are no files or classes specified for use
533 */
534 public boolean isEmpty() {
535 return ((files == null) || files.isEmpty())
536 && ((fileObjects == null) || fileObjects.isEmpty())
537 && classNames.isEmpty();
538 }
539
540 /**
541 * Gets the file manager options which may have been deferred
542 * during processArgs.
543 * @return the deferred file manager options
544 */
545 public Map<Option, String> getDeferredFileManagerOptions() {
546 return deferredFileManagerOptions;
547 }
548
549 /**
603 return List.from(doclintOpts.toArray(new String[doclintOpts.size()]));
604 }
605
606 private boolean checkDirectory(Option option) {
607 String value = options.get(option);
608 if (value == null) {
609 return true;
610 }
611 File file = new File(value);
612 if (!file.exists()) {
613 error("err.dir.not.found", value);
614 return false;
615 }
616 if (!file.isDirectory()) {
617 error("err.file.not.directory", value);
618 return false;
619 }
620 return true;
621 }
622
623 private interface ErrorReporter {
624 void report(Option o);
625 }
626
627 void checkOptionAllowed(boolean allowed, ErrorReporter r, Option... opts) {
628 if (!allowed) {
629 Stream.of(opts)
630 .filter(options :: isSet)
631 .forEach(r :: report);
632 }
633 }
634
635 void error(String key, Object... args) {
636 errors = true;
637 switch (errorMode) {
638 case ILLEGAL_ARGUMENT: {
639 String msg = log.localize(PrefixKind.JAVAC, key, args);
640 throw new PropagatedException(new IllegalArgumentException(msg));
641 }
642 case ILLEGAL_STATE: {
643 String msg = log.localize(PrefixKind.JAVAC, key, args);
644 throw new PropagatedException(new IllegalStateException(msg));
645 }
646 case LOG:
647 report(key, args);
648 log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
649 }
650 }
651
652 void warning(String key, Object... args) {
653 report(key, args);
654 }
|