aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
diff options
context:
space:
mode:
authorGravatar janakr <janakr@google.com>2018-02-02 15:52:22 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-02 15:53:55 -0800
commita56a6adf7c5d2829ea99f393f1a2d2d3d4488e0f (patch)
tree2a7ec0955afd09a9fb1d39801b85dca6c2567bba /src/main/java/com/google/devtools/build/lib/packages/Attribute.java
parent64d9a4d6dcd720a3b7a60ff550a17a7707dd41d0 (diff)
Stop allowing generic LateBoundDefault value types. Such types are always either a Label or a List<Label>. We can easily enforce this through static type checking, so do it.
This will help with LateBoundDefault serialization, since we don't have to serialize an arbitrary object. PiperOrigin-RevId: 184347100
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/packages/Attribute.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/Attribute.java261
1 files changed, 157 insertions, 104 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index d6b1cebef1..75ff0f3332 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -32,6 +32,7 @@ import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
@@ -1501,7 +1502,7 @@ public final class Attribute implements Comparable<Attribute> {
}
}
- private static final class SimpleLateBoundDefault<FragmentT, ValueT>
+ private static class SimpleLateBoundDefault<FragmentT, ValueT>
extends LateBoundDefault<FragmentT, ValueT> {
private final Resolver<FragmentT, ValueT> resolver;
@@ -1523,8 +1524,8 @@ public final class Attribute implements Comparable<Attribute> {
// TODO(b/65746853): Remove documentation about accepting BuildConfiguration when uses are cleaned
// up.
/**
- * Provider of values for late-bound attributes. See
- * {@link Attribute#value(LateBoundDefault<?, ? extends TYPE> value)}.
+ * Provider of values for late-bound attributes. See {@link Attribute#value(LateBoundDefault<?, ?
+ * extends TYPE> value)}.
*
* <p>Use sparingly - having different values for attributes during loading and analysis can
* confuse users.
@@ -1532,7 +1533,8 @@ public final class Attribute implements Comparable<Attribute> {
* @param <FragmentT> The type of value that is used to compute this value. This is usually a
* subclass of BuildConfiguration.Fragment. It may also be Void to receive null, or
* BuildConfiguration itself to receive the entire configuration.
- * @param <ValueT> The type of value returned by this class.
+ * @param <ValueT> The type of value returned by this class. Must be either {@link Void}, a {@link
+ * Label}, or a {@link List} of {@link Label} objects.
*/
@Immutable
public abstract static class LateBoundDefault<FragmentT, ValueT> {
@@ -1551,107 +1553,18 @@ public final class Attribute implements Comparable<Attribute> {
private final Class<FragmentT> fragmentClass;
/**
- * Creates a new LateBoundDefault which uses the rule, its configured attributes, and a fragment
- * of the target configuration.
- *
- * <p>Note that the configuration fragment here does not take into account any transitions that
- * are on the attribute with this LateBoundDefault as its value. The configuration will be the
- * same as the configuration given to the target bearing the attribute.
- *
- * <p>Nearly all LateBoundDefaults should use this constructor. There are few situations where
- * it isn't the appropriate option.
- *
- * <p>If you want a late-bound dependency which is configured in the host configuration, just
- * use this method with {@link com.google.devtools.build.lib.analysis.config.HostTransition}.
- * If you also need to decide the label of the dependency with information gained from the host
- * configuration - and it's very unlikely that you do - you can use
- * {@link #fromHostConfiguration} as well.
- *
- * <p>If you want to decide an attribute's value based on the value of its other attributes,
- * use a subclass of {@link ComputedDefault}. The only time you should need
- * {@link #fromRuleAndAttributes} is if you need access to three or more configurable
- * attributes, or if you need to match names with a late-bound attribute on another rule.
- *
- * <p>If you have a constant-valued attribute, but you need it to have the same name as an
- * attribute on another rule which is late-bound, use {@link #fromConstant} or
- * {@link #alwaysNull}.
- *
- * @param fragmentClass The fragment to receive from the target configuration. May also be
- * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
- * you must only use methods of BuildConfiguration itself, and not use any fragments.
- * @param defaultValue The default value to return at loading time, when the configuration is
- * not available.
- * @param resolver A function which will compute the actual value with the configuration.
- */
- public static <FragmentT, ValueT> LateBoundDefault<FragmentT, ValueT> fromTargetConfiguration(
- Class<FragmentT> fragmentClass, ValueT defaultValue, Resolver<FragmentT, ValueT> resolver) {
- Preconditions.checkArgument(
- !fragmentClass.equals(Void.class),
- "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
- + "configuration.");
- return new SimpleLateBoundDefault<>(false, fragmentClass, defaultValue, resolver);
- }
-
- /**
- * Creates a new LateBoundDefault which uses the rule, its configured attributes, and a fragment
- * of the host configuration.
- *
- * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
- * need this method, just {@link #fromTargetConfiguration} and
- * {@link com.google.devtools.build.lib.analysis.config.HostTransition}.
- *
- * <p>This method only affects the configuration fragment passed to {@link #resolve}. You must
- * also use {@link com.google.devtools.build.lib.analysis.config.HostTransition}, so that the
- * dependency will be analyzed in the host configuration.
- *
- * @param fragmentClass The fragment to receive from the host configuration. May also be
- * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
- * you must only use methods of BuildConfiguration itself, and not use any fragments.
- * It is very rare that a LateBoundDefault should need a host configuration fragment; use
- * {@link #fromTargetConfiguration} in most cases.
- * @param defaultValue The default value to return at loading time, when the configuration is
- * not available.
- * @param resolver A function which will compute the actual value with the configuration.
- */
- public static <FragmentT, ValueT> LateBoundDefault<FragmentT, ValueT> fromHostConfiguration(
- Class<FragmentT> fragmentClass, ValueT defaultValue, Resolver<FragmentT, ValueT> resolver) {
- Preconditions.checkArgument(
- !fragmentClass.equals(Void.class),
- "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
- + "configuration.");
- return new SimpleLateBoundDefault<>(true, fragmentClass, defaultValue, resolver);
- }
-
- /**
- * Creates a new LateBoundDefault which uses only the rule and its configured attributes.
- *
- * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
- * need this method, just use {@link ComputedDefault}.
- *
- * <p>This is used primarily for computing values based on three or more configurable
- * attributes and/or matching names with late-bound attributes on other rules.
- *
- * @param defaultValue The default value to return when the configuration is not available at
- * loading time.
- * @param resolver A function which will compute the actual value with the configuration.
- */
- public static <ValueT> LateBoundDefault<Void, ValueT> fromRuleAndAttributesOnly(
- ValueT defaultValue, Resolver<Void, ValueT> resolver) {
- return new SimpleLateBoundDefault<>(false, Void.class, defaultValue, resolver);
- }
-
- /**
* Creates a new LateBoundDefault which always returns the given value.
*
* <p>This is used primarily for matching names with late-bound attributes on other rules and
* for testing. Use normal default values if the name does not matter.
*/
- public static <ValueT> LateBoundDefault<Void, ValueT> fromConstant(final ValueT defaultValue) {
- if (defaultValue == null) {
- return alwaysNull();
- }
- return new SimpleLateBoundDefault<>(
- false, Void.class, defaultValue, (rule, attributes, unused) -> defaultValue);
+ @VisibleForTesting
+ public static LabelLateBoundDefault<Void> fromConstantForTesting(Label defaultValue) {
+ return new LabelLateBoundDefault<Void>(
+ false,
+ Void.class,
+ Preconditions.checkNotNull(defaultValue),
+ (rule, attributes, unused) -> defaultValue) {};
}
/**
@@ -1662,12 +1575,9 @@ public final class Attribute implements Comparable<Attribute> {
*/
@SuppressWarnings("unchecked") // bivariant implementation
public static <ValueT> LateBoundDefault<Void, ValueT> alwaysNull() {
- return (LateBoundDefault<Void, ValueT>) ALWAYS_NULL;
+ return (LateBoundDefault<Void, ValueT>) AlwaysNullLateBoundDefault.INSTANCE;
}
- private static final LateBoundDefault<Void, Void> ALWAYS_NULL =
- new SimpleLateBoundDefault<>(false, Void.class, null, (rule, attributes, unused) -> null);
-
protected LateBoundDefault(
boolean useHostConfiguration,
Class<FragmentT> fragmentClass,
@@ -1716,6 +1626,149 @@ public final class Attribute implements Comparable<Attribute> {
public abstract ValueT resolve(Rule rule, AttributeMap attributes, FragmentT input);
}
+ /**
+ * An abstract {@link LateBoundDefault} class so that {@code SkylarkLateBoundDefault} can derive
+ * from {@link LateBoundDefault} without compromising the type-safety of the second generic
+ * parameter to {@link LateBoundDefault}.
+ */
+ public abstract static class AbstractLabelLateBoundDefault<FragmentT>
+ extends LateBoundDefault<FragmentT, Label> {
+ protected AbstractLabelLateBoundDefault(
+ boolean useHostConfiguration, Class<FragmentT> fragmentClass, Label defaultValue) {
+ super(useHostConfiguration, fragmentClass, defaultValue);
+ }
+ }
+
+ private static class AlwaysNullLateBoundDefault extends SimpleLateBoundDefault<Void, Void> {
+ static final AlwaysNullLateBoundDefault INSTANCE = new AlwaysNullLateBoundDefault();
+
+ private AlwaysNullLateBoundDefault() {
+ super(false, Void.class, null, (rule, attributes, unused) -> null);
+ }
+ }
+
+ /** A {@link LateBoundDefault} for a {@link Label}. */
+ public static class LabelLateBoundDefault<FragmentT>
+ extends SimpleLateBoundDefault<FragmentT, Label> {
+ private LabelLateBoundDefault(
+ boolean useHostConfiguration,
+ Class<FragmentT> fragmentClass,
+ Label defaultValue,
+ Resolver<FragmentT, Label> resolver) {
+ super(useHostConfiguration, fragmentClass, defaultValue, resolver);
+ }
+
+ /**
+ * Creates a new LabelLateBoundDefault which uses the rule, its configured attributes, and a
+ * fragment of the target configuration.
+ *
+ * <p>Note that the configuration fragment here does not take into account any transitions that
+ * are on the attribute with this LabelLateBoundDefault as its value. The configuration will be
+ * the same as the configuration given to the target bearing the attribute.
+ *
+ * <p>Nearly all LateBoundDefaults should use this constructor or {@link
+ * LabelListLateBoundDefault#fromTargetConfiguration}. There are few situations where it isn't
+ * the appropriate option.
+ *
+ * <p>If you want a late-bound dependency which is configured in the host configuration, just
+ * use this method with {@link com.google.devtools.build.lib.analysis.config.HostTransition}. If
+ * you also need to decide the label of the dependency with information gained from the host
+ * configuration - and it's very unlikely that you do - you can use {@link
+ * LabelLateBoundDefault#fromHostConfiguration} as well.
+ *
+ * <p>If you want to decide an attribute's value based on the value of its other attributes, use
+ * a subclass of {@link ComputedDefault}. The only time you should need {@link
+ * LabelListLateBoundDefault#fromRuleAndAttributesOnly} is if you need access to three or more
+ * configurable attributes, or if you need to match names with a late-bound attribute on another
+ * rule.
+ *
+ * <p>If you have a constant-valued attribute, but you need it to have the same name as an
+ * attribute on another rule which is late-bound, use {@link #alwaysNull}.
+ *
+ * @param fragmentClass The fragment to receive from the target configuration. May also be
+ * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
+ * you must only use methods of BuildConfiguration itself, and not use any fragments.
+ * @param defaultValue The default {@link Label} to return at loading time, when the
+ * configuration is not available.
+ * @param resolver A function which will compute the actual value with the configuration.
+ */
+ public static <FragmentT> LabelLateBoundDefault<FragmentT> fromTargetConfiguration(
+ Class<FragmentT> fragmentClass, Label defaultValue, Resolver<FragmentT, Label> resolver) {
+ Preconditions.checkArgument(
+ !fragmentClass.equals(Void.class),
+ "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
+ + "configuration.");
+ return new LabelLateBoundDefault<>(false, fragmentClass, defaultValue, resolver);
+ }
+
+ /**
+ * Creates a new LateBoundDefault which uses the rule, its configured attributes, and a fragment
+ * of the host configuration.
+ *
+ * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
+ * need this method, just {@link #fromTargetConfiguration} and {@link
+ * com.google.devtools.build.lib.analysis.config.HostTransition}.
+ *
+ * <p>This method only affects the configuration fragment passed to {@link #resolve}. You must
+ * also use {@link com.google.devtools.build.lib.analysis.config.HostTransition}, so that the
+ * dependency will be analyzed in the host configuration.
+ *
+ * @param fragmentClass The fragment to receive from the host configuration. May also be
+ * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
+ * you must only use methods of BuildConfiguration itself, and not use any fragments. It is
+ * very rare that a LateBoundDefault should need a host configuration fragment; use {@link
+ * #fromTargetConfiguration} in most cases.
+ * @param defaultValue The default {@link Label} to return at loading time, when the
+ * configuration is not available.
+ * @param resolver A function which will compute the actual value with the configuration.
+ */
+ public static <FragmentT> LabelLateBoundDefault<FragmentT> fromHostConfiguration(
+ Class<FragmentT> fragmentClass, Label defaultValue, Resolver<FragmentT, Label> resolver) {
+ Preconditions.checkArgument(
+ !fragmentClass.equals(Void.class),
+ "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
+ + "configuration.");
+ return new LabelLateBoundDefault<>(true, fragmentClass, defaultValue, resolver);
+ }
+ }
+
+ /** A {@link LateBoundDefault} for a {@link List} of {@link Label} objects. */
+ public static class LabelListLateBoundDefault<FragmentT>
+ extends SimpleLateBoundDefault<FragmentT, List<Label>> {
+ private LabelListLateBoundDefault(
+ boolean useHostConfiguration,
+ Class<FragmentT> fragmentClass,
+ Resolver<FragmentT, List<Label>> resolver) {
+ super(useHostConfiguration, fragmentClass, ImmutableList.of(), resolver);
+ }
+
+ public static <FragmentT> LabelListLateBoundDefault<FragmentT> fromTargetConfiguration(
+ Class<FragmentT> fragmentClass, Resolver<FragmentT, List<Label>> resolver) {
+ Preconditions.checkArgument(
+ !fragmentClass.equals(Void.class),
+ "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
+ + "configuration.");
+ return new LabelListLateBoundDefault<>(false, fragmentClass, resolver);
+ }
+
+ /**
+ * Creates a new LabelListLateBoundDefault which uses only the rule and its configured
+ * attributes.
+ *
+ * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
+ * need this method, just use {@link ComputedDefault}.
+ *
+ * <p>This is used primarily for computing values based on three or more configurable attributes
+ * and/or matching names with late-bound attributes on other rules.
+ *
+ * @param resolver A function which will compute the actual value with the configuration.
+ */
+ public static LabelListLateBoundDefault<Void> fromRuleAndAttributesOnly(
+ Resolver<Void, List<Label>> resolver) {
+ return new LabelListLateBoundDefault<>(false, Void.class, resolver);
+ }
+ }
+
private final String name;
private final Type<?> type;