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.ServiceLoader;
37 import java.util.Set;
38 import java.util.stream.Stream;
39 import java.util.stream.StreamSupport;
40
41 import javax.tools.JavaFileManager;
42 import javax.tools.JavaFileObject;
43 import javax.tools.StandardJavaFileManager;
44 import javax.tools.StandardLocation;
45
46 import com.sun.tools.doclint.DocLint;
47 import com.sun.tools.javac.code.Lint.LintCategory;
48 import com.sun.tools.javac.code.Source;
49 import com.sun.tools.javac.file.BaseFileManager;
50 import com.sun.tools.javac.file.JavacFileManager;
51 import com.sun.tools.javac.jvm.Profile;
52 import com.sun.tools.javac.jvm.Target;
53 import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
54 import com.sun.tools.javac.platform.PlatformProvider;
55 import com.sun.tools.javac.platform.PlatformProviderFactory;
56 import com.sun.tools.javac.util.Context;
57 import com.sun.tools.javac.util.List;
58 import com.sun.tools.javac.util.ListBuffer;
59 import com.sun.tools.javac.util.Log;
60 import com.sun.tools.javac.util.Log.PrefixKind;
61 import com.sun.tools.javac.util.Log.WriterKind;
62 import com.sun.tools.javac.util.Options;
63 import com.sun.tools.javac.util.PropagatedException;
64
65 /**
66 * Shared option and argument handling for command line and API usage of javac.
67 */
68 public class Arguments {
69
70 /**
71 * The context key for the arguments.
72 */
73 protected static final Context.Key<Arguments> argsKey = new Context.Key<>();
74
75 private String ownName;
76 private Set<String> classNames;
77 private Set<File> files;
78 private Map<Option, String> deferredFileManagerOptions;
79 private Set<JavaFileObject> fileObjects;
80 private final Options options;
81
266 */
267 public Set<String> getClassNames() {
268 return classNames;
269 }
270
271 /**
272 * Processes strings containing options and operands.
273 * @param args the strings to be processed
274 * @param allowableOpts the set of option declarations that are applicable
275 * @param helper a help for use by Option.process
276 * @param allowOperands whether or not to check for files and classes
277 * @param checkFileManager whether or not to check if the file manager can handle
278 * options which are not recognized by any of allowableOpts
279 * @return true if all the strings were successfully processed; false otherwise
280 * @throws IllegalArgumentException if a problem occurs and errorMode is set to
281 * ILLEGAL_ARGUMENT
282 */
283 private boolean processArgs(Iterable<String> args,
284 Set<Option> allowableOpts, OptionHelper helper,
285 boolean allowOperands, boolean checkFileManager) {
286 if (!doProcessArgs(args, allowableOpts, helper, allowOperands, checkFileManager))
287 return false;
288
289 String platformString = options.get(Option.PLATFORM);
290
291 checkOptionAllowed(platformString == null,
292 option -> error("err.platform.bootclasspath.conflict", option.getText()),
293 Option.BOOTCLASSPATH, Option.XBOOTCLASSPATH, Option.XBOOTCLASSPATH_APPEND,
294 Option.XBOOTCLASSPATH_PREPEND, Option.ENDORSEDDIRS, Option.EXTDIRS, Option.SOURCE,
295 Option.TARGET);
296
297 if (platformString != null) {
298 PlatformProvider platformProvider = lookupPlatformProvider(platformString);
299
300 if (platformProvider == null) {
301 error("err.unsupported.platform.version", platformString);
302 return false;
303 }
304
305 options.put(Option.SOURCE, platformProvider.getSourceVersion());
306 options.put(Option.TARGET, platformProvider.getTargetVersion());
307
308 context.put(PlatformProvider.class, platformProvider);
309
310 if (!doProcessArgs(platformProvider.getAdditionalOptions(), allowableOpts, helper, allowOperands, checkFileManager))
311 return false;
312
313 Collection<Path> platformCP = platformProvider.getPlatformPath();
314
315 if (platformCP != null) {
316 JavaFileManager fm = getFileManager();
317
318 if (!(fm instanceof StandardJavaFileManager)) {
319 error("err.platform.not.standard.file.manager");
320 return false;
321 }
322
323 try {
324 StandardJavaFileManager sfm = (StandardJavaFileManager) fm;
325
326 sfm.setLocationFromPaths(StandardLocation.PLATFORM_CLASS_PATH, platformCP);
327 } catch (IOException ex) {
328 log.printLines(PrefixKind.JAVAC, "msg.io");
329 ex.printStackTrace(log.getWriter(WriterKind.NOTICE));
330 return false;
331 }
332 }
333 }
334
335 options.notifyListeners();
336
337 return true;
338 }
339
340 private boolean doProcessArgs(Iterable<String> args,
341 Set<Option> allowableOpts, OptionHelper helper,
342 boolean allowOperands, boolean checkFileManager) {
343 JavaFileManager fm = checkFileManager ? getFileManager() : null;
344 Iterator<String> argIter = args.iterator();
345 while (argIter.hasNext()) {
346 String arg = argIter.next();
347 if (arg.isEmpty()) {
348 error("err.invalid.flag", arg);
349 return false;
350 }
351
352 Option option = null;
353 if (arg.startsWith("-")) {
354 for (Option o : allowableOpts) {
355 if (o.matches(arg)) {
356 option = o;
357 break;
358 }
359 }
360 } else if (allowOperands && Option.SOURCEFILE.matches(arg)) {
361 option = Option.SOURCEFILE;
362 }
366 continue;
367 }
368 error("err.invalid.flag", arg);
369 return false;
370 }
371
372 if (option.hasArg()) {
373 if (!argIter.hasNext()) {
374 error("err.req.arg", arg);
375 return false;
376 }
377 String operand = argIter.next();
378 if (option.process(helper, arg, operand)) {
379 return false;
380 }
381 } else {
382 if (option.process(helper, arg)) {
383 return false;
384 }
385 }
386 }
387
388 return true;
389 }
390
391 /**
392 * Validates the overall consistency of the options and operands
393 * processed by processOptions.
394 * @return true if all args are successfully validating; false otherwise.
395 * @throws IllegalStateException if a problem is found and errorMode is set to
396 * ILLEGAL_STATE
397 */
398 public boolean validate() {
399 if (isEmpty()) {
400 // It is allowed to compile nothing if just asking for help or version info.
401 // But also note that none of these options are supported in API mode.
402 if (options.isSet(Option.HELP)
403 || options.isSet(Option.X)
404 || options.isSet(Option.VERSION)
405 || options.isSet(Option.FULLVERSION))
406 return true;
407
453 }
454 }
455 }
456
457 String profileString = options.get(Option.PROFILE);
458 if (profileString != null) {
459 Profile profile = Profile.lookup(profileString);
460 if (!profile.isValid(target)) {
461 error("warn.profile.target.conflict", profileString, target.name);
462 }
463
464 // This check is only effective in command line mode,
465 // where the file manager options are added to options
466 if (options.get(Option.BOOTCLASSPATH) != null) {
467 error("err.profile.bootclasspath.conflict");
468 }
469 }
470
471 boolean lintOptions = options.isUnset(Option.XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option);
472
473 if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.PLATFORM)) {
474 JavaFileManager fm = getFileManager();
475 if (fm instanceof BaseFileManager) {
476 if (((BaseFileManager) fm).isDefaultBootClassPath())
477 log.warning(LintCategory.OPTIONS, "source.no.bootclasspath", source.name);
478 }
479 }
480
481 boolean obsoleteOptionFound = false;
482
483 if (source.compareTo(Source.MIN) < 0) {
484 log.error("option.removed.source", source.name, Source.MIN.name);
485 } else if (source == Source.MIN && lintOptions) {
486 log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name);
487 obsoleteOptionFound = true;
488 }
489
490 if (target.compareTo(Target.MIN) < 0) {
491 log.error("option.removed.target", target.name, Target.MIN.name);
492 } else if (target == Target.MIN && lintOptions) {
493 log.warning(LintCategory.OPTIONS, "option.obsolete.target", target.name);
494 obsoleteOptionFound = true;
495 }
496
497 if (obsoleteOptionFound)
498 log.warning(LintCategory.OPTIONS, "option.obsolete.suppression");
499
500 return !errors;
501 }
502
503 private PlatformProvider lookupPlatformProvider(String platform) {
504 Iterable<PlatformProviderFactory> factories =
505 ServiceLoader.load(PlatformProviderFactory.class, Arguments.class.getClassLoader());
506 return StreamSupport.stream(factories.spliterator(), false)
507 .flatMap(factory -> StreamSupport.stream(factory.createPlatformProviders()
508 .spliterator(),
509 false))
510 .filter(provider -> platform.equals(provider.getName()))
511 .findFirst()
512 .orElse(null);
513 }
514
515 /**
516 * Returns true if there are no files or classes specified for use.
517 * @return true if there are no files or classes specified for use
518 */
519 public boolean isEmpty() {
520 return ((files == null) || files.isEmpty())
521 && ((fileObjects == null) || fileObjects.isEmpty())
522 && classNames.isEmpty();
523 }
524
525 /**
526 * Gets the file manager options which may have been deferred
527 * during processArgs.
528 * @return the deferred file manager options
529 */
530 public Map<Option, String> getDeferredFileManagerOptions() {
531 return deferredFileManagerOptions;
532 }
533
534 /**
588 return List.from(doclintOpts.toArray(new String[doclintOpts.size()]));
589 }
590
591 private boolean checkDirectory(Option option) {
592 String value = options.get(option);
593 if (value == null) {
594 return true;
595 }
596 File file = new File(value);
597 if (!file.exists()) {
598 error("err.dir.not.found", value);
599 return false;
600 }
601 if (!file.isDirectory()) {
602 error("err.file.not.directory", value);
603 return false;
604 }
605 return true;
606 }
607
608 private interface ErrorReporter {
609 void report(Option o);
610 }
611
612 void checkOptionAllowed(boolean allowed, ErrorReporter r, Option... opts) {
613 if (!allowed) {
614 Stream.of(opts)
615 .filter(options :: isSet)
616 .forEach(r :: report);
617 }
618 }
619
620 void error(String key, Object... args) {
621 errors = true;
622 switch (errorMode) {
623 case ILLEGAL_ARGUMENT: {
624 String msg = log.localize(PrefixKind.JAVAC, key, args);
625 throw new PropagatedException(new IllegalArgumentException(msg));
626 }
627 case ILLEGAL_STATE: {
628 String msg = log.localize(PrefixKind.JAVAC, key, args);
629 throw new PropagatedException(new IllegalStateException(msg));
630 }
631 case LOG:
632 report(key, args);
633 log.printLines(PrefixKind.JAVAC, "msg.usage", ownName);
634 }
635 }
636
637 void warning(String key, Object... args) {
638 report(key, args);
639 }
|