summaryrefslogtreecommitdiff
path: root/java/com/google/devtools/common/options
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/google/devtools/common/options')
-rw-r--r--java/com/google/devtools/common/options/Converters.java129
-rw-r--r--java/com/google/devtools/common/options/InvocationPolicyEnforcer.java33
-rw-r--r--java/com/google/devtools/common/options/Option.java18
-rw-r--r--java/com/google/devtools/common/options/OptionDefinition.java7
-rw-r--r--java/com/google/devtools/common/options/OptionFilterDescriptions.java3
-rw-r--r--java/com/google/devtools/common/options/OptionInstanceOrigin.java12
-rw-r--r--java/com/google/devtools/common/options/OptionMetadataTag.java12
-rw-r--r--java/com/google/devtools/common/options/OptionPriority.java77
-rw-r--r--java/com/google/devtools/common/options/OptionValueDescription.java70
-rw-r--r--java/com/google/devtools/common/options/OptionsBase.java3
-rw-r--r--java/com/google/devtools/common/options/OptionsParser.java28
-rw-r--r--java/com/google/devtools/common/options/OptionsParserImpl.java116
-rw-r--r--java/com/google/devtools/common/options/OptionsProvider.java12
-rw-r--r--java/com/google/devtools/common/options/ParsedOptionDescription.java53
-rw-r--r--java/com/google/devtools/common/options/processor/OptionProcessor.java46
15 files changed, 316 insertions, 303 deletions
diff --git a/java/com/google/devtools/common/options/Converters.java b/java/com/google/devtools/common/options/Converters.java
index 35f2da4..fb3bbfa 100644
--- a/java/com/google/devtools/common/options/Converters.java
+++ b/java/com/google/devtools/common/options/Converters.java
@@ -26,10 +26,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
-/**
- * Some convenient converters used by blaze. Note: These are specific to
- * blaze.
- */
+/** Some convenient converters used by blaze. Note: These are specific to blaze. */
public final class Converters {
/** Standard converter for booleans. Accepts common shorthands/synonyms. */
@@ -180,9 +177,7 @@ public final class Converters {
}
}
- /**
- * Standard converter for the {@link java.time.Duration} type.
- */
+ /** Standard converter for the {@link java.time.Duration} type. */
public static class DurationConverter implements Converter<Duration> {
private final Pattern durationRegex = Pattern.compile("^([0-9]+)(d|h|m|s|ms)$");
@@ -198,7 +193,7 @@ public final class Converters {
}
long duration = Long.parseLong(m.group(1));
String unit = m.group(2);
- switch(unit) {
+ switch (unit) {
case "d":
return Duration.ofDays(duration);
case "h":
@@ -210,8 +205,8 @@ public final class Converters {
case "ms":
return Duration.ofMillis(duration);
default:
- throw new IllegalStateException("This must not happen. Did you update the regex without "
- + "the switch case?");
+ throw new IllegalStateException(
+ "This must not happen. Did you update the regex without the switch case?");
}
}
@@ -240,14 +235,8 @@ public final class Converters {
.build();
/**
- * Join a list of words as in English. Examples:
- * "nothing"
- * "one"
- * "one or two"
- * "one and two"
- * "one, two or three".
- * "one, two and three".
- * The toString method of each element is used.
+ * Join a list of words as in English. Examples: "nothing" "one" "one or two" "one and two" "one,
+ * two or three". "one, two and three". The toString method of each element is used.
*/
static String joinEnglishList(Iterable<?> choices) {
StringBuilder buf = new StringBuilder();
@@ -261,14 +250,12 @@ public final class Converters {
return buf.length() == 0 ? "nothing" : buf.toString();
}
- public static class SeparatedOptionListConverter
- implements Converter<List<String>> {
+ public static class SeparatedOptionListConverter implements Converter<List<String>> {
private final String separatorDescription;
private final Splitter splitter;
- protected SeparatedOptionListConverter(char separator,
- String separatorDescription) {
+ protected SeparatedOptionListConverter(char separator, String separatorDescription) {
this.separatorDescription = separatorDescription;
this.splitter = Splitter.on(separator);
}
@@ -284,8 +271,7 @@ public final class Converters {
}
}
- public static class CommaSeparatedOptionListConverter
- extends SeparatedOptionListConverter {
+ public static class CommaSeparatedOptionListConverter extends SeparatedOptionListConverter {
public CommaSeparatedOptionListConverter() {
super(',', "comma");
}
@@ -299,10 +285,10 @@ public final class Converters {
public static class LogLevelConverter implements Converter<Level> {
- public static final Level[] LEVELS = new Level[] {
- Level.OFF, Level.SEVERE, Level.WARNING, Level.INFO, Level.FINE,
- Level.FINER, Level.FINEST
- };
+ public static final Level[] LEVELS =
+ new Level[] {
+ Level.OFF, Level.SEVERE, Level.WARNING, Level.INFO, Level.FINE, Level.FINER, Level.FINEST
+ };
@Override
public Level convert(String input) throws OptionsParsingException {
@@ -318,12 +304,9 @@ public final class Converters {
public String getTypeDescription() {
return "0 <= an integer <= " + (LEVELS.length - 1);
}
-
}
- /**
- * Checks whether a string is part of a set of strings.
- */
+ /** Checks whether a string is part of a set of strings. */
public static class StringSetConverter implements Converter<String> {
// TODO(bazel-team): if this class never actually contains duplicates, we could s/List/Set/
@@ -349,9 +332,7 @@ public final class Converters {
}
}
- /**
- * Checks whether a string is a valid regex pattern and compiles it.
- */
+ /** Checks whether a string is a valid regex pattern and compiles it. */
public static class RegexPatternConverter implements Converter<Pattern> {
@Override
@@ -369,9 +350,7 @@ public final class Converters {
}
}
- /**
- * Limits the length of a string argument.
- */
+ /** Limits the length of a string argument. */
public static class LengthLimitingConverter implements Converter<String> {
private final int maxSize;
@@ -393,9 +372,7 @@ public final class Converters {
}
}
- /**
- * Checks whether an integer is in the given range.
- */
+ /** Checks whether an integer is in the given range. */
public static class RangeConverter implements Converter<Integer> {
final int minValue;
final int maxValue;
@@ -432,25 +409,27 @@ public final class Converters {
return "an integer, >= " + minValue;
} else {
return "an integer in "
- + (minValue < 0 ? "(" + minValue + ")" : minValue) + "-" + maxValue + " range";
+ + (minValue < 0 ? "(" + minValue + ")" : minValue)
+ + "-"
+ + maxValue
+ + " range";
}
}
}
/**
- * A converter for variable assignments from the parameter list of a blaze
- * command invocation. Assignments are expected to have the form "name=value",
- * where names and values are defined to be as permissive as possible.
+ * A converter for variable assignments from the parameter list of a blaze command invocation.
+ * Assignments are expected to have the form "name=value", where names and values are defined to
+ * be as permissive as possible.
*/
public static class AssignmentConverter implements Converter<Map.Entry<String, String>> {
@Override
- public Map.Entry<String, String> convert(String input)
- throws OptionsParsingException {
+ public Map.Entry<String, String> convert(String input) throws OptionsParsingException {
int pos = input.indexOf("=");
if (pos <= 0) {
- throw new OptionsParsingException("Variable definitions must be in the form of a "
- + "'name=value' assignment");
+ throw new OptionsParsingException(
+ "Variable definitions must be in the form of a 'name=value' assignment");
}
String name = input.substring(0, pos);
String value = input.substring(pos + 1);
@@ -461,24 +440,22 @@ public final class Converters {
public String getTypeDescription() {
return "a 'name=value' assignment";
}
-
}
/**
- * A converter for variable assignments from the parameter list of a blaze
- * command invocation. Assignments are expected to have the form "name[=value]",
- * where names and values are defined to be as permissive as possible and value
- * part can be optional (in which case it is considered to be null).
+ * A converter for variable assignments from the parameter list of a blaze command invocation.
+ * Assignments are expected to have the form "name[=value]", where names and values are defined to
+ * be as permissive as possible and value part can be optional (in which case it is considered to
+ * be null).
*/
public static class OptionalAssignmentConverter implements Converter<Map.Entry<String, String>> {
@Override
- public Map.Entry<String, String> convert(String input)
- throws OptionsParsingException {
- int pos = input.indexOf("=");
+ public Map.Entry<String, String> convert(String input) throws OptionsParsingException {
+ int pos = input.indexOf('=');
if (pos == 0 || input.length() == 0) {
- throw new OptionsParsingException("Variable definitions must be in the form of a "
- + "'name=value' or 'name' assignment");
+ throw new OptionsParsingException(
+ "Variable definitions must be in the form of a 'name=value' or 'name' assignment");
} else if (pos < 0) {
return Maps.immutableEntry(input, null);
}
@@ -491,7 +468,40 @@ public final class Converters {
public String getTypeDescription() {
return "a 'name=value' assignment with an optional value part";
}
+ }
+
+ /**
+ * A converter for named integers of the form "[name=]value". When no name is specified, an empty
+ * string is used for the key.
+ */
+ public static class NamedIntegersConverter implements Converter<Map.Entry<String, Integer>> {
+ @Override
+ public Map.Entry<String, Integer> convert(String input) throws OptionsParsingException {
+ int pos = input.indexOf('=');
+ if (pos == 0 || input.length() == 0) {
+ throw new OptionsParsingException(
+ "Specify either 'value' or 'name=value', where 'value' is an integer");
+ } else if (pos < 0) {
+ try {
+ return Maps.immutableEntry("", Integer.parseInt(input));
+ } catch (NumberFormatException e) {
+ throw new OptionsParsingException("'" + input + "' is not an int");
+ }
+ }
+ String name = input.substring(0, pos);
+ String value = input.substring(pos + 1);
+ try {
+ return Maps.immutableEntry(name, Integer.parseInt(value));
+ } catch (NumberFormatException e) {
+ throw new OptionsParsingException("'" + value + "' is not an int");
+ }
+ }
+
+ @Override
+ public String getTypeDescription() {
+ return "an integer or a named integer, 'name=value'";
+ }
}
public static class HelpVerbosityConverter extends EnumConverter<OptionsParser.HelpVerbosity> {
@@ -508,5 +518,4 @@ public final class Converters {
super(0, 100);
}
}
-
}
diff --git a/java/com/google/devtools/common/options/InvocationPolicyEnforcer.java b/java/com/google/devtools/common/options/InvocationPolicyEnforcer.java
index a53ff5b..3b42a29 100644
--- a/java/com/google/devtools/common/options/InvocationPolicyEnforcer.java
+++ b/java/com/google/devtools/common/options/InvocationPolicyEnforcer.java
@@ -248,6 +248,15 @@ public final class InvocationPolicyEnforcer {
OptionPriority nextPriority =
OptionPriority.lowestOptionPriorityAtCategory(PriorityCategory.INVOCATION_POLICY);
for (FlagPolicy policy : invocationPolicy.getFlagPoliciesList()) {
+ // Explicitly disallow --config in invocation policy.
+ if (policy.getFlagName().equals("config")) {
+ throw new OptionsParsingException(
+ "Invocation policy is applied after --config expansion, changing config values now "
+ + "would have no effect and is disallowed to prevent confusion. Please remove the "
+ + "following policy : "
+ + policy);
+ }
+
// These policies are high-level, before expansion, and so are not the implicitDependents or
// expansions of any other flag, other than in an obtuse sense from --invocation_policy.
OptionPriority currentPriority = nextPriority;
@@ -306,9 +315,7 @@ public final class InvocationPolicyEnforcer {
* <p>None of the flagPolicies returned should be on expansion flags.
*/
private static List<FlagPolicyWithContext> expandPolicy(
- FlagPolicyWithContext originalPolicy,
- OptionsParser parser,
- Level loglevel)
+ FlagPolicyWithContext originalPolicy, OptionsParser parser, Level loglevel)
throws OptionsParsingException {
List<FlagPolicyWithContext> expandedPolicies = new ArrayList<>();
@@ -701,11 +708,15 @@ public final class InvocationPolicyEnforcer {
}
// Check that if the default value of the flag is disallowed by the policy, that the policy
- // does not also set use_default. Otherwise the default value would will still be set if the
+ // does not also set use_default. Otherwise the default value would still be set if the
// user uses a disallowed value. This doesn't apply to repeatable flags since the default
- // value for repeatable flags is always the empty list.
- if (!optionDescription.getOptionDefinition().allowsMultiple()) {
-
+ // value for repeatable flags is always the empty list. It also doesn't apply to flags that
+ // are null by default, since these flags' default value is not parsed by the converter, so
+ // there is no guarantee that there exists an accepted user-input value that would also set
+ // the value to NULL. In these cases, we assume that "unset" is a distinct value that is
+ // always allowed.
+ if (!optionDescription.getOptionDefinition().allowsMultiple()
+ && !optionDescription.getOptionDefinition().isSpecialNullDefault()) {
boolean defaultValueAllowed =
isFlagValueAllowed(
convertedPolicyValues, optionDescription.getOptionDefinition().getDefaultValue());
@@ -749,8 +760,12 @@ public final class InvocationPolicyEnforcer {
throws OptionsParsingException {
OptionDefinition optionDefinition = optionDescription.getOptionDefinition();
- if (!isFlagValueAllowed(
- convertedPolicyValues, optionDescription.getOptionDefinition().getDefaultValue())) {
+ if (optionDefinition.isSpecialNullDefault()) {
+ // Do nothing, the unset value by definition cannot be set. In option filtering operations,
+ // the value is being filtered, but the value that is `no value` passes any filter.
+ // Otherwise, there is no way to "usedefault" on one of these options that has no value by
+ // default.
+ } else if (!isFlagValueAllowed(convertedPolicyValues, optionDefinition.getDefaultValue())) {
if (newValue != null) {
// Use the default value from the policy, since the original default is not allowed
logger.log(
diff --git a/java/com/google/devtools/common/options/Option.java b/java/com/google/devtools/common/options/Option.java
index 45f320a..f26a136 100644
--- a/java/com/google/devtools/common/options/Option.java
+++ b/java/com/google/devtools/common/options/Option.java
@@ -186,22 +186,4 @@ public @interface Option {
* that the old name is deprecated and the new name should be used.
*/
String oldName() default "";
-
- /**
- * Indicates that this option is a wrapper for other options, and will be unwrapped when parsed.
- * For example, if foo is a wrapper option, then "--foo=--bar=baz" will be parsed as the flag
- * "--bar=baz" (rather than --foo taking the value "--bar=baz"). A wrapper option should have the
- * type {@link Void} (if it is something other than Void, the parser will not assign a value to
- * it). The {@link Option#implicitRequirements()}, {@link Option#expansion()}, {@link
- * Option#converter()} attributes will not be processed. Wrapper options are implicitly repeatable
- * (i.e., as though {@link Option#allowMultiple()} is true regardless of its value in the
- * annotation).
- *
- * <p>Wrapper options are provided only for transitioning flags which appear as values to other
- * flags, to top-level flags. Wrapper options should not be used in Invocation Policy, as
- * expansion flags to other flags, or as implicit requirements to other flags. Use the inner flags
- * instead.
- */
- @Deprecated
- boolean wrapperOption() default false;
}
diff --git a/java/com/google/devtools/common/options/OptionDefinition.java b/java/com/google/devtools/common/options/OptionDefinition.java
index 84a9d2d..e89234b 100644
--- a/java/com/google/devtools/common/options/OptionDefinition.java
+++ b/java/com/google/devtools/common/options/OptionDefinition.java
@@ -137,7 +137,7 @@ public class OptionDefinition implements Comparable<OptionDefinition> {
}
/** {@link Option#expansionFunction()} ()} */
- Class<? extends ExpansionFunction> getExpansionFunction() {
+ public Class<? extends ExpansionFunction> getExpansionFunction() {
return optionAnnotation.expansionFunction();
}
@@ -156,11 +156,6 @@ public class OptionDefinition implements Comparable<OptionDefinition> {
return optionAnnotation.oldName();
}
- /** {@link Option#wrapperOption()} ()} ()} */
- public boolean isWrapperOption() {
- return optionAnnotation.wrapperOption();
- }
-
/** Returns whether an option --foo has a negative equivalent --nofoo. */
public boolean hasNegativeOption() {
return getType().equals(boolean.class) || getType().equals(TriState.class);
diff --git a/java/com/google/devtools/common/options/OptionFilterDescriptions.java b/java/com/google/devtools/common/options/OptionFilterDescriptions.java
index 2a7999d..4b4373a 100644
--- a/java/com/google/devtools/common/options/OptionFilterDescriptions.java
+++ b/java/com/google/devtools/common/options/OptionFilterDescriptions.java
@@ -170,6 +170,9 @@ public class OptionFilterDescriptions {
"This option is deprecated. It might be that the feature it affects is deprecated, "
+ "or that another method of supplying the information is preferred.")
.put(
+ OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES,
+ "This option is triggered by the expansion option --all_incompatible_changes.")
+ .put(
OptionMetadataTag.HIDDEN, // Here for completeness, these options are UNDOCUMENTED.
"This option should not be used by a user, and should not be logged.")
.put(
diff --git a/java/com/google/devtools/common/options/OptionInstanceOrigin.java b/java/com/google/devtools/common/options/OptionInstanceOrigin.java
index 584e75b..b0782f8 100644
--- a/java/com/google/devtools/common/options/OptionInstanceOrigin.java
+++ b/java/com/google/devtools/common/options/OptionInstanceOrigin.java
@@ -22,14 +22,14 @@ import javax.annotation.Nullable;
public class OptionInstanceOrigin {
private final OptionPriority priority;
@Nullable private final String source;
- @Nullable private final OptionDefinition implicitDependent;
- @Nullable private final OptionDefinition expandedFrom;
+ @Nullable private final ParsedOptionDescription implicitDependent;
+ @Nullable private final ParsedOptionDescription expandedFrom;
public OptionInstanceOrigin(
OptionPriority priority,
String source,
- OptionDefinition implicitDependent,
- OptionDefinition expandedFrom) {
+ ParsedOptionDescription implicitDependent,
+ ParsedOptionDescription expandedFrom) {
this.priority = priority;
this.source = source;
this.implicitDependent = implicitDependent;
@@ -46,12 +46,12 @@ public class OptionInstanceOrigin {
}
@Nullable
- public OptionDefinition getImplicitDependent() {
+ public ParsedOptionDescription getImplicitDependent() {
return implicitDependent;
}
@Nullable
- public OptionDefinition getExpandedFrom() {
+ public ParsedOptionDescription getExpandedFrom() {
return expandedFrom;
}
}
diff --git a/java/com/google/devtools/common/options/OptionMetadataTag.java b/java/com/google/devtools/common/options/OptionMetadataTag.java
index c511fa6..563aa3e 100644
--- a/java/com/google/devtools/common/options/OptionMetadataTag.java
+++ b/java/com/google/devtools/common/options/OptionMetadataTag.java
@@ -55,7 +55,17 @@ public enum OptionMetadataTag {
*
* <p>These should be in category {@code OptionDocumentationCategory.UNDOCUMENTED}.
*/
- INTERNAL(4);
+ INTERNAL(4),
+
+ /**
+ * Options that are triggered by --all_incompatible_changes.
+ *
+ * <p>These must also be labelled {@link OptionMetadataTag#INCOMPATIBLE_CHANGE} and have the
+ * prefix --incompatible_. Note that the option name prefix is also a triggering case for the
+ * --all_incompatible_changes expansion, and so all options that start with the "incompatible_"
+ * prefix must have this tag.
+ */
+ TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES(5);
private final int value;
diff --git a/java/com/google/devtools/common/options/OptionPriority.java b/java/com/google/devtools/common/options/OptionPriority.java
index ec5d0d8..53f0d75 100644
--- a/java/com/google/devtools/common/options/OptionPriority.java
+++ b/java/com/google/devtools/common/options/OptionPriority.java
@@ -13,6 +13,7 @@
// limitations under the License.
package com.google.devtools.common.options;
+import com.google.common.collect.ImmutableList;
import java.util.Objects;
/**
@@ -25,43 +26,63 @@ import java.util.Objects;
*/
public class OptionPriority implements Comparable<OptionPriority> {
private final PriorityCategory priorityCategory;
- private final int index;
- private final boolean locked;
+ /**
+ * Each option that is passed explicitly has 0 ancestors, so it only has its command line index
+ * (or rc index, etc., depending on the category), but expanded options have the command line
+ * index of its parent and then its position within the options that were expanded at that point.
+ * Since options can expand to expanding options, and --config can expand to expansion options as
+ * well, this can technically go arbitrarily deep, but in practice this is very short, of length <
+ * 5, most commonly of length 1.
+ */
+ private final ImmutableList<Integer> priorityIndices;
+
+ private boolean alreadyExpanded = false;
- private OptionPriority(PriorityCategory priorityCategory, int index, boolean locked) {
+ private OptionPriority(
+ PriorityCategory priorityCategory, ImmutableList<Integer> priorityIndices) {
this.priorityCategory = priorityCategory;
- this.index = index;
- this.locked = locked;
+ this.priorityIndices = priorityIndices;
}
/** Get the first OptionPriority for that category. */
static OptionPriority lowestOptionPriorityAtCategory(PriorityCategory category) {
- return new OptionPriority(category, 0, false);
+ return new OptionPriority(category, ImmutableList.of(0));
}
/**
* Get the priority for the option following this one. In normal, incremental option parsing, the
- * returned priority would compareTo as after the current one. Does not increment locked
+ * returned priority would compareTo as after the current one. Does not increment ancestor
* priorities.
*/
static OptionPriority nextOptionPriority(OptionPriority priority) {
- if (priority.locked) {
- return priority;
- }
- return new OptionPriority(priority.priorityCategory, priority.index + 1, false);
+ int lastElementPosition = priority.priorityIndices.size() - 1;
+ return new OptionPriority(
+ priority.priorityCategory,
+ ImmutableList.<Integer>builder()
+ .addAll(priority.priorityIndices.subList(0, lastElementPosition))
+ .add(priority.priorityIndices.get(lastElementPosition) + 1)
+ .build());
}
/**
- * Return a priority for this option that will avoid priority increases by calls to
- * nextOptionPriority.
+ * Some options are expanded to other options, and the children options need to have their order
+ * preserved while maintaining their position between the options that flank the parent option.
*
- * <p>Some options are expanded in-place, and need to be all parsed at the priority of the
- * original option. In this case, parsing one of these after another should not cause the option
- * to be considered as higher priority than the ones before it (this would cause overlap between
- * the expansion of --expansion_flag and a option following it in the same list of options).
+ * @return the priority for the first child of the passed priority. This child's ordering can be
+ * tracked the same way that the parent's was.
*/
- public static OptionPriority getLockedPriority(OptionPriority priority) {
- return new OptionPriority(priority.priorityCategory, priority.index, true);
+ public static OptionPriority getChildPriority(OptionPriority parentPriority)
+ throws OptionsParsingException {
+ if (parentPriority.alreadyExpanded) {
+ throw new OptionsParsingException("Tried to expand option too many times");
+ }
+ // Prevent this option from being re-expanded.
+ parentPriority.alreadyExpanded = true;
+
+ // The child priority has 1 more level of nesting than its parent.
+ return new OptionPriority(
+ parentPriority.priorityCategory,
+ ImmutableList.<Integer>builder().addAll(parentPriority.priorityIndices).add(0).build());
}
public PriorityCategory getPriorityCategory() {
@@ -71,28 +92,36 @@ public class OptionPriority implements Comparable<OptionPriority> {
@Override
public int compareTo(OptionPriority o) {
if (priorityCategory.equals(o.priorityCategory)) {
- return index - o.index;
+ for (int i = 0; i < priorityIndices.size() && i < o.priorityIndices.size(); ++i) {
+ if (!priorityIndices.get(i).equals(o.priorityIndices.get(i))) {
+ return priorityIndices.get(i).compareTo(o.priorityIndices.get(i));
+ }
+ }
+ // The values are up to the shorter one's length are the same, so the shorter one is a direct
+ // ancestor and comes first.
+ return Integer.compare(priorityIndices.size(), o.priorityIndices.size());
}
- return priorityCategory.ordinal() - o.priorityCategory.ordinal();
+ return Integer.compare(priorityCategory.ordinal(), o.priorityCategory.ordinal());
}
@Override
public boolean equals(Object o) {
if (o instanceof OptionPriority) {
OptionPriority other = (OptionPriority) o;
- return other.priorityCategory.equals(priorityCategory) && other.index == index;
+ return priorityCategory.equals(other.priorityCategory)
+ && priorityIndices.equals(other.priorityIndices);
}
return false;
}
@Override
public int hashCode() {
- return Objects.hash(priorityCategory, index);
+ return Objects.hash(priorityCategory, priorityIndices);
}
@Override
public String toString() {
- return String.format("OptionPriority(%s,%s)", priorityCategory, index);
+ return String.format("OptionPriority(%s,%s)", priorityCategory, priorityIndices);
}
/**
diff --git a/java/com/google/devtools/common/options/OptionValueDescription.java b/java/com/google/devtools/common/options/OptionValueDescription.java
index 616b3b5..11ad7fe 100644
--- a/java/com/google/devtools/common/options/OptionValueDescription.java
+++ b/java/com/google/devtools/common/options/OptionValueDescription.java
@@ -22,7 +22,7 @@ import com.google.devtools.common.options.OptionsParser.ConstructionException;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
-import java.util.Map.Entry;
+import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@@ -98,8 +98,6 @@ public abstract class OptionValueDescription {
return new RepeatableOptionValueDescription(option);
} else if (option.hasImplicitRequirements()) {
return new OptionWithImplicitRequirementsValueDescription(option);
- } else if (option.isWrapperOption()) {
- return new WrapperOptionValueDescription(option);
} else {
return new SingleOptionValueDescription(option);
}
@@ -187,11 +185,11 @@ public abstract class OptionValueDescription {
// log warnings describing the change.
if (parsedOption.getPriority().compareTo(effectiveOptionInstance.getPriority()) >= 0) {
// Identify the option that might have led to the current and new value of this option.
- OptionDefinition implicitDependent = parsedOption.getImplicitDependent();
- OptionDefinition expandedFrom = parsedOption.getExpandedFrom();
- OptionDefinition optionThatDependsOnEffectiveValue =
+ ParsedOptionDescription implicitDependent = parsedOption.getImplicitDependent();
+ ParsedOptionDescription expandedFrom = parsedOption.getExpandedFrom();
+ ParsedOptionDescription optionThatDependsOnEffectiveValue =
effectiveOptionInstance.getImplicitDependent();
- OptionDefinition optionThatExpandedToEffectiveValue =
+ ParsedOptionDescription optionThatExpandedToEffectiveValue =
effectiveOptionInstance.getExpandedFrom();
Object newValue = parsedOption.getConvertedValue();
@@ -227,7 +225,7 @@ public abstract class OptionValueDescription {
// Create a warning if an expansion option overrides an explicit option:
warnings.add(
String.format(
- "%s was expanded and now overrides a previous explicitly specified %s with %s",
+ "%s was expanded and now overrides the explicit option %s with %s",
expandedFrom,
effectiveOptionInstance.getCommandLineForm(),
parsedOption.getCommandLineForm()));
@@ -278,8 +276,8 @@ public abstract class OptionValueDescription {
.asMap()
.entrySet()
.stream()
- .sorted(Comparator.comparing(Entry::getKey))
- .map(Entry::getValue)
+ .sorted(Comparator.comparing(Map.Entry::getKey))
+ .map(Map.Entry::getValue)
.flatMap(Collection::stream)
.map(ParsedOptionDescription::getSource)
.distinct()
@@ -294,8 +292,8 @@ public abstract class OptionValueDescription {
.asMap()
.entrySet()
.stream()
- .sorted(Comparator.comparing(Entry::getKey))
- .map(Entry::getValue)
+ .sorted(Comparator.comparing(Map.Entry::getKey))
+ .map(Map.Entry::getValue)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
@@ -322,8 +320,8 @@ public abstract class OptionValueDescription {
.asMap()
.entrySet()
.stream()
- .sorted(Comparator.comparing(Entry::getKey))
- .map(Entry::getValue)
+ .sorted(Comparator.comparing(Map.Entry::getKey))
+ .map(Map.Entry::getValue)
.flatMap(Collection::stream)
// Only provide the options that aren't implied elsewhere.
.filter(optionDesc -> optionDesc.getImplicitDependent() == null)
@@ -430,50 +428,6 @@ public abstract class OptionValueDescription {
optionDefinition, parsedOption.getSource()));
}
}
-
- /** Form for options that contain other options in the value text to which they expand. */
- private static final class WrapperOptionValueDescription extends OptionValueDescription {
-
- WrapperOptionValueDescription(OptionDefinition optionDefinition) {
- super(optionDefinition);
- }
-
- @Override
- public Object getValue() {
- return null;
- }
-
- @Override
- public String getSourceString() {
- return null;
- }
-
- @Override
- ExpansionBundle addOptionInstance(ParsedOptionDescription parsedOption, List<String> warnings)
- throws OptionsParsingException {
- if (!parsedOption.getUnconvertedValue().startsWith("-")) {
- throw new OptionsParsingException(
- String.format(
- "Invalid value format for %s. You may have meant --%s=--%s",
- optionDefinition,
- optionDefinition.getOptionName(),
- parsedOption.getUnconvertedValue()));
- }
- return new ExpansionBundle(
- ImmutableList.of(parsedOption.getUnconvertedValue()),
- (parsedOption.getSource() == null)
- ? String.format("unwrapped from %s", optionDefinition)
- : String.format(
- "unwrapped from %s (source %s)", optionDefinition, parsedOption.getSource()));
- }
-
- @Override
- public ImmutableList<ParsedOptionDescription> getCanonicalInstances() {
- // No wrapper options get listed in the canonical form - the options they are wrapping will
- // be in the right place.
- return ImmutableList.of();
- }
- }
}
diff --git a/java/com/google/devtools/common/options/OptionsBase.java b/java/com/google/devtools/common/options/OptionsBase.java
index 6b9f2f1..9496c65 100644
--- a/java/com/google/devtools/common/options/OptionsBase.java
+++ b/java/com/google/devtools/common/options/OptionsBase.java
@@ -20,7 +20,6 @@ import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
/**
* Base class for all options classes. Extend this class, adding public instance fields annotated
@@ -93,7 +92,7 @@ public abstract class OptionsBase {
public final String cacheKey() {
StringBuilder result = new StringBuilder(getClass().getName()).append("{");
- for (Entry<String, Object> entry : asMap().entrySet()) {
+ for (Map.Entry<String, Object> entry : asMap().entrySet()) {
result.append(entry.getKey()).append("=");
Object value = entry.getValue();
diff --git a/java/com/google/devtools/common/options/OptionsParser.java b/java/com/google/devtools/common/options/OptionsParser.java
index fb7161c..6f1d7b6 100644
--- a/java/com/google/devtools/common/options/OptionsParser.java
+++ b/java/com/google/devtools/common/options/OptionsParser.java
@@ -33,7 +33,6 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -299,7 +298,7 @@ public class OptionsParser implements OptionsProvider {
getOptionsSortedByCategory();
ImmutableMap<OptionDocumentationCategory, String> optionCategoryDescriptions =
OptionFilterDescriptions.getOptionCategoriesEnumDescription(productName);
- for (Entry<OptionDocumentationCategory, List<OptionDefinition>> e :
+ for (Map.Entry<OptionDocumentationCategory, List<OptionDefinition>> e :
optionsByCategory.entrySet()) {
String categoryDescription = optionCategoryDescriptions.get(e.getKey());
List<OptionDefinition> categorizedOptionList = e.getValue();
@@ -463,7 +462,7 @@ public class OptionsParser implements OptionsProvider {
ImmutableMap<OptionDocumentationCategory, String> optionCategoryDescriptions =
OptionFilterDescriptions.getOptionCategoriesEnumDescription(productName);
- for (Entry<OptionDocumentationCategory, List<OptionDefinition>> e :
+ for (Map.Entry<OptionDocumentationCategory, List<OptionDefinition>> e :
optionsByCategory.entrySet()) {
desc.append("<dl>");
String categoryDescription = optionCategoryDescriptions.get(e.getKey());
@@ -619,13 +618,26 @@ public class OptionsParser implements OptionsProvider {
}
}
- public void parseOptionsFixedAtSpecificPriority(
- OptionPriority priority, String source, List<String> args) throws OptionsParsingException {
- Preconditions.checkNotNull(priority, "Priority not specified for arglist " + args);
+ /**
+ * Parses the args at the priority of the provided option. This is useful for after-the-fact
+ * expansion.
+ *
+ * @param optionToExpand the option that is being "expanded" after the fact. The provided args
+ * will have the same priority as this option.
+ * @param source a description of where the expansion arguments came from.
+ * @param args the arguments to parse as the expansion. Order matters, as the value of a flag may
+ * be in the following argument.
+ */
+ public void parseArgsAsExpansionOfOption(
+ ParsedOptionDescription optionToExpand, String source, List<String> args)
+ throws OptionsParsingException {
+ Preconditions.checkNotNull(
+ optionToExpand, "Option for expansion not specified for arglist " + args);
Preconditions.checkArgument(
- priority.getPriorityCategory() != OptionPriority.PriorityCategory.DEFAULT,
+ optionToExpand.getPriority().getPriorityCategory()
+ != OptionPriority.PriorityCategory.DEFAULT,
"Priority cannot be default, which was specified for arglist " + args);
- residue.addAll(impl.parseOptionsFixedAtSpecificPriority(priority, o -> source, args));
+ residue.addAll(impl.parseArgsAsExpansionOfOption(optionToExpand, o -> source, args));
if (!allowResidue && !residue.isEmpty()) {
String errorMsg = "Unrecognized arguments: " + Joiner.on(' ').join(residue);
throw new OptionsParsingException(errorMsg);
diff --git a/java/com/google/devtools/common/options/OptionsParserImpl.java b/java/com/google/devtools/common/options/OptionsParserImpl.java
index 496927b..2c15430 100644
--- a/java/com/google/devtools/common/options/OptionsParserImpl.java
+++ b/java/com/google/devtools/common/options/OptionsParserImpl.java
@@ -142,9 +142,10 @@ class OptionsParserImpl {
return optionValues
.keySet()
.stream()
- .sorted()
.map(optionDefinition -> optionValues.get(optionDefinition).getCanonicalInstances())
.flatMap(Collection::stream)
+ // Return the effective (canonical) options in the order they were applied.
+ .sorted(comparing(ParsedOptionDescription::getPriority))
.collect(ImmutableList.toImmutableList());
}
@@ -204,30 +205,33 @@ class OptionsParserImpl {
* OptionInstanceOrigin)}
*/
ImmutableList<ParsedOptionDescription> getExpansionValueDescriptions(
- OptionDefinition expansionFlag, OptionInstanceOrigin originOfExpansionFlag)
+ OptionDefinition expansionFlagDef, OptionInstanceOrigin originOfExpansionFlag)
throws OptionsParsingException {
ImmutableList.Builder<ParsedOptionDescription> builder = ImmutableList.builder();
- OptionInstanceOrigin originOfSubflags;
+
+ // Values needed to correctly track the origin of the expanded options.
+ OptionPriority nextOptionPriority =
+ OptionPriority.getChildPriority(originOfExpansionFlag.getPriority());
+ String source;
+ ParsedOptionDescription implicitDependent = null;
+ ParsedOptionDescription expandedFrom = null;
+
ImmutableList<String> options;
- if (expansionFlag.hasImplicitRequirements()) {
- options = ImmutableList.copyOf(expansionFlag.getImplicitRequirements());
- originOfSubflags =
- new OptionInstanceOrigin(
- originOfExpansionFlag.getPriority(),
- String.format(
- "implicitly required by %s (source: %s)",
- expansionFlag, originOfExpansionFlag.getSource()),
- expansionFlag,
- null);
- } else if (expansionFlag.isExpansionOption()) {
- options = optionsData.getEvaluatedExpansion(expansionFlag);
- originOfSubflags =
- new OptionInstanceOrigin(
- originOfExpansionFlag.getPriority(),
- String.format(
- "expanded by %s (source: %s)", expansionFlag, originOfExpansionFlag.getSource()),
- null,
- expansionFlag);
+ ParsedOptionDescription expansionFlagParsedDummy =
+ ParsedOptionDescription.newDummyInstance(expansionFlagDef, originOfExpansionFlag);
+ if (expansionFlagDef.hasImplicitRequirements()) {
+ options = ImmutableList.copyOf(expansionFlagDef.getImplicitRequirements());
+ source =
+ String.format(
+ "implicitly required by %s (source: %s)",
+ expansionFlagDef, originOfExpansionFlag.getSource());
+ implicitDependent = expansionFlagParsedDummy;
+ } else if (expansionFlagDef.isExpansionOption()) {
+ options = optionsData.getEvaluatedExpansion(expansionFlagDef);
+ source =
+ String.format(
+ "expanded by %s (source: %s)", expansionFlagDef, originOfExpansionFlag.getSource());
+ expandedFrom = expansionFlagParsedDummy;
} else {
return ImmutableList.of();
}
@@ -239,11 +243,12 @@ class OptionsParserImpl {
identifyOptionAndPossibleArgument(
unparsedFlagExpression,
optionsIterator,
- originOfSubflags.getPriority(),
- o -> originOfSubflags.getSource(),
- originOfSubflags.getImplicitDependent(),
- originOfSubflags.getExpandedFrom());
+ nextOptionPriority,
+ o -> source,
+ implicitDependent,
+ expandedFrom);
builder.add(parsedOption);
+ nextOptionPriority = OptionPriority.nextOptionPriority(nextOptionPriority);
}
return builder.build();
}
@@ -284,12 +289,19 @@ class OptionsParserImpl {
}
}
- /** Parses the args at the fixed priority. */
- List<String> parseOptionsFixedAtSpecificPriority(
- OptionPriority priority, Function<OptionDefinition, String> sourceFunction, List<String> args)
+ /** Implements {@link OptionsParser#parseArgsAsExpansionOfOption} */
+ List<String> parseArgsAsExpansionOfOption(
+ ParsedOptionDescription optionToExpand,
+ Function<OptionDefinition, String> sourceFunction,
+ List<String> args)
throws OptionsParsingException {
ResidueAndPriority residueAndPriority =
- parse(OptionPriority.getLockedPriority(priority), sourceFunction, null, null, args);
+ parse(
+ OptionPriority.getChildPriority(optionToExpand.getPriority()),
+ sourceFunction,
+ null,
+ optionToExpand,
+ args);
return residueAndPriority.residue;
}
@@ -304,8 +316,8 @@ class OptionsParserImpl {
private ResidueAndPriority parse(
OptionPriority priority,
Function<OptionDefinition, String> sourceFunction,
- OptionDefinition implicitDependent,
- OptionDefinition expandedFrom,
+ ParsedOptionDescription implicitDependent,
+ ParsedOptionDescription expandedFrom,
List<String> args)
throws OptionsParsingException {
List<String> unparsedArgs = new ArrayList<>();
@@ -369,7 +381,7 @@ class OptionsParserImpl {
priorityCategory);
handleNewParsedOption(
- new ParsedOptionDescription(
+ ParsedOptionDescription.newParsedOptionDescription(
option,
String.format("--%s=%s", option.getOptionName(), unconvertedValue),
unconvertedValue,
@@ -392,16 +404,15 @@ class OptionsParserImpl {
@Nullable String unconvertedValue = parsedOption.getUnconvertedValue();
// There are 3 types of flags that expand to other flag values. Expansion flags are the
- // accepted way to do this, but two legacy features remain: implicit requirements and wrapper
- // options. We rely on the OptionProcessor compile-time check's guarantee that no option sets
- // multiple of these behaviors. (In Bazel, --config is another such flag, but that expansion
+ // accepted way to do this, but implicit requirements also do this. We rely on the
+ // OptionProcessor compile-time check's guarantee that no option sets
+ // both expansion behaviors. (In Bazel, --config is another such flag, but that expansion
// is not controlled within the options parser, so we ignore it here)
// As much as possible, we want the behaviors of these different types of flags to be
// identical, as this minimizes the number of edge cases, but we do not yet track these values
- // in the same way. Wrapper options are replaced by their value and implicit requirements are
- // hidden from the reported lists of parsed options.
- if (parsedOption.getImplicitDependent() == null && !optionDefinition.isWrapperOption()) {
+ // in the same way.
+ if (parsedOption.getImplicitDependent() == null) {
// Log explicit options and expanded options in the order they are parsed (can be sorted
// later). This information is needed to correctly canonicalize flags.
parsedOptions.add(parsedOption);
@@ -410,19 +421,13 @@ class OptionsParserImpl {
if (expansionBundle != null) {
ResidueAndPriority residueAndPriority =
parse(
- OptionPriority.getLockedPriority(parsedOption.getPriority()),
+ OptionPriority.getChildPriority(parsedOption.getPriority()),
o -> expansionBundle.sourceOfExpansionArgs,
- optionDefinition.hasImplicitRequirements() ? optionDefinition : null,
- optionDefinition.isExpansionOption() ? optionDefinition : null,
+ optionDefinition.hasImplicitRequirements() ? parsedOption : null,
+ optionDefinition.isExpansionOption() ? parsedOption : null,
expansionBundle.expansionArgs);
if (!residueAndPriority.residue.isEmpty()) {
- if (optionDefinition.isWrapperOption()) {
- throw new OptionsParsingException(
- "Unparsed options remain after unwrapping "
- + unconvertedValue
- + ": "
- + Joiner.on(' ').join(residueAndPriority.residue));
- } else {
+
// Throw an assertion here, because this indicates an error in the definition of this
// option's expansion or requirements, not with the input as provided by the user.
throw new AssertionError(
@@ -430,7 +435,7 @@ class OptionsParserImpl {
+ unconvertedValue
+ ": "
+ Joiner.on(' ').join(residueAndPriority.residue));
- }
+
}
}
}
@@ -440,8 +445,8 @@ class OptionsParserImpl {
Iterator<String> nextArgs,
OptionPriority priority,
Function<OptionDefinition, String> sourceFunction,
- OptionDefinition implicitDependent,
- OptionDefinition expandedFrom)
+ ParsedOptionDescription implicitDependent,
+ ParsedOptionDescription expandedFrom)
throws OptionsParsingException {
// Store the way this option was parsed on the command line.
@@ -506,9 +511,8 @@ class OptionsParserImpl {
// Special-case boolean to supply value based on presence of "no" prefix.
if (optionDefinition.usesBooleanValueSyntax()) {
unconvertedValue = booleanValue ? "1" : "0";
- } else if (optionDefinition.getType().equals(Void.class)
- && !optionDefinition.isWrapperOption()) {
- // This is expected, Void type options have no args (unless they're wrapper options).
+ } else if (optionDefinition.getType().equals(Void.class)) {
+ // This is expected, Void type options have no args.
} else if (nextArgs.hasNext()) {
// "--flag value" form
unconvertedValue = nextArgs.next();
@@ -518,7 +522,7 @@ class OptionsParserImpl {
}
}
- return new ParsedOptionDescription(
+ return ParsedOptionDescription.newParsedOptionDescription(
optionDefinition,
commandLineForm.toString(),
unconvertedValue,
diff --git a/java/com/google/devtools/common/options/OptionsProvider.java b/java/com/google/devtools/common/options/OptionsProvider.java
index d467fe5..ece5d5d 100644
--- a/java/com/google/devtools/common/options/OptionsProvider.java
+++ b/java/com/google/devtools/common/options/OptionsProvider.java
@@ -73,11 +73,13 @@ public interface OptionsProvider extends OptionsClassProvider {
List<OptionValueDescription> asListOfOptionValues();
/**
- * Canonicalizes the list of options that this OptionsParser has parsed. The
- * contract is that if the returned set of options is passed to an options
- * parser with the same options classes, then that will have the same effect
- * as using the original args (which are passed in here), except for cosmetic
- * differences.
+ * Canonicalizes the list of options that this OptionsParser has parsed.
+ *
+ * <p>The contract is that if the returned set of options is passed to an options parser with the
+ * same options classes, then that will have the same effect as using the original args (which are
+ * passed in here), except for cosmetic differences. We do not guarantee that the 'canonical' list
+ * is unique, since some flags may have effects unknown to the parser (--config, for Bazel), so we
+ * do not reorder flags to further simplify the list.
*/
List<String> canonicalize();
}
diff --git a/java/com/google/devtools/common/options/ParsedOptionDescription.java b/java/com/google/devtools/common/options/ParsedOptionDescription.java
index f55f8ad..5088153 100644
--- a/java/com/google/devtools/common/options/ParsedOptionDescription.java
+++ b/java/com/google/devtools/common/options/ParsedOptionDescription.java
@@ -14,6 +14,7 @@
package com.google.devtools.common.options;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.function.Function;
import javax.annotation.Nullable;
@@ -27,25 +28,49 @@ import javax.annotation.Nullable;
public final class ParsedOptionDescription {
private final OptionDefinition optionDefinition;
- private final String commandLineForm;
+ @Nullable private final String commandLineForm;
@Nullable private final String unconvertedValue;
private final OptionInstanceOrigin origin;
- public ParsedOptionDescription(
+ private ParsedOptionDescription(
OptionDefinition optionDefinition,
- String commandLineForm,
+ @Nullable String commandLineForm,
@Nullable String unconvertedValue,
OptionInstanceOrigin origin) {
- this.optionDefinition = optionDefinition;
+ this.optionDefinition = Preconditions.checkNotNull(optionDefinition);
this.commandLineForm = commandLineForm;
this.unconvertedValue = unconvertedValue;
- this.origin = origin;
+ this.origin = Preconditions.checkNotNull(origin);
+ }
+
+ static ParsedOptionDescription newParsedOptionDescription(
+ OptionDefinition optionDefinition,
+ String commandLineForm,
+ @Nullable String unconvertedValue,
+ OptionInstanceOrigin origin) {
+ // An actual ParsedOptionDescription should always have a form in which it was parsed, but some
+ // options, such as expansion options, legitimately have no value.
+ return new ParsedOptionDescription(
+ optionDefinition,
+ Preconditions.checkNotNull(commandLineForm),
+ unconvertedValue,
+ origin);
+ }
+
+ /**
+ * This factory should be used when there is no actual parsed option, since in those cases we do
+ * not have an original value or form that the option took.
+ */
+ static ParsedOptionDescription newDummyInstance(
+ OptionDefinition optionDefinition, OptionInstanceOrigin origin) {
+ return new ParsedOptionDescription(optionDefinition, null, null, origin);
}
public OptionDefinition getOptionDefinition() {
return optionDefinition;
}
+ @Nullable
public String getCommandLineForm() {
return commandLineForm;
}
@@ -127,11 +152,11 @@ public final class ParsedOptionDescription {
return origin.getSource();
}
- OptionDefinition getImplicitDependent() {
+ ParsedOptionDescription getImplicitDependent() {
return origin.getImplicitDependent();
}
- OptionDefinition getExpandedFrom() {
+ ParsedOptionDescription getExpandedFrom() {
return origin.getExpandedFrom();
}
@@ -152,14 +177,14 @@ public final class ParsedOptionDescription {
@Override
public String toString() {
- StringBuilder result = new StringBuilder();
- result.append(optionDefinition);
- result.append("set to '").append(unconvertedValue).append("' ");
- result.append("with priority ").append(origin.getPriority());
- if (origin.getSource() != null) {
- result.append(" and source '").append(origin.getSource()).append("'");
+ // Check that a dummy value-less option instance does not output all the default information.
+ if (commandLineForm == null) {
+ return optionDefinition.toString();
}
- return result.toString();
+ String source = origin.getSource();
+ return String.format(
+ "option '%s'%s",
+ commandLineForm, source == null ? "" : String.format(" (source %s)", source));
}
}
diff --git a/java/com/google/devtools/common/options/processor/OptionProcessor.java b/java/com/google/devtools/common/options/processor/OptionProcessor.java
index fd7c023..485efcd 100644
--- a/java/com/google/devtools/common/options/processor/OptionProcessor.java
+++ b/java/com/google/devtools/common/options/processor/OptionProcessor.java
@@ -15,7 +15,6 @@ package com.google.devtools.common.options.processor;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
import com.google.devtools.common.options.Converter;
import com.google.devtools.common.options.Converters;
import com.google.devtools.common.options.ExpansionFunction;
@@ -27,7 +26,7 @@ import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import java.util.List;
-import java.util.Map.Entry;
+import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -36,7 +35,6 @@ import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
-import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
@@ -74,7 +72,6 @@ import javax.tools.Diagnostic;
* <p>These properties can be relied upon at runtime without additional checks.
*/
@SupportedAnnotationTypes({"com.google.devtools.common.options.Option"})
-@SupportedSourceVersion(SourceVersion.RELEASE_8)
public final class OptionProcessor extends AbstractProcessor {
private Types typeUtils;
@@ -84,6 +81,11 @@ public final class OptionProcessor extends AbstractProcessor {
private ImmutableMap<Class<?>, PrimitiveType> primitiveTypeMap;
@Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+
+ @Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
typeUtils = processingEnv.getTypeUtils();
@@ -93,18 +95,19 @@ public final class OptionProcessor extends AbstractProcessor {
// Because of the discrepancies between the java.lang and javax.lang type models, we can't
// directly use the get() method for the default converter map. Instead, we'll convert it once,
// to be more usable, and with the boxed type return values of convert() as the keys.
- ImmutableMap.Builder<TypeMirror, Converter<?>> converterMapBuilder = new Builder<>();
+ ImmutableMap.Builder<TypeMirror, Converter<?>> converterMapBuilder =
+ new ImmutableMap.Builder<>();
// Create a link from the primitive Classes to their primitive types. This intentionally
// only contains the types in the DEFAULT_CONVERTERS map.
- ImmutableMap.Builder<Class<?>, PrimitiveType> builder = new Builder<>();
+ ImmutableMap.Builder<Class<?>, PrimitiveType> builder = new ImmutableMap.Builder<>();
builder.put(int.class, typeUtils.getPrimitiveType(TypeKind.INT));
builder.put(double.class, typeUtils.getPrimitiveType(TypeKind.DOUBLE));
builder.put(boolean.class, typeUtils.getPrimitiveType(TypeKind.BOOLEAN));
builder.put(long.class, typeUtils.getPrimitiveType(TypeKind.LONG));
primitiveTypeMap = builder.build();
- for (Entry<Class<?>, Converter<?>> entry : Converters.DEFAULT_CONVERTERS.entrySet()) {
+ for (Map.Entry<Class<?>, Converter<?>> entry : Converters.DEFAULT_CONVERTERS.entrySet()) {
Class<?> converterClass = entry.getKey();
String typeName = converterClass.getCanonicalName();
TypeElement typeElement = elementUtils.getTypeElement(typeName);
@@ -476,10 +479,6 @@ public final class OptionProcessor extends AbstractProcessor {
}
if (isExpansion || hasImplicitRequirements) {
- if (annotation.wrapperOption()) {
- throw new OptionProcessorException(
- optionField, "Wrapper options cannot have expansions or implicit requirements.");
- }
if (annotation.allowMultiple()) {
throw new OptionProcessorException(
optionField,
@@ -488,30 +487,6 @@ public final class OptionProcessor extends AbstractProcessor {
}
}
- /**
- * Some flags wrap other flags. They are objectively useless, as there is no difference between
- * passing --wrapper=--foo and --foo other than the "source" information tracked. This
- * functionality comes from requiring compatibility at some past point in time, but is actively
- * being deprecated. No non-deprecated flag can use this feature.
- */
- private void checkWrapperOptions(VariableElement optionField) throws OptionProcessorException {
- Option annotation = optionField.getAnnotation(Option.class);
- if (annotation.wrapperOption()) {
- if (annotation.deprecationWarning().isEmpty()) {
- throw new OptionProcessorException(
- optionField,
- "Can't have non deprecated wrapper options, this feature is deprecated. "
- + "Please add a deprecationWarning.");
- }
- if (!ImmutableList.copyOf(annotation.metadataTags()).contains(OptionMetadataTag.DEPRECATED)) {
- throw new OptionProcessorException(
- optionField,
- "Can't have non deprecated wrapper options, this feature is deprecated. "
- + "Please add the metadata tag DEPRECATED.");
- }
- }
- }
-
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(Option.class)) {
@@ -528,7 +503,6 @@ public final class OptionProcessor extends AbstractProcessor {
checkConverter(optionField);
checkEffectTagRationality(optionField);
checkMetadataTagAndCategoryRationality(optionField);
- checkWrapperOptions(optionField);
} catch (OptionProcessorException e) {
error(e.getElementInError(), e.getMessage());
}