diff options
Diffstat (limited to 'java/com/google/devtools/common')
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()); } |