| // Copyright 2014 The Bazel Authors. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //    http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package com.google.devtools.build.lib.packages; | 
 |  | 
 | import com.google.common.annotations.VisibleForTesting; | 
 | import com.google.common.base.Function; | 
 | import com.google.common.base.Predicate; | 
 | import com.google.common.base.Predicates; | 
 | import com.google.common.base.Verify; | 
 | import com.google.common.collect.ImmutableList; | 
 | import com.google.common.collect.ImmutableMap; | 
 | import com.google.common.collect.ImmutableSet; | 
 | import com.google.common.collect.Iterables; | 
 | import com.google.common.collect.Ordering; | 
 | import com.google.common.collect.Sets; | 
 | import com.google.devtools.build.lib.analysis.TransitiveInfoProvider; | 
 | 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.syntax.ClassObject; | 
 | import com.google.devtools.build.lib.syntax.EvalException; | 
 | import com.google.devtools.build.lib.syntax.EvalUtils; | 
 | import com.google.devtools.build.lib.syntax.Runtime; | 
 | import com.google.devtools.build.lib.syntax.SkylarkCallbackFunction; | 
 | import com.google.devtools.build.lib.syntax.Type; | 
 | import com.google.devtools.build.lib.syntax.Type.ConversionException; | 
 | import com.google.devtools.build.lib.util.FileType; | 
 | import com.google.devtools.build.lib.util.FileTypeSet; | 
 | import com.google.devtools.build.lib.util.Preconditions; | 
 | import com.google.devtools.build.lib.util.StringUtil; | 
 | import java.util.ArrayList; | 
 | import java.util.Arrays; | 
 | import java.util.Collection; | 
 | import java.util.EnumSet; | 
 | import java.util.HashMap; | 
 | import java.util.LinkedHashMap; | 
 | import java.util.List; | 
 | import java.util.Map; | 
 | import java.util.Set; | 
 | import java.util.concurrent.atomic.AtomicReference; | 
 | import javax.annotation.concurrent.Immutable; | 
 |  | 
 | /** | 
 |  * Metadata of a rule attribute. Contains the attribute name and type, and an | 
 |  * default value to be used if none is provided in a rule declaration in a BUILD | 
 |  * file. Attributes are immutable, and may be shared by more than one rule (for | 
 |  * example, <code>foo_binary</code> and <code>foo_library</code> may share many | 
 |  * attributes in common). | 
 |  */ | 
 | @Immutable | 
 | public final class Attribute implements Comparable<Attribute> { | 
 |  | 
 |   public static final Predicate<RuleClass> ANY_RULE = Predicates.alwaysTrue(); | 
 |  | 
 |   public static final Predicate<RuleClass> NO_RULE = Predicates.alwaysFalse(); | 
 |  | 
 |   /** | 
 |    * Wraps the information necessary to construct an Aspect. | 
 |    */ | 
 |   private abstract static class RuleAspect<C extends AspectClass> { | 
 |     protected final C aspectClass; | 
 |     protected final Function<Rule, AspectParameters> parametersExtractor; | 
 |  | 
 |     protected RuleAspect(C aspectClass, Function<Rule, AspectParameters> parametersExtractor) { | 
 |       this.aspectClass = aspectClass; | 
 |       this.parametersExtractor = parametersExtractor; | 
 |     } | 
 |  | 
 |     public String getName() { | 
 |       return this.aspectClass.getName(); | 
 |     } | 
 |  | 
 |     public ImmutableSet<String> getRequiredParameters() { | 
 |       return ImmutableSet.<String>of(); | 
 |     } | 
 |  | 
 |     public abstract Aspect getAspect(Rule rule); | 
 |  | 
 |     public C getAspectClass() { | 
 |       return aspectClass; | 
 |     } | 
 |   } | 
 |  | 
 |   private static class NativeRuleAspect extends RuleAspect<NativeAspectClass> { | 
 |     public NativeRuleAspect(NativeAspectClass aspectClass, | 
 |         Function<Rule, AspectParameters> parametersExtractor) { | 
 |       super(aspectClass, parametersExtractor); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public Aspect getAspect(Rule rule) { | 
 |       return Aspect.forNative(aspectClass, parametersExtractor.apply(rule)); | 
 |     } | 
 |   } | 
 |  | 
 |   private static class SkylarkRuleAspect extends RuleAspect<SkylarkAspectClass> { | 
 |     private final SkylarkAspect aspect; | 
 |  | 
 |     public SkylarkRuleAspect(SkylarkAspect aspect) { | 
 |       super(aspect.getAspectClass(), aspect.getDefaultParametersExtractor()); | 
 |       this.aspect = aspect; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public ImmutableSet<String> getRequiredParameters() { | 
 |       return aspect.getParamAttributes(); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public Aspect getAspect(Rule rule) { | 
 |       AspectParameters parameters = parametersExtractor.apply(rule); | 
 |       return Aspect.forSkylark(aspectClass, aspect.getDefinition(parameters), parameters); | 
 |     } | 
 |   } | 
 |  | 
 |   /** A RuleAspect that just wraps a pre-existing Aspect that doesn't vary with the Rule. */ | 
 |   private static class PredefinedRuleAspect extends RuleAspect<AspectClass> { | 
 |     private Aspect aspect; | 
 |  | 
 |     public PredefinedRuleAspect(Aspect aspect) { | 
 |       super(aspect.getAspectClass(), null); | 
 |       this.aspect = aspect; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public Aspect getAspect(Rule rule) { | 
 |       return aspect; | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * A configuration transition. | 
 |    */ | 
 |   public interface Transition { | 
 |     /** | 
 |      * Usually, a non-existent entry in the configuration transition table indicates an error. | 
 |      * Unfortunately, that means that we need to always build the full table. This method allows a | 
 |      * transition to indicate that a non-existent entry indicates a self transition, i.e., that the | 
 |      * resulting configuration is the same as the current configuration. This can simplify the code | 
 |      * needed to set up the transition table. | 
 |      */ | 
 |     boolean defaultsToSelf(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * A configuration split transition; this should be used to transition to multiple configurations | 
 |    * simultaneously. Note that the corresponding rule implementations must have special support to | 
 |    * handle this. | 
 |    * | 
 |    * <p>{@code T} must always be {@code BuildOptions}, but it can't be defined that way because | 
 |    * the symbol isn't available here. | 
 |    */ | 
 |   // TODO(bazel-team): Serializability constraints? | 
 |   public interface SplitTransition<T> extends Transition { | 
 |     /** | 
 |      * Return the list of {@code BuildOptions} after splitting; empty if not applicable. | 
 |      */ | 
 |     List<T> split(T buildOptions); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Declaration how the configuration should change when following a label or label list attribute. | 
 |    */ | 
 |   public enum ConfigurationTransition implements Transition { | 
 |     /** No transition, i.e., the same configuration as the current. */ | 
 |     NONE, | 
 |  | 
 |     /** Transition to the host configuration. */ | 
 |     HOST, | 
 |  | 
 |     /** Transition to a null configuration (applies to, e.g., input files). */ | 
 |     NULL, | 
 |  | 
 |     /** Transition from the target configuration to the data configuration. */ | 
 |     // TODO(bazel-team): Move this elsewhere. | 
 |     DATA, | 
 |  | 
 |     /** | 
 |      * Transition to one or more configurations. To obtain the actual child configurations, | 
 |      * invoke {@link Attribute#getSplitTransition(Rule)}. See {@link SplitTransition}. | 
 |      **/ | 
 |     SPLIT(true); | 
 |  | 
 |     private boolean defaultsToSelf; | 
 |  | 
 |     ConfigurationTransition() { | 
 |       this(false); | 
 |     } | 
 |  | 
 |     ConfigurationTransition(boolean defaultsToSelf) { | 
 |       this.defaultsToSelf = defaultsToSelf; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean defaultsToSelf() { | 
 |       return defaultsToSelf; | 
 |     } | 
 |   } | 
 |  | 
 |   private enum PropertyFlag { | 
 |     MANDATORY, | 
 |     EXECUTABLE, | 
 |     UNDOCUMENTED, | 
 |     TAGGABLE, | 
 |  | 
 |     /** | 
 |      * Whether the list attribute is order-independent and can be sorted. | 
 |      */ | 
 |     ORDER_INDEPENDENT, | 
 |  | 
 |     /** | 
 |      * Whether the allowedRuleClassesForLabels or allowedFileTypesForLabels are | 
 |      * set to custom values. If so, and the attribute is called "deps", the | 
 |      * legacy deps checking is skipped, and the new stricter checks are used | 
 |      * instead. For non-"deps" attributes, this allows skipping the check if it | 
 |      * would pass anyway, as the default setting allows any rule classes and | 
 |      * file types. | 
 |      */ | 
 |     STRICT_LABEL_CHECKING, | 
 |  | 
 |     /** | 
 |      * Set for things that would cause the a compile or lint-like action to | 
 |      * be executed when the input changes.  Used by compile_one_dependency. | 
 |      * Set for attributes like hdrs and srcs on cc_ rules or srcs on java_ | 
 |      * or py_rules.  Generally not set on data/resource attributes. | 
 |      */ | 
 |     DIRECT_COMPILE_TIME_INPUT, | 
 |  | 
 |     /** | 
 |      * Whether the value of the list type attribute must not be an empty list. | 
 |      */ | 
 |     NON_EMPTY, | 
 |  | 
 |     /** | 
 |      * Verifies that the referenced rule produces a single artifact. Note that this check happens | 
 |      * on a per label basis, i.e. the check happens separately for every label in a label list. | 
 |      */ | 
 |     SINGLE_ARTIFACT, | 
 |  | 
 |     /** | 
 |      * Whether we perform silent ruleclass filtering of the dependencies of the label type | 
 |      * attribute according to their rule classes. I.e. elements of the list which don't match the | 
 |      * allowedRuleClasses predicate or not rules will be filtered out without throwing any errors. | 
 |      * This flag is introduced to handle plugins, do not use it in other cases. | 
 |      */ | 
 |     SILENT_RULECLASS_FILTER, | 
 |  | 
 |     // TODO(bazel-team): This is a hack introduced because of the bad design of the original rules. | 
 |     // Depot cleanup would be too expensive, but don't migrate this to Skylark. | 
 |     /** | 
 |      * Whether to perform analysis time filetype check on this label-type attribute or not. | 
 |      * If the flag is set, we skip the check that applies the allowedFileTypes filter | 
 |      * to generated files. Do not use this if avoidable. | 
 |      */ | 
 |     SKIP_ANALYSIS_TIME_FILETYPE_CHECK, | 
 |  | 
 |     /** | 
 |      * Whether the value of the attribute should come from a given set of values. | 
 |      */ | 
 |     CHECK_ALLOWED_VALUES, | 
 |  | 
 |     /** | 
 |      * Whether this attribute is opted out of "configurability", i.e. the ability to determine | 
 |      * its value based on properties of the build configuration. | 
 |      */ | 
 |     NONCONFIGURABLE, | 
 |  | 
 |     /** | 
 |      * Whether we should skip dependency validation checks done by | 
 |      * {@link com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.PrerequisiteValidator} | 
 |      * (for visibility, etc.). | 
 |      */ | 
 |     SKIP_PREREQ_VALIDATOR_CHECKS, | 
 |  | 
 |     /** | 
 |      * Whether we should check constraints on this attribute even if default enforcement policy | 
 |      * would skip it. See | 
 |      * {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for more on | 
 |      * constraints. | 
 |      */ | 
 |     CHECK_CONSTRAINTS_OVERRIDE, | 
 |  | 
 |     /** | 
 |      * Whether we should skip constraints checking on this attribute even if default enforcement | 
 |      * policy would check it. | 
 |      */ | 
 |     SKIP_CONSTRAINTS_OVERRIDE, | 
 |  | 
 |     /** | 
 |      * Whether we should use output_licenses to check the licences on this attribute. | 
 |      */ | 
 |     OUTPUT_LICENSES, | 
 |   } | 
 |  | 
 |   // TODO(bazel-team): modify this interface to extend Predicate and have an extra error | 
 |   // message function like AllowedValues does | 
 |   /** | 
 |    * A predicate-like class that determines whether an edge between two rules is valid or not. | 
 |    */ | 
 |   public interface ValidityPredicate { | 
 |     /** | 
 |      * This method should return null if the edge is valid, or a suitable error message | 
 |      * if it is not. Note that warnings are not supported. | 
 |      */ | 
 |     String checkValid(Rule from, Rule to); | 
 |   } | 
 |  | 
 |   public static final ValidityPredicate ANY_EDGE = | 
 |       new ValidityPredicate() { | 
 |         @Override | 
 |         public String checkValid(Rule from, Rule to) { | 
 |           return null; | 
 |         } | 
 |       }; | 
 |  | 
 |   /** | 
 |    * Using this callback function, rules can set the configuration of their dependencies during the | 
 |    * analysis phase. | 
 |    */ | 
 |   public interface Configurator<TConfig, TRule> { | 
 |     TConfig apply(TRule fromRule, TConfig fromConfiguration, Attribute attribute, Target toTarget); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Provides a {@link SplitTransition} given the originating target {@link Rule}. The split | 
 |    * transition may be constant for all instances of the originating rule, or it may differ | 
 |    * based on attributes of that rule. For instance, a split transition on a rule's deps may differ | 
 |    * depending on the 'platform' attribute of the rule. | 
 |    */ | 
 |   public interface SplitTransitionProvider { | 
 |     /** | 
 |      * Returns the {@link SplitTransition} given the originating rule. | 
 |      */ | 
 |     SplitTransition<?> apply(Rule fromRule); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Implementation of {@link SplitTransitionProvider} that returns a single {@link SplitTransition} | 
 |    * regardless of the originating rule. | 
 |    */ | 
 |   private static class BasicSplitTransitionProvider implements SplitTransitionProvider { | 
 |  | 
 |     private final SplitTransition<?> splitTransition; | 
 |  | 
 |     BasicSplitTransitionProvider(SplitTransition<?> splitTransition) { | 
 |       this.splitTransition = splitTransition; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public SplitTransition<?> apply(Rule fromRule) { | 
 |       return splitTransition; | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * A predicate class to check if the value of the attribute comes from a predefined set. | 
 |    */ | 
 |   public static class AllowedValueSet implements PredicateWithMessage<Object> { | 
 |  | 
 |     private final Set<Object> allowedValues; | 
 |  | 
 |     public <T> AllowedValueSet(T... values) { | 
 |       this(Arrays.asList(values)); | 
 |     } | 
 |  | 
 |     public AllowedValueSet(Iterable<?> values) { | 
 |       Preconditions.checkNotNull(values); | 
 |       Preconditions.checkArgument(!Iterables.isEmpty(values)); | 
 |       // Do not remove <Object>: workaround for Java 7 type inference. | 
 |       allowedValues = ImmutableSet.<Object>copyOf(values); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean apply(Object input) { | 
 |       return allowedValues.contains(input); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public String getErrorReason(Object value) { | 
 |       return String.format("has to be one of %s instead of '%s'", | 
 |           StringUtil.joinEnglishList(allowedValues, "or", "'"), value); | 
 |     } | 
 |  | 
 |     @VisibleForTesting | 
 |     public Collection<Object> getAllowedValues() { | 
 |       return allowedValues; | 
 |     } | 
 |   } | 
 |  | 
 |   public ImmutableMap<String, ImmutableSet<String>> getRequiredAspectParameters() { | 
 |     ImmutableMap.Builder<String, ImmutableSet<String>> paramBuilder = ImmutableMap.builder(); | 
 |     for (RuleAspect<?> aspect : aspects) { | 
 |       paramBuilder.put(aspect.getName(), aspect.getRequiredParameters()); | 
 |     } | 
 |     return paramBuilder.build(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Creates a new attribute builder. | 
 |    * | 
 |    * @param name attribute name | 
 |    * @param type attribute type | 
 |    * @return attribute builder | 
 |    * | 
 |    * @param <TYPE> attribute type class | 
 |    */ | 
 |   public static <TYPE> Attribute.Builder<TYPE> attr(String name, Type<TYPE> type) { | 
 |     return new Builder<>(name, type); | 
 |   } | 
 |  | 
 |   /** | 
 |    * A fluent builder for the {@code Attribute} instances. | 
 |    * | 
 |    * <p>All methods could be called only once per builder. The attribute | 
 |    * already undocumented based on its name cannot be marked as undocumented. | 
 |    */ | 
 |   public static class Builder <TYPE> { | 
 |     private String name; | 
 |     private final Type<TYPE> type; | 
 |     private Transition configTransition = ConfigurationTransition.NONE; | 
 |     private Predicate<RuleClass> allowedRuleClassesForLabels = Predicates.alwaysTrue(); | 
 |     private Predicate<RuleClass> allowedRuleClassesForLabelsWarning = Predicates.alwaysFalse(); | 
 |     private Configurator<?, ?> configurator; | 
 |     private SplitTransitionProvider splitTransitionProvider; | 
 |     private FileTypeSet allowedFileTypesForLabels; | 
 |     private ValidityPredicate validityPredicate = ANY_EDGE; | 
 |     private Object value; | 
 |     private AttributeValueSource valueSource = AttributeValueSource.DIRECT; | 
 |     private boolean valueSet; | 
 |     private Predicate<AttributeMap> condition; | 
 |     private Set<PropertyFlag> propertyFlags = EnumSet.noneOf(PropertyFlag.class); | 
 |     private PredicateWithMessage<Object> allowedValues = null; | 
 |     private ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList = | 
 |         ImmutableList.<ImmutableSet<SkylarkProviderIdentifier>>of(); | 
 |     private ImmutableList<ImmutableList<Class<? extends TransitiveInfoProvider>>> | 
 |         mandatoryNativeProvidersList = ImmutableList.of(); | 
 |     private HashMap<String, RuleAspect<?>> aspects = new LinkedHashMap<>(); | 
 |  | 
 |     /** | 
 |      * Creates an attribute builder with given name and type. This attribute is optional, uses | 
 |      * target configuration and has a default value the same as its type default value. This | 
 |      * attribute will be marked as undocumented if its name starts with the dollar sign ({@code $}) | 
 |      * or colon ({@code :}). | 
 |      * | 
 |      * @param name attribute name | 
 |      * @param type attribute type | 
 |      */ | 
 |     public Builder(String name, Type<TYPE> type) { | 
 |       this.name = Preconditions.checkNotNull(name); | 
 |       this.type = Preconditions.checkNotNull(type); | 
 |       if (isImplicit(name) || isLateBound(name)) { | 
 |         setPropertyFlag(PropertyFlag.UNDOCUMENTED, "undocumented"); | 
 |       } | 
 |     } | 
 |  | 
 |     private Builder<TYPE> setPropertyFlag(PropertyFlag flag, String propertyName) { | 
 |       Preconditions.checkState( | 
 |           !propertyFlags.contains(flag), "%s flag is already set", propertyName); | 
 |       propertyFlags.add(flag); | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the property flag of the corresponding name if exists, otherwise throws an Exception. | 
 |      * Only meant to use from Skylark, do not use from Java. | 
 |      */ | 
 |     public Builder<TYPE> setPropertyFlag(String propertyName) { | 
 |       PropertyFlag flag = null; | 
 |       try { | 
 |         flag = PropertyFlag.valueOf(propertyName); | 
 |       } catch (IllegalArgumentException e) { | 
 |         throw new IllegalArgumentException("unknown attribute flag " + propertyName); | 
 |       } | 
 |       setPropertyFlag(flag, propertyName); | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Makes the built attribute mandatory. | 
 |      */ | 
 |     public Builder<TYPE> mandatory() { | 
 |       return setPropertyFlag(PropertyFlag.MANDATORY, "mandatory"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Makes the built attribute non empty, meaning the attribute cannot have an empty list value. | 
 |      * Only applicable for list type attributes. | 
 |      */ | 
 |     public Builder<TYPE> nonEmpty() { | 
 |       Preconditions.checkNotNull(type.getListElementType(), "attribute '%s' must be a list", name); | 
 |       return setPropertyFlag(PropertyFlag.NON_EMPTY, "non_empty"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Makes the built attribute producing a single artifact. | 
 |      */ | 
 |     public Builder<TYPE> singleArtifact() { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "attribute '%s' must be a label-valued type", name); | 
 |       return setPropertyFlag(PropertyFlag.SINGLE_ARTIFACT, "single_artifact"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Forces silent ruleclass filtering on the label type attribute. | 
 |      * This flag is introduced to handle plugins, do not use it in other cases. | 
 |      */ | 
 |     public Builder<TYPE> silentRuleClassFilter() { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       return setPropertyFlag(PropertyFlag.SILENT_RULECLASS_FILTER, "silent_ruleclass_filter"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Skip analysis time filetype check. Don't use it if avoidable. | 
 |      */ | 
 |     public Builder<TYPE> skipAnalysisTimeFileTypeCheck() { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       return setPropertyFlag(PropertyFlag.SKIP_ANALYSIS_TIME_FILETYPE_CHECK, | 
 |           "skip_analysis_time_filetype_check"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Mark the built attribute as order-independent. | 
 |      */ | 
 |     public Builder<TYPE> orderIndependent() { | 
 |       Preconditions.checkNotNull(type.getListElementType(), "attribute '%s' must be a list", name); | 
 |       return setPropertyFlag(PropertyFlag.ORDER_INDEPENDENT, "order-independent"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Mark the built attribute as to use output_licenses for license checking. | 
 |      */ | 
 |     public Builder<TYPE> useOutputLicenses() { | 
 |       Preconditions.checkState(BuildType.isLabelType(type), "must be a label type"); | 
 |       return setPropertyFlag(PropertyFlag.OUTPUT_LICENSES, "output_license"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Defines the configuration transition for this attribute. | 
 |      */ | 
 |     public Builder<TYPE> cfg(SplitTransitionProvider splitTransitionProvider) { | 
 |       Preconditions.checkState(this.configTransition == ConfigurationTransition.NONE, | 
 |           "the configuration transition is already set"); | 
 |  | 
 |       this.splitTransitionProvider = Preconditions.checkNotNull(splitTransitionProvider); | 
 |       this.configTransition = ConfigurationTransition.SPLIT; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Defines the configuration transition for this attribute. Defaults to | 
 |      * {@code NONE}. | 
 |      */ | 
 |     public Builder<TYPE> cfg(SplitTransition<?> configTransition) { | 
 |       return cfg(new BasicSplitTransitionProvider(Preconditions.checkNotNull(configTransition))); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Defines the configuration transition for this attribute. Defaults to | 
 |      * {@code NONE}. | 
 |      */ | 
 |     public Builder<TYPE> cfg(Transition configTransition) { | 
 |       Preconditions.checkState(this.configTransition == ConfigurationTransition.NONE, | 
 |           "the configuration transition is already set"); | 
 |       Preconditions.checkArgument(configTransition != ConfigurationTransition.SPLIT, | 
 |           "split transitions must be defined using the SplitTransition object"); | 
 |       if (configTransition instanceof SplitTransition) { | 
 |         return cfg((SplitTransition<?>) configTransition); | 
 |       } else { | 
 |         this.configTransition = configTransition; | 
 |         return this; | 
 |       } | 
 |     } | 
 |  | 
 |     public Builder<TYPE> cfg(Configurator<?, ?> configurator) { | 
 |       this.configurator = configurator; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Requires the attribute target to be executable; only for label or label | 
 |      * list attributes. Defaults to {@code false}. | 
 |      */ | 
 |     public Builder<TYPE> exec() { | 
 |       return setPropertyFlag(PropertyFlag.EXECUTABLE, "executable"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Indicates that the attribute (like srcs or hdrs) should be used as an input when calculating | 
 |      * compile_one_dependency. | 
 |      */ | 
 |     public Builder<TYPE> direct_compile_time_input() { | 
 |       return setPropertyFlag(PropertyFlag.DIRECT_COMPILE_TIME_INPUT, | 
 |                              "direct_compile_time_input"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Makes the built attribute undocumented. | 
 |      * | 
 |      * @param reason explanation why the attribute is undocumented. This is not | 
 |      *        used but required for documentation | 
 |      */ | 
 |     public Builder<TYPE> undocumented(String reason) { | 
 |       return setPropertyFlag(PropertyFlag.UNDOCUMENTED, "undocumented"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the attribute default value. The type of the default value must | 
 |      * match the type parameter. (e.g. list=[], integer=0, string="", | 
 |      * label=null). The {@code defaultValue} must be immutable. | 
 |      * | 
 |      * <p>If defaultValue is of type Label and is a target, that target will | 
 |      * become an implicit dependency of the Rule; we will load the target | 
 |      * (and its dependencies) if it encounters the Rule and build the target | 
 |      * if needs to apply the Rule. | 
 |      */ | 
 |     public Builder<TYPE> value(TYPE defaultValue) { | 
 |       Preconditions.checkState(!valueSet, "the default value is already set"); | 
 |       value = defaultValue; | 
 |       valueSet = true; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * See value(TYPE) above. This method is only meant for Skylark usage. | 
 |      * | 
 |      * <p>The parameter {@code context} is relevant iff the default value is a Label string. | 
 |      * In this case, {@code context} must point to the parent Label in order to be able to convert | 
 |      * the default value string to a proper Label. | 
 |      */ | 
 |     public Builder<TYPE> defaultValue(Object defaultValue, Object context) | 
 |         throws ConversionException { | 
 |       Preconditions.checkState(!valueSet, "the default value is already set"); | 
 |       value = type.convert(defaultValue, "attribute " + name, context); | 
 |       valueSet = true; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** See value(TYPE) above. This method is only meant for Skylark usage. */ | 
 |     public Builder<TYPE> defaultValue(Object defaultValue) throws ConversionException { | 
 |       return defaultValue(defaultValue, null); | 
 |     } | 
 |  | 
 |     public boolean isValueSet() { | 
 |       return valueSet; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the attribute default value to a computed default value - use this when the default | 
 |      * value is a function of other attributes of the Rule. The type of the computed default value | 
 |      * for a mandatory attribute must match the type parameter: (e.g. list=[], integer=0, string="", | 
 |      * label=null). The {@code defaultValue} implementation must be immutable. | 
 |      * | 
 |      * <p>If the computed default returns a Label that is a target, that target will become an | 
 |      * implicit dependency of this Rule; we will load the target (and its dependencies) if it | 
 |      * encounters the Rule and build the target if needs to apply the Rule. | 
 |      */ | 
 |     public Builder<TYPE> value(ComputedDefault defaultValue) { | 
 |       Preconditions.checkState(!valueSet, "the default value is already set"); | 
 |       value = defaultValue; | 
 |       valueSource = AttributeValueSource.COMPUTED_DEFAULT; | 
 |       valueSet = true; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the attribute default value to a Skylark computed default template. Like a native | 
 |      * Computed Default, this allows a Skylark-defined Rule Class to specify that the default value | 
 |      * of an attribute is a function of other attributes of the Rule. | 
 |      * | 
 |      * <p>During the loading phase, the computed default template will be specialized for each rule | 
 |      * it applies to. Those rules' attribute values will not be references to {@link | 
 |      * SkylarkComputedDefaultTemplate}s, but instead will be references to {@link | 
 |      * SkylarkComputedDefault}s. | 
 |      * | 
 |      * <p>If the computed default returns a Label that is a target, that target will become an | 
 |      * implicit dependency of this Rule; we will load the target (and its dependencies) if it | 
 |      * encounters the Rule and build the target if needs to apply the Rule. | 
 |      */ | 
 |     public Builder<TYPE> value(SkylarkComputedDefaultTemplate skylarkComputedDefaultTemplate) { | 
 |       Preconditions.checkState(!valueSet, "the default value is already set"); | 
 |       value = skylarkComputedDefaultTemplate; | 
 |       valueSource = AttributeValueSource.COMPUTED_DEFAULT; | 
 |       valueSet = true; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the attribute default value to be late-bound, i.e., it is derived from the build | 
 |      * configuration. | 
 |      */ | 
 |     public Builder<TYPE> value(LateBoundDefault<?> defaultValue) { | 
 |       Preconditions.checkState(!valueSet, "the default value is already set"); | 
 |       Preconditions.checkState(name.isEmpty() || isLateBound(name)); | 
 |       value = defaultValue; | 
 |       valueSource = AttributeValueSource.LATE_BOUND; | 
 |       valueSet = true; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Returns where the value of this attribute comes from. Useful only for Skylark. | 
 |      */ | 
 |     public AttributeValueSource getValueSource() { | 
 |       return valueSource; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets a condition predicate. The default value of the attribute only applies if the condition | 
 |      * evaluates to true. If the value is explicitly provided, then this condition is ignored. | 
 |      * | 
 |      * <p>The condition is only evaluated if the attribute is not explicitly set, and after all | 
 |      * explicit attributes have been set. It can generally not access default values of other | 
 |      * attributes. | 
 |      */ | 
 |     public Builder<TYPE> condition(Predicate<AttributeMap> condition) { | 
 |       Preconditions.checkState(this.condition == null, "the condition is already set"); | 
 |       this.condition = condition; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Switches on the capability of an attribute to be published to the rule's | 
 |      * tag set. | 
 |      */ | 
 |     public Builder<TYPE> taggable() { | 
 |       return setPropertyFlag(PropertyFlag.TAGGABLE, "taggable"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Disables dependency checks done by | 
 |      * {@link com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.PrerequisiteValidator}. | 
 |      */ | 
 |     public Builder<TYPE> skipPrereqValidatorCheck() { | 
 |       return setPropertyFlag(PropertyFlag.SKIP_PREREQ_VALIDATOR_CHECKS, | 
 |           "skip_prereq_validator_checks"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Enforces constraint checking on this attribute even if default enforcement policy would skip | 
 |      * it. If default policy checks the attribute, this is a no-op. | 
 |      * | 
 |      * <p>Most attributes are enforced by default, so in the common case this call is unnecessary. | 
 |      * | 
 |      * <p>See {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics#getConstraintCheckedDependencies} | 
 |      * for enforcement policy details. | 
 |      */ | 
 |     public Builder<TYPE> checkConstraints() { | 
 |       Verify.verify(!propertyFlags.contains(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE), | 
 |           "constraint checking is already overridden to be skipped"); | 
 |       return setPropertyFlag(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE, "check_constraints"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Skips constraint checking on this attribute even if default enforcement policy would check | 
 |      * it. If default policy skips the attribute, this is a no-op. | 
 |      * | 
 |      * <p>See {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics#getConstraintCheckedDependencies} | 
 |      * for enforcement policy details. | 
 |      */ | 
 |     public Builder<TYPE> dontCheckConstraints() { | 
 |       Verify.verify(!propertyFlags.contains(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE), | 
 |           "constraint checking is already overridden to be checked"); | 
 |       return setPropertyFlag(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE, "dont_check_constraints"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * rule types for the labels occurring in the attribute. If the attribute | 
 |      * contains Labels of any other rule type, then an error is produced during | 
 |      * the analysis phase. Defaults to allow any types. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedRuleClasses(Iterable<String> allowedRuleClasses) { | 
 |       return allowedRuleClasses( | 
 |           new RuleClass.Builder.RuleClassNamePredicate(allowedRuleClasses)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * rule types for the labels occurring in the attribute. If the attribute | 
 |      * contains Labels of any other rule type, then an error is produced during | 
 |      * the analysis phase. Defaults to allow any types. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedRuleClasses(Predicate<RuleClass> allowedRuleClasses) { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING); | 
 |       allowedRuleClassesForLabels = allowedRuleClasses; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * rule types for the labels occurring in the attribute. If the attribute | 
 |      * contains Labels of any other rule type, then an error is produced during | 
 |      * the analysis phase. Defaults to allow any types. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedRuleClasses(String... allowedRuleClasses) { | 
 |       return allowedRuleClasses(ImmutableSet.copyOf(allowedRuleClasses)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * file types for file labels occurring in the attribute. If the attribute | 
 |      * contains labels that correspond to files of any other type, then an error | 
 |      * is produced during the analysis phase. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedFileTypes(FileTypeSet allowedFileTypes) { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING); | 
 |       allowedFileTypesForLabels = Preconditions.checkNotNull(allowedFileTypes); | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Allow all files for legacy compatibility. All uses of this method should be audited and then | 
 |      * removed. In some cases, it's correct to allow any file, but mostly the set of files should be | 
 |      * restricted to a reasonable set. | 
 |      */ | 
 |     public Builder<TYPE> legacyAllowAnyFileType() { | 
 |       return allowedFileTypes(FileTypeSet.ANY_FILE); | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * file types for file labels occurring in the attribute. If the attribute | 
 |      * contains labels that correspond to files of any other type, then an error | 
 |      * is produced during the analysis phase. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedFileTypes(FileType... allowedFileTypes) { | 
 |       return allowedFileTypes(FileTypeSet.of(allowedFileTypes)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * rule types with warning for the labels occurring in the attribute. If the attribute | 
 |      * contains Labels of any other rule type (other than this or those set in | 
 |      * allowedRuleClasses()), then a warning is produced during | 
 |      * the analysis phase. Defaults to deny any types. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedRuleClassesWithWarning(Collection<String> allowedRuleClasses) { | 
 |       return allowedRuleClassesWithWarning( | 
 |           new RuleClass.Builder.RuleClassNamePredicate(allowedRuleClasses)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * rule types for the labels occurring in the attribute. If the attribute | 
 |      * contains Labels of any other rule type (other than this or those set in | 
 |      * allowedRuleClasses()), then a warning is produced during | 
 |      * the analysis phase. Defaults to deny any types. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedRuleClassesWithWarning(Predicate<RuleClass> allowedRuleClasses) { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING); | 
 |       allowedRuleClassesForLabelsWarning = allowedRuleClasses; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * If this is a label or label-list attribute, then this sets the allowed | 
 |      * rule types for the labels occurring in the attribute. If the attribute | 
 |      * contains Labels of any other rule type (other than this or those set in | 
 |      * allowedRuleClasses()), then a warning is produced during | 
 |      * the analysis phase. Defaults to deny any types. | 
 |      * | 
 |      * <p>This only works on a per-target basis, not on a per-file basis; with | 
 |      * other words, it works for 'deps' attributes, but not 'srcs' attributes. | 
 |      */ | 
 |     public Builder<TYPE> allowedRuleClassesWithWarning(String... allowedRuleClasses) { | 
 |       return allowedRuleClassesWithWarning(ImmutableSet.copyOf(allowedRuleClasses)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets a list of lists of mandatory native providers. Every configured target occurring in this | 
 |      * label type attribute has to provide all the providers from one of those lists, otherwise an | 
 |      * error is produced during the analysis phase. | 
 |      */ | 
 |     public final Builder<TYPE> mandatoryNativeProvidersList( | 
 |         Iterable<? extends Iterable<Class<? extends TransitiveInfoProvider>>> providersList) { | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       ImmutableList.Builder<ImmutableList<Class<? extends TransitiveInfoProvider>>> listBuilder | 
 |           = ImmutableList.builder(); | 
 |       for (Iterable<Class<? extends TransitiveInfoProvider>> providers : providersList) { | 
 |         listBuilder.add(ImmutableList.<Class<? extends TransitiveInfoProvider>>copyOf(providers)); | 
 |       } | 
 |       this.mandatoryNativeProvidersList = listBuilder.build(); | 
 |       return this; | 
 |     } | 
 |  | 
 |     public Builder<TYPE> mandatoryNativeProviders( | 
 |         Iterable<Class<? extends TransitiveInfoProvider>> providers) { | 
 |       if (providers.iterator().hasNext()) { | 
 |         mandatoryNativeProvidersList(ImmutableList.of(providers)); | 
 |       } | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets a list of sets of mandatory Skylark providers. Every configured target occurring in | 
 |      * this label type attribute has to provide all the providers from one of those sets, | 
 |      * or be one of {@link #allowedRuleClasses}, otherwise an error is produced during | 
 |      * the analysis phase. | 
 |      */ | 
 |     public Builder<TYPE> mandatoryProvidersList( | 
 |         Iterable<? extends Iterable<SkylarkProviderIdentifier>> providersList){ | 
 |       Preconditions.checkState((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST), | 
 |           "must be a label-valued type"); | 
 |       ImmutableList.Builder<ImmutableSet<SkylarkProviderIdentifier>> listBuilder | 
 |           = ImmutableList.builder(); | 
 |       for (Iterable<SkylarkProviderIdentifier> providers : providersList) { | 
 |         listBuilder.add(ImmutableSet.copyOf(providers)); | 
 |       } | 
 |       this.mandatoryProvidersList = listBuilder.build(); | 
 |       return this; | 
 |     } | 
 |  | 
 |     public Builder<TYPE> legacyMandatoryProviders(String... ids) { | 
 |       return mandatoryProviders( | 
 |           Iterables.transform(Arrays.asList(ids), | 
 |               new Function<String, SkylarkProviderIdentifier>() { | 
 |         @Override | 
 |         public SkylarkProviderIdentifier apply(String s) { | 
 |           Preconditions.checkNotNull(s); | 
 |           return SkylarkProviderIdentifier.forLegacy(s); | 
 |         } | 
 |       })); | 
 |     } | 
 |  | 
 |     public Builder<TYPE> mandatoryProviders(Iterable<SkylarkProviderIdentifier> providers) { | 
 |       if (providers.iterator().hasNext()) { | 
 |         mandatoryProvidersList(ImmutableList.of(providers)); | 
 |       } | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Asserts that a particular parameterized aspect probably needs to be computed for all direct | 
 |      * dependencies through this attribute. | 
 |      * | 
 |      * @param evaluator function that extracts aspect parameters from rule. | 
 |      */ | 
 |     public Builder<TYPE> aspect( | 
 |         NativeAspectClass aspect, Function<Rule, AspectParameters> evaluator) { | 
 |       NativeRuleAspect nativeRuleAspect = new NativeRuleAspect(aspect, evaluator); | 
 |       RuleAspect<?> oldAspect = this.aspects.put(nativeRuleAspect.getName(), nativeRuleAspect); | 
 |       if (oldAspect != null) { | 
 |         throw new AssertionError( | 
 |             String.format("Aspect %s has already been added", oldAspect.getName())); | 
 |       } | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Asserts that a particular parameterized aspect probably needs to be computed for all direct | 
 |      * dependencies through this attribute. | 
 |      */ | 
 |     public Builder<TYPE> aspect(NativeAspectClass aspect) { | 
 |       Function<Rule, AspectParameters> noParameters = | 
 |           new Function<Rule, AspectParameters>() { | 
 |             @Override | 
 |             public AspectParameters apply(Rule input) { | 
 |               return AspectParameters.EMPTY; | 
 |             } | 
 |           }; | 
 |       return this.aspect(aspect, noParameters); | 
 |     } | 
 |  | 
 |     public Builder<TYPE> aspect( | 
 |         SkylarkAspect skylarkAspect, Location location) throws EvalException { | 
 |       SkylarkRuleAspect skylarkRuleAspect = new SkylarkRuleAspect(skylarkAspect); | 
 |       RuleAspect<?> oldAspect = this.aspects.put(skylarkAspect.getName(), skylarkRuleAspect); | 
 |       if (oldAspect != null) { | 
 |         throw new EvalException( | 
 |             location, String.format("aspect %s added more than once", skylarkAspect.getName())); | 
 |       } | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Should only be used for deserialization. | 
 |      */ | 
 |     public Builder<TYPE> aspect(final Aspect aspect) { | 
 |       PredefinedRuleAspect predefinedRuleAspect = new PredefinedRuleAspect(aspect); | 
 |       RuleAspect<?> oldAspect = | 
 |           this.aspects.put(predefinedRuleAspect.getName(), predefinedRuleAspect); | 
 |       if (oldAspect != null) { | 
 |         throw new AssertionError( | 
 |             String.format("Aspect %s has already been added", oldAspect.getName())); | 
 |       } | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Sets the predicate-like edge validity checker. | 
 |      */ | 
 |     public Builder<TYPE> validityPredicate(ValidityPredicate validityPredicate) { | 
 |       propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING); | 
 |       this.validityPredicate = validityPredicate; | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * The value of the attribute must be one of allowedValues. | 
 |      */ | 
 |     public Builder<TYPE> allowedValues(PredicateWithMessage<Object> allowedValues) { | 
 |       this.allowedValues = allowedValues; | 
 |       propertyFlags.add(PropertyFlag.CHECK_ALLOWED_VALUES); | 
 |       return this; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Makes the built attribute "non-configurable", i.e. its value cannot be influenced by | 
 |      * the build configuration. Attributes are "configurable" unless explicitly opted out here. | 
 |      * | 
 |      * <p>Non-configurability indicates an exceptional state: there exists Blaze logic that needs | 
 |      * the attribute's value, has no access to configurations, and can't apply a workaround | 
 |      * through an appropriate {@link AbstractAttributeMapper} implementation. Scenarios like | 
 |      * this should be as uncommon as possible, so it's important we maintain clear documentation | 
 |      * on what causes them and why users consequently can't configure certain attributes. | 
 |      * | 
 |      * @param reason why this attribute can't be configurable. This isn't used by Blaze - it's | 
 |      *    solely a documentation mechanism. | 
 |      */ | 
 |     public Builder<TYPE> nonconfigurable(String reason) { | 
 |       Preconditions.checkState(!reason.isEmpty()); | 
 |       return setPropertyFlag(PropertyFlag.NONCONFIGURABLE, "nonconfigurable"); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Creates the attribute. Uses name, type, optionality, configuration type | 
 |      * and the default value configured by the builder. | 
 |      */ | 
 |     public Attribute build() { | 
 |       return build(this.name); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Creates the attribute. Uses type, optionality, configuration type | 
 |      * and the default value configured by the builder. Use the name | 
 |      * passed as an argument. This function is used by Skylark where the | 
 |      * name is provided only when we build. We don't want to modify the | 
 |      * builder, as it is shared in a multithreaded environment. | 
 |      */ | 
 |     public Attribute build(String name) { | 
 |       Preconditions.checkState(!name.isEmpty(), "name has not been set"); | 
 |       // TODO(bazel-team): Set the default to be no file type, then remove this check, and also | 
 |       // remove all allowedFileTypes() calls without parameters. | 
 |  | 
 |       // do not modify this.allowedFileTypesForLabels, instead create a copy. | 
 |       FileTypeSet allowedFileTypesForLabels = this.allowedFileTypesForLabels; | 
 |       if ((type == BuildType.LABEL) || (type == BuildType.LABEL_LIST)) { | 
 |         if (isPrivateAttribute(name) && allowedFileTypesForLabels == null) { | 
 |           allowedFileTypesForLabels = FileTypeSet.ANY_FILE; | 
 |         } | 
 |         Preconditions.checkNotNull( | 
 |             allowedFileTypesForLabels, "allowedFileTypesForLabels not set for %s", name); | 
 |       } else if ((type == BuildType.OUTPUT) || (type == BuildType.OUTPUT_LIST)) { | 
 |         // TODO(bazel-team): Set the default to no file type and make explicit calls instead. | 
 |         if (allowedFileTypesForLabels == null) { | 
 |           allowedFileTypesForLabels = FileTypeSet.ANY_FILE; | 
 |         } | 
 |       } | 
 |       return new Attribute( | 
 |           name, | 
 |           type, | 
 |           Sets.immutableEnumSet(propertyFlags), | 
 |           valueSet ? value : type.getDefaultValue(), | 
 |           configTransition, | 
 |           configurator, | 
 |           splitTransitionProvider, | 
 |           allowedRuleClassesForLabels, | 
 |           allowedRuleClassesForLabelsWarning, | 
 |           allowedFileTypesForLabels, | 
 |           validityPredicate, | 
 |           condition, | 
 |           allowedValues, | 
 |           mandatoryProvidersList, | 
 |           mandatoryNativeProvidersList, | 
 |           ImmutableList.copyOf(aspects.values())); | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * A strategy for dealing with too many computations, used when creating lookup tables for {@link | 
 |    * ComputedDefault}s. | 
 |    * | 
 |    * @param <TException> The type of exception this strategy throws if too many computations are | 
 |    *     attempted. | 
 |    */ | 
 |   interface ComputationLimiter<TException extends Exception> { | 
 |     void onComputationCount(int count) throws TException; | 
 |   } | 
 |  | 
 |   /** | 
 |    * An implementation of {@link ComputationLimiter} that never throws. For use with | 
 |    * natively-defined {@link ComputedDefault}s, which are limited in the number of configurable | 
 |    * attributes they depend on, not on the number of different combinations of possible inputs. | 
 |    */ | 
 |   private static final ComputationLimiter<RuntimeException> NULL_COMPUTATION_LIMITER = | 
 |       new ComputationLimiter<RuntimeException>() { | 
 |         @Override | 
 |         public void onComputationCount(int count) throws RuntimeException {} | 
 |       }; | 
 |  | 
 |   /** Exception for computed default attributes that depend on too many configurable attributes. */ | 
 |   private static class TooManyConfigurableAttributesException extends Exception { | 
 |     TooManyConfigurableAttributesException(int max) { | 
 |       super( | 
 |           String.format( | 
 |               "Too many configurable attributes to compute all possible values: " | 
 |                   + "Found more than %d possible values.", | 
 |               max)); | 
 |     } | 
 |   } | 
 |  | 
 |   private static class FixedComputationLimiter | 
 |       implements ComputationLimiter<TooManyConfigurableAttributesException> { | 
 |  | 
 |     /** Upper bound of the number of combinations of values for a computed default attribute. */ | 
 |     private static final int COMPUTED_DEFAULT_MAX_COMBINATIONS = 64; | 
 |  | 
 |     private static final FixedComputationLimiter INSTANCE = new FixedComputationLimiter(); | 
 |  | 
 |     @Override | 
 |     public void onComputationCount(int count) throws TooManyConfigurableAttributesException { | 
 |       if (count > COMPUTED_DEFAULT_MAX_COMBINATIONS) { | 
 |         throw new TooManyConfigurableAttributesException(COMPUTED_DEFAULT_MAX_COMBINATIONS); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * Specifies how values of {@link ComputedDefault} attributes are computed based on the values of | 
 |    * other attributes. | 
 |    * | 
 |    * <p>The {@code TComputeException} type parameter allows the two specializations of this class to | 
 |    * describe whether and how their computations throw. For natively defined computed defaults, | 
 |    * computation does not throw, but for Skylark-defined computed defaults, computation may throw | 
 |    * {@link InterruptedException}. | 
 |    */ | 
 |   private abstract static class ComputationStrategy<TComputeException extends Exception> { | 
 |     abstract Object compute(AttributeMap map) throws TComputeException; | 
 |  | 
 |     /** | 
 |      * Returns a lookup table mapping from: | 
 |      * | 
 |      * <ul> | 
 |      * <li>tuples of values that may be assigned by {@code rule} to attributes with names in {@code | 
 |      *     dependencies} (note that there may be more than one such tuple for any given rule, if any | 
 |      *     of the dependencies are configurable) | 
 |      * </ul> | 
 |      * | 
 |      * <p>to: | 
 |      * | 
 |      * <ul> | 
 |      * <li>the value {@link #compute(AttributeMap)} evaluates to when the provided {@link | 
 |      *     AttributeMap} contains the values specified by that assignment, or {@code null} if the | 
 |      *     {@link ComputationStrategy} failed to evaluate. | 
 |      * </ul> | 
 |      * | 
 |      * <p>The lookup table contains a tuple for each possible assignment to the {@code dependencies} | 
 |      * attributes. The meaning of each tuple is well-defined because {@code dependencies} is | 
 |      * ordered. | 
 |      * | 
 |      * <p>This is useful because configurable attributes may have many possible values. During the | 
 |      * loading phase a configurable attribute can't be resolved to a single value. Configuration | 
 |      * information, needed to resolve such an attribute, is only available during analysis. However, | 
 |      * any labels that a ComputedDefault attribute may evaluate to must be loaded during the loading | 
 |      * phase. | 
 |      */ | 
 |     <T, TLimitException extends Exception> Map<List<Object>, T> computeValuesForAllCombinations( | 
 |         List<String> dependencies, | 
 |         Type<T> type, | 
 |         Rule rule, | 
 |         ComputationLimiter<TLimitException> limiter) | 
 |         throws TComputeException, TLimitException { | 
 |       // This will hold every (value1, value2, ..) combination of the declared dependencies. | 
 |       // Collect those combinations. | 
 |       AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule); | 
 |       List<Map<String, Object>> depMaps = mapper.visitAttributes(dependencies, limiter); | 
 |       // For each combination, call compute() on a specialized AttributeMap providing those | 
 |       // values. | 
 |       Map<List<Object>, T> valueMap = new HashMap<>(depMaps.size()); | 
 |       for (Map<String, Object> depMap : depMaps) { | 
 |         AttributeMap attrMap = mapper.createMapBackedAttributeMap(depMap); | 
 |         Object value = compute(attrMap); | 
 |         List<Object> key = createDependencyAssignmentTuple(dependencies, attrMap); | 
 |         valueMap.put(key, type.cast(value)); | 
 |       } | 
 |       return valueMap; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Given an {@link AttributeMap}, containing an assignment to each attribute in {@code | 
 |      * dependencies}, this returns a list of the assigned values, ordered as {@code dependencies} is | 
 |      * ordered. | 
 |      */ | 
 |     static List<Object> createDependencyAssignmentTuple( | 
 |         List<String> dependencies, AttributeMap attrMap) { | 
 |       ArrayList<Object> tuple = new ArrayList<>(dependencies.size()); | 
 |       for (String attrName : dependencies) { | 
 |         Type<?> attrType = attrMap.getAttributeType(attrName); | 
 |         tuple.add(attrMap.get(attrName, attrType)); | 
 |       } | 
 |       return tuple; | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * A computed default is a default value for a Rule attribute that is a function of other | 
 |    * attributes of the rule. | 
 |    * | 
 |    * <p>Attributes whose defaults are computed are first initialized to the default for their type, | 
 |    * and then the computed defaults are evaluated after all non-computed defaults have been | 
 |    * initialized. There is no defined order among computed defaults, so they must not depend on each | 
 |    * other. | 
 |    * | 
 |    * <p>If a computed default reads the value of another attribute, at least one of the following | 
 |    * must be true: | 
 |    * | 
 |    * <ol> | 
 |    * <li>The other attribute must be declared in the computed default's constructor | 
 |    * <li>The other attribute must be non-configurable ({@link Builder#nonconfigurable} | 
 |    * </ol> | 
 |    * | 
 |    * <p>The reason for enforced declarations is that, since attribute values might be configurable, | 
 |    * a computed default that depends on them may itself take multiple values. Since we have no | 
 |    * access to a target's configuration at the time these values are computed, we need the ability | 
 |    * to probe the default's *complete* dependency space. Declared dependencies allow us to do so | 
 |    * sanely. Non-configurable attributes don't have this problem because their value is fixed and | 
 |    * known even without configuration information. | 
 |    * | 
 |    * <p>Implementations of this interface must be immutable. | 
 |    */ | 
 |   public abstract static class ComputedDefault { | 
 |     private final ImmutableList<String> dependencies; | 
 |  | 
 |     /** | 
 |      * Create a computed default that can read all non-configurable attribute values and no | 
 |      * configurable attribute values. | 
 |      */ | 
 |     public ComputedDefault() { | 
 |       this(ImmutableList.<String>of()); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Create a computed default that can read all non-configurable attributes values and one | 
 |      * explicitly specified configurable attribute value | 
 |      */ | 
 |     public ComputedDefault(String depAttribute) { | 
 |       this(ImmutableList.of(depAttribute)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Create a computed default that can read all non-configurable attributes values and two | 
 |      * explicitly specified configurable attribute values. | 
 |      */ | 
 |     public ComputedDefault(String depAttribute1, String depAttribute2) { | 
 |       this(ImmutableList.of(depAttribute1, depAttribute2)); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Creates a computed default that can read all non-configurable attributes and some explicitly | 
 |      * specified configurable attribute values. | 
 |      * | 
 |      * <p>This constructor should not be used by native {@link ComputedDefault} functions. The limit | 
 |      * of at-most-two depended-on configurable attributes is intended, to limit the exponential | 
 |      * growth of possible values. {@link SkylarkComputedDefault} uses this, but is limited by {@link | 
 |      * FixedComputationLimiter#COMPUTED_DEFAULT_MAX_COMBINATIONS}. | 
 |      */ | 
 |     protected ComputedDefault(ImmutableList<String> dependencies) { | 
 |       // Order is important for #createDependencyAssignmentTuple. | 
 |       this.dependencies = Ordering.natural().immutableSortedCopy(dependencies); | 
 |     } | 
 |  | 
 |     <T> Iterable<T> getPossibleValues(Type<T> type, Rule rule) { | 
 |       final ComputedDefault owner = ComputedDefault.this; | 
 |       ComputationStrategy<RuntimeException> strategy = | 
 |           new ComputationStrategy<RuntimeException>() { | 
 |             @Override | 
 |             public Object compute(AttributeMap map) { | 
 |               return owner.getDefault(map); | 
 |             } | 
 |           }; | 
 |       // Note that this uses ArrayList instead of something like ImmutableList because some | 
 |       // values may be null. | 
 |       return new ArrayList<>( | 
 |           strategy | 
 |               .computeValuesForAllCombinations(dependencies, type, rule, NULL_COMPUTATION_LIMITER) | 
 |               .values()); | 
 |     } | 
 |  | 
 |     /** The list of configurable attributes this ComputedDefault declares it may read. */ | 
 |     public ImmutableList<String> dependencies() { | 
 |       return dependencies; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Returns the value this {@link ComputedDefault} evaluates to, given the inputs contained in | 
 |      * {@code rule}. | 
 |      */ | 
 |     public abstract Object getDefault(AttributeMap rule); | 
 |   } | 
 |  | 
 |   /** | 
 |    * A Skylark-defined computed default, which can be precomputed for a specific {@link Rule} by | 
 |    * calling {@link #computePossibleValues}, which returns a {@link SkylarkComputedDefault} that | 
 |    * contains a lookup table. | 
 |    */ | 
 |   public static final class SkylarkComputedDefaultTemplate { | 
 |     private final Type<?> type; | 
 |     private final SkylarkCallbackFunction callback; | 
 |     private final Location location; | 
 |     private final ImmutableList<String> dependencies; | 
 |  | 
 |     /** | 
 |      * Creates a new SkylarkComputedDefaultTemplate that allows the computation of attribute values | 
 |      * via a callback function during loading phase. | 
 |      * | 
 |      * @param type The type of the value of this attribute. | 
 |      * @param dependencies A list of all names of other attributes that are accessed by this | 
 |      *     attribute. | 
 |      * @param callback A function to compute the actual attribute value. | 
 |      * @param location The location of the Skylark function. | 
 |      */ | 
 |     public SkylarkComputedDefaultTemplate( | 
 |         Type<?> type, | 
 |         ImmutableList<String> dependencies, | 
 |         SkylarkCallbackFunction callback, | 
 |         Location location) { | 
 |       this.type = Preconditions.checkNotNull(type); | 
 |       // Order is important for #createDependencyAssignmentTuple. | 
 |       this.dependencies = | 
 |           Ordering.natural().immutableSortedCopy(Preconditions.checkNotNull(dependencies)); | 
 |       this.callback = Preconditions.checkNotNull(callback); | 
 |       this.location = Preconditions.checkNotNull(location); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Returns a {@link SkylarkComputedDefault} containing a lookup table specifying the output of | 
 |      * this {@link SkylarkComputedDefaultTemplate}'s callback given each possible assignment {@code | 
 |      * rule} might make to the attributes specified by {@link #dependencies}. | 
 |      * | 
 |      * <p>If the rule is missing an attribute specified by {@link #dependencies}, or if there are | 
 |      * too many possible assignments, or if any evaluation fails, this throws {@link | 
 |      * CannotPrecomputeDefaultsException}. | 
 |      * | 
 |      * <p>May only be called after all non-{@link ComputedDefault} attributes have been set on the | 
 |      * {@code rule}. | 
 |      */ | 
 |     SkylarkComputedDefault computePossibleValues( | 
 |         Attribute attr, final Rule rule, final EventHandler eventHandler) | 
 |         throws InterruptedException, CannotPrecomputeDefaultsException { | 
 |  | 
 |       final SkylarkComputedDefaultTemplate owner = SkylarkComputedDefaultTemplate.this; | 
 |       final String msg = | 
 |           String.format( | 
 |               "Cannot compute default value of attribute '%s' in rule '%s': ", | 
 |               attr.getPublicName(), rule.getLabel()); | 
 |       final AtomicReference<EvalException> caughtEvalExceptionIfAny = new AtomicReference<>(); | 
 |       ComputationStrategy<InterruptedException> strategy = | 
 |           new ComputationStrategy<InterruptedException>() { | 
 |             @Override | 
 |             public Object compute(AttributeMap map) throws InterruptedException { | 
 |               try { | 
 |                 return owner.computeValue(map); | 
 |               } catch (EvalException ex) { | 
 |                 caughtEvalExceptionIfAny.compareAndSet(null, ex); | 
 |                 return null; | 
 |               } | 
 |             } | 
 |           }; | 
 |  | 
 |       ImmutableList.Builder<Type<?>> dependencyTypesBuilder = ImmutableList.builder(); | 
 |       Map<List<Object>, Object> lookupTable = new HashMap<>(); | 
 |       try { | 
 |         for (String dependency : dependencies) { | 
 |           Attribute attribute = rule.getRuleClassObject().getAttributeByNameMaybe(dependency); | 
 |           if (attribute == null) { | 
 |             throw new AttributeNotFoundException( | 
 |                 String.format("No such attribute %s in rule %s", dependency, rule.getLabel())); | 
 |           } | 
 |           dependencyTypesBuilder.add(attribute.getType()); | 
 |         } | 
 |         lookupTable.putAll( | 
 |             strategy.computeValuesForAllCombinations( | 
 |                 dependencies, attr.getType(), rule, FixedComputationLimiter.INSTANCE)); | 
 |         if (caughtEvalExceptionIfAny.get() != null) { | 
 |           throw caughtEvalExceptionIfAny.get(); | 
 |         } | 
 |       } catch (AttributeNotFoundException | 
 |           | TooManyConfigurableAttributesException | 
 |           | EvalException ex) { | 
 |         String error = msg + ex.getMessage(); | 
 |         rule.reportError(error, eventHandler); | 
 |         throw new CannotPrecomputeDefaultsException(error); | 
 |       } | 
 |       return new SkylarkComputedDefault(dependencies, dependencyTypesBuilder.build(), lookupTable); | 
 |     } | 
 |  | 
 |     private Object computeValue(AttributeMap rule) throws EvalException, InterruptedException { | 
 |       Map<String, Object> attrValues = new HashMap<>(); | 
 |       for (String attrName : rule.getAttributeNames()) { | 
 |         Attribute attr = rule.getAttributeDefinition(attrName); | 
 |         if (!attr.hasComputedDefault()) { | 
 |           Object value = rule.get(attrName, attr.getType()); | 
 |           if (!EvalUtils.isNullOrNone(value)) { | 
 |             attrValues.put(attr.getName(), value); | 
 |           } | 
 |         } | 
 |       } | 
 |       return invokeCallback(attrValues); | 
 |     } | 
 |  | 
 |     private Object invokeCallback(Map<String, Object> attrValues) | 
 |         throws EvalException, InterruptedException { | 
 |       ClassObject attrs = | 
 |           SkylarkClassObjectConstructor.STRUCT.create( | 
 |               attrValues, "No such regular (non computed) attribute '%s'."); | 
 |       Object result = callback.call(attrs); | 
 |       try { | 
 |         return type.cast((result == Runtime.NONE) ? type.getDefaultValue() : result); | 
 |       } catch (ClassCastException ex) { | 
 |         throw new EvalException( | 
 |             location, | 
 |             String.format( | 
 |                 "expected '%s', but got '%s'", type, EvalUtils.getDataTypeName(result, true))); | 
 |       } | 
 |     } | 
 |  | 
 |     private static class AttributeNotFoundException extends Exception { | 
 |       private AttributeNotFoundException(String message) { | 
 |         super(message); | 
 |       } | 
 |     } | 
 |  | 
 |     static class CannotPrecomputeDefaultsException extends Exception { | 
 |       private CannotPrecomputeDefaultsException(String message) { | 
 |         super(message); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * A class for computed attributes defined in Skylark. | 
 |    * | 
 |    * <p>Unlike {@link ComputedDefault}, instances of this class contain a pre-computed table of all | 
 |    * possible assignments of depended-on attributes and what the Skylark function evaluates to, and | 
 |    * {@link #getPossibleValues(Type, Rule)} and {@link #getDefault(AttributeMap)} do lookups in that | 
 |    * table. | 
 |    */ | 
 |   static final class SkylarkComputedDefault extends ComputedDefault { | 
 |  | 
 |     private final List<Type<?>> dependencyTypes; | 
 |     private final Map<List<Object>, Object> lookupTable; | 
 |  | 
 |     /** | 
 |      * Creates a new SkylarkComputedDefault containing a lookup table. | 
 |      * | 
 |      * @param requiredAttributes A list of all names of other attributes that are accessed by this | 
 |      *     attribute. | 
 |      * @param dependencyTypes A list of requiredAttributes' types. | 
 |      * @param lookupTable An exhaustive mapping from requiredAttributes assignments to values this | 
 |      *     computed default evaluates to. | 
 |      */ | 
 |     SkylarkComputedDefault( | 
 |         ImmutableList<String> requiredAttributes, | 
 |         ImmutableList<Type<?>> dependencyTypes, | 
 |         Map<List<Object>, Object> lookupTable) { | 
 |       super(Preconditions.checkNotNull(requiredAttributes)); | 
 |       this.dependencyTypes = Preconditions.checkNotNull(dependencyTypes); | 
 |       this.lookupTable = Preconditions.checkNotNull(lookupTable); | 
 |     } | 
 |  | 
 |     List<Type<?>> getDependencyTypes() { | 
 |       return dependencyTypes; | 
 |     } | 
 |  | 
 |     Map<List<Object>, Object> getLookupTable() { | 
 |       return lookupTable; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public Object getDefault(AttributeMap rule) { | 
 |       List<Object> key = ComputationStrategy.createDependencyAssignmentTuple(dependencies(), rule); | 
 |       Preconditions.checkState( | 
 |           lookupTable.containsKey(key), | 
 |           "Error in rule '%s': precomputed value missing for dependencies: %s. Available keys: %s.", | 
 |           rule.getLabel(), | 
 |           Iterables.toString(key), | 
 |           Iterables.toString(lookupTable.keySet())); | 
 |       return lookupTable.get(key); | 
 |     } | 
 |  | 
 |     @Override | 
 |     <T> Iterable<T> getPossibleValues(Type<T> type, Rule rule) { | 
 |       List<T> result = new ArrayList<>(lookupTable.size()); | 
 |       for (Object obj : lookupTable.values()) { | 
 |         result.add(type.cast(obj)); | 
 |       } | 
 |       return result; | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * Marker interface for late-bound values. Unfortunately, we can't refer to BuildConfiguration | 
 |    * right now, since that is in a separate compilation unit. | 
 |    * | 
 |    * <p>Implementations of this interface must be immutable. | 
 |    * | 
 |    * <p>Use sparingly - having different values for attributes during loading and analysis can | 
 |    * confuse users. | 
 |    */ | 
 |   public interface LateBoundDefault<T> { | 
 |     /** | 
 |      * Whether to look up the label in the host configuration. This is only here for host | 
 |      * compilation tools - we usually need to look up labels in the target configuration. | 
 |      * | 
 |      * <p>This method only sets the configuration passed to {@link #resolve}. If you want the | 
 |      * dependency to also be analyzed in the host configuration, use | 
 |      * {@link ConfigurationTransition#HOST}. | 
 |      */ | 
 |     boolean useHostConfiguration(); | 
 |  | 
 |     /** | 
 |      * Returns the set of required configuration fragments, i.e., fragments that will be accessed by | 
 |      * the code. | 
 |      */ | 
 |     Set<Class<?>> getRequiredConfigurationFragments(); | 
 |  | 
 |     /** | 
 |      * The default value for the attribute that is set during the loading phase. | 
 |      */ | 
 |     Object getDefault(); | 
 |  | 
 |     /** | 
 |      * The actual value for the attribute for the analysis phase, which depends on the build | 
 |      * configuration. Note that configurations transitions are applied after the late-bound | 
 |      * attribute was evaluated. | 
 |      * | 
 |      * @param rule the rule being evaluated | 
 |      * @param attributes interface for retrieving the values of the rule's other attributes | 
 |      * @param o the configuration to evaluate with | 
 |      */ | 
 |     Object resolve(Rule rule, AttributeMap attributes, T o) | 
 |         throws EvalException, InterruptedException; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Abstract super class for label-typed {@link LateBoundDefault} implementations that simplifies | 
 |    * the client code a little and makes it a bit more type-safe. | 
 |    */ | 
 |   public abstract static class LateBoundLabel<T> implements LateBoundDefault<T> { | 
 |     private final Label label; | 
 |     private final ImmutableSet<Class<?>> requiredConfigurationFragments; | 
 |  | 
 |     public LateBoundLabel() { | 
 |       this((Label) null); | 
 |     } | 
 |  | 
 |     public LateBoundLabel(Class<?>... requiredConfigurationFragments) { | 
 |       this((Label) null, requiredConfigurationFragments); | 
 |     } | 
 |  | 
 |     public LateBoundLabel(Label label) { | 
 |       this.label = label; | 
 |       this.requiredConfigurationFragments = ImmutableSet.of(); | 
 |     } | 
 |  | 
 |     public LateBoundLabel(Label label, Class<?>... requiredConfigurationFragments) { | 
 |       this.label = label; | 
 |       this.requiredConfigurationFragments = ImmutableSet.copyOf(requiredConfigurationFragments); | 
 |     } | 
 |  | 
 |     public LateBoundLabel(String label) { | 
 |       this(Label.parseAbsoluteUnchecked(label)); | 
 |     } | 
 |  | 
 |     public LateBoundLabel(String label, Class<?>... requiredConfigurationFragments) { | 
 |       this(Label.parseAbsoluteUnchecked(label), requiredConfigurationFragments); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean useHostConfiguration() { | 
 |       return false; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public ImmutableSet<Class<?>> getRequiredConfigurationFragments() { | 
 |       return requiredConfigurationFragments; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public final Label getDefault() { | 
 |       return label; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public abstract Label resolve(Rule rule, AttributeMap attributes, T configuration); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Abstract super class for label-list-typed {@link LateBoundDefault} implementations that | 
 |    * simplifies the client code a little and makes it a bit more type-safe. | 
 |    */ | 
 |   public abstract static class LateBoundLabelList<T> implements LateBoundDefault<T> { | 
 |     private final ImmutableList<Label> labels; | 
 |     private final ImmutableSet<Class<?>> requiredConfigurationFragments; | 
 |  | 
 |     public LateBoundLabelList() { | 
 |       this(ImmutableList.<Label>of()); | 
 |     } | 
 |  | 
 |     public LateBoundLabelList(List<Label> labels, Class<?>... requiredConfigurationFragments) { | 
 |       this.labels = ImmutableList.copyOf(labels); | 
 |       this.requiredConfigurationFragments = ImmutableSet.copyOf(requiredConfigurationFragments); | 
 |     } | 
 |  | 
 |     @Override | 
 |     public boolean useHostConfiguration() { | 
 |       return false; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public ImmutableSet<Class<?>> getRequiredConfigurationFragments() { | 
 |       return requiredConfigurationFragments; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public final List<Label> getDefault() { | 
 |       return labels; | 
 |     } | 
 |  | 
 |     @Override | 
 |     public abstract List<Label> resolve(Rule rule, AttributeMap attributes, T configuration); | 
 |   } | 
 |  | 
 |   private final String name; | 
 |  | 
 |   private final Type<?> type; | 
 |  | 
 |   private final Set<PropertyFlag> propertyFlags; | 
 |  | 
 |   // Exactly one of these conditions is true: | 
 |   // 1. defaultValue == null. | 
 |   // 2. defaultValue instanceof ComputedDefault && | 
 |   //    type.isValid(defaultValue.getDefault()) | 
 |   // 3. defaultValue instanceof SkylarkComputedDefaultTemplate && | 
 |   //    type.isValid(defaultValue.computePossibleValues().getDefault()) | 
 |   // 4. type.isValid(defaultValue). | 
 |   // 5. defaultValue instanceof LateBoundDefault && | 
 |   //    type.isValid(defaultValue.getDefault(configuration)) | 
 |   // (We assume a hypothetical Type.isValid(Object) predicate.) | 
 |   private final Object defaultValue; | 
 |  | 
 |   private final Transition configTransition; | 
 |  | 
 |   private final Configurator<?, ?> configurator; | 
 |   private final SplitTransitionProvider splitTransitionProvider; | 
 |  | 
 |   /** | 
 |    * For label or label-list attributes, this predicate returns which rule | 
 |    * classes are allowed for the targets in the attribute. | 
 |    */ | 
 |   private final Predicate<RuleClass> allowedRuleClassesForLabels; | 
 |  | 
 |   /** | 
 |    * For label or label-list attributes, this predicate returns which rule | 
 |    * classes are allowed for the targets in the attribute with warning. | 
 |    */ | 
 |   private final Predicate<RuleClass> allowedRuleClassesForLabelsWarning; | 
 |  | 
 |   /** | 
 |    * For label or label-list attributes, this predicate returns which file | 
 |    * types are allowed for targets in the attribute that happen to be file | 
 |    * targets (rather than rules). | 
 |    */ | 
 |   private final FileTypeSet allowedFileTypesForLabels; | 
 |  | 
 |   /** | 
 |    * This predicate-like object checks | 
 |    * if the edge between two rules using this attribute is valid | 
 |    * in the dependency graph. Returns null if valid, otherwise an error message. | 
 |    */ | 
 |   private final ValidityPredicate validityPredicate; | 
 |  | 
 |   private final Predicate<AttributeMap> condition; | 
 |  | 
 |   private final PredicateWithMessage<Object> allowedValues; | 
 |  | 
 |   private final ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList; | 
 |  | 
 |   private final ImmutableList<ImmutableList<Class<? extends TransitiveInfoProvider>>> | 
 |       mandatoryNativeProvidersList; | 
 |  | 
 |   private final ImmutableList<RuleAspect<?>> aspects; | 
 |  | 
 |   /** | 
 |    * Constructs a rule attribute with the specified name, type and default | 
 |    * value. | 
 |    * | 
 |    * @param name the name of the attribute | 
 |    * @param type the type of the attribute | 
 |    * @param defaultValue the default value to use for this attribute if none is | 
 |    *        specified in rule declaration in the BUILD file. Must be null, or of | 
 |    *        type "type". May be an instance of ComputedDefault, in which case | 
 |    *        its getDefault() method must return an instance of "type", or null. | 
 |    *        Must be immutable. | 
 |    * @param configTransition the configuration transition for this attribute | 
 |    *        (which must be of type LABEL, LABEL_LIST, NODEP_LABEL or | 
 |    *        NODEP_LABEL_LIST). | 
 |    */ | 
 |   private Attribute( | 
 |       String name, | 
 |       Type<?> type, | 
 |       Set<PropertyFlag> propertyFlags, | 
 |       Object defaultValue, | 
 |       Transition configTransition, | 
 |       Configurator<?, ?> configurator, | 
 |       SplitTransitionProvider splitTransitionProvider, | 
 |       Predicate<RuleClass> allowedRuleClassesForLabels, | 
 |       Predicate<RuleClass> allowedRuleClassesForLabelsWarning, | 
 |       FileTypeSet allowedFileTypesForLabels, | 
 |       ValidityPredicate validityPredicate, | 
 |       Predicate<AttributeMap> condition, | 
 |       PredicateWithMessage<Object> allowedValues, | 
 |       ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList, | 
 |       ImmutableList<ImmutableList<Class<? extends TransitiveInfoProvider>>> | 
 |           mandatoryNativeProvidersList, | 
 |       ImmutableList<RuleAspect<?>> aspects) { | 
 |     Preconditions.checkNotNull(configTransition); | 
 |     Preconditions.checkArgument( | 
 |         (configTransition == ConfigurationTransition.NONE && configurator == null) | 
 |         || type == BuildType.LABEL || type == BuildType.LABEL_LIST | 
 |         || type == BuildType.NODEP_LABEL || type == BuildType.NODEP_LABEL_LIST, | 
 |         "Configuration transitions can only be specified for label or label list attributes"); | 
 |     Preconditions.checkArgument( | 
 |         isLateBound(name) == (defaultValue instanceof LateBoundDefault), | 
 |         "late bound attributes require a default value that is late bound (and vice versa): %s", | 
 |         name); | 
 |     if (isLateBound(name)) { | 
 |       LateBoundDefault<?> lateBoundDefault = (LateBoundDefault<?>) defaultValue; | 
 |       Preconditions.checkArgument((configurator == null), | 
 |           "a late bound attribute cannot specify a configurator"); | 
 |       Preconditions.checkArgument(!lateBoundDefault.useHostConfiguration() | 
 |           || (configTransition == ConfigurationTransition.HOST), | 
 |           "a late bound default value using the host configuration must use the host transition"); | 
 |     } | 
 |  | 
 |     this.name = name; | 
 |     this.type = type; | 
 |     this.propertyFlags = propertyFlags; | 
 |     this.defaultValue = defaultValue; | 
 |     this.configTransition = configTransition; | 
 |     this.configurator = configurator; | 
 |     this.splitTransitionProvider = splitTransitionProvider; | 
 |     this.allowedRuleClassesForLabels = allowedRuleClassesForLabels; | 
 |     this.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning; | 
 |     this.allowedFileTypesForLabels = allowedFileTypesForLabels; | 
 |     this.validityPredicate = validityPredicate; | 
 |     this.condition = condition; | 
 |     this.allowedValues = allowedValues; | 
 |     this.mandatoryProvidersList = mandatoryProvidersList; | 
 |     this.mandatoryNativeProvidersList = mandatoryNativeProvidersList; | 
 |     this.aspects = aspects; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the name of this attribute. | 
 |    */ | 
 |   public String getName() { | 
 |     return name; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the public name of this attribute. This is the name we use in Skylark code | 
 |    * and we can use it to display to the end-user. | 
 |    * Implicit and late-bound attributes start with '_' (instead of '$' or ':'). | 
 |    */ | 
 |   public String getPublicName() { | 
 |     return getSkylarkName(getName()); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the logical type of this attribute. (May differ from the actual | 
 |    * representation as a value in the build interpreter; for example, an | 
 |    * attribute may logically be a list of labels, but be represented as a list | 
 |    * of strings.) | 
 |    */ | 
 |   public Type<?> getType() { | 
 |     return type; | 
 |   } | 
 |  | 
 |   private boolean getPropertyFlag(PropertyFlag flag) { | 
 |     return propertyFlags.contains(flag); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if this parameter is mandatory. | 
 |    */ | 
 |   public boolean isMandatory() { | 
 |     return getPropertyFlag(PropertyFlag.MANDATORY); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if this list parameter cannot have an empty list as a value. | 
 |    */ | 
 |   public boolean isNonEmpty() { | 
 |     return getPropertyFlag(PropertyFlag.NON_EMPTY); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if this label parameter must produce a single artifact. | 
 |    */ | 
 |   public boolean isSingleArtifact() { | 
 |     return getPropertyFlag(PropertyFlag.SINGLE_ARTIFACT); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if this label type parameter is checked by silent ruleclass filtering. | 
 |    */ | 
 |   public boolean isSilentRuleClassFilter() { | 
 |     return getPropertyFlag(PropertyFlag.SILENT_RULECLASS_FILTER); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if this label type parameter skips the analysis time filetype check. | 
 |    */ | 
 |   public boolean isSkipAnalysisTimeFileTypeCheck() { | 
 |     return getPropertyFlag(PropertyFlag.SKIP_ANALYSIS_TIME_FILETYPE_CHECK); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if this parameter is order-independent. | 
 |    */ | 
 |   public boolean isOrderIndependent() { | 
 |     return getPropertyFlag(PropertyFlag.ORDER_INDEPENDENT); | 
 |   } | 
 |  | 
 |   /** | 
 |    *  Returns true if output_licenses should be used for checking licensing. | 
 |    */ | 
 |   public boolean useOutputLicenses() { | 
 |     return getPropertyFlag(PropertyFlag.OUTPUT_LICENSES); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the configuration transition for this attribute for label or label | 
 |    * list attributes. For other attributes it will always return {@code NONE}. | 
 |    */ | 
 |   public Transition getConfigurationTransition() { | 
 |     return configTransition; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the configurator instance for this attribute for label or label list attributes. | 
 |    * For other attributes it will always return {@code null}. | 
 |    */ | 
 |   public Configurator<?, ?> getConfigurator() { | 
 |     return configurator; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the split configuration transition for this attribute. | 
 |    * | 
 |    * @param rule the originating {@link Rule} which owns this attribute | 
 |    * @return a SplitTransition<BuildOptions> object | 
 |    * @throws IllegalStateException if {@link #hasSplitConfigurationTransition} is not true | 
 |    */ | 
 |   public SplitTransition<?> getSplitTransition(Rule rule) { | 
 |     Preconditions.checkState(hasSplitConfigurationTransition()); | 
 |     return splitTransitionProvider.apply(rule); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns true if this attribute transitions on a split transition. | 
 |    * See {@link SplitTransition}. | 
 |    */ | 
 |   public boolean hasSplitConfigurationTransition() { | 
 |     return (splitTransitionProvider != null); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns whether the target is required to be executable for label or label | 
 |    * list attributes. For other attributes it always returns {@code false}. | 
 |    */ | 
 |   public boolean isExecutable() { | 
 |     return getPropertyFlag(PropertyFlag.EXECUTABLE); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns {@code true} iff the rule is a direct input for an action. | 
 |    */ | 
 |   public boolean isDirectCompileTimeInput() { | 
 |     return getPropertyFlag(PropertyFlag.DIRECT_COMPILE_TIME_INPUT); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns {@code true} iff this attribute requires documentation. | 
 |    */ | 
 |   public boolean isDocumented() { | 
 |     return !getPropertyFlag(PropertyFlag.UNDOCUMENTED); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns {@code true} iff this attribute should be published to the rule's | 
 |    * tag set. Note that not all Type classes support tag conversion. | 
 |    */ | 
 |   public boolean isTaggable() { | 
 |     return getPropertyFlag(PropertyFlag.TAGGABLE); | 
 |   } | 
 |  | 
 |   public boolean isStrictLabelCheckingEnabled() { | 
 |     return getPropertyFlag(PropertyFlag.STRICT_LABEL_CHECKING); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns true if the value of this attribute should be a part of a given set. | 
 |    */ | 
 |   public boolean checkAllowedValues() { | 
 |     return getPropertyFlag(PropertyFlag.CHECK_ALLOWED_VALUES); | 
 |   } | 
 |  | 
 |   public boolean performPrereqValidatorCheck() { | 
 |     return !getPropertyFlag(PropertyFlag.SKIP_PREREQ_VALIDATOR_CHECKS); | 
 |   } | 
 |  | 
 |   public boolean checkConstraintsOverride() { | 
 |     return getPropertyFlag(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE); | 
 |   } | 
 |  | 
 |   public boolean skipConstraintsOverride() { | 
 |     return getPropertyFlag(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns true if this attribute's value can be influenced by the build configuration. | 
 |    */ | 
 |   public boolean isConfigurable() { | 
 |     return !(type == BuildType.OUTPUT      // Excluded because of Rule#populateExplicitOutputFiles. | 
 |         || type == BuildType.OUTPUT_LIST | 
 |         || getPropertyFlag(PropertyFlag.NONCONFIGURABLE)); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns a predicate that evaluates to true for rule classes that are | 
 |    * allowed labels in this attribute. If this is not a label or label-list | 
 |    * attribute, the returned predicate always evaluates to true. | 
 |    */ | 
 |   public Predicate<RuleClass> getAllowedRuleClassesPredicate() { | 
 |     return allowedRuleClassesForLabels; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns a predicate that evaluates to true for rule classes that are | 
 |    * allowed labels in this attribute with warning. If this is not a label or label-list | 
 |    * attribute, the returned predicate always evaluates to true. | 
 |    */ | 
 |   public Predicate<RuleClass> getAllowedRuleClassesWarningPredicate() { | 
 |     return allowedRuleClassesForLabelsWarning; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the list of sets of mandatory Skylark providers. | 
 |    */ | 
 |   public ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> getMandatoryProvidersList() { | 
 |     return mandatoryProvidersList; | 
 |   } | 
 |  | 
 |   /** Returns the list of lists of mandatory native providers. */ | 
 |   public ImmutableList<ImmutableList<Class<? extends TransitiveInfoProvider>>> | 
 |       getMandatoryNativeProvidersList() { | 
 |     return mandatoryNativeProvidersList; | 
 |   } | 
 |  | 
 |   public FileTypeSet getAllowedFileTypesPredicate() { | 
 |     return allowedFileTypesForLabels; | 
 |   } | 
 |  | 
 |   public ValidityPredicate getValidityPredicate() { | 
 |     return validityPredicate; | 
 |   } | 
 |  | 
 |   public Predicate<AttributeMap> getCondition() { | 
 |     return condition == null ? Predicates.<AttributeMap>alwaysTrue() : condition; | 
 |   } | 
 |  | 
 |   public PredicateWithMessage<Object> getAllowedValues() { | 
 |     return allowedValues; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the list of aspects required for dependencies through this attribute. | 
 |    */ | 
 |   public ImmutableList<Aspect> getAspects(Rule rule) { | 
 |     ImmutableList.Builder<Aspect> builder = ImmutableList.builder(); | 
 |     for (RuleAspect aspect : aspects) { | 
 |       builder.add(aspect.getAspect(rule)); | 
 |     } | 
 |     return builder.build(); | 
 |   } | 
 |  | 
 |   public ImmutableList<AspectClass> getAspectClasses() { | 
 |     ImmutableList.Builder<AspectClass> result = ImmutableList.builder(); | 
 |     for (RuleAspect<?> aspect : aspects) { | 
 |       result.add(aspect.getAspectClass()); | 
 |     } | 
 |     return result.build(); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the default value of this attribute in the context of the | 
 |    * specified Rule.  For attributes with a computed default, i.e. {@code | 
 |    * hasComputedDefault()}, {@code rule} must be non-null since the result may | 
 |    * depend on the values of its other attributes. | 
 |    * | 
 |    * <p>The result may be null (although this is not a value in the build | 
 |    * language). | 
 |    * | 
 |    * <p>During population of the rule's attribute dictionary, all non-computed | 
 |    * defaults must be set before all computed ones. | 
 |    * | 
 |    * @param rule the rule to which this attribute belongs; non-null if | 
 |    *   {@code hasComputedDefault()}; ignored otherwise. | 
 |    */ | 
 |   public Object getDefaultValue(Rule rule) { | 
 |     if (!getCondition().apply(rule == null ? null : NonconfigurableAttributeMapper.of(rule))) { | 
 |       return null; | 
 |     } else if (defaultValue instanceof LateBoundDefault<?>) { | 
 |       return ((LateBoundDefault<?>) defaultValue).getDefault(); | 
 |     } else { | 
 |       return defaultValue; | 
 |     } | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the default value of this attribute, even if it has a condition, is a computed default, | 
 |    * or a late-bound default. | 
 |    */ | 
 |   @VisibleForTesting | 
 |   public Object getDefaultValueForTesting() { | 
 |     return defaultValue; | 
 |   } | 
 |  | 
 |   public LateBoundDefault<?> getLateBoundDefault() { | 
 |     Preconditions.checkState(isLateBound()); | 
 |     return (LateBoundDefault<?>) defaultValue; | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns true iff this attribute has a computed default or a condition. | 
 |    * | 
 |    * @see #getDefaultValue(Rule) | 
 |    */ | 
 |   boolean hasComputedDefault() { | 
 |     return (defaultValue instanceof ComputedDefault) | 
 |         || (defaultValue instanceof SkylarkComputedDefaultTemplate) | 
 |         || (condition != null); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns if this attribute is an implicit dependency according to the naming policy that | 
 |    * designates implicit attributes. | 
 |    */ | 
 |   public boolean isImplicit() { | 
 |     return isImplicit(getName()); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns if an attribute with the given name is an implicit dependency according to the | 
 |    * naming policy that designates implicit attributes. | 
 |    */ | 
 |   public static boolean isImplicit(String name) { | 
 |     return name.startsWith("$"); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns if this attribute is late-bound according to the naming policy that designates | 
 |    * late-bound attributes. | 
 |    */ | 
 |   public boolean isLateBound() { | 
 |     return isLateBound(getName()); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns if an attribute with the given name is late-bound according to the naming policy | 
 |    * that designates late-bound attributes. | 
 |    */ | 
 |   public static boolean isLateBound(String name) { | 
 |     return name.startsWith(":"); | 
 |   } | 
 |  | 
 |   /** Returns whether this attribute is considered private in Skylark. */ | 
 |   private static boolean isPrivateAttribute(String nativeAttrName) { | 
 |     return isLateBound(nativeAttrName) || isImplicit(nativeAttrName); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns the Skylark-usable name of this attribute. | 
 |    * | 
 |    * Implicit and late-bound attributes start with '_' (instead of '$' or ':'). | 
 |    */ | 
 |   public static String getSkylarkName(String nativeAttrName) { | 
 |     if (isPrivateAttribute(nativeAttrName)) { | 
 |       return "_" + nativeAttrName.substring(1); | 
 |     } | 
 |     return nativeAttrName; | 
 |   } | 
 |  | 
 |   @Override | 
 |   public String toString() { | 
 |     return "Attribute(" + name + ", " + type + ")"; | 
 |   } | 
 |  | 
 |   @Override | 
 |   public int compareTo(Attribute other) { | 
 |     return name.compareTo(other.name); | 
 |   } | 
 |  | 
 |   /** | 
 |    * Returns a replica builder of this Attribute. | 
 |    */ | 
 |   public <TYPE> Attribute.Builder<TYPE> cloneBuilder(Type<TYPE> tp) { | 
 |     Preconditions.checkArgument(tp == this.type); | 
 |     Builder<TYPE> builder = new Builder<>(name, tp); | 
 |     builder.allowedFileTypesForLabels = allowedFileTypesForLabels; | 
 |     builder.allowedRuleClassesForLabels = allowedRuleClassesForLabels; | 
 |     builder.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning; | 
 |     builder.mandatoryNativeProvidersList = mandatoryNativeProvidersList; | 
 |     builder.mandatoryProvidersList = mandatoryProvidersList; | 
 |     builder.validityPredicate = validityPredicate; | 
 |     builder.condition = condition; | 
 |     builder.configTransition = configTransition; | 
 |     builder.splitTransitionProvider = splitTransitionProvider; | 
 |     builder.propertyFlags = propertyFlags.isEmpty() ? | 
 |         EnumSet.noneOf(PropertyFlag.class) : EnumSet.copyOf(propertyFlags); | 
 |     builder.value = defaultValue; | 
 |     builder.valueSet = false; | 
 |     builder.allowedValues = allowedValues; | 
 |     builder.aspects = new LinkedHashMap<>(); | 
 |     for (RuleAspect<?> aspect : aspects) { | 
 |       builder.aspects.put(aspect.getName(), aspect); | 
 |     } | 
 |  | 
 |     return builder; | 
 |   } | 
 |  | 
 |   public Attribute.Builder<?> cloneBuilder() { | 
 |     return cloneBuilder(this.type); | 
 |   } | 
 | } |