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