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
26 package com.sun.tools.javac.main;
27
28 import java.io.FileWriter;
29 import java.io.PrintWriter;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.text.Collator;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.EnumSet;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.LinkedHashMap;
41 import java.util.LinkedHashSet;
42 import java.util.Locale;
43 import java.util.Map;
44 import java.util.ServiceLoader;
45 import java.util.Set;
46 import java.util.TreeSet;
47 import java.util.regex.Matcher;
48 import java.util.regex.Pattern;
49 import java.util.stream.Collectors;
50 import java.util.stream.StreamSupport;
51
52 import javax.lang.model.SourceVersion;
53
54 import com.sun.tools.doclint.DocLint;
55 import com.sun.tools.javac.code.Lint;
56 import com.sun.tools.javac.code.Lint.LintCategory;
57 import com.sun.tools.javac.code.Source;
58 import com.sun.tools.javac.code.Type;
59 import com.sun.tools.javac.jvm.Profile;
60 import com.sun.tools.javac.jvm.Target;
61 import com.sun.tools.javac.platform.PlatformProvider;
62 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
63 import com.sun.tools.javac.resources.CompilerProperties.Errors;
64 import com.sun.tools.javac.util.Assert;
65 import com.sun.tools.javac.util.JDK9Wrappers;
66 import com.sun.tools.javac.util.Log;
67 import com.sun.tools.javac.util.Log.PrefixKind;
68 import com.sun.tools.javac.util.Log.WriterKind;
69 import com.sun.tools.javac.util.Options;
70 import com.sun.tools.javac.util.StringUtils;
71
72 import static com.sun.tools.javac.main.Option.ChoiceKind.*;
73 import static com.sun.tools.javac.main.Option.OptionGroup.*;
74 import static com.sun.tools.javac.main.Option.OptionKind.*;
75
76 /**
77 * Options for javac.
78 * The specific Option to handle a command-line option can be found by calling
79 * {@link #lookup}, which search some or all of the members of this enum in order,
80 * looking for the first {@link #matches match}.
81 * The action for an Option is performed {@link #handleOption}, which determines
82 * whether an argument is needed and where to find it;
83 * {@code handleOption} then calls {@link #process process} providing a suitable
617 },
618
619 LIMIT_MODULES("--limit-modules", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC) {
620 @Override
621 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException {
622 if (arg.isEmpty()) {
623 throw helper.newInvalidValueException("err.no.value.for.option", option);
624 } else if (getPattern().matcher(arg).matches()) {
625 helper.put(LIMIT_MODULES.primaryName, arg); // last one wins
626 } else {
627 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg);
628 }
629 }
630
631 @Override
632 public Pattern getPattern() {
633 return Pattern.compile(",*[^,].*");
634 }
635 },
636
637 // This option exists only for the purpose of documenting itself.
638 // It's actually implemented by the CommandLine class.
639 AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, ArgKind.ADJACENT) {
640 @Override
641 public void process(OptionHelper helper, String option) {
642 throw new AssertionError("the @ flag should be caught by CommandLine.");
643 }
644 },
645
646 // Standalone positional argument: source file or type name.
647 SOURCEFILE("sourcefile", null, HIDDEN, INFO) {
648 @Override
649 public boolean matches(String s) {
650 if (s.endsWith(".java")) // Java source file
651 return true;
652 int sep = s.indexOf('/');
653 if (sep != -1) {
654 return SourceVersion.isName(s.substring(0, sep))
655 && SourceVersion.isName(s.substring(sep + 1));
656 } else {
664 if (!Files.exists(p)) {
665 throw helper.newInvalidValueException("err.file.not.found", p);
666 }
667 if (!Files.isRegularFile(p)) {
668 throw helper.newInvalidValueException("err.file.not.file", p);
669 }
670 helper.addFile(p);
671 } else {
672 helper.addClassName(option);
673 }
674 }
675 },
676
677 MULTIRELEASE("--multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER),
678
679 INHERIT_RUNTIME_ENVIRONMENT("--inherit-runtime-environment", "opt.inherit_runtime_environment",
680 EXTENDED, BASIC) {
681 @Override
682 public void process(OptionHelper helper, String option) throws InvalidValueException {
683 try {
684 Class.forName(JDK9Wrappers.VMHelper.VM_CLASSNAME);
685 String[] runtimeArgs = JDK9Wrappers.VMHelper.getRuntimeArguments();
686 for (String arg : runtimeArgs) {
687 // Handle any supported runtime options; ignore all others.
688 // The runtime arguments always use the single token form, e.g. "--name=value".
689 for (Option o : getSupportedRuntimeOptions()) {
690 if (o.matches(arg)) {
691 switch (o) {
692 case ADD_MODULES:
693 int eq = arg.indexOf('=');
694 Assert.check(eq > 0, () -> ("invalid runtime option:" + arg));
695 // --add-modules=ALL-DEFAULT is not supported at compile-time
696 // so remove it from list, and only process the rest
697 // if the set is non-empty.
698 // Note that --add-modules=ALL-DEFAULT is automatically added
699 // by the standard javac launcher.
700 String mods = Arrays.stream(arg.substring(eq + 1).split(","))
701 .filter(s -> !s.isEmpty() && !s.equals("ALL-DEFAULT"))
702 .collect(Collectors.joining(","));
703 if (!mods.isEmpty()) {
704 String updatedArg = arg.substring(0, eq + 1) + mods;
1018 else {
1019 for (String a: arg.split(",+")) {
1020 if (!choices.contains(a))
1021 return false;
1022 }
1023 }
1024 }
1025
1026 return true;
1027 }
1028
1029 /**
1030 * Handles an option.
1031 * If an argument for the option is required, depending on spec of the option, it will be found
1032 * as part of the current arg (following ':' or '=') or in the following argument.
1033 * This is the recommended way to handle an option directly, instead of calling the underlying
1034 * {@link #process process} methods.
1035 * @param helper a helper to provide access to the environment
1036 * @param arg the arg string that identified this option
1037 * @param rest the remaining strings to be analysed
1038 * @return true if the operation was successful, and false otherwise
1039 * @implNote The return value is the opposite of that used by {@link #process}.
1040 */
1041 public void handleOption(OptionHelper helper, String arg, Iterator<String> rest) throws InvalidValueException {
1042 if (hasArg()) {
1043 String option;
1044 String operand;
1045 int sep = findSeparator(arg);
1046 if (getArgKind() == Option.ArgKind.ADJACENT) {
1047 option = primaryName; // aliases not supported
1048 operand = arg.substring(primaryName.length());
1049 } else if (sep > 0) {
1050 option = arg.substring(0, sep);
1051 operand = arg.substring(sep + 1);
1052 } else {
1053 if (!rest.hasNext()) {
1054 throw helper.newInvalidValueException("err.req.arg", arg);
1055 }
1056 option = arg;
1057 operand = rest.next();
1058 }
1067 * or which contains an argument within it, following a separator.
1068 * @param helper a helper to provide access to the environment
1069 * @param option the option to be processed
1070 * @throws InvalidValueException if an error occurred
1071 */
1072 public void process(OptionHelper helper, String option) throws InvalidValueException {
1073 if (argKind == ArgKind.NONE) {
1074 process(helper, primaryName, option);
1075 } else {
1076 int sep = findSeparator(option);
1077 process(helper, primaryName, option.substring(sep + 1));
1078 }
1079 }
1080
1081 /**
1082 * Processes an option by updating the environment via a helper object.
1083 * @param helper a helper to provide access to the environment
1084 * @param option the option to be processed
1085 * @param arg the value to associate with the option, or a default value
1086 * to be used if the option does not otherwise take an argument.
1087 */
1088 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException {
1089 if (choices != null) {
1090 if (choiceKind == ChoiceKind.ONEOF) {
1091 // some clients like to see just one of option+choice set
1092 for (String s : choices)
1093 helper.remove(primaryName + s);
1094 String opt = primaryName + arg;
1095 helper.put(opt, opt);
1096 // some clients like to see option (without trailing ":")
1097 // set to arg
1098 String nm = primaryName.substring(0, primaryName.length() - 1);
1099 helper.put(nm, arg);
1100 } else {
1101 // set option+word for each word in arg
1102 for (String a: arg.split(",+")) {
1103 String opt = primaryName + a;
1104 helper.put(opt, opt);
1105 }
1106 }
|
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
26 package com.sun.tools.javac.main;
27
28 import java.io.FileWriter;
29 import java.io.PrintWriter;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.text.Collator;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.EnumSet;
38 import java.util.Iterator;
39 import java.util.LinkedHashSet;
40 import java.util.Locale;
41 import java.util.ServiceLoader;
42 import java.util.Set;
43 import java.util.TreeSet;
44 import java.util.regex.Pattern;
45 import java.util.stream.Collectors;
46 import java.util.stream.StreamSupport;
47
48 import javax.lang.model.SourceVersion;
49
50 import com.sun.tools.doclint.DocLint;
51 import com.sun.tools.javac.code.Lint;
52 import com.sun.tools.javac.code.Lint.LintCategory;
53 import com.sun.tools.javac.code.Source;
54 import com.sun.tools.javac.code.Type;
55 import com.sun.tools.javac.jvm.Profile;
56 import com.sun.tools.javac.jvm.Target;
57 import com.sun.tools.javac.platform.PlatformProvider;
58 import com.sun.tools.javac.processing.JavacProcessingEnvironment;
59 import com.sun.tools.javac.util.Assert;
60 import com.sun.tools.javac.util.JDK9Wrappers;
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.StringUtils;
66
67 import static com.sun.tools.javac.main.Option.ChoiceKind.*;
68 import static com.sun.tools.javac.main.Option.OptionGroup.*;
69 import static com.sun.tools.javac.main.Option.OptionKind.*;
70
71 /**
72 * Options for javac.
73 * The specific Option to handle a command-line option can be found by calling
74 * {@link #lookup}, which search some or all of the members of this enum in order,
75 * looking for the first {@link #matches match}.
76 * The action for an Option is performed {@link #handleOption}, which determines
77 * whether an argument is needed and where to find it;
78 * {@code handleOption} then calls {@link #process process} providing a suitable
612 },
613
614 LIMIT_MODULES("--limit-modules", "opt.arg.limitmods", "opt.limitmods", STANDARD, BASIC) {
615 @Override
616 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException {
617 if (arg.isEmpty()) {
618 throw helper.newInvalidValueException("err.no.value.for.option", option);
619 } else if (getPattern().matcher(arg).matches()) {
620 helper.put(LIMIT_MODULES.primaryName, arg); // last one wins
621 } else {
622 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg);
623 }
624 }
625
626 @Override
627 public Pattern getPattern() {
628 return Pattern.compile(",*[^,].*");
629 }
630 },
631
632 MODULE_VERSION("--module-version", "opt.arg.module.version", "opt.module.version", STANDARD, BASIC) {
633 @Override
634 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException {
635 if (arg.isEmpty()) {
636 throw helper.newInvalidValueException("err.no.value.for.option", option);
637 } else {
638 try {
639 Class.forName(JDK9Wrappers.ModuleDescriptor.Version.CLASSNAME);
640 // use official parser if available
641 try {
642 JDK9Wrappers.ModuleDescriptor.Version.parse(arg);
643 } catch (IllegalArgumentException e) {
644 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg);
645 }
646 } catch (ClassNotFoundException ex) {
647 // fall-back to simplistic rules when running on older platform
648 if (!(arg.charAt(0) >= '0' && arg.charAt(0) <= '9') ||
649 arg.endsWith("-") ||
650 arg.endsWith("+")) {
651 throw helper.newInvalidValueException("err.bad.value.for.option", option, arg);
652 }
653 }
654 }
655 super.process(helper, option, arg);
656 }
657 },
658
659 // This option exists only for the purpose of documenting itself.
660 // It's actually implemented by the CommandLine class.
661 AT("@", "opt.arg.file", "opt.AT", STANDARD, INFO, ArgKind.ADJACENT) {
662 @Override
663 public void process(OptionHelper helper, String option) {
664 throw new AssertionError("the @ flag should be caught by CommandLine.");
665 }
666 },
667
668 // Standalone positional argument: source file or type name.
669 SOURCEFILE("sourcefile", null, HIDDEN, INFO) {
670 @Override
671 public boolean matches(String s) {
672 if (s.endsWith(".java")) // Java source file
673 return true;
674 int sep = s.indexOf('/');
675 if (sep != -1) {
676 return SourceVersion.isName(s.substring(0, sep))
677 && SourceVersion.isName(s.substring(sep + 1));
678 } else {
686 if (!Files.exists(p)) {
687 throw helper.newInvalidValueException("err.file.not.found", p);
688 }
689 if (!Files.isRegularFile(p)) {
690 throw helper.newInvalidValueException("err.file.not.file", p);
691 }
692 helper.addFile(p);
693 } else {
694 helper.addClassName(option);
695 }
696 }
697 },
698
699 MULTIRELEASE("--multi-release", "opt.arg.multi-release", "opt.multi-release", HIDDEN, FILEMANAGER),
700
701 INHERIT_RUNTIME_ENVIRONMENT("--inherit-runtime-environment", "opt.inherit_runtime_environment",
702 EXTENDED, BASIC) {
703 @Override
704 public void process(OptionHelper helper, String option) throws InvalidValueException {
705 try {
706 Class.forName(JDK9Wrappers.VMHelper.CLASSNAME);
707 String[] runtimeArgs = JDK9Wrappers.VMHelper.getRuntimeArguments();
708 for (String arg : runtimeArgs) {
709 // Handle any supported runtime options; ignore all others.
710 // The runtime arguments always use the single token form, e.g. "--name=value".
711 for (Option o : getSupportedRuntimeOptions()) {
712 if (o.matches(arg)) {
713 switch (o) {
714 case ADD_MODULES:
715 int eq = arg.indexOf('=');
716 Assert.check(eq > 0, () -> ("invalid runtime option:" + arg));
717 // --add-modules=ALL-DEFAULT is not supported at compile-time
718 // so remove it from list, and only process the rest
719 // if the set is non-empty.
720 // Note that --add-modules=ALL-DEFAULT is automatically added
721 // by the standard javac launcher.
722 String mods = Arrays.stream(arg.substring(eq + 1).split(","))
723 .filter(s -> !s.isEmpty() && !s.equals("ALL-DEFAULT"))
724 .collect(Collectors.joining(","));
725 if (!mods.isEmpty()) {
726 String updatedArg = arg.substring(0, eq + 1) + mods;
1040 else {
1041 for (String a: arg.split(",+")) {
1042 if (!choices.contains(a))
1043 return false;
1044 }
1045 }
1046 }
1047
1048 return true;
1049 }
1050
1051 /**
1052 * Handles an option.
1053 * If an argument for the option is required, depending on spec of the option, it will be found
1054 * as part of the current arg (following ':' or '=') or in the following argument.
1055 * This is the recommended way to handle an option directly, instead of calling the underlying
1056 * {@link #process process} methods.
1057 * @param helper a helper to provide access to the environment
1058 * @param arg the arg string that identified this option
1059 * @param rest the remaining strings to be analysed
1060 * @throws InvalidValueException if the value of the option was invalid
1061 * @implNote The return value is the opposite of that used by {@link #process}.
1062 */
1063 public void handleOption(OptionHelper helper, String arg, Iterator<String> rest) throws InvalidValueException {
1064 if (hasArg()) {
1065 String option;
1066 String operand;
1067 int sep = findSeparator(arg);
1068 if (getArgKind() == Option.ArgKind.ADJACENT) {
1069 option = primaryName; // aliases not supported
1070 operand = arg.substring(primaryName.length());
1071 } else if (sep > 0) {
1072 option = arg.substring(0, sep);
1073 operand = arg.substring(sep + 1);
1074 } else {
1075 if (!rest.hasNext()) {
1076 throw helper.newInvalidValueException("err.req.arg", arg);
1077 }
1078 option = arg;
1079 operand = rest.next();
1080 }
1089 * or which contains an argument within it, following a separator.
1090 * @param helper a helper to provide access to the environment
1091 * @param option the option to be processed
1092 * @throws InvalidValueException if an error occurred
1093 */
1094 public void process(OptionHelper helper, String option) throws InvalidValueException {
1095 if (argKind == ArgKind.NONE) {
1096 process(helper, primaryName, option);
1097 } else {
1098 int sep = findSeparator(option);
1099 process(helper, primaryName, option.substring(sep + 1));
1100 }
1101 }
1102
1103 /**
1104 * Processes an option by updating the environment via a helper object.
1105 * @param helper a helper to provide access to the environment
1106 * @param option the option to be processed
1107 * @param arg the value to associate with the option, or a default value
1108 * to be used if the option does not otherwise take an argument.
1109 * @throws InvalidValueException if an error occurred
1110 */
1111 public void process(OptionHelper helper, String option, String arg) throws InvalidValueException {
1112 if (choices != null) {
1113 if (choiceKind == ChoiceKind.ONEOF) {
1114 // some clients like to see just one of option+choice set
1115 for (String s : choices)
1116 helper.remove(primaryName + s);
1117 String opt = primaryName + arg;
1118 helper.put(opt, opt);
1119 // some clients like to see option (without trailing ":")
1120 // set to arg
1121 String nm = primaryName.substring(0, primaryName.length() - 1);
1122 helper.put(nm, arg);
1123 } else {
1124 // set option+word for each word in arg
1125 for (String a: arg.split(",+")) {
1126 String opt = primaryName + a;
1127 helper.put(opt, opt);
1128 }
1129 }
|