blob: 4f35aebff67940121860e3af03e608d3a54d8e58 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.packages;
16
Greg Estren4ccabd32017-03-14 17:12:45 +000017import static com.google.common.collect.Sets.newEnumSet;
18
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010019import com.google.common.annotations.VisibleForTesting;
Marian Lobur702cad72015-09-02 09:53:58 +000020import com.google.common.base.Function;
tomlua155b532017-11-08 20:12:47 +010021import com.google.common.base.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010022import com.google.common.base.Predicate;
23import com.google.common.base.Predicates;
Greg Estren9d837842016-12-01 21:36:59 +000024import com.google.common.base.Verify;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025import com.google.common.collect.ImmutableList;
Googler74558fc2016-05-06 21:47:42 +000026import com.google.common.collect.ImmutableMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import com.google.common.collect.ImmutableSet;
28import com.google.common.collect.Iterables;
djasper1b869122019-03-04 10:41:50 -080029import com.google.common.collect.Lists;
nharmatab81776f2019-02-25 15:52:33 -080030import com.google.common.collect.Maps;
Florian Weikertea6c82d2016-09-05 12:15:31 +000031import com.google.common.collect.Ordering;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032import com.google.common.collect.Sets;
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +000033import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
gregce7fa23ea2018-01-18 12:46:04 -080034import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
John Cater0a9e1ed2019-03-27 11:02:01 -070035import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
janakra56a6ad2018-02-02 15:52:22 -080036import com.google.devtools.build.lib.cmdline.Label;
Florian Weikertea6c82d2016-09-05 12:15:31 +000037import com.google.devtools.build.lib.events.EventHandler;
gregceda4c9592017-07-27 22:09:34 +020038import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
Googlerc5fcc862019-09-06 16:17:47 -070039import com.google.devtools.build.lib.packages.Type.ConversionException;
40import com.google.devtools.build.lib.packages.Type.LabelClass;
mjhalupka7b398f92018-03-08 12:08:25 -080041import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
mjhalupkacfa0bb72018-03-12 12:43:15 -070042import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043import com.google.devtools.build.lib.util.FileType;
44import com.google.devtools.build.lib.util.FileTypeSet;
45import com.google.devtools.build.lib.util.StringUtil;
Florian Weikertea6c82d2016-09-05 12:15:31 +000046import java.util.ArrayList;
Carmi Grushkoe80cccd2015-11-11 19:12:31 +000047import java.util.Arrays;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048import java.util.Collection;
49import java.util.EnumSet;
50import java.util.HashMap;
Dmitry Lomovf188dc22016-07-19 09:00:55 +000051import java.util.LinkedHashMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010052import java.util.List;
53import java.util.Map;
janakr9ba46f82018-03-13 13:07:52 -070054import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010055import java.util.Set;
Florian Weikertea6c82d2016-09-05 12:15:31 +000056import java.util.concurrent.atomic.AtomicReference;
vladmos9c787fa2017-07-04 11:45:22 -040057import javax.annotation.Nullable;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import javax.annotation.concurrent.Immutable;
adonovanb74f1602020-11-02 17:33:49 -080059import net.starlark.java.eval.Dict;
adonovan450c7ad2020-09-14 13:00:21 -070060import net.starlark.java.eval.EvalException;
61import net.starlark.java.eval.Starlark;
62import net.starlark.java.eval.StarlarkValue;
adonovan267bdaa2020-11-04 11:32:24 -080063import net.starlark.java.eval.Structure;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010064
65/**
mjhalupkacfa0bb72018-03-12 12:43:15 -070066 * Metadata of a rule attribute. Contains the attribute name and type, and an default value to be
67 * used if none is provided in a rule declaration in a BUILD file. Attributes are immutable, and may
68 * be shared by more than one rule (for example, <code>foo_binary</code> and <code>foo_library
69 * </code> may share many attributes in common).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010070 */
71@Immutable
72public final class Attribute implements Comparable<Attribute> {
73
Googler72f3a102017-12-01 16:28:28 -080074 public static final RuleClassNamePredicate ANY_RULE = RuleClassNamePredicate.unspecified();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010075
janakrf4523e72019-06-05 14:11:06 -070076 private static final RuleClassNamePredicate NO_RULE = RuleClassNamePredicate.only();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077
mjhalupkacfa0bb72018-03-12 12:43:15 -070078 /** Wraps the information necessary to construct an Aspect. */
79 @VisibleForSerialization
80 abstract static class RuleAspect<C extends AspectClass> {
Dmitry Lomove8040172016-04-06 14:53:43 +000081 protected final C aspectClass;
82 protected final Function<Rule, AspectParameters> parametersExtractor;
Marian Lobur702cad72015-09-02 09:53:58 +000083
janakrf4523e72019-06-05 14:11:06 -070084 private RuleAspect(C aspectClass, Function<Rule, AspectParameters> parametersExtractor) {
Dmitry Lomove8040172016-04-06 14:53:43 +000085 this.aspectClass = aspectClass;
Marian Lobur702cad72015-09-02 09:53:58 +000086 this.parametersExtractor = parametersExtractor;
87 }
88
Googler74558fc2016-05-06 21:47:42 +000089 public String getName() {
90 return this.aspectClass.getName();
91 }
92
93 public ImmutableSet<String> getRequiredParameters() {
94 return ImmutableSet.<String>of();
95 }
96
Dmitry Lomove8040172016-04-06 14:53:43 +000097 public abstract Aspect getAspect(Rule rule);
Carmi Grushkodf9e5e12016-11-08 23:07:57 +000098
99 public C getAspectClass() {
100 return aspectClass;
101 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000102 }
103
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +0000104 private static class NativeRuleAspect extends RuleAspect<NativeAspectClass> {
janakrf4523e72019-06-05 14:11:06 -0700105 NativeRuleAspect(
106 NativeAspectClass aspectClass, Function<Rule, AspectParameters> parametersExtractor) {
Dmitry Lomove8040172016-04-06 14:53:43 +0000107 super(aspectClass, parametersExtractor);
Marian Lobur702cad72015-09-02 09:53:58 +0000108 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000109
110 @Override
111 public Aspect getAspect(Rule rule) {
Googler459f1302017-04-05 19:40:35 +0000112 AspectParameters params = parametersExtractor.apply(rule);
113 return params == null ? null : Aspect.forNative(aspectClass, params);
Dmitry Lomove8040172016-04-06 14:53:43 +0000114 }
115 }
116
janakrf4523e72019-06-05 14:11:06 -0700117 @VisibleForSerialization
mjhalupkacfa0bb72018-03-12 12:43:15 -0700118 @AutoCodec
gregce18694cd2020-05-12 15:40:05 -0700119 static class StarlarkRuleAspect extends RuleAspect<StarlarkAspectClass> {
gregced281df72020-05-11 12:27:06 -0700120 private final StarlarkDefinedAspect aspect;
Dmitry Lomov777845c2016-04-06 15:24:36 +0000121
janakrf4523e72019-06-05 14:11:06 -0700122 @VisibleForSerialization
gregce18694cd2020-05-12 15:40:05 -0700123 StarlarkRuleAspect(StarlarkDefinedAspect aspect) {
Googler74558fc2016-05-06 21:47:42 +0000124 super(aspect.getAspectClass(), aspect.getDefaultParametersExtractor());
125 this.aspect = aspect;
126 }
127
128 @Override
129 public ImmutableSet<String> getRequiredParameters() {
130 return aspect.getParamAttributes();
Dmitry Lomove8040172016-04-06 14:53:43 +0000131 }
132
133 @Override
134 public Aspect getAspect(Rule rule) {
Googler74558fc2016-05-06 21:47:42 +0000135 AspectParameters parameters = parametersExtractor.apply(rule);
gregce18694cd2020-05-12 15:40:05 -0700136 return Aspect.forStarlark(aspectClass, aspect.getDefinition(parameters), parameters);
Googler74558fc2016-05-06 21:47:42 +0000137 }
138 }
139
Michajlo Matijkiwccd5fb12016-07-26 20:58:42 +0000140 /** A RuleAspect that just wraps a pre-existing Aspect that doesn't vary with the Rule. */
Googler74558fc2016-05-06 21:47:42 +0000141 private static class PredefinedRuleAspect extends RuleAspect<AspectClass> {
Kevin Bierhoff6f1d6082017-03-24 21:17:13 +0000142 private final Aspect aspect;
Googler74558fc2016-05-06 21:47:42 +0000143
janakrf4523e72019-06-05 14:11:06 -0700144 PredefinedRuleAspect(Aspect aspect) {
Googler74558fc2016-05-06 21:47:42 +0000145 super(aspect.getAspectClass(), null);
146 this.aspect = aspect;
147 }
148
149 @Override
150 public Aspect getAspect(Rule rule) {
151 return aspect;
Marian Lobur702cad72015-09-02 09:53:58 +0000152 }
153 }
154
janakrf4523e72019-06-05 14:11:06 -0700155 private enum PropertyFlag {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100156 MANDATORY,
157 EXECUTABLE,
158 UNDOCUMENTED,
159 TAGGABLE,
160
161 /**
162 * Whether the list attribute is order-independent and can be sorted.
163 */
164 ORDER_INDEPENDENT,
165
166 /**
167 * Whether the allowedRuleClassesForLabels or allowedFileTypesForLabels are
168 * set to custom values. If so, and the attribute is called "deps", the
169 * legacy deps checking is skipped, and the new stricter checks are used
170 * instead. For non-"deps" attributes, this allows skipping the check if it
171 * would pass anyway, as the default setting allows any rule classes and
172 * file types.
173 */
174 STRICT_LABEL_CHECKING,
175
176 /**
177 * Set for things that would cause the a compile or lint-like action to
178 * be executed when the input changes. Used by compile_one_dependency.
179 * Set for attributes like hdrs and srcs on cc_ rules or srcs on java_
180 * or py_rules. Generally not set on data/resource attributes.
181 */
182 DIRECT_COMPILE_TIME_INPUT,
183
184 /**
185 * Whether the value of the list type attribute must not be an empty list.
186 */
187 NON_EMPTY,
188
189 /**
190 * Verifies that the referenced rule produces a single artifact. Note that this check happens
191 * on a per label basis, i.e. the check happens separately for every label in a label list.
192 */
193 SINGLE_ARTIFACT,
194
195 /**
196 * Whether we perform silent ruleclass filtering of the dependencies of the label type
197 * attribute according to their rule classes. I.e. elements of the list which don't match the
198 * allowedRuleClasses predicate or not rules will be filtered out without throwing any errors.
199 * This flag is introduced to handle plugins, do not use it in other cases.
200 */
201 SILENT_RULECLASS_FILTER,
202
203 // TODO(bazel-team): This is a hack introduced because of the bad design of the original rules.
gregce3377c112020-04-13 09:29:59 -0700204 // Depot cleanup would be too expensive, but don't migrate this to Starlark.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100205 /**
gregce3377c112020-04-13 09:29:59 -0700206 * Whether to perform analysis time filetype check on this label-type attribute or not. If the
207 * flag is set, we skip the check that applies the allowedFileTypes filter to generated files.
208 * Do not use this if avoidable.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100209 */
210 SKIP_ANALYSIS_TIME_FILETYPE_CHECK,
211
212 /**
213 * Whether the value of the attribute should come from a given set of values.
214 */
215 CHECK_ALLOWED_VALUES,
216
217 /**
218 * Whether this attribute is opted out of "configurability", i.e. the ability to determine
219 * its value based on properties of the build configuration.
220 */
221 NONCONFIGURABLE,
Ulf Adams0b638972015-09-08 13:25:35 +0000222
223 /**
jcater0de10972020-04-07 12:15:05 -0700224 * Whether we should skip dependency validation checks done by {@link
225 * com.google.devtools.build.lib.analysis.RuleContext.PrerequisiteValidator} (for visibility,
226 * etc.).
Ulf Adams0b638972015-09-08 13:25:35 +0000227 */
Greg Estren875c7a72015-09-24 19:57:54 +0000228 SKIP_PREREQ_VALIDATOR_CHECKS,
Greg Estren4a102512015-10-28 20:49:22 +0000229
230 /**
Greg Estren9d837842016-12-01 21:36:59 +0000231 * Whether we should check constraints on this attribute even if default enforcement policy
232 * would skip it. See
233 * {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for more on
234 * constraints.
Greg Estren4a102512015-10-28 20:49:22 +0000235 */
Greg Estren9d837842016-12-01 21:36:59 +0000236 CHECK_CONSTRAINTS_OVERRIDE,
237
238 /**
239 * Whether we should skip constraints checking on this attribute even if default enforcement
240 * policy would check it.
241 */
242 SKIP_CONSTRAINTS_OVERRIDE,
Irina Iancu2f235992017-01-10 16:03:29 +0000243
244 /**
245 * Whether we should use output_licenses to check the licences on this attribute.
246 */
247 OUTPUT_LICENSES,
Googlerc2200fd2018-09-14 17:35:59 -0700248
249 /**
cparsonsf6266392018-10-18 15:42:52 -0700250 * Has a Starlark-defined configuration transition. Transitions for analysis testing are tracked
251 * separately: see {@link #HAS_ANALYSIS_TEST_TRANSITION}.
Googlerc2200fd2018-09-14 17:35:59 -0700252 */
cparsonsf6266392018-10-18 15:42:52 -0700253 HAS_STARLARK_DEFINED_TRANSITION,
254
255 /**
256 * Has a Starlark-defined configuration transition designed specifically for rules which
257 * run analysis tests.
258 */
259 HAS_ANALYSIS_TEST_TRANSITION,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100260 }
261
262 // TODO(bazel-team): modify this interface to extend Predicate and have an extra error
263 // message function like AllowedValues does
264 /**
265 * A predicate-like class that determines whether an edge between two rules is valid or not.
266 */
267 public interface ValidityPredicate {
268 /**
269 * This method should return null if the edge is valid, or a suitable error message
270 * if it is not. Note that warnings are not supported.
271 */
272 String checkValid(Rule from, Rule to);
273 }
274
janakrf4523e72019-06-05 14:11:06 -0700275 @AutoCodec public static final ValidityPredicate ANY_EDGE = (from, to) -> null;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100276
mjhalupkacfa0bb72018-03-12 12:43:15 -0700277 /** A predicate class to check if the value of the attribute comes from a predefined set. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100278 public static class AllowedValueSet implements PredicateWithMessage<Object> {
279
280 private final Set<Object> allowedValues;
281
brandjonaf77a302019-01-22 13:28:57 -0800282 public AllowedValueSet(Object... values) {
Carmi Grushkoe80cccd2015-11-11 19:12:31 +0000283 this(Arrays.asList(values));
284 }
285
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100286 public AllowedValueSet(Iterable<?> values) {
287 Preconditions.checkNotNull(values);
288 Preconditions.checkArgument(!Iterables.isEmpty(values));
adonovan3ed7ed52020-09-30 12:03:28 -0700289 for (Object v : values) {
290 Starlark.checkValid(v);
291 }
brandjoned249612017-07-11 22:06:22 +0200292 allowedValues = ImmutableSet.copyOf(values);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100293 }
294
295 @Override
296 public boolean apply(Object input) {
297 return allowedValues.contains(input);
298 }
299
300 @Override
301 public String getErrorReason(Object value) {
302 return String.format("has to be one of %s instead of '%s'",
303 StringUtil.joinEnglishList(allowedValues, "or", "'"), value);
304 }
305
306 @VisibleForTesting
307 public Collection<Object> getAllowedValues() {
308 return allowedValues;
309 }
310 }
311
Googler74558fc2016-05-06 21:47:42 +0000312 public ImmutableMap<String, ImmutableSet<String>> getRequiredAspectParameters() {
313 ImmutableMap.Builder<String, ImmutableSet<String>> paramBuilder = ImmutableMap.builder();
314 for (RuleAspect<?> aspect : aspects) {
315 paramBuilder.put(aspect.getName(), aspect.getRequiredParameters());
316 }
317 return paramBuilder.build();
318 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000319
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100320 /**
321 * Creates a new attribute builder.
322 *
323 * @param name attribute name
324 * @param type attribute type
325 * @return attribute builder
326 *
327 * @param <TYPE> attribute type class
328 */
329 public static <TYPE> Attribute.Builder<TYPE> attr(String name, Type<TYPE> type) {
330 return new Builder<>(name, type);
331 }
332
janakr33439dc2018-03-22 13:44:05 -0700333 /** A factory to generate {@link Attribute} instances. */
janakr33439dc2018-03-22 13:44:05 -0700334 public static class ImmutableAttributeFactory {
335 private final Type<?> type;
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800336 private final String doc;
John Cater2c0dece2019-04-02 09:18:18 -0700337 private final TransitionFactory<AttributeTransitionData> transitionFactory;
janakr33439dc2018-03-22 13:44:05 -0700338 private final RuleClassNamePredicate allowedRuleClassesForLabels;
339 private final RuleClassNamePredicate allowedRuleClassesForLabelsWarning;
janakr33439dc2018-03-22 13:44:05 -0700340 private final FileTypeSet allowedFileTypesForLabels;
341 private final ValidityPredicate validityPredicate;
342 private final Object value;
343 private final AttributeValueSource valueSource;
344 private final boolean valueSet;
345 private final Predicate<AttributeMap> condition;
346 private final ImmutableSet<PropertyFlag> propertyFlags;
347 private final PredicateWithMessage<Object> allowedValues;
348 private final RequiredProviders requiredProviders;
349 private final ImmutableList<RuleAspect<?>> aspects;
350
janakrf4523e72019-06-05 14:11:06 -0700351 private ImmutableAttributeFactory(
janakr33439dc2018-03-22 13:44:05 -0700352 Type<?> type,
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800353 String doc,
janakr33439dc2018-03-22 13:44:05 -0700354 ImmutableSet<PropertyFlag> propertyFlags,
355 Object value,
John Cater2c0dece2019-04-02 09:18:18 -0700356 TransitionFactory<AttributeTransitionData> transitionFactory,
janakr33439dc2018-03-22 13:44:05 -0700357 RuleClassNamePredicate allowedRuleClassesForLabels,
358 RuleClassNamePredicate allowedRuleClassesForLabelsWarning,
janakr33439dc2018-03-22 13:44:05 -0700359 FileTypeSet allowedFileTypesForLabels,
360 ValidityPredicate validityPredicate,
361 AttributeValueSource valueSource,
362 boolean valueSet,
363 Predicate<AttributeMap> condition,
364 PredicateWithMessage<Object> allowedValues,
365 RequiredProviders requiredProviders,
366 ImmutableList<RuleAspect<?>> aspects) {
367 this.type = type;
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800368 this.doc = doc;
John Cater5adcd3e2019-03-28 10:14:32 -0700369 this.transitionFactory = transitionFactory;
janakr33439dc2018-03-22 13:44:05 -0700370 this.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
371 this.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
janakr33439dc2018-03-22 13:44:05 -0700372 this.allowedFileTypesForLabels = allowedFileTypesForLabels;
373 this.validityPredicate = validityPredicate;
374 this.value = value;
375 this.valueSource = valueSource;
376 this.valueSet = valueSet;
377 this.condition = condition;
378 this.propertyFlags = propertyFlags;
379 this.allowedValues = allowedValues;
380 this.requiredProviders = requiredProviders;
381 this.aspects = aspects;
382 }
383
384 public AttributeValueSource getValueSource() {
385 return valueSource;
386 }
387
388 public boolean isValueSet() {
389 return valueSet;
390 }
391
392 public Attribute build(String name) {
393 Preconditions.checkState(!name.isEmpty(), "name has not been set");
394 if (valueSource == AttributeValueSource.LATE_BOUND) {
395 Preconditions.checkState(isLateBound(name));
John Cater5adcd3e2019-03-28 10:14:32 -0700396 Preconditions.checkState(!transitionFactory.isSplit());
janakr33439dc2018-03-22 13:44:05 -0700397 }
398 // TODO(bazel-team): Set the default to be no file type, then remove this check, and also
399 // remove all allowedFileTypes() calls without parameters.
400
401 // do not modify this.allowedFileTypesForLabels, instead create a copy.
402 FileTypeSet allowedFileTypesForLabels = this.allowedFileTypesForLabels;
403 if (type.getLabelClass() == LabelClass.DEPENDENCY) {
404 if (isPrivateAttribute(name) && allowedFileTypesForLabels == null) {
405 allowedFileTypesForLabels = FileTypeSet.ANY_FILE;
406 }
407 Preconditions.checkNotNull(
408 allowedFileTypesForLabels, "allowedFileTypesForLabels not set for %s", name);
409 } else if (type.getLabelClass() == LabelClass.OUTPUT) {
410 // TODO(bazel-team): Set the default to no file type and make explicit calls instead.
411 if (allowedFileTypesForLabels == null) {
412 allowedFileTypesForLabels = FileTypeSet.ANY_FILE;
413 }
414 }
415
416 return new Attribute(
417 name,
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800418 doc,
janakr33439dc2018-03-22 13:44:05 -0700419 type,
420 propertyFlags,
421 value,
John Cater5adcd3e2019-03-28 10:14:32 -0700422 transitionFactory,
janakr33439dc2018-03-22 13:44:05 -0700423 allowedRuleClassesForLabels,
424 allowedRuleClassesForLabelsWarning,
425 allowedFileTypesForLabels,
426 validityPredicate,
427 condition,
428 allowedValues,
429 requiredProviders,
430 aspects);
431 }
432 }
433
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100434 /**
435 * A fluent builder for the {@code Attribute} instances.
436 *
437 * <p>All methods could be called only once per builder. The attribute
438 * already undocumented based on its name cannot be marked as undocumented.
439 */
440 public static class Builder <TYPE> {
Kevin Bierhoff6f1d6082017-03-24 21:17:13 +0000441 private final String name;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100442 private final Type<TYPE> type;
John Cater2c0dece2019-04-02 09:18:18 -0700443 private TransitionFactory<AttributeTransitionData> transitionFactory =
444 NoTransition.createFactory();
Googler72f3a102017-12-01 16:28:28 -0800445 private RuleClassNamePredicate allowedRuleClassesForLabels = ANY_RULE;
446 private RuleClassNamePredicate allowedRuleClassesForLabelsWarning = NO_RULE;
Ulf Adams788fd1a2015-03-12 13:54:09 +0000447 private FileTypeSet allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100448 private ValidityPredicate validityPredicate = ANY_EDGE;
449 private Object value;
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800450 private String doc;
Florian Weikert438ff162016-05-12 08:49:12 +0000451 private AttributeValueSource valueSource = AttributeValueSource.DIRECT;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100452 private boolean valueSet;
453 private Predicate<AttributeMap> condition;
454 private Set<PropertyFlag> propertyFlags = EnumSet.noneOf(PropertyFlag.class);
455 private PredicateWithMessage<Object> allowedValues = null;
dslomovc13bb392017-08-02 23:29:54 +0200456 private RequiredProviders.Builder requiredProvidersBuilder =
457 RequiredProviders.acceptAnyBuilder();
Dmitry Lomovf188dc22016-07-19 09:00:55 +0000458 private HashMap<String, RuleAspect<?>> aspects = new LinkedHashMap<>();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100459
460 /**
461 * Creates an attribute builder with given name and type. This attribute is optional, uses
462 * target configuration and has a default value the same as its type default value. This
463 * attribute will be marked as undocumented if its name starts with the dollar sign ({@code $})
464 * or colon ({@code :}).
465 *
466 * @param name attribute name
467 * @param type attribute type
468 */
469 public Builder(String name, Type<TYPE> type) {
470 this.name = Preconditions.checkNotNull(name);
471 this.type = Preconditions.checkNotNull(type);
472 if (isImplicit(name) || isLateBound(name)) {
473 setPropertyFlag(PropertyFlag.UNDOCUMENTED, "undocumented");
474 }
475 }
476
477 private Builder<TYPE> setPropertyFlag(PropertyFlag flag, String propertyName) {
Ulf Adams07dba942015-03-05 14:47:37 +0000478 Preconditions.checkState(
479 !propertyFlags.contains(flag), "%s flag is already set", propertyName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100480 propertyFlags.add(flag);
481 return this;
482 }
483
484 /**
485 * Sets the property flag of the corresponding name if exists, otherwise throws an Exception.
gregce3377c112020-04-13 09:29:59 -0700486 * Only meant to use from Starlark, do not use from Java.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100487 */
488 public Builder<TYPE> setPropertyFlag(String propertyName) {
489 PropertyFlag flag = null;
490 try {
491 flag = PropertyFlag.valueOf(propertyName);
492 } catch (IllegalArgumentException e) {
493 throw new IllegalArgumentException("unknown attribute flag " + propertyName);
494 }
495 setPropertyFlag(flag, propertyName);
496 return this;
497 }
498
499 /**
500 * Makes the built attribute mandatory.
501 */
502 public Builder<TYPE> mandatory() {
503 return setPropertyFlag(PropertyFlag.MANDATORY, "mandatory");
504 }
505
506 /**
507 * Makes the built attribute non empty, meaning the attribute cannot have an empty list value.
508 * Only applicable for list type attributes.
509 */
510 public Builder<TYPE> nonEmpty() {
Ulf Adams07dba942015-03-05 14:47:37 +0000511 Preconditions.checkNotNull(type.getListElementType(), "attribute '%s' must be a list", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100512 return setPropertyFlag(PropertyFlag.NON_EMPTY, "non_empty");
513 }
514
515 /**
516 * Makes the built attribute producing a single artifact.
517 */
518 public Builder<TYPE> singleArtifact() {
Michael Staiba751f922017-02-14 15:50:04 +0000519 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Ulf Adams07dba942015-03-05 14:47:37 +0000520 "attribute '%s' must be a label-valued type", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100521 return setPropertyFlag(PropertyFlag.SINGLE_ARTIFACT, "single_artifact");
522 }
523
524 /**
525 * Forces silent ruleclass filtering on the label type attribute.
526 * This flag is introduced to handle plugins, do not use it in other cases.
527 */
528 public Builder<TYPE> silentRuleClassFilter() {
Michael Staiba751f922017-02-14 15:50:04 +0000529 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100530 "must be a label-valued type");
531 return setPropertyFlag(PropertyFlag.SILENT_RULECLASS_FILTER, "silent_ruleclass_filter");
532 }
533
534 /**
535 * Skip analysis time filetype check. Don't use it if avoidable.
536 */
537 public Builder<TYPE> skipAnalysisTimeFileTypeCheck() {
Michael Staiba751f922017-02-14 15:50:04 +0000538 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100539 "must be a label-valued type");
540 return setPropertyFlag(PropertyFlag.SKIP_ANALYSIS_TIME_FILETYPE_CHECK,
541 "skip_analysis_time_filetype_check");
542 }
543
544 /**
545 * Mark the built attribute as order-independent.
546 */
547 public Builder<TYPE> orderIndependent() {
Ulf Adams07dba942015-03-05 14:47:37 +0000548 Preconditions.checkNotNull(type.getListElementType(), "attribute '%s' must be a list", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100549 return setPropertyFlag(PropertyFlag.ORDER_INDEPENDENT, "order-independent");
550 }
551
552 /**
Irina Iancu2f235992017-01-10 16:03:29 +0000553 * Mark the built attribute as to use output_licenses for license checking.
554 */
555 public Builder<TYPE> useOutputLicenses() {
556 Preconditions.checkState(BuildType.isLabelType(type), "must be a label type");
557 return setPropertyFlag(PropertyFlag.OUTPUT_LICENSES, "output_license");
558 }
559
560 /**
cparsonsf6266392018-10-18 15:42:52 -0700561 * Indicate the attribute uses uses a starlark-defined (non-analysis-test) configuration
562 * transition. Transitions for analysis testing are tracked separately: see
563 * {@link #hasAnalysisTestTransition()}.
Googlerc2200fd2018-09-14 17:35:59 -0700564 */
cparsonsf6266392018-10-18 15:42:52 -0700565 public Builder<TYPE> hasStarlarkDefinedTransition() {
566 return setPropertyFlag(PropertyFlag.HAS_STARLARK_DEFINED_TRANSITION,
567 "starlark-defined split transition");
568 }
569
570 /**
571 * Indicate the attribute uses uses a starlark-defined analysis-test configuration transition.
572 * Such a configuration transition may only be applied on rules with {@code analysis_test=true}.
573 */
574 public Builder<TYPE> hasAnalysisTestTransition() {
575 return setPropertyFlag(PropertyFlag.HAS_ANALYSIS_TEST_TRANSITION,
576 "analysis-test split transition");
Googlerc2200fd2018-09-14 17:35:59 -0700577 }
578
John Cater0a9e1ed2019-03-27 11:02:01 -0700579 /** Defines the configuration transition for this attribute. */
John Cater2c0dece2019-04-02 09:18:18 -0700580 public Builder<TYPE> cfg(TransitionFactory<AttributeTransitionData> transitionFactory) {
John Cater5adcd3e2019-03-28 10:14:32 -0700581 Preconditions.checkNotNull(transitionFactory);
John Cater0a9e1ed2019-03-27 11:02:01 -0700582 Preconditions.checkState(
John Cater5adcd3e2019-03-28 10:14:32 -0700583 NoTransition.isInstance(this.transitionFactory),
584 "the configuration transition is already set");
585 this.transitionFactory = transitionFactory;
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000586 return this;
587 }
588
589 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100590 * Requires the attribute target to be executable; only for label or label
591 * list attributes. Defaults to {@code false}.
592 */
593 public Builder<TYPE> exec() {
594 return setPropertyFlag(PropertyFlag.EXECUTABLE, "executable");
595 }
596
597 /**
598 * Indicates that the attribute (like srcs or hdrs) should be used as an input when calculating
599 * compile_one_dependency.
600 */
601 public Builder<TYPE> direct_compile_time_input() {
602 return setPropertyFlag(PropertyFlag.DIRECT_COMPILE_TIME_INPUT,
603 "direct_compile_time_input");
604 }
605
606 /**
607 * Makes the built attribute undocumented.
608 *
609 * @param reason explanation why the attribute is undocumented. This is not
610 * used but required for documentation
611 */
612 public Builder<TYPE> undocumented(String reason) {
613 return setPropertyFlag(PropertyFlag.UNDOCUMENTED, "undocumented");
614 }
615
616 /**
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800617 * Set the doc string for the attribute.
618 *
619 * @param doc The doc string for this attribute.
620 */
621 public Builder<TYPE> setDoc(String doc) {
622 this.doc = doc;
623 return this;
624 }
625
626 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100627 * Sets the attribute default value. The type of the default value must
628 * match the type parameter. (e.g. list=[], integer=0, string="",
629 * label=null). The {@code defaultValue} must be immutable.
630 *
631 * <p>If defaultValue is of type Label and is a target, that target will
632 * become an implicit dependency of the Rule; we will load the target
633 * (and its dependencies) if it encounters the Rule and build the target
634 * if needs to apply the Rule.
635 */
636 public Builder<TYPE> value(TYPE defaultValue) {
637 Preconditions.checkState(!valueSet, "the default value is already set");
638 value = defaultValue;
639 valueSet = true;
640 return this;
641 }
642
643 /**
gregcead752cc2020-04-10 10:32:59 -0700644 * See value(TYPE) above. This method is only meant for Starlark usage.
Florian Weikertcb3d7992016-09-06 14:54:22 +0000645 *
vladmos9c787fa2017-07-04 11:45:22 -0400646 * <p>The parameter {@code context} is relevant iff the default value is a Label string. In this
647 * case, {@code context} must point to the parent Label in order to be able to convert the
648 * default value string to a proper Label.
649 *
650 * @param parameterName The name of the attribute to use in error messages
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100651 */
vladmos9c787fa2017-07-04 11:45:22 -0400652 public Builder<TYPE> defaultValue(
653 Object defaultValue, Object context, @Nullable String parameterName)
Florian Weikertcb3d7992016-09-06 14:54:22 +0000654 throws ConversionException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100655 Preconditions.checkState(!valueSet, "the default value is already set");
vladmos9c787fa2017-07-04 11:45:22 -0400656 value =
657 type.convert(
658 defaultValue,
659 ((parameterName == null) ? "" : String.format("parameter '%s' of ", parameterName))
660 + String.format("attribute '%s'", name),
661 context);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100662 valueSet = true;
663 return this;
664 }
665
gregce3377c112020-04-13 09:29:59 -0700666 /** See value(TYPE) above. This method is only meant for Starlark usage. */
Florian Weikertcb3d7992016-09-06 14:54:22 +0000667 public Builder<TYPE> defaultValue(Object defaultValue) throws ConversionException {
vladmos9c787fa2017-07-04 11:45:22 -0400668 return defaultValue(defaultValue, null, null);
Florian Weikertcb3d7992016-09-06 14:54:22 +0000669 }
670
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100671 /**
Florian Weikertea6c82d2016-09-05 12:15:31 +0000672 * Sets the attribute default value to a computed default value - use this when the default
673 * value is a function of other attributes of the Rule. The type of the computed default value
674 * for a mandatory attribute must match the type parameter: (e.g. list=[], integer=0, string="",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100675 * label=null). The {@code defaultValue} implementation must be immutable.
676 *
Florian Weikertea6c82d2016-09-05 12:15:31 +0000677 * <p>If the computed default returns a Label that is a target, that target will become an
678 * implicit dependency of this Rule; we will load the target (and its dependencies) if it
679 * encounters the Rule and build the target if needs to apply the Rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100680 */
681 public Builder<TYPE> value(ComputedDefault defaultValue) {
682 Preconditions.checkState(!valueSet, "the default value is already set");
683 value = defaultValue;
Florian Weikert438ff162016-05-12 08:49:12 +0000684 valueSource = AttributeValueSource.COMPUTED_DEFAULT;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100685 valueSet = true;
686 return this;
687 }
688
689 /**
gregce3377c112020-04-13 09:29:59 -0700690 * Sets the attribute default value to a Starlark computed default template. Like a native
691 * Computed Default, this allows a Starlark-defined Rule Class to specify that the default value
Florian Weikertea6c82d2016-09-05 12:15:31 +0000692 * of an attribute is a function of other attributes of the Rule.
693 *
694 * <p>During the loading phase, the computed default template will be specialized for each rule
695 * it applies to. Those rules' attribute values will not be references to {@link
gregce18694cd2020-05-12 15:40:05 -0700696 * StarlarkComputedDefaultTemplate}s, but instead will be references to {@link
697 * StarlarkComputedDefault}s.
Florian Weikertea6c82d2016-09-05 12:15:31 +0000698 *
699 * <p>If the computed default returns a Label that is a target, that target will become an
700 * implicit dependency of this Rule; we will load the target (and its dependencies) if it
701 * encounters the Rule and build the target if needs to apply the Rule.
702 */
gregce18694cd2020-05-12 15:40:05 -0700703 public Builder<TYPE> value(StarlarkComputedDefaultTemplate starlarkComputedDefaultTemplate) {
Florian Weikertea6c82d2016-09-05 12:15:31 +0000704 Preconditions.checkState(!valueSet, "the default value is already set");
gregce18694cd2020-05-12 15:40:05 -0700705 value = starlarkComputedDefaultTemplate;
Florian Weikertea6c82d2016-09-05 12:15:31 +0000706 valueSource = AttributeValueSource.COMPUTED_DEFAULT;
707 valueSet = true;
708 return this;
709 }
710
711 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100712 * Sets the attribute default value to be late-bound, i.e., it is derived from the build
mstaib807a9b22017-09-19 17:06:32 +0200713 * configuration and/or the rule's configured attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100714 */
mstaib807a9b22017-09-19 17:06:32 +0200715 public Builder<TYPE> value(LateBoundDefault<?, ? extends TYPE> defaultValue) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100716 Preconditions.checkState(!valueSet, "the default value is already set");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100717 value = defaultValue;
Florian Weikert438ff162016-05-12 08:49:12 +0000718 valueSource = AttributeValueSource.LATE_BOUND;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100719 valueSet = true;
720 return this;
721 }
722
gregce3377c112020-04-13 09:29:59 -0700723 /** Returns where the value of this attribute comes from. Useful only for Starlark. */
Florian Weikert438ff162016-05-12 08:49:12 +0000724 public AttributeValueSource getValueSource() {
725 return valueSource;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100726 }
727
728 /**
729 * Sets a condition predicate. The default value of the attribute only applies if the condition
730 * evaluates to true. If the value is explicitly provided, then this condition is ignored.
731 *
732 * <p>The condition is only evaluated if the attribute is not explicitly set, and after all
733 * explicit attributes have been set. It can generally not access default values of other
734 * attributes.
735 */
736 public Builder<TYPE> condition(Predicate<AttributeMap> condition) {
737 Preconditions.checkState(this.condition == null, "the condition is already set");
738 this.condition = condition;
739 return this;
740 }
741
742 /**
743 * Switches on the capability of an attribute to be published to the rule's
744 * tag set.
745 */
746 public Builder<TYPE> taggable() {
747 return setPropertyFlag(PropertyFlag.TAGGABLE, "taggable");
748 }
749
750 /**
jcater0de10972020-04-07 12:15:05 -0700751 * Disables dependency checks done by {@link
752 * com.google.devtools.build.lib.analysis.RuleContext.PrerequisiteValidator}.
Ulf Adams0b638972015-09-08 13:25:35 +0000753 */
Greg Estren875c7a72015-09-24 19:57:54 +0000754 public Builder<TYPE> skipPrereqValidatorCheck() {
755 return setPropertyFlag(PropertyFlag.SKIP_PREREQ_VALIDATOR_CHECKS,
756 "skip_prereq_validator_checks");
Ulf Adams0b638972015-09-08 13:25:35 +0000757 }
758
759 /**
Greg Estren9d837842016-12-01 21:36:59 +0000760 * Enforces constraint checking on this attribute even if default enforcement policy would skip
761 * it. If default policy checks the attribute, this is a no-op.
762 *
763 * <p>Most attributes are enforced by default, so in the common case this call is unnecessary.
Greg Estren4a102512015-10-28 20:49:22 +0000764 *
jcater802551e2020-04-15 09:59:58 -0700765 * <p>See {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for
766 * enforcement policy details.
Greg Estren4a102512015-10-28 20:49:22 +0000767 */
768 public Builder<TYPE> checkConstraints() {
Greg Estren9d837842016-12-01 21:36:59 +0000769 Verify.verify(!propertyFlags.contains(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE),
770 "constraint checking is already overridden to be skipped");
771 return setPropertyFlag(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE, "check_constraints");
772 }
773
774 /**
775 * Skips constraint checking on this attribute even if default enforcement policy would check
776 * it. If default policy skips the attribute, this is a no-op.
777 *
jcater802551e2020-04-15 09:59:58 -0700778 * <p>See {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for
779 * enforcement policy details.
Greg Estren9d837842016-12-01 21:36:59 +0000780 */
781 public Builder<TYPE> dontCheckConstraints() {
782 Verify.verify(!propertyFlags.contains(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE),
783 "constraint checking is already overridden to be checked");
784 return setPropertyFlag(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE, "dont_check_constraints");
Greg Estren4a102512015-10-28 20:49:22 +0000785 }
786
787 /**
gregceda4c9592017-07-27 22:09:34 +0200788 * If this is a label or label-list attribute, then this sets the allowed rule types for the
789 * labels occurring in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100790 *
John Cater5adcd3e2019-03-28 10:14:32 -0700791 * <p>If the attribute contains Labels of any other rule type, then if they're in {@link
792 * #allowedRuleClassesForLabelsWarning}, the build continues with a warning. Else if they
793 * fulfill {@link #mandatoryNativeProvidersList}, the build continues without error. Else the
794 * build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200795 *
796 * <p>If neither this nor {@link #allowedRuleClassesForLabelsWarning} is set, only rules that
John Cater5adcd3e2019-03-28 10:14:32 -0700797 * fulfill {@link #mandatoryNativeProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +0200798 *
John Cater5adcd3e2019-03-28 10:14:32 -0700799 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
800 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100801 */
802 public Builder<TYPE> allowedRuleClasses(Iterable<String> allowedRuleClasses) {
803 return allowedRuleClasses(
Googler72f3a102017-12-01 16:28:28 -0800804 RuleClassNamePredicate.only(allowedRuleClasses));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100805 }
806
807 /**
gregceda4c9592017-07-27 22:09:34 +0200808 * If this is a label or label-list attribute, then this sets the allowed rule types for the
809 * labels occurring in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100810 *
John Cater5adcd3e2019-03-28 10:14:32 -0700811 * <p>If the attribute contains Labels of any other rule type, then if they're in {@link
812 * #allowedRuleClassesForLabelsWarning}, the build continues with a warning. Else if they
813 * fulfill {@link #mandatoryNativeProvidersList}, the build continues without error. Else the
814 * build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200815 *
816 * <p>If neither this nor {@link #allowedRuleClassesForLabelsWarning} is set, only rules that
John Cater5adcd3e2019-03-28 10:14:32 -0700817 * fulfill {@link #mandatoryNativeProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +0200818 *
John Cater5adcd3e2019-03-28 10:14:32 -0700819 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
820 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100821 */
Googler72f3a102017-12-01 16:28:28 -0800822 public Builder<TYPE> allowedRuleClasses(RuleClassNamePredicate allowedRuleClasses) {
Michael Staiba751f922017-02-14 15:50:04 +0000823 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100824 "must be a label-valued type");
825 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
826 allowedRuleClassesForLabels = allowedRuleClasses;
827 return this;
828 }
829
830 /**
gregceda4c9592017-07-27 22:09:34 +0200831 * If this is a label or label-list attribute, then this sets the allowed rule types for the
832 * labels occurring in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100833 *
John Cater5adcd3e2019-03-28 10:14:32 -0700834 * <p>If the attribute contains Labels of any other rule type, then if they're in {@link
835 * #allowedRuleClassesForLabelsWarning}, the build continues with a warning. Else if they
836 * fulfill {@link #mandatoryNativeProvidersList}, the build continues without error. Else the
837 * build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200838 *
839 * <p>If neither this nor {@link #allowedRuleClassesForLabelsWarning} is set, only rules that
John Cater5adcd3e2019-03-28 10:14:32 -0700840 * fulfill {@link #mandatoryNativeProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +0200841 *
John Cater5adcd3e2019-03-28 10:14:32 -0700842 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
843 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100844 */
845 public Builder<TYPE> allowedRuleClasses(String... allowedRuleClasses) {
846 return allowedRuleClasses(ImmutableSet.copyOf(allowedRuleClasses));
847 }
848
849 /**
850 * If this is a label or label-list attribute, then this sets the allowed
851 * file types for file labels occurring in the attribute. If the attribute
852 * contains labels that correspond to files of any other type, then an error
853 * is produced during the analysis phase.
854 *
855 * <p>This only works on a per-target basis, not on a per-file basis; with
856 * other words, it works for 'deps' attributes, but not 'srcs' attributes.
857 */
858 public Builder<TYPE> allowedFileTypes(FileTypeSet allowedFileTypes) {
Michael Staiba751f922017-02-14 15:50:04 +0000859 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100860 "must be a label-valued type");
861 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
Ulf Adams788fd1a2015-03-12 13:54:09 +0000862 allowedFileTypesForLabels = Preconditions.checkNotNull(allowedFileTypes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100863 return this;
864 }
865
866 /**
867 * Allow all files for legacy compatibility. All uses of this method should be audited and then
868 * removed. In some cases, it's correct to allow any file, but mostly the set of files should be
869 * restricted to a reasonable set.
870 */
871 public Builder<TYPE> legacyAllowAnyFileType() {
872 return allowedFileTypes(FileTypeSet.ANY_FILE);
873 }
874
875 /**
876 * If this is a label or label-list attribute, then this sets the allowed
877 * file types for file labels occurring in the attribute. If the attribute
878 * contains labels that correspond to files of any other type, then an error
879 * is produced during the analysis phase.
880 *
881 * <p>This only works on a per-target basis, not on a per-file basis; with
882 * other words, it works for 'deps' attributes, but not 'srcs' attributes.
883 */
884 public Builder<TYPE> allowedFileTypes(FileType... allowedFileTypes) {
885 return allowedFileTypes(FileTypeSet.of(allowedFileTypes));
886 }
887
888 /**
gregceda4c9592017-07-27 22:09:34 +0200889 * If this is a label or label-list attribute, then this sets the allowed rule types with
890 * warning for the labels occurring in the attribute. This must be a disjoint set from
891 * {@link #allowedRuleClasses}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100892 *
gregceda4c9592017-07-27 22:09:34 +0200893 * <p>If the attribute contains Labels of any other rule type (other than this or those set in
894 * allowedRuleClasses()) and they fulfill {@link #getMandatoryNativeProvidersList()}}, the build
895 * continues without error. Else the build fails during analysis.
896 *
897 * <p>If neither this nor {@link #allowedRuleClassesForLabels} is set, only rules that
898 * fulfill {@link #getMandatoryNativeProvidersList()} build without error.
899 *
900 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it
901 * works for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100902 */
903 public Builder<TYPE> allowedRuleClassesWithWarning(Collection<String> allowedRuleClasses) {
904 return allowedRuleClassesWithWarning(
Googler72f3a102017-12-01 16:28:28 -0800905 RuleClassNamePredicate.only(allowedRuleClasses));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100906 }
907
908 /**
gregceda4c9592017-07-27 22:09:34 +0200909 * If this is a label or label-list attribute, then this sets the allowed rule types with
910 * warning for the labels occurring in the attribute. This must be a disjoint set from
911 * {@link #allowedRuleClasses}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100912 *
gregceda4c9592017-07-27 22:09:34 +0200913 * <p>If the attribute contains Labels of any other rule type (other than this or those set in
914 * allowedRuleClasses()) and they fulfill {@link #getMandatoryNativeProvidersList()}}, the build
915 * continues without error. Else the build fails during analysis.
916 *
917 * <p>If neither this nor {@link #allowedRuleClassesForLabels} is set, only rules that
918 * fulfill {@link #getMandatoryNativeProvidersList()} build without error.
919 *
920 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it
921 * works for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100922 */
Googler72f3a102017-12-01 16:28:28 -0800923 public Builder<TYPE> allowedRuleClassesWithWarning(RuleClassNamePredicate allowedRuleClasses) {
Michael Staiba751f922017-02-14 15:50:04 +0000924 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100925 "must be a label-valued type");
926 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
927 allowedRuleClassesForLabelsWarning = allowedRuleClasses;
928 return this;
929 }
930
931 /**
gregceda4c9592017-07-27 22:09:34 +0200932 * If this is a label or label-list attribute, then this sets the allowed rule types with
dslomovde965ac2017-07-31 21:07:51 +0200933 * warning for the labels occurring in the attribute. This must be a disjoint set from {@link
934 * #allowedRuleClasses}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100935 *
gregceda4c9592017-07-27 22:09:34 +0200936 * <p>If the attribute contains Labels of any other rule type (other than this or those set in
dslomovc13bb392017-08-02 23:29:54 +0200937 * allowedRuleClasses()) and they fulfill {@link #getRequiredProviders()}}, the build continues
938 * without error. Else the build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200939 *
dslomovc13bb392017-08-02 23:29:54 +0200940 * <p>If neither this nor {@link #allowedRuleClassesForLabels} is set, only rules that fulfill
941 * {@link #getRequiredProviders()} build without error.
gregceda4c9592017-07-27 22:09:34 +0200942 *
dslomovde965ac2017-07-31 21:07:51 +0200943 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
944 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100945 */
946 public Builder<TYPE> allowedRuleClassesWithWarning(String... allowedRuleClasses) {
947 return allowedRuleClassesWithWarning(ImmutableSet.copyOf(allowedRuleClasses));
948 }
949
950 /**
Googler861ed2c2016-09-07 19:13:17 +0000951 * Sets a list of lists of mandatory native providers. Every configured target occurring in this
952 * label type attribute has to provide all the providers from one of those lists, otherwise an
953 * error is produced during the analysis phase.
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +0000954 */
Googler861ed2c2016-09-07 19:13:17 +0000955 public final Builder<TYPE> mandatoryNativeProvidersList(
956 Iterable<? extends Iterable<Class<? extends TransitiveInfoProvider>>> providersList) {
Michael Staiba751f922017-02-14 15:50:04 +0000957 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +0000958 "must be a label-valued type");
dslomovc13bb392017-08-02 23:29:54 +0200959
Googler861ed2c2016-09-07 19:13:17 +0000960 for (Iterable<Class<? extends TransitiveInfoProvider>> providers : providersList) {
dslomovc13bb392017-08-02 23:29:54 +0200961 this.requiredProvidersBuilder.addNativeSet(ImmutableSet.copyOf(providers));
Googler861ed2c2016-09-07 19:13:17 +0000962 }
Googler861ed2c2016-09-07 19:13:17 +0000963 return this;
964 }
965
966 public Builder<TYPE> mandatoryNativeProviders(
967 Iterable<Class<? extends TransitiveInfoProvider>> providers) {
968 if (providers.iterator().hasNext()) {
969 mandatoryNativeProvidersList(ImmutableList.of(providers));
970 }
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +0000971 return this;
972 }
973
974 /**
gregce3377c112020-04-13 09:29:59 -0700975 * Sets a list of sets of mandatory Starlark providers. Every configured target occurring in
976 * this label type attribute has to provide all the providers from one of those sets, or be one
977 * of {@link #allowedRuleClasses}, otherwise an error is produced during the analysis phase.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100978 */
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +0000979 public Builder<TYPE> mandatoryProvidersList(
gregce74d84d42020-04-17 10:02:03 -0700980 Iterable<? extends Iterable<StarlarkProviderIdentifier>> providersList) {
Michael Staiba751f922017-02-14 15:50:04 +0000981 Preconditions.checkState(type.getLabelClass() == LabelClass.DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100982 "must be a label-valued type");
gregce74d84d42020-04-17 10:02:03 -0700983 for (Iterable<StarlarkProviderIdentifier> providers : providersList) {
gregce18694cd2020-05-12 15:40:05 -0700984 this.requiredProvidersBuilder.addStarlarkSet(ImmutableSet.copyOf(providers));
Yun Peng5c34e962016-02-22 15:13:19 +0000985 }
Yun Peng5c34e962016-02-22 15:13:19 +0000986 return this;
987 }
988
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +0000989 public Builder<TYPE> legacyMandatoryProviders(String... ids) {
990 return mandatoryProviders(
laurentlb3d2a68c2017-06-30 00:32:04 +0200991 Iterables.transform(
992 Arrays.asList(ids),
993 s -> {
994 Preconditions.checkNotNull(s);
gregce74d84d42020-04-17 10:02:03 -0700995 return StarlarkProviderIdentifier.forLegacy(s);
laurentlb3d2a68c2017-06-30 00:32:04 +0200996 }));
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +0000997 }
998
gregce74d84d42020-04-17 10:02:03 -0700999 public Builder<TYPE> mandatoryProviders(Iterable<StarlarkProviderIdentifier> providers) {
Yun Pengefd7ca12016-03-03 13:14:38 +00001000 if (providers.iterator().hasNext()) {
1001 mandatoryProvidersList(ImmutableList.of(providers));
1002 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001003 return this;
1004 }
1005
gregce74d84d42020-04-17 10:02:03 -07001006 public Builder<TYPE> mandatoryProviders(StarlarkProviderIdentifier... providers) {
dslomov77baa4c2017-07-10 17:15:27 +02001007 mandatoryProviders(Arrays.asList(providers));
1008 return this;
1009 }
1010
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001011 /**
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001012 * Asserts that a particular parameterized aspect probably needs to be computed for all direct
1013 * dependencies through this attribute.
1014 *
Googler459f1302017-04-05 19:40:35 +00001015 * @param evaluator function that extracts aspect parameters from rule. If it returns null,
1016 * then the aspect will not be attached.
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001017 */
Dmitry Lomove8040172016-04-06 14:53:43 +00001018 public Builder<TYPE> aspect(
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +00001019 NativeAspectClass aspect, Function<Rule, AspectParameters> evaluator) {
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001020 NativeRuleAspect nativeRuleAspect = new NativeRuleAspect(aspect, evaluator);
1021 RuleAspect<?> oldAspect = this.aspects.put(nativeRuleAspect.getName(), nativeRuleAspect);
1022 if (oldAspect != null) {
1023 throw new AssertionError(
1024 String.format("Aspect %s has already been added", oldAspect.getName()));
1025 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001026 return this;
1027 }
Marian Lobur702cad72015-09-02 09:53:58 +00001028
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001029 /**
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001030 * Asserts that a particular parameterized aspect probably needs to be computed for all direct
1031 * dependencies through this attribute.
1032 */
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +00001033 public Builder<TYPE> aspect(NativeAspectClass aspect) {
janakr123d7842018-06-19 10:30:15 -07001034 return this.aspect(aspect, EMPTY_FUNCTION);
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001035 }
1036
janakr123d7842018-06-19 10:30:15 -07001037 @AutoCodec @AutoCodec.VisibleForSerialization
1038 static final Function<Rule, AspectParameters> EMPTY_FUNCTION = input -> AspectParameters.EMPTY;
1039
gregce18694cd2020-05-12 15:40:05 -07001040 public Builder<TYPE> aspect(StarlarkDefinedAspect starlarkAspect) throws EvalException {
1041 StarlarkRuleAspect starlarkRuleAspect = new StarlarkRuleAspect(starlarkAspect);
1042 RuleAspect<?> oldAspect = this.aspects.put(starlarkAspect.getName(), starlarkRuleAspect);
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001043 if (oldAspect != null) {
gregce18694cd2020-05-12 15:40:05 -07001044 throw Starlark.errorf("aspect %s added more than once", starlarkAspect.getName());
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001045 }
Googler74558fc2016-05-06 21:47:42 +00001046 return this;
1047 }
1048
Dmitry Lomov65fde002017-02-07 17:24:04 +00001049 /**
1050 * Should only be used for deserialization.
1051 */
Googler74558fc2016-05-06 21:47:42 +00001052 public Builder<TYPE> aspect(final Aspect aspect) {
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001053 PredefinedRuleAspect predefinedRuleAspect = new PredefinedRuleAspect(aspect);
1054 RuleAspect<?> oldAspect =
1055 this.aspects.put(predefinedRuleAspect.getName(), predefinedRuleAspect);
1056 if (oldAspect != null) {
1057 throw new AssertionError(
1058 String.format("Aspect %s has already been added", oldAspect.getName()));
1059 }
Dmitry Lomove8040172016-04-06 14:53:43 +00001060 return this;
1061 }
1062
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001063 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001064 * Sets the predicate-like edge validity checker.
1065 */
1066 public Builder<TYPE> validityPredicate(ValidityPredicate validityPredicate) {
1067 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
1068 this.validityPredicate = validityPredicate;
1069 return this;
1070 }
1071
1072 /**
1073 * The value of the attribute must be one of allowedValues.
1074 */
1075 public Builder<TYPE> allowedValues(PredicateWithMessage<Object> allowedValues) {
1076 this.allowedValues = allowedValues;
1077 propertyFlags.add(PropertyFlag.CHECK_ALLOWED_VALUES);
1078 return this;
1079 }
1080
1081 /**
1082 * Makes the built attribute "non-configurable", i.e. its value cannot be influenced by
1083 * the build configuration. Attributes are "configurable" unless explicitly opted out here.
1084 *
1085 * <p>Non-configurability indicates an exceptional state: there exists Blaze logic that needs
1086 * the attribute's value, has no access to configurations, and can't apply a workaround
1087 * through an appropriate {@link AbstractAttributeMapper} implementation. Scenarios like
1088 * this should be as uncommon as possible, so it's important we maintain clear documentation
1089 * on what causes them and why users consequently can't configure certain attributes.
1090 *
1091 * @param reason why this attribute can't be configurable. This isn't used by Blaze - it's
1092 * solely a documentation mechanism.
1093 */
1094 public Builder<TYPE> nonconfigurable(String reason) {
1095 Preconditions.checkState(!reason.isEmpty());
1096 return setPropertyFlag(PropertyFlag.NONCONFIGURABLE, "nonconfigurable");
1097 }
1098
janakr33439dc2018-03-22 13:44:05 -07001099 /** Returns an {@link ImmutableAttributeFactory} that can be invoked to create attributes. */
1100 public ImmutableAttributeFactory buildPartial() {
Googler72f3a102017-12-01 16:28:28 -08001101 Preconditions.checkState(
1102 !allowedRuleClassesForLabels.consideredOverlapping(allowedRuleClassesForLabelsWarning),
1103 "allowedRuleClasses %s and allowedRuleClassesWithWarning %s "
1104 + "may not contain the same rule classes",
1105 allowedRuleClassesForLabels,
1106 allowedRuleClassesForLabelsWarning);
gregceda4c9592017-07-27 22:09:34 +02001107
janakr33439dc2018-03-22 13:44:05 -07001108 return new ImmutableAttributeFactory(
Yun Peng5c34e962016-02-22 15:13:19 +00001109 type,
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001110 doc,
Yun Peng5c34e962016-02-22 15:13:19 +00001111 Sets.immutableEnumSet(propertyFlags),
1112 valueSet ? value : type.getDefaultValue(),
John Cater5adcd3e2019-03-28 10:14:32 -07001113 transitionFactory,
Yun Peng5c34e962016-02-22 15:13:19 +00001114 allowedRuleClassesForLabels,
1115 allowedRuleClassesForLabelsWarning,
1116 allowedFileTypesForLabels,
1117 validityPredicate,
janakr33439dc2018-03-22 13:44:05 -07001118 valueSource,
1119 valueSet,
Yun Peng5c34e962016-02-22 15:13:19 +00001120 condition,
1121 allowedValues,
dslomovc13bb392017-08-02 23:29:54 +02001122 requiredProvidersBuilder.build(),
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001123 ImmutableList.copyOf(aspects.values()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001124 }
janakr33439dc2018-03-22 13:44:05 -07001125
1126 /**
1127 * Creates the attribute. Uses name, type, optionality, configuration type and the default value
1128 * configured by the builder.
1129 */
1130 public Attribute build() {
1131 return build(this.name);
1132 }
1133
1134 /**
1135 * Creates the attribute. Uses type, optionality, configuration type and the default value
1136 * configured by the builder. Use the name passed as an argument. This function is used by
gregce3377c112020-04-13 09:29:59 -07001137 * Starlark where the name is provided only when we build. We don't want to modify the builder,
janakr33439dc2018-03-22 13:44:05 -07001138 * as it is shared in a multithreaded environment.
1139 */
1140 public Attribute build(String name) {
1141 return buildPartial().build(name);
1142 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001143 }
1144
1145 /**
Florian Weikertea6c82d2016-09-05 12:15:31 +00001146 * A strategy for dealing with too many computations, used when creating lookup tables for {@link
1147 * ComputedDefault}s.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001148 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001149 * @param <TException> The type of exception this strategy throws if too many computations are
1150 * attempted.
1151 */
1152 interface ComputationLimiter<TException extends Exception> {
1153 void onComputationCount(int count) throws TException;
1154 }
1155
1156 /**
1157 * An implementation of {@link ComputationLimiter} that never throws. For use with
1158 * natively-defined {@link ComputedDefault}s, which are limited in the number of configurable
1159 * attributes they depend on, not on the number of different combinations of possible inputs.
1160 */
1161 private static final ComputationLimiter<RuntimeException> NULL_COMPUTATION_LIMITER =
1162 new ComputationLimiter<RuntimeException>() {
1163 @Override
1164 public void onComputationCount(int count) throws RuntimeException {}
1165 };
1166
1167 /** Exception for computed default attributes that depend on too many configurable attributes. */
1168 private static class TooManyConfigurableAttributesException extends Exception {
1169 TooManyConfigurableAttributesException(int max) {
1170 super(
1171 String.format(
1172 "Too many configurable attributes to compute all possible values: "
1173 + "Found more than %d possible values.",
1174 max));
1175 }
1176 }
1177
1178 private static class FixedComputationLimiter
1179 implements ComputationLimiter<TooManyConfigurableAttributesException> {
1180
1181 /** Upper bound of the number of combinations of values for a computed default attribute. */
1182 private static final int COMPUTED_DEFAULT_MAX_COMBINATIONS = 64;
1183
1184 private static final FixedComputationLimiter INSTANCE = new FixedComputationLimiter();
1185
1186 @Override
1187 public void onComputationCount(int count) throws TooManyConfigurableAttributesException {
1188 if (count > COMPUTED_DEFAULT_MAX_COMBINATIONS) {
1189 throw new TooManyConfigurableAttributesException(COMPUTED_DEFAULT_MAX_COMBINATIONS);
1190 }
1191 }
1192 }
1193
1194 /**
1195 * Specifies how values of {@link ComputedDefault} attributes are computed based on the values of
1196 * other attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001197 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001198 * <p>The {@code TComputeException} type parameter allows the two specializations of this class to
1199 * describe whether and how their computations throw. For natively defined computed defaults,
gregce3377c112020-04-13 09:29:59 -07001200 * computation does not throw, but for Starlark-defined computed defaults, computation may throw
Florian Weikertea6c82d2016-09-05 12:15:31 +00001201 * {@link InterruptedException}.
1202 */
1203 private abstract static class ComputationStrategy<TComputeException extends Exception> {
1204 abstract Object compute(AttributeMap map) throws TComputeException;
1205
1206 /**
1207 * Returns a lookup table mapping from:
1208 *
1209 * <ul>
1210 * <li>tuples of values that may be assigned by {@code rule} to attributes with names in {@code
1211 * dependencies} (note that there may be more than one such tuple for any given rule, if any
1212 * of the dependencies are configurable)
1213 * </ul>
1214 *
1215 * <p>to:
1216 *
1217 * <ul>
1218 * <li>the value {@link #compute(AttributeMap)} evaluates to when the provided {@link
1219 * AttributeMap} contains the values specified by that assignment, or {@code null} if the
1220 * {@link ComputationStrategy} failed to evaluate.
1221 * </ul>
1222 *
1223 * <p>The lookup table contains a tuple for each possible assignment to the {@code dependencies}
1224 * attributes. The meaning of each tuple is well-defined because {@code dependencies} is
1225 * ordered.
1226 *
1227 * <p>This is useful because configurable attributes may have many possible values. During the
1228 * loading phase a configurable attribute can't be resolved to a single value. Configuration
1229 * information, needed to resolve such an attribute, is only available during analysis. However,
1230 * any labels that a ComputedDefault attribute may evaluate to must be loaded during the loading
1231 * phase.
1232 */
1233 <T, TLimitException extends Exception> Map<List<Object>, T> computeValuesForAllCombinations(
1234 List<String> dependencies,
1235 Type<T> type,
1236 Rule rule,
1237 ComputationLimiter<TLimitException> limiter)
1238 throws TComputeException, TLimitException {
djasper1b869122019-03-04 10:41:50 -08001239 AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001240 // This will hold every (value1, value2, ..) combination of the declared dependencies.
1241 // Collect those combinations.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001242 List<Map<String, Object>> depMaps = mapper.visitAttributes(dependencies, limiter);
1243 // For each combination, call compute() on a specialized AttributeMap providing those
1244 // values.
nharmatab81776f2019-02-25 15:52:33 -08001245 Map<List<Object>, T> valueMap = Maps.newHashMapWithExpectedSize(depMaps.size());
Florian Weikertea6c82d2016-09-05 12:15:31 +00001246 for (Map<String, Object> depMap : depMaps) {
1247 AttributeMap attrMap = mapper.createMapBackedAttributeMap(depMap);
1248 Object value = compute(attrMap);
1249 List<Object> key = createDependencyAssignmentTuple(dependencies, attrMap);
1250 valueMap.put(key, type.cast(value));
1251 }
1252 return valueMap;
1253 }
1254
1255 /**
1256 * Given an {@link AttributeMap}, containing an assignment to each attribute in {@code
1257 * dependencies}, this returns a list of the assigned values, ordered as {@code dependencies} is
1258 * ordered.
1259 */
1260 static List<Object> createDependencyAssignmentTuple(
1261 List<String> dependencies, AttributeMap attrMap) {
1262 ArrayList<Object> tuple = new ArrayList<>(dependencies.size());
1263 for (String attrName : dependencies) {
1264 Type<?> attrType = attrMap.getAttributeType(attrName);
1265 tuple.add(attrMap.get(attrName, attrType));
1266 }
1267 return tuple;
1268 }
1269 }
1270
1271 /**
1272 * A computed default is a default value for a Rule attribute that is a function of other
1273 * attributes of the rule.
1274 *
1275 * <p>Attributes whose defaults are computed are first initialized to the default for their type,
1276 * and then the computed defaults are evaluated after all non-computed defaults have been
1277 * initialized. There is no defined order among computed defaults, so they must not depend on each
1278 * other.
1279 *
1280 * <p>If a computed default reads the value of another attribute, at least one of the following
1281 * must be true:
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001282 *
1283 * <ol>
Googler084b64b2019-11-19 14:41:30 -08001284 * <li>The other attribute must be declared in the computed default's constructor
1285 * <li>The other attribute must be non-configurable ({@link Builder#nonconfigurable}
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001286 * </ol>
1287 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001288 * <p>The reason for enforced declarations is that, since attribute values might be configurable,
1289 * a computed default that depends on them may itself take multiple values. Since we have no
1290 * access to a target's configuration at the time these values are computed, we need the ability
1291 * to probe the default's *complete* dependency space. Declared dependencies allow us to do so
1292 * sanely. Non-configurable attributes don't have this problem because their value is fixed and
1293 * known even without configuration information.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001294 *
1295 * <p>Implementations of this interface must be immutable.
1296 */
Googler34f70582019-11-25 12:27:34 -08001297 public abstract static class ComputedDefault implements StarlarkValue {
Mark Schaller93c7da62016-07-26 16:59:59 +00001298 private final ImmutableList<String> dependencies;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001299
1300 /**
1301 * Create a computed default that can read all non-configurable attribute values and no
1302 * configurable attribute values.
1303 */
1304 public ComputedDefault() {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001305 this(ImmutableList.<String>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001306 }
1307
1308 /**
1309 * Create a computed default that can read all non-configurable attributes values and one
1310 * explicitly specified configurable attribute value
1311 */
1312 public ComputedDefault(String depAttribute) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001313 this(ImmutableList.of(depAttribute));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001314 }
1315
1316 /**
1317 * Create a computed default that can read all non-configurable attributes values and two
1318 * explicitly specified configurable attribute values.
1319 */
1320 public ComputedDefault(String depAttribute1, String depAttribute2) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001321 this(ImmutableList.of(depAttribute1, depAttribute2));
1322 }
1323
1324 /**
1325 * Creates a computed default that can read all non-configurable attributes and some explicitly
1326 * specified configurable attribute values.
1327 *
1328 * <p>This constructor should not be used by native {@link ComputedDefault} functions. The limit
1329 * of at-most-two depended-on configurable attributes is intended, to limit the exponential
gregce18694cd2020-05-12 15:40:05 -07001330 * growth of possible values. {@link StarlarkComputedDefault} uses this, but is limited by
1331 * {@link FixedComputationLimiter#COMPUTED_DEFAULT_MAX_COMBINATIONS}.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001332 */
1333 protected ComputedDefault(ImmutableList<String> dependencies) {
1334 // Order is important for #createDependencyAssignmentTuple.
1335 this.dependencies = Ordering.natural().immutableSortedCopy(dependencies);
1336 }
1337
1338 <T> Iterable<T> getPossibleValues(Type<T> type, Rule rule) {
1339 final ComputedDefault owner = ComputedDefault.this;
djasper1b869122019-03-04 10:41:50 -08001340 if (dependencies.isEmpty()) {
1341 AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
1342 Object value = owner.getDefault(mapper.createMapBackedAttributeMap(ImmutableMap.of()));
1343 return Lists.newArrayList(type.cast(value));
1344 }
Florian Weikertea6c82d2016-09-05 12:15:31 +00001345 ComputationStrategy<RuntimeException> strategy =
1346 new ComputationStrategy<RuntimeException>() {
1347 @Override
1348 public Object compute(AttributeMap map) {
1349 return owner.getDefault(map);
1350 }
1351 };
1352 // Note that this uses ArrayList instead of something like ImmutableList because some
1353 // values may be null.
1354 return new ArrayList<>(
1355 strategy
1356 .computeValuesForAllCombinations(dependencies, type, rule, NULL_COMPUTATION_LIMITER)
1357 .values());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001358 }
1359
Mark Schaller93c7da62016-07-26 16:59:59 +00001360 /** The list of configurable attributes this ComputedDefault declares it may read. */
1361 public ImmutableList<String> dependencies() {
1362 return dependencies;
1363 }
1364
Florian Weikertea6c82d2016-09-05 12:15:31 +00001365 /**
1366 * Returns the value this {@link ComputedDefault} evaluates to, given the inputs contained in
1367 * {@code rule}.
1368 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001369 public abstract Object getDefault(AttributeMap rule);
1370 }
1371
1372 /**
gregce3377c112020-04-13 09:29:59 -07001373 * A Starlark-defined computed default, which can be precomputed for a specific {@link Rule} by
gregce18694cd2020-05-12 15:40:05 -07001374 * calling {@link #computePossibleValues}, which returns a {@link StarlarkComputedDefault} that
Florian Weikertea6c82d2016-09-05 12:15:31 +00001375 * contains a lookup table.
1376 */
gregce18694cd2020-05-12 15:40:05 -07001377 public static final class StarlarkComputedDefaultTemplate {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001378 private final Type<?> type;
Googlerd78a0912019-09-04 15:13:10 -07001379 private final StarlarkCallbackHelper callback;
Florian Weikertea6c82d2016-09-05 12:15:31 +00001380 private final ImmutableList<String> dependencies;
1381
1382 /**
gregce18694cd2020-05-12 15:40:05 -07001383 * Creates a new StarlarkComputedDefaultTemplate that allows the computation of attribute values
Florian Weikertea6c82d2016-09-05 12:15:31 +00001384 * via a callback function during loading phase.
1385 *
1386 * @param type The type of the value of this attribute.
1387 * @param dependencies A list of all names of other attributes that are accessed by this
1388 * attribute.
1389 * @param callback A function to compute the actual attribute value.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001390 */
gregce18694cd2020-05-12 15:40:05 -07001391 public StarlarkComputedDefaultTemplate(
adonovan7891d3b2020-01-22 12:40:50 -08001392 Type<?> type, ImmutableList<String> dependencies, StarlarkCallbackHelper callback) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001393 this.type = Preconditions.checkNotNull(type);
1394 // Order is important for #createDependencyAssignmentTuple.
1395 this.dependencies =
1396 Ordering.natural().immutableSortedCopy(Preconditions.checkNotNull(dependencies));
1397 this.callback = Preconditions.checkNotNull(callback);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001398 }
1399
1400 /**
gregce18694cd2020-05-12 15:40:05 -07001401 * Returns a {@link StarlarkComputedDefault} containing a lookup table specifying the output of
1402 * this {@link StarlarkComputedDefaultTemplate}'s callback given each possible assignment {@code
Florian Weikertea6c82d2016-09-05 12:15:31 +00001403 * rule} might make to the attributes specified by {@link #dependencies}.
1404 *
1405 * <p>If the rule is missing an attribute specified by {@link #dependencies}, or if there are
1406 * too many possible assignments, or if any evaluation fails, this throws {@link
1407 * CannotPrecomputeDefaultsException}.
1408 *
1409 * <p>May only be called after all non-{@link ComputedDefault} attributes have been set on the
1410 * {@code rule}.
1411 */
gregce18694cd2020-05-12 15:40:05 -07001412 StarlarkComputedDefault computePossibleValues(
Florian Weikertea6c82d2016-09-05 12:15:31 +00001413 Attribute attr, final Rule rule, final EventHandler eventHandler)
1414 throws InterruptedException, CannotPrecomputeDefaultsException {
1415
gregce18694cd2020-05-12 15:40:05 -07001416 final StarlarkComputedDefaultTemplate owner = StarlarkComputedDefaultTemplate.this;
Florian Weikertea6c82d2016-09-05 12:15:31 +00001417 final String msg =
1418 String.format(
1419 "Cannot compute default value of attribute '%s' in rule '%s': ",
Florian Weikertba405252017-01-30 14:42:50 +00001420 attr.getPublicName(), rule.getLabel());
Florian Weikertea6c82d2016-09-05 12:15:31 +00001421 final AtomicReference<EvalException> caughtEvalExceptionIfAny = new AtomicReference<>();
1422 ComputationStrategy<InterruptedException> strategy =
1423 new ComputationStrategy<InterruptedException>() {
1424 @Override
1425 public Object compute(AttributeMap map) throws InterruptedException {
1426 try {
vladmos076977e2017-12-02 14:15:32 -08001427 return owner.computeValue(eventHandler, map);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001428 } catch (EvalException ex) {
1429 caughtEvalExceptionIfAny.compareAndSet(null, ex);
1430 return null;
1431 }
1432 }
1433 };
1434
1435 ImmutableList.Builder<Type<?>> dependencyTypesBuilder = ImmutableList.builder();
1436 Map<List<Object>, Object> lookupTable = new HashMap<>();
1437 try {
1438 for (String dependency : dependencies) {
1439 Attribute attribute = rule.getRuleClassObject().getAttributeByNameMaybe(dependency);
1440 if (attribute == null) {
1441 throw new AttributeNotFoundException(
1442 String.format("No such attribute %s in rule %s", dependency, rule.getLabel()));
1443 }
1444 dependencyTypesBuilder.add(attribute.getType());
1445 }
1446 lookupTable.putAll(
1447 strategy.computeValuesForAllCombinations(
1448 dependencies, attr.getType(), rule, FixedComputationLimiter.INSTANCE));
1449 if (caughtEvalExceptionIfAny.get() != null) {
1450 throw caughtEvalExceptionIfAny.get();
1451 }
1452 } catch (AttributeNotFoundException
1453 | TooManyConfigurableAttributesException
1454 | EvalException ex) {
1455 String error = msg + ex.getMessage();
1456 rule.reportError(error, eventHandler);
1457 throw new CannotPrecomputeDefaultsException(error);
1458 }
gregce18694cd2020-05-12 15:40:05 -07001459 return new StarlarkComputedDefault(dependencies, dependencyTypesBuilder.build(), lookupTable);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001460 }
1461
vladmos076977e2017-12-02 14:15:32 -08001462 private Object computeValue(EventHandler eventHandler, AttributeMap rule)
1463 throws EvalException, InterruptedException {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001464 Map<String, Object> attrValues = new HashMap<>();
1465 for (String attrName : rule.getAttributeNames()) {
1466 Attribute attr = rule.getAttributeDefinition(attrName);
1467 if (!attr.hasComputedDefault()) {
1468 Object value = rule.get(attrName, attr.getType());
adonovan032a25b2020-08-26 07:04:30 -07001469 if (!Starlark.isNullOrNone(value)) {
adonovan553dc6c2019-12-10 11:22:48 -08001470 // Some attribute values are not valid Starlark values:
1471 // visibility is an ImmutableList, for example.
1472 attrValues.put(attr.getName(), Starlark.fromJava(value, /*mutability=*/ null));
Florian Weikertea6c82d2016-09-05 12:15:31 +00001473 }
1474 }
1475 }
vladmos076977e2017-12-02 14:15:32 -08001476 return invokeCallback(eventHandler, attrValues);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001477 }
1478
vladmos076977e2017-12-02 14:15:32 -08001479 private Object invokeCallback(EventHandler eventHandler, Map<String, Object> attrValues)
Florian Weikertea6c82d2016-09-05 12:15:31 +00001480 throws EvalException, InterruptedException {
adonovan267bdaa2020-11-04 11:32:24 -08001481 Structure attrs =
cparsons0c5c1c62018-05-24 10:37:03 -07001482 StructProvider.STRUCT.create(
Florian Weikertea6c82d2016-09-05 12:15:31 +00001483 attrValues, "No such regular (non computed) attribute '%s'.");
vladmos076977e2017-12-02 14:15:32 -08001484 Object result = callback.call(eventHandler, attrs);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001485 try {
Googler641bdf72019-11-12 10:32:26 -08001486 return type.cast((result == Starlark.NONE) ? type.getDefaultValue() : result);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001487 } catch (ClassCastException ex) {
adonovan8bee7072020-04-29 11:59:53 -07001488 throw Starlark.errorf("expected '%s', but got '%s'", type, Starlark.type(result));
Florian Weikertea6c82d2016-09-05 12:15:31 +00001489 }
1490 }
1491
1492 private static class AttributeNotFoundException extends Exception {
1493 private AttributeNotFoundException(String message) {
1494 super(message);
1495 }
1496 }
1497
1498 static class CannotPrecomputeDefaultsException extends Exception {
1499 private CannotPrecomputeDefaultsException(String message) {
1500 super(message);
1501 }
1502 }
1503 }
1504
1505 /**
gregce3377c112020-04-13 09:29:59 -07001506 * A class for computed attributes defined in Starlark.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001507 *
1508 * <p>Unlike {@link ComputedDefault}, instances of this class contain a pre-computed table of all
gregce3377c112020-04-13 09:29:59 -07001509 * possible assignments of depended-on attributes and what the Starlark function evaluates to, and
Florian Weikertea6c82d2016-09-05 12:15:31 +00001510 * {@link #getPossibleValues(Type, Rule)} and {@link #getDefault(AttributeMap)} do lookups in that
1511 * table.
1512 */
gregce18694cd2020-05-12 15:40:05 -07001513 static final class StarlarkComputedDefault extends ComputedDefault {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001514
1515 private final List<Type<?>> dependencyTypes;
1516 private final Map<List<Object>, Object> lookupTable;
1517
1518 /**
gregce18694cd2020-05-12 15:40:05 -07001519 * Creates a new StarlarkComputedDefault containing a lookup table.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001520 *
mjhalupka7b398f92018-03-08 12:08:25 -08001521 * @param dependencies A list of all names of other attributes that are accessed by this
Florian Weikertea6c82d2016-09-05 12:15:31 +00001522 * attribute.
1523 * @param dependencyTypes A list of requiredAttributes' types.
1524 * @param lookupTable An exhaustive mapping from requiredAttributes assignments to values this
1525 * computed default evaluates to.
1526 */
gregce18694cd2020-05-12 15:40:05 -07001527 StarlarkComputedDefault(
mjhalupka7b398f92018-03-08 12:08:25 -08001528 ImmutableList<String> dependencies,
Florian Weikertea6c82d2016-09-05 12:15:31 +00001529 ImmutableList<Type<?>> dependencyTypes,
1530 Map<List<Object>, Object> lookupTable) {
mjhalupka7b398f92018-03-08 12:08:25 -08001531 super(Preconditions.checkNotNull(dependencies));
Florian Weikertea6c82d2016-09-05 12:15:31 +00001532 this.dependencyTypes = Preconditions.checkNotNull(dependencyTypes);
1533 this.lookupTable = Preconditions.checkNotNull(lookupTable);
1534 }
1535
1536 List<Type<?>> getDependencyTypes() {
1537 return dependencyTypes;
1538 }
1539
1540 Map<List<Object>, Object> getLookupTable() {
1541 return lookupTable;
1542 }
1543
1544 @Override
1545 public Object getDefault(AttributeMap rule) {
1546 List<Object> key = ComputationStrategy.createDependencyAssignmentTuple(dependencies(), rule);
1547 Preconditions.checkState(
1548 lookupTable.containsKey(key),
1549 "Error in rule '%s': precomputed value missing for dependencies: %s. Available keys: %s.",
1550 rule.getLabel(),
1551 Iterables.toString(key),
1552 Iterables.toString(lookupTable.keySet()));
1553 return lookupTable.get(key);
1554 }
1555
1556 @Override
1557 <T> Iterable<T> getPossibleValues(Type<T> type, Rule rule) {
1558 List<T> result = new ArrayList<>(lookupTable.size());
1559 for (Object obj : lookupTable.values()) {
1560 result.add(type.cast(obj));
1561 }
1562 return result;
1563 }
1564 }
1565
janakr8688b682018-03-26 09:07:11 -07001566 static class SimpleLateBoundDefault<FragmentT, ValueT>
cparsonsd8d91722017-11-03 19:10:05 +01001567 extends LateBoundDefault<FragmentT, ValueT> {
janakrf4523e72019-06-05 14:11:06 -07001568 private final Resolver<FragmentT, ValueT> resolver;
cparsonsd8d91722017-11-03 19:10:05 +01001569
1570 private SimpleLateBoundDefault(boolean useHostConfiguration,
1571 Class<FragmentT> fragmentClass,
1572 ValueT defaultValue, Resolver<FragmentT, ValueT> resolver) {
1573 super(useHostConfiguration, fragmentClass, defaultValue);
1574
1575 this.resolver = resolver;
1576 }
1577
1578 @Override
1579 public ValueT resolve(Rule rule, AttributeMap attributes, FragmentT input) {
1580 return resolver.resolve(rule, attributes, input);
1581 }
1582 }
1583
mstaib807a9b22017-09-19 17:06:32 +02001584 // TODO(b/65746853): Remove documentation about accepting BuildConfiguration when uses are cleaned
1585 // up.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001586 /**
janakra56a6ad2018-02-02 15:52:22 -08001587 * Provider of values for late-bound attributes. See {@link Attribute#value(LateBoundDefault<?, ?
1588 * extends TYPE> value)}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001589 *
1590 * <p>Use sparingly - having different values for attributes during loading and analysis can
1591 * confuse users.
mstaib807a9b22017-09-19 17:06:32 +02001592 *
1593 * @param <FragmentT> The type of value that is used to compute this value. This is usually a
1594 * subclass of BuildConfiguration.Fragment. It may also be Void to receive null, or
1595 * BuildConfiguration itself to receive the entire configuration.
janakra56a6ad2018-02-02 15:52:22 -08001596 * @param <ValueT> The type of value returned by this class. Must be either {@link Void}, a {@link
1597 * Label}, or a {@link List} of {@link Label} objects.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001598 */
mstaib807a9b22017-09-19 17:06:32 +02001599 @Immutable
Googler34f70582019-11-25 12:27:34 -08001600 public abstract static class LateBoundDefault<FragmentT, ValueT> implements StarlarkValue {
mstaib807a9b22017-09-19 17:06:32 +02001601 /**
1602 * Functional interface for computing the value of a late-bound attribute.
1603 *
1604 * <p>Implementations of this interface must be immutable.
1605 */
1606 @FunctionalInterface
1607 public interface Resolver<FragmentT, ValueT> {
1608 ValueT resolve(Rule rule, AttributeMap attributeMap, FragmentT input);
1609 }
1610
1611 private final boolean useHostConfiguration;
1612 private final ValueT defaultValue;
1613 private final Class<FragmentT> fragmentClass;
mstaib807a9b22017-09-19 17:06:32 +02001614
1615 /**
mstaib807a9b22017-09-19 17:06:32 +02001616 * Creates a new LateBoundDefault which always returns the given value.
1617 *
1618 * <p>This is used primarily for matching names with late-bound attributes on other rules and
1619 * for testing. Use normal default values if the name does not matter.
1620 */
janakra56a6ad2018-02-02 15:52:22 -08001621 @VisibleForTesting
1622 public static LabelLateBoundDefault<Void> fromConstantForTesting(Label defaultValue) {
1623 return new LabelLateBoundDefault<Void>(
1624 false,
1625 Void.class,
1626 Preconditions.checkNotNull(defaultValue),
1627 (rule, attributes, unused) -> defaultValue) {};
mstaib807a9b22017-09-19 17:06:32 +02001628 }
1629
1630 /**
1631 * Creates a new LateBoundDefault which always returns null.
1632 *
1633 * <p>This is used primarily for matching names with late-bound attributes on other rules and
1634 * for testing. Use normal default values if the name does not matter.
1635 */
1636 @SuppressWarnings("unchecked") // bivariant implementation
1637 public static <ValueT> LateBoundDefault<Void, ValueT> alwaysNull() {
janakra56a6ad2018-02-02 15:52:22 -08001638 return (LateBoundDefault<Void, ValueT>) AlwaysNullLateBoundDefault.INSTANCE;
mstaib807a9b22017-09-19 17:06:32 +02001639 }
1640
juliexxia40fc5e82018-12-17 15:40:53 -08001641 LateBoundDefault(
1642 boolean useHostConfiguration, Class<FragmentT> fragmentClass, ValueT defaultValue) {
mstaib807a9b22017-09-19 17:06:32 +02001643 this.useHostConfiguration = useHostConfiguration;
1644 this.defaultValue = defaultValue;
1645 this.fragmentClass = fragmentClass;
mstaib807a9b22017-09-19 17:06:32 +02001646 }
1647
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001648 /**
Greg Estren974bbd92016-07-27 14:22:41 +00001649 * Whether to look up the label in the host configuration. This is only here for host
1650 * compilation tools - we usually need to look up labels in the target configuration.
mstaib807a9b22017-09-19 17:06:32 +02001651 */
cparsonsd8d91722017-11-03 19:10:05 +01001652 public final boolean useHostConfiguration() {
mstaib807a9b22017-09-19 17:06:32 +02001653 return useHostConfiguration;
1654 }
1655
1656 /**
1657 * Returns the input type that the attribute expects. This is almost always a configuration
1658 * fragment to be retrieved from the target's configuration (or the host configuration).
Greg Estren974bbd92016-07-27 14:22:41 +00001659 *
mstaib807a9b22017-09-19 17:06:32 +02001660 * <p>It may also be {@link Void} to receive null. This is rarely necessary, but can be used,
1661 * e.g., if the attribute is named to match an attribute in another rule which is late-bound.
1662 *
1663 * <p>It may also be BuildConfiguration to receive the entire configuration. This is deprecated,
1664 * and only necessary when the default is computed from methods of BuildConfiguration itself.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001665 */
cparsonsd8d91722017-11-03 19:10:05 +01001666 public final Class<FragmentT> getFragmentClass() {
mstaib807a9b22017-09-19 17:06:32 +02001667 return fragmentClass;
1668 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001669
mstaib807a9b22017-09-19 17:06:32 +02001670 /** The default value for the attribute that is set during the loading phase. */
cparsonsd8d91722017-11-03 19:10:05 +01001671 public final ValueT getDefault() {
mstaib807a9b22017-09-19 17:06:32 +02001672 return defaultValue;
1673 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001674
1675 /**
1676 * The actual value for the attribute for the analysis phase, which depends on the build
1677 * configuration. Note that configurations transitions are applied after the late-bound
1678 * attribute was evaluated.
Greg Estren33ec1912016-02-10 15:57:58 +00001679 *
1680 * @param rule the rule being evaluated
1681 * @param attributes interface for retrieving the values of the rule's other attributes
mstaib807a9b22017-09-19 17:06:32 +02001682 * @param input the configuration fragment to evaluate with
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001683 */
cparsonsd8d91722017-11-03 19:10:05 +01001684 public abstract ValueT resolve(Rule rule, AttributeMap attributes, FragmentT input);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001685 }
1686
janakra56a6ad2018-02-02 15:52:22 -08001687 /**
gregce18694cd2020-05-12 15:40:05 -07001688 * An abstract {@link LateBoundDefault} class so that {@code StarlarkLateBoundDefault} can derive
janakra56a6ad2018-02-02 15:52:22 -08001689 * from {@link LateBoundDefault} without compromising the type-safety of the second generic
1690 * parameter to {@link LateBoundDefault}.
1691 */
1692 public abstract static class AbstractLabelLateBoundDefault<FragmentT>
1693 extends LateBoundDefault<FragmentT, Label> {
1694 protected AbstractLabelLateBoundDefault(
1695 boolean useHostConfiguration, Class<FragmentT> fragmentClass, Label defaultValue) {
1696 super(useHostConfiguration, fragmentClass, defaultValue);
1697 }
1698 }
1699
janakrf4523e72019-06-05 14:11:06 -07001700 @AutoCodec.VisibleForSerialization
1701 static class AlwaysNullLateBoundDefault extends SimpleLateBoundDefault<Void, Void> {
1702 @AutoCodec @AutoCodec.VisibleForSerialization
janakra56a6ad2018-02-02 15:52:22 -08001703 static final AlwaysNullLateBoundDefault INSTANCE = new AlwaysNullLateBoundDefault();
1704
1705 private AlwaysNullLateBoundDefault() {
1706 super(false, Void.class, null, (rule, attributes, unused) -> null);
1707 }
1708 }
1709
1710 /** A {@link LateBoundDefault} for a {@link Label}. */
1711 public static class LabelLateBoundDefault<FragmentT>
1712 extends SimpleLateBoundDefault<FragmentT, Label> {
janakrf4523e72019-06-05 14:11:06 -07001713 @VisibleForTesting
juliexxia40fc5e82018-12-17 15:40:53 -08001714 protected LabelLateBoundDefault(
janakra56a6ad2018-02-02 15:52:22 -08001715 boolean useHostConfiguration,
1716 Class<FragmentT> fragmentClass,
1717 Label defaultValue,
1718 Resolver<FragmentT, Label> resolver) {
1719 super(useHostConfiguration, fragmentClass, defaultValue, resolver);
1720 }
1721
1722 /**
1723 * Creates a new LabelLateBoundDefault which uses the rule, its configured attributes, and a
1724 * fragment of the target configuration.
1725 *
1726 * <p>Note that the configuration fragment here does not take into account any transitions that
1727 * are on the attribute with this LabelLateBoundDefault as its value. The configuration will be
1728 * the same as the configuration given to the target bearing the attribute.
1729 *
1730 * <p>Nearly all LateBoundDefaults should use this constructor or {@link
1731 * LabelListLateBoundDefault#fromTargetConfiguration}. There are few situations where it isn't
1732 * the appropriate option.
1733 *
1734 * <p>If you want a late-bound dependency which is configured in the host configuration, just
1735 * use this method with {@link com.google.devtools.build.lib.analysis.config.HostTransition}. If
1736 * you also need to decide the label of the dependency with information gained from the host
1737 * configuration - and it's very unlikely that you do - you can use {@link
1738 * LabelLateBoundDefault#fromHostConfiguration} as well.
1739 *
1740 * <p>If you want to decide an attribute's value based on the value of its other attributes, use
1741 * a subclass of {@link ComputedDefault}. The only time you should need {@link
1742 * LabelListLateBoundDefault#fromRuleAndAttributesOnly} is if you need access to three or more
1743 * configurable attributes, or if you need to match names with a late-bound attribute on another
1744 * rule.
1745 *
1746 * <p>If you have a constant-valued attribute, but you need it to have the same name as an
1747 * attribute on another rule which is late-bound, use {@link #alwaysNull}.
1748 *
1749 * @param fragmentClass The fragment to receive from the target configuration. May also be
1750 * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
1751 * you must only use methods of BuildConfiguration itself, and not use any fragments.
1752 * @param defaultValue The default {@link Label} to return at loading time, when the
1753 * configuration is not available.
1754 * @param resolver A function which will compute the actual value with the configuration.
1755 */
1756 public static <FragmentT> LabelLateBoundDefault<FragmentT> fromTargetConfiguration(
1757 Class<FragmentT> fragmentClass, Label defaultValue, Resolver<FragmentT, Label> resolver) {
1758 Preconditions.checkArgument(
1759 !fragmentClass.equals(Void.class),
1760 "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
1761 + "configuration.");
1762 return new LabelLateBoundDefault<>(false, fragmentClass, defaultValue, resolver);
1763 }
1764
1765 /**
1766 * Creates a new LateBoundDefault which uses the rule, its configured attributes, and a fragment
1767 * of the host configuration.
1768 *
1769 * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
1770 * need this method, just {@link #fromTargetConfiguration} and {@link
1771 * com.google.devtools.build.lib.analysis.config.HostTransition}.
1772 *
1773 * <p>This method only affects the configuration fragment passed to {@link #resolve}. You must
1774 * also use {@link com.google.devtools.build.lib.analysis.config.HostTransition}, so that the
1775 * dependency will be analyzed in the host configuration.
1776 *
1777 * @param fragmentClass The fragment to receive from the host configuration. May also be
1778 * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
1779 * you must only use methods of BuildConfiguration itself, and not use any fragments. It is
1780 * very rare that a LateBoundDefault should need a host configuration fragment; use {@link
1781 * #fromTargetConfiguration} in most cases.
1782 * @param defaultValue The default {@link Label} to return at loading time, when the
1783 * configuration is not available.
1784 * @param resolver A function which will compute the actual value with the configuration.
1785 */
1786 public static <FragmentT> LabelLateBoundDefault<FragmentT> fromHostConfiguration(
1787 Class<FragmentT> fragmentClass, Label defaultValue, Resolver<FragmentT, Label> resolver) {
1788 Preconditions.checkArgument(
1789 !fragmentClass.equals(Void.class),
1790 "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
1791 + "configuration.");
1792 return new LabelLateBoundDefault<>(true, fragmentClass, defaultValue, resolver);
1793 }
1794 }
1795
1796 /** A {@link LateBoundDefault} for a {@link List} of {@link Label} objects. */
1797 public static class LabelListLateBoundDefault<FragmentT>
1798 extends SimpleLateBoundDefault<FragmentT, List<Label>> {
janakrf4523e72019-06-05 14:11:06 -07001799 private LabelListLateBoundDefault(
janakra56a6ad2018-02-02 15:52:22 -08001800 boolean useHostConfiguration,
1801 Class<FragmentT> fragmentClass,
1802 Resolver<FragmentT, List<Label>> resolver) {
1803 super(useHostConfiguration, fragmentClass, ImmutableList.of(), resolver);
1804 }
1805
1806 public static <FragmentT> LabelListLateBoundDefault<FragmentT> fromTargetConfiguration(
1807 Class<FragmentT> fragmentClass, Resolver<FragmentT, List<Label>> resolver) {
1808 Preconditions.checkArgument(
1809 !fragmentClass.equals(Void.class),
1810 "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
1811 + "configuration.");
1812 return new LabelListLateBoundDefault<>(false, fragmentClass, resolver);
1813 }
1814
1815 /**
1816 * Creates a new LabelListLateBoundDefault which uses only the rule and its configured
1817 * attributes.
1818 *
1819 * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
1820 * need this method, just use {@link ComputedDefault}.
1821 *
1822 * <p>This is used primarily for computing values based on three or more configurable attributes
1823 * and/or matching names with late-bound attributes on other rules.
1824 *
1825 * @param resolver A function which will compute the actual value with the configuration.
1826 */
1827 public static LabelListLateBoundDefault<Void> fromRuleAndAttributesOnly(
1828 Resolver<Void, List<Label>> resolver) {
1829 return new LabelListLateBoundDefault<>(false, Void.class, resolver);
1830 }
1831 }
1832
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001833 private final String name;
1834
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001835 private final String doc;
1836
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001837 private final Type<?> type;
1838
1839 private final Set<PropertyFlag> propertyFlags;
1840
1841 // Exactly one of these conditions is true:
1842 // 1. defaultValue == null.
1843 // 2. defaultValue instanceof ComputedDefault &&
1844 // type.isValid(defaultValue.getDefault())
gregce18694cd2020-05-12 15:40:05 -07001845 // 3. defaultValue instanceof StarlarkComputedDefaultTemplate &&
Florian Weikertea6c82d2016-09-05 12:15:31 +00001846 // type.isValid(defaultValue.computePossibleValues().getDefault())
1847 // 4. type.isValid(defaultValue).
1848 // 5. defaultValue instanceof LateBoundDefault &&
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001849 // type.isValid(defaultValue.getDefault(configuration))
1850 // (We assume a hypothetical Type.isValid(Object) predicate.)
1851 private final Object defaultValue;
1852
John Cater2c0dece2019-04-02 09:18:18 -07001853 private final TransitionFactory<AttributeTransitionData> transitionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001854
1855 /**
1856 * For label or label-list attributes, this predicate returns which rule
1857 * classes are allowed for the targets in the attribute.
1858 */
Googler72f3a102017-12-01 16:28:28 -08001859 private final RuleClassNamePredicate allowedRuleClassesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001860
1861 /**
1862 * For label or label-list attributes, this predicate returns which rule
1863 * classes are allowed for the targets in the attribute with warning.
1864 */
Googler72f3a102017-12-01 16:28:28 -08001865 private final RuleClassNamePredicate allowedRuleClassesForLabelsWarning;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001866
1867 /**
1868 * For label or label-list attributes, this predicate returns which file
1869 * types are allowed for targets in the attribute that happen to be file
1870 * targets (rather than rules).
1871 */
1872 private final FileTypeSet allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001873
1874 /**
1875 * This predicate-like object checks
1876 * if the edge between two rules using this attribute is valid
1877 * in the dependency graph. Returns null if valid, otherwise an error message.
1878 */
1879 private final ValidityPredicate validityPredicate;
1880
1881 private final Predicate<AttributeMap> condition;
1882
1883 private final PredicateWithMessage<Object> allowedValues;
1884
dslomovc13bb392017-08-02 23:29:54 +02001885 private final RequiredProviders requiredProviders;
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +00001886
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001887 private final ImmutableList<RuleAspect<?>> aspects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001888
nharmata977c8802018-03-21 12:18:21 -07001889 private final int hashCode;
1890
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001891 /**
dslomovde965ac2017-07-31 21:07:51 +02001892 * Constructs a rule attribute with the specified name, type and default value.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001893 *
1894 * @param name the name of the attribute
1895 * @param type the type of the attribute
dslomovde965ac2017-07-31 21:07:51 +02001896 * @param defaultValue the default value to use for this attribute if none is specified in rule
1897 * declaration in the BUILD file. Must be null, or of type "type". May be an instance of
1898 * ComputedDefault, in which case its getDefault() method must return an instance of "type",
1899 * or null. Must be immutable.
John Cater5adcd3e2019-03-28 10:14:32 -07001900 * @param transitionFactory the configuration transition for this attribute (which must be of type
dslomovde965ac2017-07-31 21:07:51 +02001901 * LABEL, LABEL_LIST, NODEP_LABEL or NODEP_LABEL_LIST).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001902 */
mjhalupkacfa0bb72018-03-12 12:43:15 -07001903 Attribute(
Yun Peng5c34e962016-02-22 15:13:19 +00001904 String name,
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001905 String doc,
Yun Peng5c34e962016-02-22 15:13:19 +00001906 Type<?> type,
1907 Set<PropertyFlag> propertyFlags,
1908 Object defaultValue,
John Cater2c0dece2019-04-02 09:18:18 -07001909 TransitionFactory<AttributeTransitionData> transitionFactory,
Googler72f3a102017-12-01 16:28:28 -08001910 RuleClassNamePredicate allowedRuleClassesForLabels,
1911 RuleClassNamePredicate allowedRuleClassesForLabelsWarning,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001912 FileTypeSet allowedFileTypesForLabels,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001913 ValidityPredicate validityPredicate,
1914 Predicate<AttributeMap> condition,
1915 PredicateWithMessage<Object> allowedValues,
dslomovc13bb392017-08-02 23:29:54 +02001916 RequiredProviders requiredProviders,
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001917 ImmutableList<RuleAspect<?>> aspects) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001918 Preconditions.checkArgument(
John Cater5adcd3e2019-03-28 10:14:32 -07001919 (NoTransition.isInstance(transitionFactory))
1920 || type.getLabelClass() == LabelClass.DEPENDENCY
1921 || type.getLabelClass() == LabelClass.NONDEP_REFERENCE,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001922 "Configuration transitions can only be specified for label or label list attributes");
Ulf Adams07dba942015-03-05 14:47:37 +00001923 Preconditions.checkArgument(
1924 isLateBound(name) == (defaultValue instanceof LateBoundDefault),
1925 "late bound attributes require a default value that is late bound (and vice versa): %s",
1926 name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001927 if (isLateBound(name)) {
mstaib807a9b22017-09-19 17:06:32 +02001928 LateBoundDefault<?, ?> lateBoundDefault = (LateBoundDefault<?, ?>) defaultValue;
jcater0eee8c52019-03-25 10:42:33 -07001929 Preconditions.checkArgument(
John Cater5adcd3e2019-03-28 10:14:32 -07001930 !lateBoundDefault.useHostConfiguration() || transitionFactory.isHost(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001931 "a late bound default value using the host configuration must use the host transition");
1932 }
1933
1934 this.name = name;
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001935 this.doc = doc;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001936 this.type = type;
1937 this.propertyFlags = propertyFlags;
1938 this.defaultValue = defaultValue;
John Cater5adcd3e2019-03-28 10:14:32 -07001939 this.transitionFactory = transitionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001940 this.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
1941 this.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
1942 this.allowedFileTypesForLabels = allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001943 this.validityPredicate = validityPredicate;
1944 this.condition = condition;
1945 this.allowedValues = allowedValues;
dslomovc13bb392017-08-02 23:29:54 +02001946 this.requiredProviders = requiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001947 this.aspects = aspects;
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001948 this.hashCode =
1949 Objects.hash(
1950 name,
1951 doc,
1952 type,
1953 propertyFlags,
1954 defaultValue,
John Cater5adcd3e2019-03-28 10:14:32 -07001955 transitionFactory,
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001956 allowedRuleClassesForLabels,
1957 allowedRuleClassesForLabelsWarning,
1958 allowedFileTypesForLabels,
1959 validityPredicate,
1960 condition,
1961 allowedValues,
1962 requiredProviders,
1963 aspects);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001964 }
1965
1966 /**
1967 * Returns the name of this attribute.
1968 */
1969 public String getName() {
1970 return name;
1971 }
1972
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001973 /** Returns the doc string for that attribute, if any. */
1974 public String getDoc() {
1975 return doc;
1976 }
1977
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001978 /**
gregce3377c112020-04-13 09:29:59 -07001979 * Returns the public name of this attribute. This is the name we use in Starlark code and we can
1980 * use it to display to the end-user. Implicit and late-bound attributes start with '_' (instead
1981 * of '$' or ':').
Laurent Le Brun7d903532015-08-20 20:04:41 +00001982 */
1983 public String getPublicName() {
gregced7c1cef2020-05-12 07:51:48 -07001984 return getStarlarkName(getName());
Laurent Le Brun7d903532015-08-20 20:04:41 +00001985 }
1986
1987 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001988 * Returns the logical type of this attribute. (May differ from the actual
1989 * representation as a value in the build interpreter; for example, an
1990 * attribute may logically be a list of labels, but be represented as a list
1991 * of strings.)
1992 */
1993 public Type<?> getType() {
1994 return type;
1995 }
1996
1997 private boolean getPropertyFlag(PropertyFlag flag) {
1998 return propertyFlags.contains(flag);
1999 }
2000
2001 /**
2002 * Returns true if this parameter is mandatory.
2003 */
2004 public boolean isMandatory() {
2005 return getPropertyFlag(PropertyFlag.MANDATORY);
2006 }
2007
2008 /**
2009 * Returns true if this list parameter cannot have an empty list as a value.
2010 */
2011 public boolean isNonEmpty() {
2012 return getPropertyFlag(PropertyFlag.NON_EMPTY);
2013 }
2014
2015 /**
2016 * Returns true if this label parameter must produce a single artifact.
2017 */
2018 public boolean isSingleArtifact() {
2019 return getPropertyFlag(PropertyFlag.SINGLE_ARTIFACT);
2020 }
2021
2022 /**
2023 * Returns true if this label type parameter is checked by silent ruleclass filtering.
2024 */
2025 public boolean isSilentRuleClassFilter() {
2026 return getPropertyFlag(PropertyFlag.SILENT_RULECLASS_FILTER);
2027 }
2028
2029 /**
2030 * Returns true if this label type parameter skips the analysis time filetype check.
2031 */
2032 public boolean isSkipAnalysisTimeFileTypeCheck() {
2033 return getPropertyFlag(PropertyFlag.SKIP_ANALYSIS_TIME_FILETYPE_CHECK);
2034 }
2035
2036 /**
2037 * Returns true if this parameter is order-independent.
2038 */
2039 public boolean isOrderIndependent() {
2040 return getPropertyFlag(PropertyFlag.ORDER_INDEPENDENT);
2041 }
2042
2043 /**
Irina Iancu2f235992017-01-10 16:03:29 +00002044 * Returns true if output_licenses should be used for checking licensing.
2045 */
2046 public boolean useOutputLicenses() {
2047 return getPropertyFlag(PropertyFlag.OUTPUT_LICENSES);
2048 }
2049
2050 /**
cparsonsf6266392018-10-18 15:42:52 -07002051 * Returns true if this attribute uses a starlark-defined, non analysis-test configuration
John Cater5adcd3e2019-03-28 10:14:32 -07002052 * transition. Starlark-defined analysis-test configuration transitions are handled separately.
2053 * See {@link #hasAnalysisTestTransition}.
Googlerc2200fd2018-09-14 17:35:59 -07002054 */
cparsonsf6266392018-10-18 15:42:52 -07002055 public boolean hasStarlarkDefinedTransition() {
2056 return getPropertyFlag(PropertyFlag.HAS_STARLARK_DEFINED_TRANSITION);
2057 }
2058
2059 /**
2060 * Returns true if this attributes uses Starlark-defined configuration transition designed
2061 * specifically for rules which run analysis tests.
2062 */
2063 public boolean hasAnalysisTestTransition() {
2064 return getPropertyFlag(PropertyFlag.HAS_ANALYSIS_TEST_TRANSITION);
Googlerc2200fd2018-09-14 17:35:59 -07002065 }
2066
2067 /**
John Cater5adcd3e2019-03-28 10:14:32 -07002068 * Returns the configuration transition factory for this attribute for label or label list
2069 * attributes. For other attributes it will always return {@code NONE}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002070 */
John Cater2c0dece2019-04-02 09:18:18 -07002071 public TransitionFactory<AttributeTransitionData> getTransitionFactory() {
John Cater5adcd3e2019-03-28 10:14:32 -07002072 return transitionFactory;
juliexxiacf4d89e2019-01-15 12:16:56 -08002073 }
2074
Chris Parsons2e62c0d2016-04-19 22:13:59 +00002075 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002076 * Returns whether the target is required to be executable for label or label
2077 * list attributes. For other attributes it always returns {@code false}.
2078 */
2079 public boolean isExecutable() {
2080 return getPropertyFlag(PropertyFlag.EXECUTABLE);
2081 }
2082
2083 /**
2084 * Returns {@code true} iff the rule is a direct input for an action.
2085 */
2086 public boolean isDirectCompileTimeInput() {
2087 return getPropertyFlag(PropertyFlag.DIRECT_COMPILE_TIME_INPUT);
2088 }
2089
2090 /**
2091 * Returns {@code true} iff this attribute requires documentation.
2092 */
2093 public boolean isDocumented() {
2094 return !getPropertyFlag(PropertyFlag.UNDOCUMENTED);
2095 }
2096
2097 /**
2098 * Returns {@code true} iff this attribute should be published to the rule's
2099 * tag set. Note that not all Type classes support tag conversion.
2100 */
2101 public boolean isTaggable() {
2102 return getPropertyFlag(PropertyFlag.TAGGABLE);
2103 }
2104
2105 public boolean isStrictLabelCheckingEnabled() {
2106 return getPropertyFlag(PropertyFlag.STRICT_LABEL_CHECKING);
2107 }
2108
2109 /**
2110 * Returns true if the value of this attribute should be a part of a given set.
2111 */
2112 public boolean checkAllowedValues() {
2113 return getPropertyFlag(PropertyFlag.CHECK_ALLOWED_VALUES);
2114 }
2115
Greg Estren875c7a72015-09-24 19:57:54 +00002116 public boolean performPrereqValidatorCheck() {
2117 return !getPropertyFlag(PropertyFlag.SKIP_PREREQ_VALIDATOR_CHECKS);
Ulf Adams0b638972015-09-08 13:25:35 +00002118 }
2119
Greg Estren4a102512015-10-28 20:49:22 +00002120 public boolean checkConstraintsOverride() {
Greg Estren9d837842016-12-01 21:36:59 +00002121 return getPropertyFlag(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE);
2122 }
2123
2124 public boolean skipConstraintsOverride() {
2125 return getPropertyFlag(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE);
Greg Estren4a102512015-10-28 20:49:22 +00002126 }
2127
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002128 /**
2129 * Returns true if this attribute's value can be influenced by the build configuration.
2130 */
2131 public boolean isConfigurable() {
Michael Staiba751f922017-02-14 15:50:04 +00002132 // Output types are excluded because of Rule#populateExplicitOutputFiles.
2133 return !(type.getLabelClass() == LabelClass.OUTPUT
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002134 || getPropertyFlag(PropertyFlag.NONCONFIGURABLE));
2135 }
2136
2137 /**
Googler72f3a102017-12-01 16:28:28 -08002138 * Returns a predicate that evaluates to true for rule classes that are allowed labels in this
2139 * attribute. If this is not a label or label-list attribute, the returned predicate always
2140 * evaluates to true.
2141 *
2142 * <p>NOTE: This may return Predicates.<RuleClass>alwaysTrue() as a sentinel meaning "do the right
2143 * thing", rather than actually allowing all rule classes in that attribute. Others parts of bazel
2144 * code check for that specific instance.
2145 */
2146 public Predicate<RuleClass> getAllowedRuleClassesPredicate() {
2147 return allowedRuleClassesForLabels.asPredicateOfRuleClass();
2148 }
2149
2150 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002151 * Returns a predicate that evaluates to true for rule classes that are
2152 * allowed labels in this attribute with warning. If this is not a label or label-list
2153 * attribute, the returned predicate always evaluates to true.
2154 */
2155 public Predicate<RuleClass> getAllowedRuleClassesWarningPredicate() {
Googler72f3a102017-12-01 16:28:28 -08002156 return allowedRuleClassesForLabelsWarning.asPredicateOfRuleClass();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002157 }
2158
dslomovc13bb392017-08-02 23:29:54 +02002159 public RequiredProviders getRequiredProviders() {
2160 return requiredProviders;
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +00002161 }
2162
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002163 public FileTypeSet getAllowedFileTypesPredicate() {
2164 return allowedFileTypesForLabels;
2165 }
2166
2167 public ValidityPredicate getValidityPredicate() {
2168 return validityPredicate;
2169 }
2170
2171 public Predicate<AttributeMap> getCondition() {
2172 return condition == null ? Predicates.<AttributeMap>alwaysTrue() : condition;
2173 }
2174
2175 public PredicateWithMessage<Object> getAllowedValues() {
2176 return allowedValues;
2177 }
2178
ulfjack5756b352020-01-23 04:53:22 -08002179 public boolean hasAspects() {
2180 return !aspects.isEmpty();
2181 }
2182
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002183 /**
Dmitry Lomovb487ac62015-11-09 13:09:12 +00002184 * Returns the list of aspects required for dependencies through this attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002185 */
Dmitry Lomovb487ac62015-11-09 13:09:12 +00002186 public ImmutableList<Aspect> getAspects(Rule rule) {
ulfjack5756b352020-01-23 04:53:22 -08002187 if (aspects.isEmpty()) {
2188 return ImmutableList.of();
2189 }
shreyax6b9b6072018-02-26 18:22:13 -08002190 ImmutableList.Builder<Aspect> builder = null;
Googler3e1bf5c2019-11-04 12:41:49 -08002191 for (RuleAspect<?> aspect : aspects) {
Googler459f1302017-04-05 19:40:35 +00002192 Aspect a = aspect.getAspect(rule);
2193 if (a != null) {
shreyax6b9b6072018-02-26 18:22:13 -08002194 if (builder == null) {
2195 builder = ImmutableList.builder();
2196 }
Googler459f1302017-04-05 19:40:35 +00002197 builder.add(a);
2198 }
Marian Lobur702cad72015-09-02 09:53:58 +00002199 }
shreyax6b9b6072018-02-26 18:22:13 -08002200 return builder == null ? ImmutableList.of() : builder.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002201 }
2202
Carmi Grushkodf9e5e12016-11-08 23:07:57 +00002203 public ImmutableList<AspectClass> getAspectClasses() {
2204 ImmutableList.Builder<AspectClass> result = ImmutableList.builder();
2205 for (RuleAspect<?> aspect : aspects) {
2206 result.add(aspect.getAspectClass());
2207 }
2208 return result.build();
2209 }
2210
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002211 /**
2212 * Returns the default value of this attribute in the context of the
2213 * specified Rule. For attributes with a computed default, i.e. {@code
2214 * hasComputedDefault()}, {@code rule} must be non-null since the result may
2215 * depend on the values of its other attributes.
2216 *
2217 * <p>The result may be null (although this is not a value in the build
2218 * language).
2219 *
2220 * <p>During population of the rule's attribute dictionary, all non-computed
2221 * defaults must be set before all computed ones.
2222 *
2223 * @param rule the rule to which this attribute belongs; non-null if
2224 * {@code hasComputedDefault()}; ignored otherwise.
2225 */
2226 public Object getDefaultValue(Rule rule) {
2227 if (!getCondition().apply(rule == null ? null : NonconfigurableAttributeMapper.of(rule))) {
2228 return null;
mstaib807a9b22017-09-19 17:06:32 +02002229 } else if (defaultValue instanceof LateBoundDefault<?, ?>) {
2230 return ((LateBoundDefault<?, ?>) defaultValue).getDefault();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002231 } else {
2232 return defaultValue;
2233 }
2234 }
2235
2236 /**
2237 * Returns the default value of this attribute, even if it has a condition, is a computed default,
2238 * or a late-bound default.
2239 */
2240 @VisibleForTesting
juliexxia84d1a662018-12-26 14:07:04 -08002241 public Object getDefaultValueUnchecked() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002242 return defaultValue;
2243 }
2244
mstaib807a9b22017-09-19 17:06:32 +02002245 public LateBoundDefault<?, ?> getLateBoundDefault() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002246 Preconditions.checkState(isLateBound());
mstaib807a9b22017-09-19 17:06:32 +02002247 return (LateBoundDefault<?, ?>) defaultValue;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002248 }
2249
2250 /**
2251 * Returns true iff this attribute has a computed default or a condition.
2252 *
2253 * @see #getDefaultValue(Rule)
2254 */
2255 boolean hasComputedDefault() {
Florian Weikertea6c82d2016-09-05 12:15:31 +00002256 return (defaultValue instanceof ComputedDefault)
gregce18694cd2020-05-12 15:40:05 -07002257 || (defaultValue instanceof StarlarkComputedDefaultTemplate)
Florian Weikertea6c82d2016-09-05 12:15:31 +00002258 || (condition != null);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002259 }
2260
2261 /**
2262 * Returns if this attribute is an implicit dependency according to the naming policy that
2263 * designates implicit attributes.
2264 */
2265 public boolean isImplicit() {
2266 return isImplicit(getName());
2267 }
2268
2269 /**
2270 * Returns if an attribute with the given name is an implicit dependency according to the
2271 * naming policy that designates implicit attributes.
2272 */
2273 public static boolean isImplicit(String name) {
2274 return name.startsWith("$");
2275 }
2276
2277 /**
2278 * Returns if this attribute is late-bound according to the naming policy that designates
2279 * late-bound attributes.
2280 */
2281 public boolean isLateBound() {
2282 return isLateBound(getName());
2283 }
2284
2285 /**
2286 * Returns if an attribute with the given name is late-bound according to the naming policy
2287 * that designates late-bound attributes.
2288 */
2289 public static boolean isLateBound(String name) {
2290 return name.startsWith(":");
2291 }
2292
gregce3377c112020-04-13 09:29:59 -07002293 /** Returns whether this attribute is considered private in Starlark. */
Florian Weikertba405252017-01-30 14:42:50 +00002294 private static boolean isPrivateAttribute(String nativeAttrName) {
2295 return isLateBound(nativeAttrName) || isImplicit(nativeAttrName);
2296 }
2297
2298 /**
gregce3377c112020-04-13 09:29:59 -07002299 * Returns the Starlark-usable name of this attribute.
Florian Weikertba405252017-01-30 14:42:50 +00002300 *
gregce3377c112020-04-13 09:29:59 -07002301 * <p>Implicit and late-bound attributes start with '_' (instead of '$' or ':').
Florian Weikertba405252017-01-30 14:42:50 +00002302 */
gregced7c1cef2020-05-12 07:51:48 -07002303 public static String getStarlarkName(String nativeAttrName) {
Florian Weikertba405252017-01-30 14:42:50 +00002304 if (isPrivateAttribute(nativeAttrName)) {
2305 return "_" + nativeAttrName.substring(1);
2306 }
2307 return nativeAttrName;
2308 }
2309
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002310 @Override
2311 public String toString() {
2312 return "Attribute(" + name + ", " + type + ")";
2313 }
2314
2315 @Override
2316 public int compareTo(Attribute other) {
2317 return name.compareTo(other.name);
2318 }
2319
janakr9ba46f82018-03-13 13:07:52 -07002320 @Override
2321 public boolean equals(Object o) {
2322 if (this == o) {
2323 return true;
2324 }
2325 if (o == null || getClass() != o.getClass()) {
2326 return false;
2327 }
2328 Attribute attribute = (Attribute) o;
nharmata977c8802018-03-21 12:18:21 -07002329 return Objects.equals(hashCode, attribute.hashCode)
2330 && Objects.equals(name, attribute.name)
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002331 && Objects.equals(doc, attribute.doc)
janakr9ba46f82018-03-13 13:07:52 -07002332 && Objects.equals(type, attribute.type)
2333 && Objects.equals(propertyFlags, attribute.propertyFlags)
2334 && Objects.equals(defaultValue, attribute.defaultValue)
John Cater5adcd3e2019-03-28 10:14:32 -07002335 && Objects.equals(transitionFactory, attribute.transitionFactory)
janakr9ba46f82018-03-13 13:07:52 -07002336 && Objects.equals(allowedRuleClassesForLabels, attribute.allowedRuleClassesForLabels)
2337 && Objects.equals(
2338 allowedRuleClassesForLabelsWarning, attribute.allowedRuleClassesForLabelsWarning)
2339 && Objects.equals(allowedFileTypesForLabels, attribute.allowedFileTypesForLabels)
2340 && Objects.equals(validityPredicate, attribute.validityPredicate)
2341 && Objects.equals(condition, attribute.condition)
2342 && Objects.equals(allowedValues, attribute.allowedValues)
2343 && Objects.equals(requiredProviders, attribute.requiredProviders)
2344 && Objects.equals(aspects, attribute.aspects);
2345 }
2346
2347 @Override
2348 public int hashCode() {
nharmata977c8802018-03-21 12:18:21 -07002349 return hashCode;
janakr9ba46f82018-03-13 13:07:52 -07002350 }
2351
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002352 /**
2353 * Returns a replica builder of this Attribute.
2354 */
Googler74558fc2016-05-06 21:47:42 +00002355 public <TYPE> Attribute.Builder<TYPE> cloneBuilder(Type<TYPE> tp) {
2356 Preconditions.checkArgument(tp == this.type);
Michajlo Matijkiw69d9b412016-10-06 20:06:59 +00002357 Builder<TYPE> builder = new Builder<>(name, tp);
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002358 builder.doc = doc;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002359 builder.allowedFileTypesForLabels = allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002360 builder.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
2361 builder.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
dslomovc13bb392017-08-02 23:29:54 +02002362 builder.requiredProvidersBuilder = requiredProviders.copyAsBuilder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002363 builder.validityPredicate = validityPredicate;
2364 builder.condition = condition;
John Cater5adcd3e2019-03-28 10:14:32 -07002365 builder.transitionFactory = transitionFactory;
Greg Estren4ccabd32017-03-14 17:12:45 +00002366 builder.propertyFlags = newEnumSet(propertyFlags, PropertyFlag.class);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002367 builder.value = defaultValue;
2368 builder.valueSet = false;
2369 builder.allowedValues = allowedValues;
Dmitry Lomovf188dc22016-07-19 09:00:55 +00002370 builder.aspects = new LinkedHashMap<>();
2371 for (RuleAspect<?> aspect : aspects) {
2372 builder.aspects.put(aspect.getName(), aspect);
2373 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002374
2375 return builder;
2376 }
Googler74558fc2016-05-06 21:47:42 +00002377
2378 public Attribute.Builder<?> cloneBuilder() {
2379 return cloneBuilder(this.type);
2380 }
adonovanb74f1602020-11-02 17:33:49 -08002381
2382 /**
2383 * Converts a rule attribute value from internal form to Starlark form. Internal form may use any
2384 * subtype of {@link List} or {@link Map} for {@code list} and {@code dict} attributes, whereas
2385 * Starlark uses only immutable {@link StarlarkList} and {@link Dict}.
2386 *
2387 * <p>The conversion is similar to {@link Starlark#fromJava} for all types except {@code
2388 * attr.string_list_dict} ({@code Map<String, List<String>>}), for which fromJava does not
2389 * recursively convert elements. (Doing so is expensive.)
2390 *
2391 * <p>It is tempting to require that attributes are stored internally in Starlark form. However, a
2392 * number of obstacles would need to be overcome:
2393 *
2394 * <ol>
2395 * <li>Some obscure attribute types such as TRISTATE and DISTRIBUTION are not currently legal
2396 * Starlark values.
2397 * <li>ImmutableList is significantly more compact than StarlarkList for small lists (n &lt; 2).
2398 * StarlarkList would need multiple representations and a builder to achieve parity.
2399 * <li>The types used by the Type mechanism would need changing; this has extensive
2400 * ramifications.
2401 * </ol>
2402 */
2403 public static Object valueToStarlark(Object x) {
2404 // Is x a non-empty string_list_dict?
2405 if (x instanceof Map) {
2406 Map<?, ?> map = (Map) x;
2407 if (!map.isEmpty() && map.values().iterator().next() instanceof List) {
2408 // Recursively convert subelements.
2409 Dict.Builder<Object, Object> dict = Dict.builder();
2410 for (Map.Entry<?, ?> e : map.entrySet()) {
2411 dict.put((String) e.getKey(), Starlark.fromJava(e.getValue(), null));
2412 }
2413 return dict.buildImmutable();
2414 }
2415 }
2416
2417 // For all other attribute values, shallow conversion is safe.
2418 return Starlark.fromJava(x, null);
2419 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002420}