blob: 29149fe6d66dd94792c08f98e045356e06468b06 [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> {
messaf8c34082021-06-04 02:51:04 -070081 private static final ImmutableList<String> ALL_ATTR_ASPECTS = ImmutableList.of("*");
82
Dmitry Lomove8040172016-04-06 14:53:43 +000083 protected final C aspectClass;
84 protected final Function<Rule, AspectParameters> parametersExtractor;
Marian Lobur702cad72015-09-02 09:53:58 +000085
messaf8c34082021-06-04 02:51:04 -070086 protected String baseAspectName;
87 protected ImmutableList.Builder<ImmutableSet<StarlarkProviderIdentifier>>
88 inheritedRequiredProviders;
89 protected ImmutableList.Builder<String> inheritedAttributeAspects;
90 protected boolean inheritedAllProviders = false;
91 protected boolean inheritedAllAttributes = false;
92
janakrf4523e72019-06-05 14:11:06 -070093 private RuleAspect(C aspectClass, Function<Rule, AspectParameters> parametersExtractor) {
Dmitry Lomove8040172016-04-06 14:53:43 +000094 this.aspectClass = aspectClass;
Marian Lobur702cad72015-09-02 09:53:58 +000095 this.parametersExtractor = parametersExtractor;
messaf8c34082021-06-04 02:51:04 -070096 this.inheritedRequiredProviders = ImmutableList.builder();
97 this.inheritedAttributeAspects = ImmutableList.builder();
98 }
99
100 private RuleAspect(
101 C aspectClass,
102 Function<Rule, AspectParameters> parametersExtractor,
103 String baseAspectName,
104 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProviders,
105 ImmutableList<String> inheritedAttributeAspects) {
106 this.aspectClass = aspectClass;
107 this.parametersExtractor = parametersExtractor;
108 this.baseAspectName = baseAspectName;
109 this.inheritedRequiredProviders = ImmutableList.builder();
110 this.inheritedAttributeAspects = ImmutableList.builder();
111 if (baseAspectName != null) {
112 updateInheritedRequiredProviders(inheritedRequiredProviders);
113 updateInheritedAttributeAspects(inheritedAttributeAspects);
114 }
Marian Lobur702cad72015-09-02 09:53:58 +0000115 }
116
Googler74558fc2016-05-06 21:47:42 +0000117 public String getName() {
118 return this.aspectClass.getName();
119 }
120
121 public ImmutableSet<String> getRequiredParameters() {
122 return ImmutableSet.<String>of();
123 }
124
Dmitry Lomove8040172016-04-06 14:53:43 +0000125 public abstract Aspect getAspect(Rule rule);
Carmi Grushkodf9e5e12016-11-08 23:07:57 +0000126
127 public C getAspectClass() {
128 return aspectClass;
129 }
messaf8c34082021-06-04 02:51:04 -0700130
131 protected void updateInheritedRequiredProviders(
132 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> requiredProviders) {
133 if (!inheritedAllProviders && !requiredProviders.isEmpty()) {
134 inheritedRequiredProviders.addAll(requiredProviders);
135 } else {
136 inheritedAllProviders = true;
137 }
138 }
139
140 protected void updateInheritedAttributeAspects(ImmutableList<String> attributeAspects) {
141 if (!inheritedAllAttributes && !ALL_ATTR_ASPECTS.equals(attributeAspects)) {
142 inheritedAttributeAspects.addAll(attributeAspects);
143 } else {
144 inheritedAllAttributes = true;
145 }
146 }
147
148 protected RequiredProviders buildInheritedRequiredProviders() {
149 if (baseAspectName == null) {
150 return RequiredProviders.acceptNoneBuilder().build();
151 } else if (inheritedAllProviders) {
152 return RequiredProviders.acceptAnyBuilder().build();
153 } else {
154 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProvidersList =
155 inheritedRequiredProviders.build();
156 RequiredProviders.Builder inheritedRequiredProvidersBuilder =
157 RequiredProviders.acceptAnyBuilder();
158 for (ImmutableSet<StarlarkProviderIdentifier> providerSet :
159 inheritedRequiredProvidersList) {
160 if (!providerSet.isEmpty()) {
161 inheritedRequiredProvidersBuilder.addStarlarkSet(providerSet);
162 }
163 }
164 return inheritedRequiredProvidersBuilder.build();
165 }
166 }
167
168 @Nullable
169 protected ImmutableSet<String> buildInheritedAttributeAspects() {
170 if (baseAspectName == null) {
171 return ImmutableSet.of();
172 } else if (inheritedAllAttributes) {
173 return null;
174 } else {
175 return ImmutableSet.<String>copyOf(inheritedAttributeAspects.build());
176 }
177 }
178
179 @VisibleForSerialization
180 public ImmutableList<ImmutableSet<StarlarkProviderIdentifier>>
181 getInheritedRequiredProvidersList() {
182 return inheritedRequiredProviders.build();
183 }
184
185 @VisibleForSerialization
186 public ImmutableList<String> getInheritedAttributeAspectsList() {
187 return inheritedAttributeAspects.build();
188 }
189
190 @VisibleForSerialization
191 public String getBaseAspectName() {
192 return baseAspectName;
193 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000194 }
195
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +0000196 private static class NativeRuleAspect extends RuleAspect<NativeAspectClass> {
janakrf4523e72019-06-05 14:11:06 -0700197 NativeRuleAspect(
198 NativeAspectClass aspectClass, Function<Rule, AspectParameters> parametersExtractor) {
Dmitry Lomove8040172016-04-06 14:53:43 +0000199 super(aspectClass, parametersExtractor);
Marian Lobur702cad72015-09-02 09:53:58 +0000200 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000201
messaf8c34082021-06-04 02:51:04 -0700202 NativeRuleAspect(
203 NativeAspectClass aspectClass,
204 Function<Rule, AspectParameters> parametersExtractor,
205 String baseAspectName,
206 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProvidersList,
207 ImmutableList<String> inheritedAttributeAspectsList) {
208 super(
209 aspectClass,
210 parametersExtractor,
211 baseAspectName,
212 inheritedRequiredProvidersList,
213 inheritedAttributeAspectsList);
214 }
215
Dmitry Lomove8040172016-04-06 14:53:43 +0000216 @Override
217 public Aspect getAspect(Rule rule) {
Googler459f1302017-04-05 19:40:35 +0000218 AspectParameters params = parametersExtractor.apply(rule);
messaf8c34082021-06-04 02:51:04 -0700219 return params == null
220 ? null
221 : Aspect.forNative(
222 aspectClass,
223 params,
224 buildInheritedRequiredProviders(),
225 buildInheritedAttributeAspects());
Dmitry Lomove8040172016-04-06 14:53:43 +0000226 }
227 }
228
janakrf4523e72019-06-05 14:11:06 -0700229 @VisibleForSerialization
mjhalupkacfa0bb72018-03-12 12:43:15 -0700230 @AutoCodec
gregce18694cd2020-05-12 15:40:05 -0700231 static class StarlarkRuleAspect extends RuleAspect<StarlarkAspectClass> {
gregced281df72020-05-11 12:27:06 -0700232 private final StarlarkDefinedAspect aspect;
Dmitry Lomov777845c2016-04-06 15:24:36 +0000233
janakrf4523e72019-06-05 14:11:06 -0700234 @VisibleForSerialization
messaf8c34082021-06-04 02:51:04 -0700235 StarlarkRuleAspect(
236 StarlarkDefinedAspect aspect,
237 String baseAspectName,
238 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProvidersList,
239 ImmutableList<String> inheritedAttributeAspectsList) {
240 super(
241 aspect.getAspectClass(),
242 aspect.getDefaultParametersExtractor(),
243 baseAspectName,
244 inheritedRequiredProvidersList,
245 inheritedAttributeAspectsList);
Googler74558fc2016-05-06 21:47:42 +0000246 this.aspect = aspect;
247 }
248
249 @Override
250 public ImmutableSet<String> getRequiredParameters() {
251 return aspect.getParamAttributes();
Dmitry Lomove8040172016-04-06 14:53:43 +0000252 }
253
254 @Override
255 public Aspect getAspect(Rule rule) {
Googler74558fc2016-05-06 21:47:42 +0000256 AspectParameters parameters = parametersExtractor.apply(rule);
messaf8c34082021-06-04 02:51:04 -0700257 return Aspect.forStarlark(
258 aspectClass,
259 aspect.getDefinition(parameters),
260 parameters,
261 buildInheritedRequiredProviders(),
262 buildInheritedAttributeAspects());
Googler74558fc2016-05-06 21:47:42 +0000263 }
264 }
265
Michajlo Matijkiwccd5fb12016-07-26 20:58:42 +0000266 /** A RuleAspect that just wraps a pre-existing Aspect that doesn't vary with the Rule. */
Googler74558fc2016-05-06 21:47:42 +0000267 private static class PredefinedRuleAspect extends RuleAspect<AspectClass> {
Kevin Bierhoff6f1d6082017-03-24 21:17:13 +0000268 private final Aspect aspect;
Googler74558fc2016-05-06 21:47:42 +0000269
janakrf4523e72019-06-05 14:11:06 -0700270 PredefinedRuleAspect(Aspect aspect) {
Googler74558fc2016-05-06 21:47:42 +0000271 super(aspect.getAspectClass(), null);
272 this.aspect = aspect;
273 }
274
275 @Override
276 public Aspect getAspect(Rule rule) {
277 return aspect;
Marian Lobur702cad72015-09-02 09:53:58 +0000278 }
279 }
280
janakrf4523e72019-06-05 14:11:06 -0700281 private enum PropertyFlag {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100282 MANDATORY,
283 EXECUTABLE,
284 UNDOCUMENTED,
285 TAGGABLE,
286
messa4fc24bc2021-05-20 01:42:18 -0700287 /** Whether the list attribute is order-independent and can be sorted. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100288 ORDER_INDEPENDENT,
289
290 /**
messa4fc24bc2021-05-20 01:42:18 -0700291 * Whether the allowedRuleClassesForLabels or allowedFileTypesForLabels are set to custom
292 * values. If so, and the attribute is called "deps", the legacy deps checking is skipped, and
293 * the new stricter checks are used instead. For non-"deps" attributes, this allows skipping the
294 * check if it would pass anyway, as the default setting allows any rule classes and file types.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100295 */
296 STRICT_LABEL_CHECKING,
297
298 /**
messa4fc24bc2021-05-20 01:42:18 -0700299 * Set for things that would cause the a compile or lint-like action to be executed when the
300 * input changes. Used by compile_one_dependency. Set for attributes like hdrs and srcs on cc_
301 * rules or srcs on java_ or py_rules. Generally not set on data/resource attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100302 */
303 DIRECT_COMPILE_TIME_INPUT,
304
messa4fc24bc2021-05-20 01:42:18 -0700305 /** Whether the value of the list type attribute must not be an empty list. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100306 NON_EMPTY,
307
308 /**
messa4fc24bc2021-05-20 01:42:18 -0700309 * Verifies that the referenced rule produces a single artifact. Note that this check happens on
310 * a per label basis, i.e. the check happens separately for every label in a label list.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100311 */
312 SINGLE_ARTIFACT,
313
314 /**
messa4fc24bc2021-05-20 01:42:18 -0700315 * Whether we perform silent ruleclass filtering of the dependencies of the label type attribute
316 * according to their rule classes. I.e. elements of the list which don't match the
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100317 * allowedRuleClasses predicate or not rules will be filtered out without throwing any errors.
318 * This flag is introduced to handle plugins, do not use it in other cases.
319 */
320 SILENT_RULECLASS_FILTER,
321
322 // TODO(bazel-team): This is a hack introduced because of the bad design of the original rules.
gregce3377c112020-04-13 09:29:59 -0700323 // Depot cleanup would be too expensive, but don't migrate this to Starlark.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100324 /**
gregce3377c112020-04-13 09:29:59 -0700325 * Whether to perform analysis time filetype check on this label-type attribute or not. If the
326 * flag is set, we skip the check that applies the allowedFileTypes filter to generated files.
327 * Do not use this if avoidable.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100328 */
329 SKIP_ANALYSIS_TIME_FILETYPE_CHECK,
330
messa4fc24bc2021-05-20 01:42:18 -0700331 /** Whether the value of the attribute should come from a given set of values. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100332 CHECK_ALLOWED_VALUES,
333
334 /**
messa4fc24bc2021-05-20 01:42:18 -0700335 * Whether this attribute is opted out of "configurability", i.e. the ability to determine its
336 * value based on properties of the build configuration.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100337 */
338 NONCONFIGURABLE,
Ulf Adams0b638972015-09-08 13:25:35 +0000339
340 /**
jcater0de10972020-04-07 12:15:05 -0700341 * Whether we should skip dependency validation checks done by {@link
342 * com.google.devtools.build.lib.analysis.RuleContext.PrerequisiteValidator} (for visibility,
343 * etc.).
Ulf Adams0b638972015-09-08 13:25:35 +0000344 */
Greg Estren875c7a72015-09-24 19:57:54 +0000345 SKIP_PREREQ_VALIDATOR_CHECKS,
Greg Estren4a102512015-10-28 20:49:22 +0000346
347 /**
Greg Estren9d837842016-12-01 21:36:59 +0000348 * Whether we should check constraints on this attribute even if default enforcement policy
messa4fc24bc2021-05-20 01:42:18 -0700349 * would skip it. See {@link
350 * com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for more on
Greg Estren9d837842016-12-01 21:36:59 +0000351 * constraints.
Greg Estren4a102512015-10-28 20:49:22 +0000352 */
Greg Estren9d837842016-12-01 21:36:59 +0000353 CHECK_CONSTRAINTS_OVERRIDE,
354
355 /**
356 * Whether we should skip constraints checking on this attribute even if default enforcement
357 * policy would check it.
358 */
359 SKIP_CONSTRAINTS_OVERRIDE,
Irina Iancu2f235992017-01-10 16:03:29 +0000360
messa4fc24bc2021-05-20 01:42:18 -0700361 /** Whether we should use output_licenses to check the licences on this attribute. */
Irina Iancu2f235992017-01-10 16:03:29 +0000362 OUTPUT_LICENSES,
Googlerc2200fd2018-09-14 17:35:59 -0700363
364 /**
cparsonsf6266392018-10-18 15:42:52 -0700365 * Has a Starlark-defined configuration transition. Transitions for analysis testing are tracked
366 * separately: see {@link #HAS_ANALYSIS_TEST_TRANSITION}.
Googlerc2200fd2018-09-14 17:35:59 -0700367 */
cparsonsf6266392018-10-18 15:42:52 -0700368 HAS_STARLARK_DEFINED_TRANSITION,
369
370 /**
messa4fc24bc2021-05-20 01:42:18 -0700371 * Has a Starlark-defined configuration transition designed specifically for rules which run
372 * analysis tests.
cparsonsf6266392018-10-18 15:42:52 -0700373 */
374 HAS_ANALYSIS_TEST_TRANSITION,
jcater024deb52021-05-24 14:33:12 -0700375
376 /**
377 * Signals that a dependency attribute is used as a tool (regardless of the actual configuration
378 * or transition). Cannot be used for non-dependency attributes.
379 */
380 IS_TOOL_DEPENDENCY,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100381 }
382
383 // TODO(bazel-team): modify this interface to extend Predicate and have an extra error
384 // message function like AllowedValues does
messa4fc24bc2021-05-20 01:42:18 -0700385 /** A predicate-like class that determines whether an edge between two rules is valid or not. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100386 public interface ValidityPredicate {
387 /**
messa4fc24bc2021-05-20 01:42:18 -0700388 * This method should return null if the edge is valid, or a suitable error message if it is
389 * not. Note that warnings are not supported.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100390 */
391 String checkValid(Rule from, Rule to);
392 }
393
janakrf4523e72019-06-05 14:11:06 -0700394 @AutoCodec public static final ValidityPredicate ANY_EDGE = (from, to) -> null;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100395
mjhalupkacfa0bb72018-03-12 12:43:15 -0700396 /** A predicate class to check if the value of the attribute comes from a predefined set. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100397 public static class AllowedValueSet implements PredicateWithMessage<Object> {
398
399 private final Set<Object> allowedValues;
400
brandjonaf77a302019-01-22 13:28:57 -0800401 public AllowedValueSet(Object... values) {
Carmi Grushkoe80cccd2015-11-11 19:12:31 +0000402 this(Arrays.asList(values));
403 }
404
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100405 public AllowedValueSet(Iterable<?> values) {
406 Preconditions.checkNotNull(values);
407 Preconditions.checkArgument(!Iterables.isEmpty(values));
adonovan3ed7ed52020-09-30 12:03:28 -0700408 for (Object v : values) {
409 Starlark.checkValid(v);
410 }
brandjoned249612017-07-11 22:06:22 +0200411 allowedValues = ImmutableSet.copyOf(values);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100412 }
413
414 @Override
415 public boolean apply(Object input) {
416 return allowedValues.contains(input);
417 }
418
419 @Override
420 public String getErrorReason(Object value) {
messa4fc24bc2021-05-20 01:42:18 -0700421 return String.format(
422 "has to be one of %s instead of '%s'",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100423 StringUtil.joinEnglishList(allowedValues, "or", "'"), value);
424 }
425
426 @VisibleForTesting
427 public Collection<Object> getAllowedValues() {
428 return allowedValues;
429 }
430 }
431
Googler74558fc2016-05-06 21:47:42 +0000432 public ImmutableMap<String, ImmutableSet<String>> getRequiredAspectParameters() {
433 ImmutableMap.Builder<String, ImmutableSet<String>> paramBuilder = ImmutableMap.builder();
434 for (RuleAspect<?> aspect : aspects) {
435 paramBuilder.put(aspect.getName(), aspect.getRequiredParameters());
436 }
437 return paramBuilder.build();
438 }
Dmitry Lomove8040172016-04-06 14:53:43 +0000439
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100440 /**
441 * Creates a new attribute builder.
442 *
443 * @param name attribute name
444 * @param type attribute type
445 * @return attribute builder
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100446 * @param <TYPE> attribute type class
447 */
448 public static <TYPE> Attribute.Builder<TYPE> attr(String name, Type<TYPE> type) {
449 return new Builder<>(name, type);
450 }
451
janakr33439dc2018-03-22 13:44:05 -0700452 /** A factory to generate {@link Attribute} instances. */
janakr33439dc2018-03-22 13:44:05 -0700453 public static class ImmutableAttributeFactory {
454 private final Type<?> type;
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800455 private final String doc;
John Cater2c0dece2019-04-02 09:18:18 -0700456 private final TransitionFactory<AttributeTransitionData> transitionFactory;
janakr33439dc2018-03-22 13:44:05 -0700457 private final RuleClassNamePredicate allowedRuleClassesForLabels;
458 private final RuleClassNamePredicate allowedRuleClassesForLabelsWarning;
janakr33439dc2018-03-22 13:44:05 -0700459 private final FileTypeSet allowedFileTypesForLabels;
460 private final ValidityPredicate validityPredicate;
461 private final Object value;
462 private final AttributeValueSource valueSource;
463 private final boolean valueSet;
464 private final Predicate<AttributeMap> condition;
465 private final ImmutableSet<PropertyFlag> propertyFlags;
466 private final PredicateWithMessage<Object> allowedValues;
467 private final RequiredProviders requiredProviders;
468 private final ImmutableList<RuleAspect<?>> aspects;
469
janakrf4523e72019-06-05 14:11:06 -0700470 private ImmutableAttributeFactory(
janakr33439dc2018-03-22 13:44:05 -0700471 Type<?> type,
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800472 String doc,
janakr33439dc2018-03-22 13:44:05 -0700473 ImmutableSet<PropertyFlag> propertyFlags,
474 Object value,
John Cater2c0dece2019-04-02 09:18:18 -0700475 TransitionFactory<AttributeTransitionData> transitionFactory,
janakr33439dc2018-03-22 13:44:05 -0700476 RuleClassNamePredicate allowedRuleClassesForLabels,
477 RuleClassNamePredicate allowedRuleClassesForLabelsWarning,
janakr33439dc2018-03-22 13:44:05 -0700478 FileTypeSet allowedFileTypesForLabels,
479 ValidityPredicate validityPredicate,
480 AttributeValueSource valueSource,
481 boolean valueSet,
482 Predicate<AttributeMap> condition,
483 PredicateWithMessage<Object> allowedValues,
484 RequiredProviders requiredProviders,
485 ImmutableList<RuleAspect<?>> aspects) {
486 this.type = type;
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800487 this.doc = doc;
John Cater5adcd3e2019-03-28 10:14:32 -0700488 this.transitionFactory = transitionFactory;
janakr33439dc2018-03-22 13:44:05 -0700489 this.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
490 this.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
janakr33439dc2018-03-22 13:44:05 -0700491 this.allowedFileTypesForLabels = allowedFileTypesForLabels;
492 this.validityPredicate = validityPredicate;
493 this.value = value;
494 this.valueSource = valueSource;
495 this.valueSet = valueSet;
496 this.condition = condition;
497 this.propertyFlags = propertyFlags;
498 this.allowedValues = allowedValues;
499 this.requiredProviders = requiredProviders;
500 this.aspects = aspects;
501 }
502
503 public AttributeValueSource getValueSource() {
504 return valueSource;
505 }
506
507 public boolean isValueSet() {
508 return valueSet;
509 }
510
511 public Attribute build(String name) {
512 Preconditions.checkState(!name.isEmpty(), "name has not been set");
513 if (valueSource == AttributeValueSource.LATE_BOUND) {
514 Preconditions.checkState(isLateBound(name));
John Cater5adcd3e2019-03-28 10:14:32 -0700515 Preconditions.checkState(!transitionFactory.isSplit());
janakr33439dc2018-03-22 13:44:05 -0700516 }
517 // TODO(bazel-team): Set the default to be no file type, then remove this check, and also
518 // remove all allowedFileTypes() calls without parameters.
519
520 // do not modify this.allowedFileTypesForLabels, instead create a copy.
521 FileTypeSet allowedFileTypesForLabels = this.allowedFileTypesForLabels;
522 if (type.getLabelClass() == LabelClass.DEPENDENCY) {
523 if (isPrivateAttribute(name) && allowedFileTypesForLabels == null) {
524 allowedFileTypesForLabels = FileTypeSet.ANY_FILE;
525 }
526 Preconditions.checkNotNull(
527 allowedFileTypesForLabels, "allowedFileTypesForLabels not set for %s", name);
528 } else if (type.getLabelClass() == LabelClass.OUTPUT) {
529 // TODO(bazel-team): Set the default to no file type and make explicit calls instead.
530 if (allowedFileTypesForLabels == null) {
531 allowedFileTypesForLabels = FileTypeSet.ANY_FILE;
532 }
533 }
534
535 return new Attribute(
536 name,
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800537 doc,
janakr33439dc2018-03-22 13:44:05 -0700538 type,
539 propertyFlags,
540 value,
John Cater5adcd3e2019-03-28 10:14:32 -0700541 transitionFactory,
janakr33439dc2018-03-22 13:44:05 -0700542 allowedRuleClassesForLabels,
543 allowedRuleClassesForLabelsWarning,
544 allowedFileTypesForLabels,
545 validityPredicate,
546 condition,
547 allowedValues,
548 requiredProviders,
549 aspects);
550 }
551 }
552
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100553 /**
554 * A fluent builder for the {@code Attribute} instances.
555 *
messa4fc24bc2021-05-20 01:42:18 -0700556 * <p>All methods could be called only once per builder. The attribute already undocumented based
557 * on its name cannot be marked as undocumented.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100558 */
messa4fc24bc2021-05-20 01:42:18 -0700559 public static class Builder<TYPE> {
Kevin Bierhoff6f1d6082017-03-24 21:17:13 +0000560 private final String name;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100561 private final Type<TYPE> type;
John Cater2c0dece2019-04-02 09:18:18 -0700562 private TransitionFactory<AttributeTransitionData> transitionFactory =
563 NoTransition.createFactory();
Googler72f3a102017-12-01 16:28:28 -0800564 private RuleClassNamePredicate allowedRuleClassesForLabels = ANY_RULE;
565 private RuleClassNamePredicate allowedRuleClassesForLabelsWarning = NO_RULE;
Ulf Adams788fd1a2015-03-12 13:54:09 +0000566 private FileTypeSet allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100567 private ValidityPredicate validityPredicate = ANY_EDGE;
568 private Object value;
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800569 private String doc;
Florian Weikert438ff162016-05-12 08:49:12 +0000570 private AttributeValueSource valueSource = AttributeValueSource.DIRECT;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100571 private boolean valueSet;
572 private Predicate<AttributeMap> condition;
573 private Set<PropertyFlag> propertyFlags = EnumSet.noneOf(PropertyFlag.class);
574 private PredicateWithMessage<Object> allowedValues = null;
dslomovc13bb392017-08-02 23:29:54 +0200575 private RequiredProviders.Builder requiredProvidersBuilder =
576 RequiredProviders.acceptAnyBuilder();
Dmitry Lomovf188dc22016-07-19 09:00:55 +0000577 private HashMap<String, RuleAspect<?>> aspects = new LinkedHashMap<>();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100578
579 /**
580 * Creates an attribute builder with given name and type. This attribute is optional, uses
581 * target configuration and has a default value the same as its type default value. This
582 * attribute will be marked as undocumented if its name starts with the dollar sign ({@code $})
583 * or colon ({@code :}).
584 *
585 * @param name attribute name
586 * @param type attribute type
587 */
588 public Builder(String name, Type<TYPE> type) {
589 this.name = Preconditions.checkNotNull(name);
590 this.type = Preconditions.checkNotNull(type);
591 if (isImplicit(name) || isLateBound(name)) {
592 setPropertyFlag(PropertyFlag.UNDOCUMENTED, "undocumented");
593 }
594 }
595
596 private Builder<TYPE> setPropertyFlag(PropertyFlag flag, String propertyName) {
Ulf Adams07dba942015-03-05 14:47:37 +0000597 Preconditions.checkState(
arostovtsev7d783712021-03-01 06:48:37 -0800598 !propertyFlags.contains(flag), "'%s' flag is already set", propertyName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100599 propertyFlags.add(flag);
600 return this;
601 }
602
603 /**
604 * Sets the property flag of the corresponding name if exists, otherwise throws an Exception.
gregce3377c112020-04-13 09:29:59 -0700605 * Only meant to use from Starlark, do not use from Java.
arostovtsev7d783712021-03-01 06:48:37 -0800606 *
607 * @throws EvalException if a property flag with the provided name does not exist or cannot be
608 * set.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100609 */
arostovtsev7d783712021-03-01 06:48:37 -0800610 public Builder<TYPE> setPropertyFlag(String propertyName) throws EvalException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100611 PropertyFlag flag = null;
612 try {
613 flag = PropertyFlag.valueOf(propertyName);
614 } catch (IllegalArgumentException e) {
arostovtsev7d783712021-03-01 06:48:37 -0800615 throw Starlark.errorf("unknown attribute flag '%s'", propertyName);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100616 }
arostovtsev7d783712021-03-01 06:48:37 -0800617 try {
618 setPropertyFlag(flag, propertyName);
619 } catch (IllegalStateException e) {
620 throw new EvalException(e);
621 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100622 return this;
623 }
624
messa4fc24bc2021-05-20 01:42:18 -0700625 /** Makes the built attribute mandatory. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100626 public Builder<TYPE> mandatory() {
627 return setPropertyFlag(PropertyFlag.MANDATORY, "mandatory");
628 }
629
630 /**
631 * Makes the built attribute non empty, meaning the attribute cannot have an empty list value.
632 * Only applicable for list type attributes.
633 */
634 public Builder<TYPE> nonEmpty() {
Ulf Adams07dba942015-03-05 14:47:37 +0000635 Preconditions.checkNotNull(type.getListElementType(), "attribute '%s' must be a list", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100636 return setPropertyFlag(PropertyFlag.NON_EMPTY, "non_empty");
637 }
638
messa4fc24bc2021-05-20 01:42:18 -0700639 /** Makes the built attribute producing a single artifact. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100640 public Builder<TYPE> singleArtifact() {
messa4fc24bc2021-05-20 01:42:18 -0700641 Preconditions.checkState(
642 type.getLabelClass() == LabelClass.DEPENDENCY,
643 "attribute '%s' must be a label-valued type",
644 name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100645 return setPropertyFlag(PropertyFlag.SINGLE_ARTIFACT, "single_artifact");
646 }
647
648 /**
messa4fc24bc2021-05-20 01:42:18 -0700649 * Forces silent ruleclass filtering on the label type attribute. This flag is introduced to
650 * handle plugins, do not use it in other cases.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100651 */
652 public Builder<TYPE> silentRuleClassFilter() {
messa4fc24bc2021-05-20 01:42:18 -0700653 Preconditions.checkState(
654 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100655 return setPropertyFlag(PropertyFlag.SILENT_RULECLASS_FILTER, "silent_ruleclass_filter");
656 }
657
messa4fc24bc2021-05-20 01:42:18 -0700658 /** Skip analysis time filetype check. Don't use it if avoidable. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100659 public Builder<TYPE> skipAnalysisTimeFileTypeCheck() {
messa4fc24bc2021-05-20 01:42:18 -0700660 Preconditions.checkState(
661 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
662 return setPropertyFlag(
663 PropertyFlag.SKIP_ANALYSIS_TIME_FILETYPE_CHECK, "skip_analysis_time_filetype_check");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100664 }
665
messa4fc24bc2021-05-20 01:42:18 -0700666 /** Mark the built attribute as order-independent. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100667 public Builder<TYPE> orderIndependent() {
Ulf Adams07dba942015-03-05 14:47:37 +0000668 Preconditions.checkNotNull(type.getListElementType(), "attribute '%s' must be a list", name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100669 return setPropertyFlag(PropertyFlag.ORDER_INDEPENDENT, "order-independent");
670 }
671
messa4fc24bc2021-05-20 01:42:18 -0700672 /** Mark the built attribute as to use output_licenses for license checking. */
Irina Iancu2f235992017-01-10 16:03:29 +0000673 public Builder<TYPE> useOutputLicenses() {
674 Preconditions.checkState(BuildType.isLabelType(type), "must be a label type");
675 return setPropertyFlag(PropertyFlag.OUTPUT_LICENSES, "output_license");
676 }
677
678 /**
cparsonsf6266392018-10-18 15:42:52 -0700679 * Indicate the attribute uses uses a starlark-defined (non-analysis-test) configuration
messa4fc24bc2021-05-20 01:42:18 -0700680 * transition. Transitions for analysis testing are tracked separately: see {@link
681 * #hasAnalysisTestTransition()}.
Googlerc2200fd2018-09-14 17:35:59 -0700682 */
cparsonsf6266392018-10-18 15:42:52 -0700683 public Builder<TYPE> hasStarlarkDefinedTransition() {
messa4fc24bc2021-05-20 01:42:18 -0700684 return setPropertyFlag(
685 PropertyFlag.HAS_STARLARK_DEFINED_TRANSITION, "starlark-defined split transition");
cparsonsf6266392018-10-18 15:42:52 -0700686 }
687
688 /**
689 * Indicate the attribute uses uses a starlark-defined analysis-test configuration transition.
690 * Such a configuration transition may only be applied on rules with {@code analysis_test=true}.
691 */
692 public Builder<TYPE> hasAnalysisTestTransition() {
messa4fc24bc2021-05-20 01:42:18 -0700693 return setPropertyFlag(
694 PropertyFlag.HAS_ANALYSIS_TEST_TRANSITION, "analysis-test split transition");
Googlerc2200fd2018-09-14 17:35:59 -0700695 }
696
John Cater0a9e1ed2019-03-27 11:02:01 -0700697 /** Defines the configuration transition for this attribute. */
John Cater2c0dece2019-04-02 09:18:18 -0700698 public Builder<TYPE> cfg(TransitionFactory<AttributeTransitionData> transitionFactory) {
John Cater5adcd3e2019-03-28 10:14:32 -0700699 Preconditions.checkNotNull(transitionFactory);
John Cater0a9e1ed2019-03-27 11:02:01 -0700700 Preconditions.checkState(
John Cater5adcd3e2019-03-28 10:14:32 -0700701 NoTransition.isInstance(this.transitionFactory),
702 "the configuration transition is already set");
703 this.transitionFactory = transitionFactory;
Chris Parsons2e62c0d2016-04-19 22:13:59 +0000704 return this;
705 }
706
707 /**
messa4fc24bc2021-05-20 01:42:18 -0700708 * Requires the attribute target to be executable; only for label or label list attributes.
709 * Defaults to {@code false}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100710 */
711 public Builder<TYPE> exec() {
712 return setPropertyFlag(PropertyFlag.EXECUTABLE, "executable");
713 }
714
715 /**
716 * Indicates that the attribute (like srcs or hdrs) should be used as an input when calculating
717 * compile_one_dependency.
718 */
719 public Builder<TYPE> direct_compile_time_input() {
messa4fc24bc2021-05-20 01:42:18 -0700720 return setPropertyFlag(PropertyFlag.DIRECT_COMPILE_TIME_INPUT, "direct_compile_time_input");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100721 }
722
723 /**
724 * Makes the built attribute undocumented.
725 *
messa4fc24bc2021-05-20 01:42:18 -0700726 * @param reason explanation why the attribute is undocumented. This is not used but required
727 * for documentation
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100728 */
729 public Builder<TYPE> undocumented(String reason) {
730 return setPropertyFlag(PropertyFlag.UNDOCUMENTED, "undocumented");
731 }
732
733 /**
Klaus Aehlig04952fc2019-03-01 11:36:16 -0800734 * Set the doc string for the attribute.
735 *
736 * @param doc The doc string for this attribute.
737 */
738 public Builder<TYPE> setDoc(String doc) {
739 this.doc = doc;
740 return this;
741 }
742
743 /**
messa4fc24bc2021-05-20 01:42:18 -0700744 * Sets the attribute default value. The type of the default value must match the type
745 * parameter. (e.g. list=[], integer=0, string="", label=null). The {@code defaultValue} must be
746 * immutable.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100747 *
messa4fc24bc2021-05-20 01:42:18 -0700748 * <p>If defaultValue is of type Label and is a target, that target will become an implicit
749 * dependency of the Rule; we will load the target (and its dependencies) if it encounters the
750 * Rule and build the target if needs to apply the Rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100751 */
752 public Builder<TYPE> value(TYPE defaultValue) {
753 Preconditions.checkState(!valueSet, "the default value is already set");
754 value = defaultValue;
755 valueSet = true;
756 return this;
757 }
758
759 /**
gregcead752cc2020-04-10 10:32:59 -0700760 * See value(TYPE) above. This method is only meant for Starlark usage.
Florian Weikertcb3d7992016-09-06 14:54:22 +0000761 *
vladmos9c787fa2017-07-04 11:45:22 -0400762 * <p>The parameter {@code context} is relevant iff the default value is a Label string. In this
763 * case, {@code context} must point to the parent Label in order to be able to convert the
764 * default value string to a proper Label.
765 *
766 * @param parameterName The name of the attribute to use in error messages
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100767 */
vladmos9c787fa2017-07-04 11:45:22 -0400768 public Builder<TYPE> defaultValue(
769 Object defaultValue, Object context, @Nullable String parameterName)
Florian Weikertcb3d7992016-09-06 14:54:22 +0000770 throws ConversionException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100771 Preconditions.checkState(!valueSet, "the default value is already set");
vladmos9c787fa2017-07-04 11:45:22 -0400772 value =
773 type.convert(
774 defaultValue,
775 ((parameterName == null) ? "" : String.format("parameter '%s' of ", parameterName))
776 + String.format("attribute '%s'", name),
777 context);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100778 valueSet = true;
779 return this;
780 }
781
gregce3377c112020-04-13 09:29:59 -0700782 /** See value(TYPE) above. This method is only meant for Starlark usage. */
Florian Weikertcb3d7992016-09-06 14:54:22 +0000783 public Builder<TYPE> defaultValue(Object defaultValue) throws ConversionException {
vladmos9c787fa2017-07-04 11:45:22 -0400784 return defaultValue(defaultValue, null, null);
Florian Weikertcb3d7992016-09-06 14:54:22 +0000785 }
786
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100787 /**
Florian Weikertea6c82d2016-09-05 12:15:31 +0000788 * Sets the attribute default value to a computed default value - use this when the default
789 * value is a function of other attributes of the Rule. The type of the computed default value
790 * for a mandatory attribute must match the type parameter: (e.g. list=[], integer=0, string="",
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100791 * label=null). The {@code defaultValue} implementation must be immutable.
792 *
Florian Weikertea6c82d2016-09-05 12:15:31 +0000793 * <p>If the computed default returns a Label that is a target, that target will become an
794 * implicit dependency of this Rule; we will load the target (and its dependencies) if it
795 * encounters the Rule and build the target if needs to apply the Rule.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100796 */
797 public Builder<TYPE> value(ComputedDefault defaultValue) {
798 Preconditions.checkState(!valueSet, "the default value is already set");
799 value = defaultValue;
Florian Weikert438ff162016-05-12 08:49:12 +0000800 valueSource = AttributeValueSource.COMPUTED_DEFAULT;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100801 valueSet = true;
802 return this;
803 }
804
805 /**
gregce3377c112020-04-13 09:29:59 -0700806 * Sets the attribute default value to a Starlark computed default template. Like a native
807 * Computed Default, this allows a Starlark-defined Rule Class to specify that the default value
Florian Weikertea6c82d2016-09-05 12:15:31 +0000808 * of an attribute is a function of other attributes of the Rule.
809 *
810 * <p>During the loading phase, the computed default template will be specialized for each rule
811 * it applies to. Those rules' attribute values will not be references to {@link
gregce18694cd2020-05-12 15:40:05 -0700812 * StarlarkComputedDefaultTemplate}s, but instead will be references to {@link
813 * StarlarkComputedDefault}s.
Florian Weikertea6c82d2016-09-05 12:15:31 +0000814 *
815 * <p>If the computed default returns a Label that is a target, that target will become an
816 * implicit dependency of this Rule; we will load the target (and its dependencies) if it
817 * encounters the Rule and build the target if needs to apply the Rule.
818 */
gregce18694cd2020-05-12 15:40:05 -0700819 public Builder<TYPE> value(StarlarkComputedDefaultTemplate starlarkComputedDefaultTemplate) {
Florian Weikertea6c82d2016-09-05 12:15:31 +0000820 Preconditions.checkState(!valueSet, "the default value is already set");
gregce18694cd2020-05-12 15:40:05 -0700821 value = starlarkComputedDefaultTemplate;
Florian Weikertea6c82d2016-09-05 12:15:31 +0000822 valueSource = AttributeValueSource.COMPUTED_DEFAULT;
823 valueSet = true;
824 return this;
825 }
826
827 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100828 * Sets the attribute default value to be late-bound, i.e., it is derived from the build
mstaib807a9b22017-09-19 17:06:32 +0200829 * configuration and/or the rule's configured attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100830 */
mstaib807a9b22017-09-19 17:06:32 +0200831 public Builder<TYPE> value(LateBoundDefault<?, ? extends TYPE> defaultValue) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100832 Preconditions.checkState(!valueSet, "the default value is already set");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100833 value = defaultValue;
Florian Weikert438ff162016-05-12 08:49:12 +0000834 valueSource = AttributeValueSource.LATE_BOUND;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100835 valueSet = true;
836 return this;
837 }
838
gregce3377c112020-04-13 09:29:59 -0700839 /** Returns where the value of this attribute comes from. Useful only for Starlark. */
Florian Weikert438ff162016-05-12 08:49:12 +0000840 public AttributeValueSource getValueSource() {
841 return valueSource;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100842 }
843
844 /**
845 * Sets a condition predicate. The default value of the attribute only applies if the condition
846 * evaluates to true. If the value is explicitly provided, then this condition is ignored.
847 *
848 * <p>The condition is only evaluated if the attribute is not explicitly set, and after all
849 * explicit attributes have been set. It can generally not access default values of other
850 * attributes.
851 */
852 public Builder<TYPE> condition(Predicate<AttributeMap> condition) {
853 Preconditions.checkState(this.condition == null, "the condition is already set");
854 this.condition = condition;
855 return this;
856 }
857
messa4fc24bc2021-05-20 01:42:18 -0700858 /** Switches on the capability of an attribute to be published to the rule's tag set. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100859 public Builder<TYPE> taggable() {
860 return setPropertyFlag(PropertyFlag.TAGGABLE, "taggable");
861 }
862
863 /**
jcater0de10972020-04-07 12:15:05 -0700864 * Disables dependency checks done by {@link
865 * com.google.devtools.build.lib.analysis.RuleContext.PrerequisiteValidator}.
Ulf Adams0b638972015-09-08 13:25:35 +0000866 */
Greg Estren875c7a72015-09-24 19:57:54 +0000867 public Builder<TYPE> skipPrereqValidatorCheck() {
messa4fc24bc2021-05-20 01:42:18 -0700868 return setPropertyFlag(
869 PropertyFlag.SKIP_PREREQ_VALIDATOR_CHECKS, "skip_prereq_validator_checks");
Ulf Adams0b638972015-09-08 13:25:35 +0000870 }
871
872 /**
Greg Estren9d837842016-12-01 21:36:59 +0000873 * Enforces constraint checking on this attribute even if default enforcement policy would skip
874 * it. If default policy checks the attribute, this is a no-op.
875 *
876 * <p>Most attributes are enforced by default, so in the common case this call is unnecessary.
Greg Estren4a102512015-10-28 20:49:22 +0000877 *
jcater802551e2020-04-15 09:59:58 -0700878 * <p>See {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for
879 * enforcement policy details.
Greg Estren4a102512015-10-28 20:49:22 +0000880 */
881 public Builder<TYPE> checkConstraints() {
messa4fc24bc2021-05-20 01:42:18 -0700882 Verify.verify(
883 !propertyFlags.contains(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE),
Greg Estren9d837842016-12-01 21:36:59 +0000884 "constraint checking is already overridden to be skipped");
885 return setPropertyFlag(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE, "check_constraints");
886 }
887
888 /**
889 * Skips constraint checking on this attribute even if default enforcement policy would check
890 * it. If default policy skips the attribute, this is a no-op.
891 *
jcater802551e2020-04-15 09:59:58 -0700892 * <p>See {@link com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics} for
893 * enforcement policy details.
Greg Estren9d837842016-12-01 21:36:59 +0000894 */
895 public Builder<TYPE> dontCheckConstraints() {
messa4fc24bc2021-05-20 01:42:18 -0700896 Verify.verify(
897 !propertyFlags.contains(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE),
Greg Estren9d837842016-12-01 21:36:59 +0000898 "constraint checking is already overridden to be checked");
899 return setPropertyFlag(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE, "dont_check_constraints");
Greg Estren4a102512015-10-28 20:49:22 +0000900 }
901
902 /**
gregceda4c9592017-07-27 22:09:34 +0200903 * If this is a label or label-list attribute, then this sets the allowed rule types for the
904 * labels occurring in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100905 *
John Cater5adcd3e2019-03-28 10:14:32 -0700906 * <p>If the attribute contains Labels of any other rule type, then if they're in {@link
907 * #allowedRuleClassesForLabelsWarning}, the build continues with a warning. Else if they
adonovandd000462020-11-06 12:57:38 -0800908 * fulfill {@link #mandatoryBuiltinProvidersList}, the build continues without error. Else the
John Cater5adcd3e2019-03-28 10:14:32 -0700909 * build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200910 *
911 * <p>If neither this nor {@link #allowedRuleClassesForLabelsWarning} is set, only rules that
adonovandd000462020-11-06 12:57:38 -0800912 * fulfill {@link #mandatoryBuiltinProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +0200913 *
John Cater5adcd3e2019-03-28 10:14:32 -0700914 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
915 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100916 */
917 public Builder<TYPE> allowedRuleClasses(Iterable<String> allowedRuleClasses) {
messa4fc24bc2021-05-20 01:42:18 -0700918 return allowedRuleClasses(RuleClassNamePredicate.only(allowedRuleClasses));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100919 }
920
921 /**
gregceda4c9592017-07-27 22:09:34 +0200922 * If this is a label or label-list attribute, then this sets the allowed rule types for the
923 * labels occurring in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100924 *
John Cater5adcd3e2019-03-28 10:14:32 -0700925 * <p>If the attribute contains Labels of any other rule type, then if they're in {@link
926 * #allowedRuleClassesForLabelsWarning}, the build continues with a warning. Else if they
adonovandd000462020-11-06 12:57:38 -0800927 * fulfill {@link #mandatoryBuiltinProvidersList}, the build continues without error. Else the
John Cater5adcd3e2019-03-28 10:14:32 -0700928 * build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200929 *
930 * <p>If neither this nor {@link #allowedRuleClassesForLabelsWarning} is set, only rules that
adonovandd000462020-11-06 12:57:38 -0800931 * fulfill {@link #mandatoryBuiltinProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +0200932 *
John Cater5adcd3e2019-03-28 10:14:32 -0700933 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
934 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100935 */
Googler72f3a102017-12-01 16:28:28 -0800936 public Builder<TYPE> allowedRuleClasses(RuleClassNamePredicate allowedRuleClasses) {
messa4fc24bc2021-05-20 01:42:18 -0700937 Preconditions.checkState(
938 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100939 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
940 allowedRuleClassesForLabels = allowedRuleClasses;
941 return this;
942 }
943
944 /**
gregceda4c9592017-07-27 22:09:34 +0200945 * If this is a label or label-list attribute, then this sets the allowed rule types for the
946 * labels occurring in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100947 *
John Cater5adcd3e2019-03-28 10:14:32 -0700948 * <p>If the attribute contains Labels of any other rule type, then if they're in {@link
949 * #allowedRuleClassesForLabelsWarning}, the build continues with a warning. Else if they
adonovandd000462020-11-06 12:57:38 -0800950 * fulfill {@link #mandatoryBuiltinProvidersList}, the build continues without error. Else the
John Cater5adcd3e2019-03-28 10:14:32 -0700951 * build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +0200952 *
953 * <p>If neither this nor {@link #allowedRuleClassesForLabelsWarning} is set, only rules that
adonovandd000462020-11-06 12:57:38 -0800954 * fulfill {@link #mandatoryBuiltinProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +0200955 *
John Cater5adcd3e2019-03-28 10:14:32 -0700956 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
957 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100958 */
959 public Builder<TYPE> allowedRuleClasses(String... allowedRuleClasses) {
960 return allowedRuleClasses(ImmutableSet.copyOf(allowedRuleClasses));
961 }
962
963 /**
messa4fc24bc2021-05-20 01:42:18 -0700964 * If this is a label or label-list attribute, then this sets the allowed file types for file
965 * labels occurring in the attribute. If the attribute contains labels that correspond to files
966 * of any other type, then an error is produced during the analysis phase.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100967 *
messa4fc24bc2021-05-20 01:42:18 -0700968 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
969 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100970 */
971 public Builder<TYPE> allowedFileTypes(FileTypeSet allowedFileTypes) {
messa4fc24bc2021-05-20 01:42:18 -0700972 Preconditions.checkState(
973 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100974 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
Ulf Adams788fd1a2015-03-12 13:54:09 +0000975 allowedFileTypesForLabels = Preconditions.checkNotNull(allowedFileTypes);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100976 return this;
977 }
978
979 /**
980 * Allow all files for legacy compatibility. All uses of this method should be audited and then
981 * removed. In some cases, it's correct to allow any file, but mostly the set of files should be
982 * restricted to a reasonable set.
983 */
984 public Builder<TYPE> legacyAllowAnyFileType() {
985 return allowedFileTypes(FileTypeSet.ANY_FILE);
986 }
987
988 /**
messa4fc24bc2021-05-20 01:42:18 -0700989 * If this is a label or label-list attribute, then this sets the allowed file types for file
990 * labels occurring in the attribute. If the attribute contains labels that correspond to files
991 * of any other type, then an error is produced during the analysis phase.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100992 *
messa4fc24bc2021-05-20 01:42:18 -0700993 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
994 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100995 */
996 public Builder<TYPE> allowedFileTypes(FileType... allowedFileTypes) {
997 return allowedFileTypes(FileTypeSet.of(allowedFileTypes));
998 }
999
1000 /**
gregceda4c9592017-07-27 22:09:34 +02001001 * If this is a label or label-list attribute, then this sets the allowed rule types with
adonovandd000462020-11-06 12:57:38 -08001002 * warning for the labels occurring in the attribute. This must be a disjoint set from {@link
1003 * #allowedRuleClasses}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001004 *
gregceda4c9592017-07-27 22:09:34 +02001005 * <p>If the attribute contains Labels of any other rule type (other than this or those set in
adonovandd000462020-11-06 12:57:38 -08001006 * allowedRuleClasses()) and they fulfill {@link #mandatoryBuiltinProvidersList}}, the build
gregceda4c9592017-07-27 22:09:34 +02001007 * continues without error. Else the build fails during analysis.
1008 *
adonovandd000462020-11-06 12:57:38 -08001009 * <p>If neither this nor {@link #allowedRuleClassesForLabels} is set, only rules that fulfill
1010 * {@link #mandatoryBuiltinProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +02001011 *
adonovandd000462020-11-06 12:57:38 -08001012 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
1013 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001014 */
1015 public Builder<TYPE> allowedRuleClassesWithWarning(Collection<String> allowedRuleClasses) {
messa4fc24bc2021-05-20 01:42:18 -07001016 return allowedRuleClassesWithWarning(RuleClassNamePredicate.only(allowedRuleClasses));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001017 }
1018
1019 /**
gregceda4c9592017-07-27 22:09:34 +02001020 * If this is a label or label-list attribute, then this sets the allowed rule types with
adonovandd000462020-11-06 12:57:38 -08001021 * warning for the labels occurring in the attribute. This must be a disjoint set from {@link
1022 * #allowedRuleClasses}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001023 *
gregceda4c9592017-07-27 22:09:34 +02001024 * <p>If the attribute contains Labels of any other rule type (other than this or those set in
adonovandd000462020-11-06 12:57:38 -08001025 * allowedRuleClasses()) and they fulfill {@link #mandatoryBuiltinProvidersList}}, the build
gregceda4c9592017-07-27 22:09:34 +02001026 * continues without error. Else the build fails during analysis.
1027 *
adonovandd000462020-11-06 12:57:38 -08001028 * <p>If neither this nor {@link #allowedRuleClassesForLabels} is set, only rules that fulfill
1029 * {@link #mandatoryBuiltinProvidersList} build without error.
gregceda4c9592017-07-27 22:09:34 +02001030 *
adonovandd000462020-11-06 12:57:38 -08001031 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
1032 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001033 */
Googler72f3a102017-12-01 16:28:28 -08001034 public Builder<TYPE> allowedRuleClassesWithWarning(RuleClassNamePredicate allowedRuleClasses) {
messa4fc24bc2021-05-20 01:42:18 -07001035 Preconditions.checkState(
1036 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001037 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
1038 allowedRuleClassesForLabelsWarning = allowedRuleClasses;
1039 return this;
1040 }
1041
1042 /**
gregceda4c9592017-07-27 22:09:34 +02001043 * If this is a label or label-list attribute, then this sets the allowed rule types with
dslomovde965ac2017-07-31 21:07:51 +02001044 * warning for the labels occurring in the attribute. This must be a disjoint set from {@link
1045 * #allowedRuleClasses}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001046 *
gregceda4c9592017-07-27 22:09:34 +02001047 * <p>If the attribute contains Labels of any other rule type (other than this or those set in
dslomovc13bb392017-08-02 23:29:54 +02001048 * allowedRuleClasses()) and they fulfill {@link #getRequiredProviders()}}, the build continues
1049 * without error. Else the build fails during analysis.
gregceda4c9592017-07-27 22:09:34 +02001050 *
dslomovc13bb392017-08-02 23:29:54 +02001051 * <p>If neither this nor {@link #allowedRuleClassesForLabels} is set, only rules that fulfill
1052 * {@link #getRequiredProviders()} build without error.
gregceda4c9592017-07-27 22:09:34 +02001053 *
dslomovde965ac2017-07-31 21:07:51 +02001054 * <p>This only works on a per-target basis, not on a per-file basis; with other words, it works
1055 * for 'deps' attributes, but not 'srcs' attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001056 */
1057 public Builder<TYPE> allowedRuleClassesWithWarning(String... allowedRuleClasses) {
1058 return allowedRuleClassesWithWarning(ImmutableSet.copyOf(allowedRuleClasses));
1059 }
1060
1061 /**
adonovandd000462020-11-06 12:57:38 -08001062 * Sets a list of lists of mandatory built-in providers. Every configured target occurring in
1063 * this label type attribute has to provide all the providers from one of those lists, otherwise
1064 * an error is produced during the analysis phase.
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +00001065 */
adonovandd000462020-11-06 12:57:38 -08001066 public final Builder<TYPE> mandatoryBuiltinProvidersList(
Googler861ed2c2016-09-07 19:13:17 +00001067 Iterable<? extends Iterable<Class<? extends TransitiveInfoProvider>>> providersList) {
messa4fc24bc2021-05-20 01:42:18 -07001068 Preconditions.checkState(
1069 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
dslomovc13bb392017-08-02 23:29:54 +02001070
Googler861ed2c2016-09-07 19:13:17 +00001071 for (Iterable<Class<? extends TransitiveInfoProvider>> providers : providersList) {
adonovandd000462020-11-06 12:57:38 -08001072 this.requiredProvidersBuilder.addBuiltinSet(ImmutableSet.copyOf(providers));
Googler861ed2c2016-09-07 19:13:17 +00001073 }
Googler861ed2c2016-09-07 19:13:17 +00001074 return this;
1075 }
1076
adonovandd000462020-11-06 12:57:38 -08001077 public Builder<TYPE> mandatoryBuiltinProviders(
Googler861ed2c2016-09-07 19:13:17 +00001078 Iterable<Class<? extends TransitiveInfoProvider>> providers) {
1079 if (providers.iterator().hasNext()) {
adonovandd000462020-11-06 12:57:38 -08001080 mandatoryBuiltinProvidersList(ImmutableList.of(providers));
Googler861ed2c2016-09-07 19:13:17 +00001081 }
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +00001082 return this;
1083 }
1084
1085 /**
gregce3377c112020-04-13 09:29:59 -07001086 * Sets a list of sets of mandatory Starlark providers. Every configured target occurring in
1087 * this label type attribute has to provide all the providers from one of those sets, or be one
1088 * of {@link #allowedRuleClasses}, otherwise an error is produced during the analysis phase.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001089 */
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +00001090 public Builder<TYPE> mandatoryProvidersList(
gregce74d84d42020-04-17 10:02:03 -07001091 Iterable<? extends Iterable<StarlarkProviderIdentifier>> providersList) {
messa4fc24bc2021-05-20 01:42:18 -07001092 Preconditions.checkState(
1093 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
gregce74d84d42020-04-17 10:02:03 -07001094 for (Iterable<StarlarkProviderIdentifier> providers : providersList) {
gregce18694cd2020-05-12 15:40:05 -07001095 this.requiredProvidersBuilder.addStarlarkSet(ImmutableSet.copyOf(providers));
Yun Peng5c34e962016-02-22 15:13:19 +00001096 }
Yun Peng5c34e962016-02-22 15:13:19 +00001097 return this;
1098 }
1099
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +00001100 public Builder<TYPE> legacyMandatoryProviders(String... ids) {
1101 return mandatoryProviders(
laurentlb3d2a68c2017-06-30 00:32:04 +02001102 Iterables.transform(
1103 Arrays.asList(ids),
1104 s -> {
1105 Preconditions.checkNotNull(s);
gregce74d84d42020-04-17 10:02:03 -07001106 return StarlarkProviderIdentifier.forLegacy(s);
laurentlb3d2a68c2017-06-30 00:32:04 +02001107 }));
Dmitry Lomovfd2bdc32016-10-07 08:52:10 +00001108 }
1109
gregce74d84d42020-04-17 10:02:03 -07001110 public Builder<TYPE> mandatoryProviders(Iterable<StarlarkProviderIdentifier> providers) {
Yun Pengefd7ca12016-03-03 13:14:38 +00001111 if (providers.iterator().hasNext()) {
1112 mandatoryProvidersList(ImmutableList.of(providers));
1113 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001114 return this;
1115 }
1116
gregce74d84d42020-04-17 10:02:03 -07001117 public Builder<TYPE> mandatoryProviders(StarlarkProviderIdentifier... providers) {
dslomov77baa4c2017-07-10 17:15:27 +02001118 mandatoryProviders(Arrays.asList(providers));
1119 return this;
1120 }
1121
messaf8c34082021-06-04 02:51:04 -07001122 @AutoCodec @AutoCodec.VisibleForSerialization
1123 static final Function<Rule, AspectParameters> EMPTY_FUNCTION = input -> AspectParameters.EMPTY;
1124
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001125 /**
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001126 * Asserts that a particular parameterized aspect probably needs to be computed for all direct
1127 * dependencies through this attribute.
1128 *
messa4fc24bc2021-05-20 01:42:18 -07001129 * @param evaluator function that extracts aspect parameters from rule. If it returns null, then
1130 * the aspect will not be attached.
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001131 */
Dmitry Lomove8040172016-04-06 14:53:43 +00001132 public Builder<TYPE> aspect(
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +00001133 NativeAspectClass aspect, Function<Rule, AspectParameters> evaluator) {
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001134 NativeRuleAspect nativeRuleAspect = new NativeRuleAspect(aspect, evaluator);
1135 RuleAspect<?> oldAspect = this.aspects.put(nativeRuleAspect.getName(), nativeRuleAspect);
1136 if (oldAspect != null) {
1137 throw new AssertionError(
1138 String.format("Aspect %s has already been added", oldAspect.getName()));
1139 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001140 return this;
1141 }
Marian Lobur702cad72015-09-02 09:53:58 +00001142
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001143 /**
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001144 * Asserts that a particular parameterized aspect probably needs to be computed for all direct
1145 * dependencies through this attribute.
1146 */
Luis Fernando Pino Duquee82713d2016-04-26 16:22:38 +00001147 public Builder<TYPE> aspect(NativeAspectClass aspect) {
janakr123d7842018-06-19 10:30:15 -07001148 return this.aspect(aspect, EMPTY_FUNCTION);
Dmitry Lomov5a8f1c02015-11-26 10:49:16 +00001149 }
1150
messaf8c34082021-06-04 02:51:04 -07001151 public Builder<TYPE> aspect(
1152 StarlarkDefinedAspect starlarkAspect,
1153 String baseAspectName,
1154 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProviders,
1155 ImmutableList<String> inheritedAttributeAspects)
1156 throws EvalException {
1157 boolean needsToAdd =
1158 checkAndUpdateExistingAspects(
1159 starlarkAspect.getName(),
1160 baseAspectName,
1161 inheritedRequiredProviders,
1162 inheritedAttributeAspects);
1163 if (needsToAdd) {
1164 StarlarkRuleAspect starlarkRuleAspect =
1165 new StarlarkRuleAspect(
1166 starlarkAspect,
1167 baseAspectName,
1168 inheritedRequiredProviders,
1169 inheritedAttributeAspects);
1170 this.aspects.put(starlarkAspect.getName(), starlarkRuleAspect);
1171 }
1172 return this;
1173 }
janakr123d7842018-06-19 10:30:15 -07001174
messaf8c34082021-06-04 02:51:04 -07001175 public Builder<TYPE> aspect(
1176 NativeAspectClass nativeAspect,
1177 String baseAspectName,
1178 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProviders,
1179 ImmutableList<String> inheritedAttributeAspects)
1180 throws EvalException {
1181 boolean needsToAdd =
1182 checkAndUpdateExistingAspects(
1183 nativeAspect.getName(),
1184 baseAspectName,
1185 inheritedRequiredProviders,
1186 inheritedAttributeAspects);
1187 if (needsToAdd) {
1188 NativeRuleAspect nativeRuleAspect =
1189 new NativeRuleAspect(
1190 nativeAspect,
1191 EMPTY_FUNCTION,
1192 baseAspectName,
1193 inheritedRequiredProviders,
1194 inheritedAttributeAspects);
1195 this.aspects.put(nativeAspect.getName(), nativeRuleAspect);
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001196 }
Googler74558fc2016-05-06 21:47:42 +00001197 return this;
1198 }
1199
messa4fc24bc2021-05-20 01:42:18 -07001200 /** Should only be used for deserialization. */
Googler74558fc2016-05-06 21:47:42 +00001201 public Builder<TYPE> aspect(final Aspect aspect) {
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001202 PredefinedRuleAspect predefinedRuleAspect = new PredefinedRuleAspect(aspect);
1203 RuleAspect<?> oldAspect =
1204 this.aspects.put(predefinedRuleAspect.getName(), predefinedRuleAspect);
1205 if (oldAspect != null) {
1206 throw new AssertionError(
1207 String.format("Aspect %s has already been added", oldAspect.getName()));
1208 }
Dmitry Lomove8040172016-04-06 14:53:43 +00001209 return this;
1210 }
1211
messaf8c34082021-06-04 02:51:04 -07001212 private boolean checkAndUpdateExistingAspects(
1213 String aspectName,
1214 String baseAspectName,
1215 ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProviders,
1216 ImmutableList<String> inheritedAttributeAspects)
1217 throws EvalException {
1218
1219 RuleAspect<?> oldAspect = this.aspects.get(aspectName);
1220
1221 if (oldAspect != null) {
1222 // If the aspect to be added is required by another aspect, i.e. {@code baseAspectName} is
1223 // not null, then we need to update its inherited required providers and propgation
1224 // attributes.
1225 if (baseAspectName != null) {
1226 oldAspect.baseAspectName = baseAspectName;
1227 oldAspect.updateInheritedRequiredProviders(inheritedRequiredProviders);
1228 oldAspect.updateInheritedAttributeAspects(inheritedAttributeAspects);
1229 return false; // no need to add the new aspect
1230 } else {
1231 // If the aspect to be added is not required by another aspect, then we
1232 // should throw an error
1233 String oldAspectBaseAspectName = oldAspect.baseAspectName;
1234 if (oldAspectBaseAspectName != null) {
1235 throw Starlark.errorf(
1236 "aspect %s was added before as a required aspect of aspect %s",
1237 oldAspect.getName(), oldAspectBaseAspectName);
1238 }
1239 throw Starlark.errorf("aspect %s added more than once", oldAspect.getName());
1240 }
1241 }
1242
1243 return true; // we need to add the new aspect
1244 }
1245
messa4fc24bc2021-05-20 01:42:18 -07001246 /** Sets the predicate-like edge validity checker. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001247 public Builder<TYPE> validityPredicate(ValidityPredicate validityPredicate) {
1248 propertyFlags.add(PropertyFlag.STRICT_LABEL_CHECKING);
1249 this.validityPredicate = validityPredicate;
1250 return this;
1251 }
1252
messa4fc24bc2021-05-20 01:42:18 -07001253 /** The value of the attribute must be one of allowedValues. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001254 public Builder<TYPE> allowedValues(PredicateWithMessage<Object> allowedValues) {
1255 this.allowedValues = allowedValues;
1256 propertyFlags.add(PropertyFlag.CHECK_ALLOWED_VALUES);
1257 return this;
1258 }
1259
1260 /**
messa4fc24bc2021-05-20 01:42:18 -07001261 * Makes the built attribute "non-configurable", i.e. its value cannot be influenced by the
1262 * build configuration. Attributes are "configurable" unless explicitly opted out here.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001263 *
1264 * <p>Non-configurability indicates an exceptional state: there exists Blaze logic that needs
messa4fc24bc2021-05-20 01:42:18 -07001265 * the attribute's value, has no access to configurations, and can't apply a workaround through
1266 * an appropriate {@link AbstractAttributeMapper} implementation. Scenarios like this should be
1267 * as uncommon as possible, so it's important we maintain clear documentation on what causes
1268 * them and why users consequently can't configure certain attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001269 *
1270 * @param reason why this attribute can't be configurable. This isn't used by Blaze - it's
messa4fc24bc2021-05-20 01:42:18 -07001271 * solely a documentation mechanism.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001272 */
1273 public Builder<TYPE> nonconfigurable(String reason) {
1274 Preconditions.checkState(!reason.isEmpty());
1275 return setPropertyFlag(PropertyFlag.NONCONFIGURABLE, "nonconfigurable");
1276 }
1277
jcater024deb52021-05-24 14:33:12 -07001278 public Builder<TYPE> tool(String reason) {
1279 Preconditions.checkState(
1280 type.getLabelClass() == LabelClass.DEPENDENCY, "must be a label-valued type");
1281 Preconditions.checkState(!reason.isEmpty());
1282 return setPropertyFlag(PropertyFlag.IS_TOOL_DEPENDENCY, "is_tool_dependency");
1283 }
1284
janakr33439dc2018-03-22 13:44:05 -07001285 /** Returns an {@link ImmutableAttributeFactory} that can be invoked to create attributes. */
1286 public ImmutableAttributeFactory buildPartial() {
Googler72f3a102017-12-01 16:28:28 -08001287 Preconditions.checkState(
1288 !allowedRuleClassesForLabels.consideredOverlapping(allowedRuleClassesForLabelsWarning),
1289 "allowedRuleClasses %s and allowedRuleClassesWithWarning %s "
1290 + "may not contain the same rule classes",
1291 allowedRuleClassesForLabels,
1292 allowedRuleClassesForLabelsWarning);
gregceda4c9592017-07-27 22:09:34 +02001293
janakr33439dc2018-03-22 13:44:05 -07001294 return new ImmutableAttributeFactory(
Yun Peng5c34e962016-02-22 15:13:19 +00001295 type,
Klaus Aehlig04952fc2019-03-01 11:36:16 -08001296 doc,
Yun Peng5c34e962016-02-22 15:13:19 +00001297 Sets.immutableEnumSet(propertyFlags),
1298 valueSet ? value : type.getDefaultValue(),
John Cater5adcd3e2019-03-28 10:14:32 -07001299 transitionFactory,
Yun Peng5c34e962016-02-22 15:13:19 +00001300 allowedRuleClassesForLabels,
1301 allowedRuleClassesForLabelsWarning,
1302 allowedFileTypesForLabels,
1303 validityPredicate,
janakr33439dc2018-03-22 13:44:05 -07001304 valueSource,
1305 valueSet,
Yun Peng5c34e962016-02-22 15:13:19 +00001306 condition,
1307 allowedValues,
dslomovc13bb392017-08-02 23:29:54 +02001308 requiredProvidersBuilder.build(),
Dmitry Lomovf188dc22016-07-19 09:00:55 +00001309 ImmutableList.copyOf(aspects.values()));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001310 }
janakr33439dc2018-03-22 13:44:05 -07001311
1312 /**
1313 * Creates the attribute. Uses name, type, optionality, configuration type and the default value
1314 * configured by the builder.
1315 */
1316 public Attribute build() {
1317 return build(this.name);
1318 }
1319
1320 /**
1321 * Creates the attribute. Uses type, optionality, configuration type and the default value
1322 * configured by the builder. Use the name passed as an argument. This function is used by
gregce3377c112020-04-13 09:29:59 -07001323 * Starlark where the name is provided only when we build. We don't want to modify the builder,
janakr33439dc2018-03-22 13:44:05 -07001324 * as it is shared in a multithreaded environment.
1325 */
1326 public Attribute build(String name) {
1327 return buildPartial().build(name);
1328 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001329 }
1330
1331 /**
Florian Weikertea6c82d2016-09-05 12:15:31 +00001332 * A strategy for dealing with too many computations, used when creating lookup tables for {@link
1333 * ComputedDefault}s.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001334 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001335 * @param <TException> The type of exception this strategy throws if too many computations are
1336 * attempted.
1337 */
1338 interface ComputationLimiter<TException extends Exception> {
1339 void onComputationCount(int count) throws TException;
1340 }
1341
1342 /**
1343 * An implementation of {@link ComputationLimiter} that never throws. For use with
1344 * natively-defined {@link ComputedDefault}s, which are limited in the number of configurable
1345 * attributes they depend on, not on the number of different combinations of possible inputs.
1346 */
1347 private static final ComputationLimiter<RuntimeException> NULL_COMPUTATION_LIMITER =
1348 new ComputationLimiter<RuntimeException>() {
1349 @Override
1350 public void onComputationCount(int count) throws RuntimeException {}
1351 };
1352
1353 /** Exception for computed default attributes that depend on too many configurable attributes. */
1354 private static class TooManyConfigurableAttributesException extends Exception {
1355 TooManyConfigurableAttributesException(int max) {
1356 super(
1357 String.format(
1358 "Too many configurable attributes to compute all possible values: "
1359 + "Found more than %d possible values.",
1360 max));
1361 }
1362 }
1363
1364 private static class FixedComputationLimiter
1365 implements ComputationLimiter<TooManyConfigurableAttributesException> {
1366
1367 /** Upper bound of the number of combinations of values for a computed default attribute. */
1368 private static final int COMPUTED_DEFAULT_MAX_COMBINATIONS = 64;
1369
1370 private static final FixedComputationLimiter INSTANCE = new FixedComputationLimiter();
1371
1372 @Override
1373 public void onComputationCount(int count) throws TooManyConfigurableAttributesException {
1374 if (count > COMPUTED_DEFAULT_MAX_COMBINATIONS) {
1375 throw new TooManyConfigurableAttributesException(COMPUTED_DEFAULT_MAX_COMBINATIONS);
1376 }
1377 }
1378 }
1379
1380 /**
1381 * Specifies how values of {@link ComputedDefault} attributes are computed based on the values of
1382 * other attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001383 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001384 * <p>The {@code TComputeException} type parameter allows the two specializations of this class to
1385 * describe whether and how their computations throw. For natively defined computed defaults,
gregce3377c112020-04-13 09:29:59 -07001386 * computation does not throw, but for Starlark-defined computed defaults, computation may throw
Florian Weikertea6c82d2016-09-05 12:15:31 +00001387 * {@link InterruptedException}.
1388 */
1389 private abstract static class ComputationStrategy<TComputeException extends Exception> {
1390 abstract Object compute(AttributeMap map) throws TComputeException;
1391
1392 /**
1393 * Returns a lookup table mapping from:
1394 *
1395 * <ul>
messa4fc24bc2021-05-20 01:42:18 -07001396 * <li>tuples of values that may be assigned by {@code rule} to attributes with names in
1397 * {@code dependencies} (note that there may be more than one such tuple for any given
1398 * rule, if any of the dependencies are configurable)
Florian Weikertea6c82d2016-09-05 12:15:31 +00001399 * </ul>
1400 *
1401 * <p>to:
1402 *
1403 * <ul>
messa4fc24bc2021-05-20 01:42:18 -07001404 * <li>the value {@link #compute(AttributeMap)} evaluates to when the provided {@link
1405 * AttributeMap} contains the values specified by that assignment, or {@code null} if the
1406 * {@link ComputationStrategy} failed to evaluate.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001407 * </ul>
1408 *
1409 * <p>The lookup table contains a tuple for each possible assignment to the {@code dependencies}
1410 * attributes. The meaning of each tuple is well-defined because {@code dependencies} is
1411 * ordered.
1412 *
1413 * <p>This is useful because configurable attributes may have many possible values. During the
1414 * loading phase a configurable attribute can't be resolved to a single value. Configuration
1415 * information, needed to resolve such an attribute, is only available during analysis. However,
1416 * any labels that a ComputedDefault attribute may evaluate to must be loaded during the loading
1417 * phase.
1418 */
1419 <T, TLimitException extends Exception> Map<List<Object>, T> computeValuesForAllCombinations(
1420 List<String> dependencies,
1421 Type<T> type,
1422 Rule rule,
1423 ComputationLimiter<TLimitException> limiter)
1424 throws TComputeException, TLimitException {
djasper1b869122019-03-04 10:41:50 -08001425 AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001426 // This will hold every (value1, value2, ..) combination of the declared dependencies.
1427 // Collect those combinations.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001428 List<Map<String, Object>> depMaps = mapper.visitAttributes(dependencies, limiter);
1429 // For each combination, call compute() on a specialized AttributeMap providing those
1430 // values.
nharmatab81776f2019-02-25 15:52:33 -08001431 Map<List<Object>, T> valueMap = Maps.newHashMapWithExpectedSize(depMaps.size());
Florian Weikertea6c82d2016-09-05 12:15:31 +00001432 for (Map<String, Object> depMap : depMaps) {
1433 AttributeMap attrMap = mapper.createMapBackedAttributeMap(depMap);
1434 Object value = compute(attrMap);
1435 List<Object> key = createDependencyAssignmentTuple(dependencies, attrMap);
1436 valueMap.put(key, type.cast(value));
1437 }
1438 return valueMap;
1439 }
1440
1441 /**
1442 * Given an {@link AttributeMap}, containing an assignment to each attribute in {@code
1443 * dependencies}, this returns a list of the assigned values, ordered as {@code dependencies} is
1444 * ordered.
1445 */
1446 static List<Object> createDependencyAssignmentTuple(
1447 List<String> dependencies, AttributeMap attrMap) {
1448 ArrayList<Object> tuple = new ArrayList<>(dependencies.size());
1449 for (String attrName : dependencies) {
1450 Type<?> attrType = attrMap.getAttributeType(attrName);
1451 tuple.add(attrMap.get(attrName, attrType));
1452 }
1453 return tuple;
1454 }
1455 }
1456
1457 /**
1458 * A computed default is a default value for a Rule attribute that is a function of other
1459 * attributes of the rule.
1460 *
1461 * <p>Attributes whose defaults are computed are first initialized to the default for their type,
1462 * and then the computed defaults are evaluated after all non-computed defaults have been
1463 * initialized. There is no defined order among computed defaults, so they must not depend on each
1464 * other.
1465 *
1466 * <p>If a computed default reads the value of another attribute, at least one of the following
1467 * must be true:
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001468 *
1469 * <ol>
Googler084b64b2019-11-19 14:41:30 -08001470 * <li>The other attribute must be declared in the computed default's constructor
1471 * <li>The other attribute must be non-configurable ({@link Builder#nonconfigurable}
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001472 * </ol>
1473 *
Florian Weikertea6c82d2016-09-05 12:15:31 +00001474 * <p>The reason for enforced declarations is that, since attribute values might be configurable,
1475 * a computed default that depends on them may itself take multiple values. Since we have no
1476 * access to a target's configuration at the time these values are computed, we need the ability
1477 * to probe the default's *complete* dependency space. Declared dependencies allow us to do so
1478 * sanely. Non-configurable attributes don't have this problem because their value is fixed and
1479 * known even without configuration information.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001480 *
1481 * <p>Implementations of this interface must be immutable.
1482 */
Googler34f70582019-11-25 12:27:34 -08001483 public abstract static class ComputedDefault implements StarlarkValue {
Mark Schaller93c7da62016-07-26 16:59:59 +00001484 private final ImmutableList<String> dependencies;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001485
1486 /**
1487 * Create a computed default that can read all non-configurable attribute values and no
1488 * configurable attribute values.
1489 */
1490 public ComputedDefault() {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001491 this(ImmutableList.<String>of());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001492 }
1493
1494 /**
1495 * Create a computed default that can read all non-configurable attributes values and one
1496 * explicitly specified configurable attribute value
1497 */
1498 public ComputedDefault(String depAttribute) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001499 this(ImmutableList.of(depAttribute));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001500 }
1501
1502 /**
1503 * Create a computed default that can read all non-configurable attributes values and two
1504 * explicitly specified configurable attribute values.
1505 */
1506 public ComputedDefault(String depAttribute1, String depAttribute2) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001507 this(ImmutableList.of(depAttribute1, depAttribute2));
1508 }
1509
1510 /**
1511 * Creates a computed default that can read all non-configurable attributes and some explicitly
1512 * specified configurable attribute values.
1513 *
1514 * <p>This constructor should not be used by native {@link ComputedDefault} functions. The limit
1515 * of at-most-two depended-on configurable attributes is intended, to limit the exponential
gregce18694cd2020-05-12 15:40:05 -07001516 * growth of possible values. {@link StarlarkComputedDefault} uses this, but is limited by
1517 * {@link FixedComputationLimiter#COMPUTED_DEFAULT_MAX_COMBINATIONS}.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001518 */
1519 protected ComputedDefault(ImmutableList<String> dependencies) {
1520 // Order is important for #createDependencyAssignmentTuple.
1521 this.dependencies = Ordering.natural().immutableSortedCopy(dependencies);
1522 }
1523
1524 <T> Iterable<T> getPossibleValues(Type<T> type, Rule rule) {
1525 final ComputedDefault owner = ComputedDefault.this;
djasper1b869122019-03-04 10:41:50 -08001526 if (dependencies.isEmpty()) {
1527 AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
1528 Object value = owner.getDefault(mapper.createMapBackedAttributeMap(ImmutableMap.of()));
1529 return Lists.newArrayList(type.cast(value));
1530 }
Florian Weikertea6c82d2016-09-05 12:15:31 +00001531 ComputationStrategy<RuntimeException> strategy =
1532 new ComputationStrategy<RuntimeException>() {
1533 @Override
1534 public Object compute(AttributeMap map) {
1535 return owner.getDefault(map);
1536 }
1537 };
1538 // Note that this uses ArrayList instead of something like ImmutableList because some
1539 // values may be null.
1540 return new ArrayList<>(
1541 strategy
1542 .computeValuesForAllCombinations(dependencies, type, rule, NULL_COMPUTATION_LIMITER)
1543 .values());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001544 }
1545
Mark Schaller93c7da62016-07-26 16:59:59 +00001546 /** The list of configurable attributes this ComputedDefault declares it may read. */
1547 public ImmutableList<String> dependencies() {
1548 return dependencies;
1549 }
1550
Florian Weikertea6c82d2016-09-05 12:15:31 +00001551 /**
1552 * Returns the value this {@link ComputedDefault} evaluates to, given the inputs contained in
1553 * {@code rule}.
1554 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001555 public abstract Object getDefault(AttributeMap rule);
1556 }
1557
1558 /**
gregce3377c112020-04-13 09:29:59 -07001559 * A Starlark-defined computed default, which can be precomputed for a specific {@link Rule} by
gregce18694cd2020-05-12 15:40:05 -07001560 * calling {@link #computePossibleValues}, which returns a {@link StarlarkComputedDefault} that
Florian Weikertea6c82d2016-09-05 12:15:31 +00001561 * contains a lookup table.
1562 */
gregce18694cd2020-05-12 15:40:05 -07001563 public static final class StarlarkComputedDefaultTemplate {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001564 private final Type<?> type;
Googlerd78a0912019-09-04 15:13:10 -07001565 private final StarlarkCallbackHelper callback;
Florian Weikertea6c82d2016-09-05 12:15:31 +00001566 private final ImmutableList<String> dependencies;
1567
1568 /**
gregce18694cd2020-05-12 15:40:05 -07001569 * Creates a new StarlarkComputedDefaultTemplate that allows the computation of attribute values
Florian Weikertea6c82d2016-09-05 12:15:31 +00001570 * via a callback function during loading phase.
1571 *
1572 * @param type The type of the value of this attribute.
1573 * @param dependencies A list of all names of other attributes that are accessed by this
1574 * attribute.
1575 * @param callback A function to compute the actual attribute value.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001576 */
gregce18694cd2020-05-12 15:40:05 -07001577 public StarlarkComputedDefaultTemplate(
adonovan7891d3b2020-01-22 12:40:50 -08001578 Type<?> type, ImmutableList<String> dependencies, StarlarkCallbackHelper callback) {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001579 this.type = Preconditions.checkNotNull(type);
1580 // Order is important for #createDependencyAssignmentTuple.
1581 this.dependencies =
1582 Ordering.natural().immutableSortedCopy(Preconditions.checkNotNull(dependencies));
1583 this.callback = Preconditions.checkNotNull(callback);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001584 }
1585
1586 /**
gregce18694cd2020-05-12 15:40:05 -07001587 * Returns a {@link StarlarkComputedDefault} containing a lookup table specifying the output of
1588 * this {@link StarlarkComputedDefaultTemplate}'s callback given each possible assignment {@code
Florian Weikertea6c82d2016-09-05 12:15:31 +00001589 * rule} might make to the attributes specified by {@link #dependencies}.
1590 *
1591 * <p>If the rule is missing an attribute specified by {@link #dependencies}, or if there are
1592 * too many possible assignments, or if any evaluation fails, this throws {@link
1593 * CannotPrecomputeDefaultsException}.
1594 *
1595 * <p>May only be called after all non-{@link ComputedDefault} attributes have been set on the
1596 * {@code rule}.
1597 */
gregce18694cd2020-05-12 15:40:05 -07001598 StarlarkComputedDefault computePossibleValues(
Florian Weikertea6c82d2016-09-05 12:15:31 +00001599 Attribute attr, final Rule rule, final EventHandler eventHandler)
1600 throws InterruptedException, CannotPrecomputeDefaultsException {
1601
gregce18694cd2020-05-12 15:40:05 -07001602 final StarlarkComputedDefaultTemplate owner = StarlarkComputedDefaultTemplate.this;
Florian Weikertea6c82d2016-09-05 12:15:31 +00001603 final String msg =
1604 String.format(
1605 "Cannot compute default value of attribute '%s' in rule '%s': ",
Florian Weikertba405252017-01-30 14:42:50 +00001606 attr.getPublicName(), rule.getLabel());
Florian Weikertea6c82d2016-09-05 12:15:31 +00001607 final AtomicReference<EvalException> caughtEvalExceptionIfAny = new AtomicReference<>();
1608 ComputationStrategy<InterruptedException> strategy =
1609 new ComputationStrategy<InterruptedException>() {
1610 @Override
1611 public Object compute(AttributeMap map) throws InterruptedException {
1612 try {
vladmos076977e2017-12-02 14:15:32 -08001613 return owner.computeValue(eventHandler, map);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001614 } catch (EvalException ex) {
1615 caughtEvalExceptionIfAny.compareAndSet(null, ex);
1616 return null;
1617 }
1618 }
1619 };
1620
1621 ImmutableList.Builder<Type<?>> dependencyTypesBuilder = ImmutableList.builder();
1622 Map<List<Object>, Object> lookupTable = new HashMap<>();
1623 try {
1624 for (String dependency : dependencies) {
1625 Attribute attribute = rule.getRuleClassObject().getAttributeByNameMaybe(dependency);
1626 if (attribute == null) {
1627 throw new AttributeNotFoundException(
1628 String.format("No such attribute %s in rule %s", dependency, rule.getLabel()));
1629 }
1630 dependencyTypesBuilder.add(attribute.getType());
1631 }
1632 lookupTable.putAll(
1633 strategy.computeValuesForAllCombinations(
1634 dependencies, attr.getType(), rule, FixedComputationLimiter.INSTANCE));
1635 if (caughtEvalExceptionIfAny.get() != null) {
1636 throw caughtEvalExceptionIfAny.get();
1637 }
1638 } catch (AttributeNotFoundException
1639 | TooManyConfigurableAttributesException
1640 | EvalException ex) {
1641 String error = msg + ex.getMessage();
1642 rule.reportError(error, eventHandler);
1643 throw new CannotPrecomputeDefaultsException(error);
1644 }
gregce18694cd2020-05-12 15:40:05 -07001645 return new StarlarkComputedDefault(dependencies, dependencyTypesBuilder.build(), lookupTable);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001646 }
1647
vladmos076977e2017-12-02 14:15:32 -08001648 private Object computeValue(EventHandler eventHandler, AttributeMap rule)
1649 throws EvalException, InterruptedException {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001650 Map<String, Object> attrValues = new HashMap<>();
1651 for (String attrName : rule.getAttributeNames()) {
1652 Attribute attr = rule.getAttributeDefinition(attrName);
1653 if (!attr.hasComputedDefault()) {
1654 Object value = rule.get(attrName, attr.getType());
adonovan032a25b2020-08-26 07:04:30 -07001655 if (!Starlark.isNullOrNone(value)) {
adonovan553dc6c2019-12-10 11:22:48 -08001656 // Some attribute values are not valid Starlark values:
1657 // visibility is an ImmutableList, for example.
1658 attrValues.put(attr.getName(), Starlark.fromJava(value, /*mutability=*/ null));
Florian Weikertea6c82d2016-09-05 12:15:31 +00001659 }
1660 }
1661 }
vladmos076977e2017-12-02 14:15:32 -08001662 return invokeCallback(eventHandler, attrValues);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001663 }
1664
vladmos076977e2017-12-02 14:15:32 -08001665 private Object invokeCallback(EventHandler eventHandler, Map<String, Object> attrValues)
Florian Weikertea6c82d2016-09-05 12:15:31 +00001666 throws EvalException, InterruptedException {
adonovan267bdaa2020-11-04 11:32:24 -08001667 Structure attrs =
cparsons0c5c1c62018-05-24 10:37:03 -07001668 StructProvider.STRUCT.create(
Florian Weikertea6c82d2016-09-05 12:15:31 +00001669 attrValues, "No such regular (non computed) attribute '%s'.");
vladmos076977e2017-12-02 14:15:32 -08001670 Object result = callback.call(eventHandler, attrs);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001671 try {
Googler641bdf72019-11-12 10:32:26 -08001672 return type.cast((result == Starlark.NONE) ? type.getDefaultValue() : result);
Florian Weikertea6c82d2016-09-05 12:15:31 +00001673 } catch (ClassCastException ex) {
adonovan8bee7072020-04-29 11:59:53 -07001674 throw Starlark.errorf("expected '%s', but got '%s'", type, Starlark.type(result));
Florian Weikertea6c82d2016-09-05 12:15:31 +00001675 }
1676 }
1677
1678 private static class AttributeNotFoundException extends Exception {
1679 private AttributeNotFoundException(String message) {
1680 super(message);
1681 }
1682 }
1683
1684 static class CannotPrecomputeDefaultsException extends Exception {
1685 private CannotPrecomputeDefaultsException(String message) {
1686 super(message);
1687 }
1688 }
1689 }
1690
1691 /**
gregce3377c112020-04-13 09:29:59 -07001692 * A class for computed attributes defined in Starlark.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001693 *
1694 * <p>Unlike {@link ComputedDefault}, instances of this class contain a pre-computed table of all
gregce3377c112020-04-13 09:29:59 -07001695 * possible assignments of depended-on attributes and what the Starlark function evaluates to, and
Florian Weikertea6c82d2016-09-05 12:15:31 +00001696 * {@link #getPossibleValues(Type, Rule)} and {@link #getDefault(AttributeMap)} do lookups in that
1697 * table.
1698 */
gregce18694cd2020-05-12 15:40:05 -07001699 static final class StarlarkComputedDefault extends ComputedDefault {
Florian Weikertea6c82d2016-09-05 12:15:31 +00001700
1701 private final List<Type<?>> dependencyTypes;
1702 private final Map<List<Object>, Object> lookupTable;
1703
1704 /**
gregce18694cd2020-05-12 15:40:05 -07001705 * Creates a new StarlarkComputedDefault containing a lookup table.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001706 *
mjhalupka7b398f92018-03-08 12:08:25 -08001707 * @param dependencies A list of all names of other attributes that are accessed by this
Florian Weikertea6c82d2016-09-05 12:15:31 +00001708 * attribute.
1709 * @param dependencyTypes A list of requiredAttributes' types.
1710 * @param lookupTable An exhaustive mapping from requiredAttributes assignments to values this
1711 * computed default evaluates to.
1712 */
gregce18694cd2020-05-12 15:40:05 -07001713 StarlarkComputedDefault(
mjhalupka7b398f92018-03-08 12:08:25 -08001714 ImmutableList<String> dependencies,
Florian Weikertea6c82d2016-09-05 12:15:31 +00001715 ImmutableList<Type<?>> dependencyTypes,
1716 Map<List<Object>, Object> lookupTable) {
mjhalupka7b398f92018-03-08 12:08:25 -08001717 super(Preconditions.checkNotNull(dependencies));
Florian Weikertea6c82d2016-09-05 12:15:31 +00001718 this.dependencyTypes = Preconditions.checkNotNull(dependencyTypes);
1719 this.lookupTable = Preconditions.checkNotNull(lookupTable);
1720 }
1721
1722 List<Type<?>> getDependencyTypes() {
1723 return dependencyTypes;
1724 }
1725
1726 Map<List<Object>, Object> getLookupTable() {
1727 return lookupTable;
1728 }
1729
1730 @Override
1731 public Object getDefault(AttributeMap rule) {
1732 List<Object> key = ComputationStrategy.createDependencyAssignmentTuple(dependencies(), rule);
1733 Preconditions.checkState(
1734 lookupTable.containsKey(key),
1735 "Error in rule '%s': precomputed value missing for dependencies: %s. Available keys: %s.",
1736 rule.getLabel(),
1737 Iterables.toString(key),
1738 Iterables.toString(lookupTable.keySet()));
1739 return lookupTable.get(key);
1740 }
1741
1742 @Override
1743 <T> Iterable<T> getPossibleValues(Type<T> type, Rule rule) {
1744 List<T> result = new ArrayList<>(lookupTable.size());
1745 for (Object obj : lookupTable.values()) {
1746 result.add(type.cast(obj));
1747 }
1748 return result;
1749 }
1750 }
1751
janakr8688b682018-03-26 09:07:11 -07001752 static class SimpleLateBoundDefault<FragmentT, ValueT>
cparsonsd8d91722017-11-03 19:10:05 +01001753 extends LateBoundDefault<FragmentT, ValueT> {
janakrf4523e72019-06-05 14:11:06 -07001754 private final Resolver<FragmentT, ValueT> resolver;
cparsonsd8d91722017-11-03 19:10:05 +01001755
messa4fc24bc2021-05-20 01:42:18 -07001756 private SimpleLateBoundDefault(
1757 boolean useHostConfiguration,
cparsonsd8d91722017-11-03 19:10:05 +01001758 Class<FragmentT> fragmentClass,
messa4fc24bc2021-05-20 01:42:18 -07001759 ValueT defaultValue,
1760 Resolver<FragmentT, ValueT> resolver) {
cparsonsd8d91722017-11-03 19:10:05 +01001761 super(useHostConfiguration, fragmentClass, defaultValue);
1762
1763 this.resolver = resolver;
1764 }
1765
1766 @Override
1767 public ValueT resolve(Rule rule, AttributeMap attributes, FragmentT input) {
1768 return resolver.resolve(rule, attributes, input);
1769 }
1770 }
1771
mstaib807a9b22017-09-19 17:06:32 +02001772 // TODO(b/65746853): Remove documentation about accepting BuildConfiguration when uses are cleaned
1773 // up.
Florian Weikertea6c82d2016-09-05 12:15:31 +00001774 /**
janakra56a6ad2018-02-02 15:52:22 -08001775 * Provider of values for late-bound attributes. See {@link Attribute#value(LateBoundDefault<?, ?
1776 * extends TYPE> value)}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001777 *
1778 * <p>Use sparingly - having different values for attributes during loading and analysis can
1779 * confuse users.
mstaib807a9b22017-09-19 17:06:32 +02001780 *
1781 * @param <FragmentT> The type of value that is used to compute this value. This is usually a
1782 * subclass of BuildConfiguration.Fragment. It may also be Void to receive null, or
1783 * BuildConfiguration itself to receive the entire configuration.
janakra56a6ad2018-02-02 15:52:22 -08001784 * @param <ValueT> The type of value returned by this class. Must be either {@link Void}, a {@link
1785 * Label}, or a {@link List} of {@link Label} objects.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001786 */
mstaib807a9b22017-09-19 17:06:32 +02001787 @Immutable
Googler34f70582019-11-25 12:27:34 -08001788 public abstract static class LateBoundDefault<FragmentT, ValueT> implements StarlarkValue {
mstaib807a9b22017-09-19 17:06:32 +02001789 /**
1790 * Functional interface for computing the value of a late-bound attribute.
1791 *
1792 * <p>Implementations of this interface must be immutable.
1793 */
1794 @FunctionalInterface
1795 public interface Resolver<FragmentT, ValueT> {
1796 ValueT resolve(Rule rule, AttributeMap attributeMap, FragmentT input);
1797 }
1798
1799 private final boolean useHostConfiguration;
1800 private final ValueT defaultValue;
1801 private final Class<FragmentT> fragmentClass;
mstaib807a9b22017-09-19 17:06:32 +02001802
1803 /**
mstaib807a9b22017-09-19 17:06:32 +02001804 * Creates a new LateBoundDefault which always returns the given value.
1805 *
1806 * <p>This is used primarily for matching names with late-bound attributes on other rules and
1807 * for testing. Use normal default values if the name does not matter.
1808 */
janakra56a6ad2018-02-02 15:52:22 -08001809 @VisibleForTesting
1810 public static LabelLateBoundDefault<Void> fromConstantForTesting(Label defaultValue) {
1811 return new LabelLateBoundDefault<Void>(
1812 false,
1813 Void.class,
1814 Preconditions.checkNotNull(defaultValue),
1815 (rule, attributes, unused) -> defaultValue) {};
mstaib807a9b22017-09-19 17:06:32 +02001816 }
1817
1818 /**
1819 * Creates a new LateBoundDefault which always returns null.
1820 *
1821 * <p>This is used primarily for matching names with late-bound attributes on other rules and
1822 * for testing. Use normal default values if the name does not matter.
1823 */
1824 @SuppressWarnings("unchecked") // bivariant implementation
1825 public static <ValueT> LateBoundDefault<Void, ValueT> alwaysNull() {
janakra56a6ad2018-02-02 15:52:22 -08001826 return (LateBoundDefault<Void, ValueT>) AlwaysNullLateBoundDefault.INSTANCE;
mstaib807a9b22017-09-19 17:06:32 +02001827 }
1828
juliexxia40fc5e82018-12-17 15:40:53 -08001829 LateBoundDefault(
1830 boolean useHostConfiguration, Class<FragmentT> fragmentClass, ValueT defaultValue) {
mstaib807a9b22017-09-19 17:06:32 +02001831 this.useHostConfiguration = useHostConfiguration;
1832 this.defaultValue = defaultValue;
1833 this.fragmentClass = fragmentClass;
mstaib807a9b22017-09-19 17:06:32 +02001834 }
1835
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001836 /**
Greg Estren974bbd92016-07-27 14:22:41 +00001837 * Whether to look up the label in the host configuration. This is only here for host
1838 * compilation tools - we usually need to look up labels in the target configuration.
mstaib807a9b22017-09-19 17:06:32 +02001839 */
cparsonsd8d91722017-11-03 19:10:05 +01001840 public final boolean useHostConfiguration() {
mstaib807a9b22017-09-19 17:06:32 +02001841 return useHostConfiguration;
1842 }
1843
1844 /**
1845 * Returns the input type that the attribute expects. This is almost always a configuration
1846 * fragment to be retrieved from the target's configuration (or the host configuration).
Greg Estren974bbd92016-07-27 14:22:41 +00001847 *
mstaib807a9b22017-09-19 17:06:32 +02001848 * <p>It may also be {@link Void} to receive null. This is rarely necessary, but can be used,
1849 * e.g., if the attribute is named to match an attribute in another rule which is late-bound.
1850 *
1851 * <p>It may also be BuildConfiguration to receive the entire configuration. This is deprecated,
1852 * and only necessary when the default is computed from methods of BuildConfiguration itself.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001853 */
cparsonsd8d91722017-11-03 19:10:05 +01001854 public final Class<FragmentT> getFragmentClass() {
mstaib807a9b22017-09-19 17:06:32 +02001855 return fragmentClass;
1856 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001857
mstaib807a9b22017-09-19 17:06:32 +02001858 /** The default value for the attribute that is set during the loading phase. */
cparsonsd8d91722017-11-03 19:10:05 +01001859 public final ValueT getDefault() {
mstaib807a9b22017-09-19 17:06:32 +02001860 return defaultValue;
1861 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001862
1863 /**
1864 * The actual value for the attribute for the analysis phase, which depends on the build
1865 * configuration. Note that configurations transitions are applied after the late-bound
1866 * attribute was evaluated.
Greg Estren33ec1912016-02-10 15:57:58 +00001867 *
1868 * @param rule the rule being evaluated
1869 * @param attributes interface for retrieving the values of the rule's other attributes
mstaib807a9b22017-09-19 17:06:32 +02001870 * @param input the configuration fragment to evaluate with
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001871 */
cparsonsd8d91722017-11-03 19:10:05 +01001872 public abstract ValueT resolve(Rule rule, AttributeMap attributes, FragmentT input);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01001873 }
1874
janakra56a6ad2018-02-02 15:52:22 -08001875 /**
gregce18694cd2020-05-12 15:40:05 -07001876 * An abstract {@link LateBoundDefault} class so that {@code StarlarkLateBoundDefault} can derive
janakra56a6ad2018-02-02 15:52:22 -08001877 * from {@link LateBoundDefault} without compromising the type-safety of the second generic
1878 * parameter to {@link LateBoundDefault}.
1879 */
1880 public abstract static class AbstractLabelLateBoundDefault<FragmentT>
1881 extends LateBoundDefault<FragmentT, Label> {
1882 protected AbstractLabelLateBoundDefault(
1883 boolean useHostConfiguration, Class<FragmentT> fragmentClass, Label defaultValue) {
1884 super(useHostConfiguration, fragmentClass, defaultValue);
1885 }
1886 }
1887
janakrf4523e72019-06-05 14:11:06 -07001888 @AutoCodec.VisibleForSerialization
1889 static class AlwaysNullLateBoundDefault extends SimpleLateBoundDefault<Void, Void> {
1890 @AutoCodec @AutoCodec.VisibleForSerialization
janakra56a6ad2018-02-02 15:52:22 -08001891 static final AlwaysNullLateBoundDefault INSTANCE = new AlwaysNullLateBoundDefault();
1892
1893 private AlwaysNullLateBoundDefault() {
1894 super(false, Void.class, null, (rule, attributes, unused) -> null);
1895 }
1896 }
1897
1898 /** A {@link LateBoundDefault} for a {@link Label}. */
1899 public static class LabelLateBoundDefault<FragmentT>
1900 extends SimpleLateBoundDefault<FragmentT, Label> {
janakrf4523e72019-06-05 14:11:06 -07001901 @VisibleForTesting
juliexxia40fc5e82018-12-17 15:40:53 -08001902 protected LabelLateBoundDefault(
janakra56a6ad2018-02-02 15:52:22 -08001903 boolean useHostConfiguration,
1904 Class<FragmentT> fragmentClass,
1905 Label defaultValue,
1906 Resolver<FragmentT, Label> resolver) {
1907 super(useHostConfiguration, fragmentClass, defaultValue, resolver);
1908 }
1909
1910 /**
1911 * Creates a new LabelLateBoundDefault which uses the rule, its configured attributes, and a
1912 * fragment of the target configuration.
1913 *
1914 * <p>Note that the configuration fragment here does not take into account any transitions that
1915 * are on the attribute with this LabelLateBoundDefault as its value. The configuration will be
1916 * the same as the configuration given to the target bearing the attribute.
1917 *
1918 * <p>Nearly all LateBoundDefaults should use this constructor or {@link
1919 * LabelListLateBoundDefault#fromTargetConfiguration}. There are few situations where it isn't
1920 * the appropriate option.
1921 *
1922 * <p>If you want a late-bound dependency which is configured in the host configuration, just
1923 * use this method with {@link com.google.devtools.build.lib.analysis.config.HostTransition}. If
1924 * you also need to decide the label of the dependency with information gained from the host
1925 * configuration - and it's very unlikely that you do - you can use {@link
1926 * LabelLateBoundDefault#fromHostConfiguration} as well.
1927 *
1928 * <p>If you want to decide an attribute's value based on the value of its other attributes, use
1929 * a subclass of {@link ComputedDefault}. The only time you should need {@link
1930 * LabelListLateBoundDefault#fromRuleAndAttributesOnly} is if you need access to three or more
1931 * configurable attributes, or if you need to match names with a late-bound attribute on another
1932 * rule.
1933 *
1934 * <p>If you have a constant-valued attribute, but you need it to have the same name as an
1935 * attribute on another rule which is late-bound, use {@link #alwaysNull}.
1936 *
1937 * @param fragmentClass The fragment to receive from the target configuration. May also be
1938 * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
1939 * you must only use methods of BuildConfiguration itself, and not use any fragments.
1940 * @param defaultValue The default {@link Label} to return at loading time, when the
1941 * configuration is not available.
1942 * @param resolver A function which will compute the actual value with the configuration.
1943 */
1944 public static <FragmentT> LabelLateBoundDefault<FragmentT> fromTargetConfiguration(
1945 Class<FragmentT> fragmentClass, Label defaultValue, Resolver<FragmentT, Label> resolver) {
1946 Preconditions.checkArgument(
1947 !fragmentClass.equals(Void.class),
1948 "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
1949 + "configuration.");
1950 return new LabelLateBoundDefault<>(false, fragmentClass, defaultValue, resolver);
1951 }
1952
1953 /**
1954 * Creates a new LateBoundDefault which uses the rule, its configured attributes, and a fragment
1955 * of the host configuration.
1956 *
1957 * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
1958 * need this method, just {@link #fromTargetConfiguration} and {@link
1959 * com.google.devtools.build.lib.analysis.config.HostTransition}.
1960 *
1961 * <p>This method only affects the configuration fragment passed to {@link #resolve}. You must
1962 * also use {@link com.google.devtools.build.lib.analysis.config.HostTransition}, so that the
1963 * dependency will be analyzed in the host configuration.
1964 *
1965 * @param fragmentClass The fragment to receive from the host configuration. May also be
1966 * BuildConfiguration.class to receive the entire configuration (deprecated) - in this case,
1967 * you must only use methods of BuildConfiguration itself, and not use any fragments. It is
1968 * very rare that a LateBoundDefault should need a host configuration fragment; use {@link
1969 * #fromTargetConfiguration} in most cases.
1970 * @param defaultValue The default {@link Label} to return at loading time, when the
1971 * configuration is not available.
1972 * @param resolver A function which will compute the actual value with the configuration.
1973 */
1974 public static <FragmentT> LabelLateBoundDefault<FragmentT> fromHostConfiguration(
1975 Class<FragmentT> fragmentClass, Label defaultValue, Resolver<FragmentT, Label> resolver) {
1976 Preconditions.checkArgument(
1977 !fragmentClass.equals(Void.class),
1978 "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
1979 + "configuration.");
1980 return new LabelLateBoundDefault<>(true, fragmentClass, defaultValue, resolver);
1981 }
1982 }
1983
1984 /** A {@link LateBoundDefault} for a {@link List} of {@link Label} objects. */
1985 public static class LabelListLateBoundDefault<FragmentT>
1986 extends SimpleLateBoundDefault<FragmentT, List<Label>> {
janakrf4523e72019-06-05 14:11:06 -07001987 private LabelListLateBoundDefault(
janakra56a6ad2018-02-02 15:52:22 -08001988 boolean useHostConfiguration,
1989 Class<FragmentT> fragmentClass,
1990 Resolver<FragmentT, List<Label>> resolver) {
1991 super(useHostConfiguration, fragmentClass, ImmutableList.of(), resolver);
1992 }
1993
1994 public static <FragmentT> LabelListLateBoundDefault<FragmentT> fromTargetConfiguration(
1995 Class<FragmentT> fragmentClass, Resolver<FragmentT, List<Label>> resolver) {
1996 Preconditions.checkArgument(
1997 !fragmentClass.equals(Void.class),
1998 "Use fromRuleAndAttributesOnly to specify a LateBoundDefault which does not use "
1999 + "configuration.");
2000 return new LabelListLateBoundDefault<>(false, fragmentClass, resolver);
2001 }
2002
2003 /**
2004 * Creates a new LabelListLateBoundDefault which uses only the rule and its configured
2005 * attributes.
2006 *
2007 * <p>This should only be necessary in very specialized cases. In almost all cases, you don't
2008 * need this method, just use {@link ComputedDefault}.
2009 *
2010 * <p>This is used primarily for computing values based on three or more configurable attributes
2011 * and/or matching names with late-bound attributes on other rules.
2012 *
2013 * @param resolver A function which will compute the actual value with the configuration.
2014 */
2015 public static LabelListLateBoundDefault<Void> fromRuleAndAttributesOnly(
2016 Resolver<Void, List<Label>> resolver) {
2017 return new LabelListLateBoundDefault<>(false, Void.class, resolver);
2018 }
2019 }
2020
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002021 private final String name;
2022
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002023 private final String doc;
2024
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002025 private final Type<?> type;
2026
2027 private final Set<PropertyFlag> propertyFlags;
2028
2029 // Exactly one of these conditions is true:
2030 // 1. defaultValue == null.
2031 // 2. defaultValue instanceof ComputedDefault &&
2032 // type.isValid(defaultValue.getDefault())
gregce18694cd2020-05-12 15:40:05 -07002033 // 3. defaultValue instanceof StarlarkComputedDefaultTemplate &&
Florian Weikertea6c82d2016-09-05 12:15:31 +00002034 // type.isValid(defaultValue.computePossibleValues().getDefault())
2035 // 4. type.isValid(defaultValue).
2036 // 5. defaultValue instanceof LateBoundDefault &&
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002037 // type.isValid(defaultValue.getDefault(configuration))
2038 // (We assume a hypothetical Type.isValid(Object) predicate.)
2039 private final Object defaultValue;
2040
John Cater2c0dece2019-04-02 09:18:18 -07002041 private final TransitionFactory<AttributeTransitionData> transitionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002042
2043 /**
messa4fc24bc2021-05-20 01:42:18 -07002044 * For label or label-list attributes, this predicate returns which rule classes are allowed for
2045 * the targets in the attribute.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002046 */
Googler72f3a102017-12-01 16:28:28 -08002047 private final RuleClassNamePredicate allowedRuleClassesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002048
2049 /**
messa4fc24bc2021-05-20 01:42:18 -07002050 * For label or label-list attributes, this predicate returns which rule classes are allowed for
2051 * the targets in the attribute with warning.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002052 */
Googler72f3a102017-12-01 16:28:28 -08002053 private final RuleClassNamePredicate allowedRuleClassesForLabelsWarning;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002054
2055 /**
messa4fc24bc2021-05-20 01:42:18 -07002056 * For label or label-list attributes, this predicate returns which file types are allowed for
2057 * targets in the attribute that happen to be file targets (rather than rules).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002058 */
2059 private final FileTypeSet allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002060
2061 /**
messa4fc24bc2021-05-20 01:42:18 -07002062 * This predicate-like object checks if the edge between two rules using this attribute is valid
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002063 * in the dependency graph. Returns null if valid, otherwise an error message.
2064 */
2065 private final ValidityPredicate validityPredicate;
2066
2067 private final Predicate<AttributeMap> condition;
2068
2069 private final PredicateWithMessage<Object> allowedValues;
2070
dslomovc13bb392017-08-02 23:29:54 +02002071 private final RequiredProviders requiredProviders;
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +00002072
Dmitry Lomovf188dc22016-07-19 09:00:55 +00002073 private final ImmutableList<RuleAspect<?>> aspects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002074
nharmata977c8802018-03-21 12:18:21 -07002075 private final int hashCode;
2076
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002077 /**
dslomovde965ac2017-07-31 21:07:51 +02002078 * Constructs a rule attribute with the specified name, type and default value.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002079 *
2080 * @param name the name of the attribute
2081 * @param type the type of the attribute
dslomovde965ac2017-07-31 21:07:51 +02002082 * @param defaultValue the default value to use for this attribute if none is specified in rule
2083 * declaration in the BUILD file. Must be null, or of type "type". May be an instance of
2084 * ComputedDefault, in which case its getDefault() method must return an instance of "type",
2085 * or null. Must be immutable.
John Cater5adcd3e2019-03-28 10:14:32 -07002086 * @param transitionFactory the configuration transition for this attribute (which must be of type
dslomovde965ac2017-07-31 21:07:51 +02002087 * LABEL, LABEL_LIST, NODEP_LABEL or NODEP_LABEL_LIST).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002088 */
mjhalupkacfa0bb72018-03-12 12:43:15 -07002089 Attribute(
Yun Peng5c34e962016-02-22 15:13:19 +00002090 String name,
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002091 String doc,
Yun Peng5c34e962016-02-22 15:13:19 +00002092 Type<?> type,
2093 Set<PropertyFlag> propertyFlags,
2094 Object defaultValue,
John Cater2c0dece2019-04-02 09:18:18 -07002095 TransitionFactory<AttributeTransitionData> transitionFactory,
Googler72f3a102017-12-01 16:28:28 -08002096 RuleClassNamePredicate allowedRuleClassesForLabels,
2097 RuleClassNamePredicate allowedRuleClassesForLabelsWarning,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002098 FileTypeSet allowedFileTypesForLabels,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002099 ValidityPredicate validityPredicate,
2100 Predicate<AttributeMap> condition,
2101 PredicateWithMessage<Object> allowedValues,
dslomovc13bb392017-08-02 23:29:54 +02002102 RequiredProviders requiredProviders,
Dmitry Lomovf188dc22016-07-19 09:00:55 +00002103 ImmutableList<RuleAspect<?>> aspects) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002104 Preconditions.checkArgument(
John Cater5adcd3e2019-03-28 10:14:32 -07002105 (NoTransition.isInstance(transitionFactory))
2106 || type.getLabelClass() == LabelClass.DEPENDENCY
2107 || type.getLabelClass() == LabelClass.NONDEP_REFERENCE,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002108 "Configuration transitions can only be specified for label or label list attributes");
Ulf Adams07dba942015-03-05 14:47:37 +00002109 Preconditions.checkArgument(
2110 isLateBound(name) == (defaultValue instanceof LateBoundDefault),
2111 "late bound attributes require a default value that is late bound (and vice versa): %s",
2112 name);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002113 if (isLateBound(name)) {
mstaib807a9b22017-09-19 17:06:32 +02002114 LateBoundDefault<?, ?> lateBoundDefault = (LateBoundDefault<?, ?>) defaultValue;
jcater0eee8c52019-03-25 10:42:33 -07002115 Preconditions.checkArgument(
John Cater5adcd3e2019-03-28 10:14:32 -07002116 !lateBoundDefault.useHostConfiguration() || transitionFactory.isHost(),
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002117 "a late bound default value using the host configuration must use the host transition");
2118 }
2119
2120 this.name = name;
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002121 this.doc = doc;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002122 this.type = type;
2123 this.propertyFlags = propertyFlags;
2124 this.defaultValue = defaultValue;
John Cater5adcd3e2019-03-28 10:14:32 -07002125 this.transitionFactory = transitionFactory;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002126 this.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
2127 this.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
2128 this.allowedFileTypesForLabels = allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002129 this.validityPredicate = validityPredicate;
2130 this.condition = condition;
2131 this.allowedValues = allowedValues;
dslomovc13bb392017-08-02 23:29:54 +02002132 this.requiredProviders = requiredProviders;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002133 this.aspects = aspects;
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002134 this.hashCode =
2135 Objects.hash(
2136 name,
2137 doc,
2138 type,
2139 propertyFlags,
2140 defaultValue,
John Cater5adcd3e2019-03-28 10:14:32 -07002141 transitionFactory,
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002142 allowedRuleClassesForLabels,
2143 allowedRuleClassesForLabelsWarning,
2144 allowedFileTypesForLabels,
2145 validityPredicate,
2146 condition,
2147 allowedValues,
2148 requiredProviders,
2149 aspects);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002150 }
2151
messa4fc24bc2021-05-20 01:42:18 -07002152 /** Returns the name of this attribute. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002153 public String getName() {
2154 return name;
2155 }
2156
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002157 /** Returns the doc string for that attribute, if any. */
2158 public String getDoc() {
2159 return doc;
2160 }
2161
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002162 /**
gregce3377c112020-04-13 09:29:59 -07002163 * Returns the public name of this attribute. This is the name we use in Starlark code and we can
2164 * use it to display to the end-user. Implicit and late-bound attributes start with '_' (instead
2165 * of '$' or ':').
Laurent Le Brun7d903532015-08-20 20:04:41 +00002166 */
2167 public String getPublicName() {
gregced7c1cef2020-05-12 07:51:48 -07002168 return getStarlarkName(getName());
Laurent Le Brun7d903532015-08-20 20:04:41 +00002169 }
2170
2171 /**
messa4fc24bc2021-05-20 01:42:18 -07002172 * Returns the logical type of this attribute. (May differ from the actual representation as a
2173 * value in the build interpreter; for example, an attribute may logically be a list of labels,
2174 * but be represented as a list of strings.)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002175 */
2176 public Type<?> getType() {
2177 return type;
2178 }
2179
2180 private boolean getPropertyFlag(PropertyFlag flag) {
2181 return propertyFlags.contains(flag);
2182 }
2183
messa4fc24bc2021-05-20 01:42:18 -07002184 /** Returns true if this parameter is mandatory. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002185 public boolean isMandatory() {
2186 return getPropertyFlag(PropertyFlag.MANDATORY);
2187 }
2188
messa4fc24bc2021-05-20 01:42:18 -07002189 /** Returns true if this list parameter cannot have an empty list as a value. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002190 public boolean isNonEmpty() {
2191 return getPropertyFlag(PropertyFlag.NON_EMPTY);
2192 }
2193
messa4fc24bc2021-05-20 01:42:18 -07002194 /** Returns true if this label parameter must produce a single artifact. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002195 public boolean isSingleArtifact() {
2196 return getPropertyFlag(PropertyFlag.SINGLE_ARTIFACT);
2197 }
2198
messa4fc24bc2021-05-20 01:42:18 -07002199 /** Returns true if this label type parameter is checked by silent ruleclass filtering. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002200 public boolean isSilentRuleClassFilter() {
2201 return getPropertyFlag(PropertyFlag.SILENT_RULECLASS_FILTER);
2202 }
2203
messa4fc24bc2021-05-20 01:42:18 -07002204 /** Returns true if this label type parameter skips the analysis time filetype check. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002205 public boolean isSkipAnalysisTimeFileTypeCheck() {
2206 return getPropertyFlag(PropertyFlag.SKIP_ANALYSIS_TIME_FILETYPE_CHECK);
2207 }
2208
messa4fc24bc2021-05-20 01:42:18 -07002209 /** Returns true if this parameter is order-independent. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002210 public boolean isOrderIndependent() {
2211 return getPropertyFlag(PropertyFlag.ORDER_INDEPENDENT);
2212 }
2213
messa4fc24bc2021-05-20 01:42:18 -07002214 /** Returns true if output_licenses should be used for checking licensing. */
Irina Iancu2f235992017-01-10 16:03:29 +00002215 public boolean useOutputLicenses() {
2216 return getPropertyFlag(PropertyFlag.OUTPUT_LICENSES);
2217 }
2218
2219 /**
cparsonsf6266392018-10-18 15:42:52 -07002220 * Returns true if this attribute uses a starlark-defined, non analysis-test configuration
John Cater5adcd3e2019-03-28 10:14:32 -07002221 * transition. Starlark-defined analysis-test configuration transitions are handled separately.
2222 * See {@link #hasAnalysisTestTransition}.
Googlerc2200fd2018-09-14 17:35:59 -07002223 */
cparsonsf6266392018-10-18 15:42:52 -07002224 public boolean hasStarlarkDefinedTransition() {
2225 return getPropertyFlag(PropertyFlag.HAS_STARLARK_DEFINED_TRANSITION);
2226 }
2227
2228 /**
2229 * Returns true if this attributes uses Starlark-defined configuration transition designed
2230 * specifically for rules which run analysis tests.
2231 */
2232 public boolean hasAnalysisTestTransition() {
2233 return getPropertyFlag(PropertyFlag.HAS_ANALYSIS_TEST_TRANSITION);
Googlerc2200fd2018-09-14 17:35:59 -07002234 }
2235
2236 /**
John Cater5adcd3e2019-03-28 10:14:32 -07002237 * Returns the configuration transition factory for this attribute for label or label list
2238 * attributes. For other attributes it will always return {@code NONE}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002239 */
John Cater2c0dece2019-04-02 09:18:18 -07002240 public TransitionFactory<AttributeTransitionData> getTransitionFactory() {
John Cater5adcd3e2019-03-28 10:14:32 -07002241 return transitionFactory;
juliexxiacf4d89e2019-01-15 12:16:56 -08002242 }
2243
Chris Parsons2e62c0d2016-04-19 22:13:59 +00002244 /**
messa4fc24bc2021-05-20 01:42:18 -07002245 * Returns whether the target is required to be executable for label or label list attributes. For
2246 * other attributes it always returns {@code false}.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002247 */
2248 public boolean isExecutable() {
2249 return getPropertyFlag(PropertyFlag.EXECUTABLE);
2250 }
2251
messa4fc24bc2021-05-20 01:42:18 -07002252 /** Returns {@code true} iff the rule is a direct input for an action. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002253 public boolean isDirectCompileTimeInput() {
2254 return getPropertyFlag(PropertyFlag.DIRECT_COMPILE_TIME_INPUT);
2255 }
2256
messa4fc24bc2021-05-20 01:42:18 -07002257 /** Returns {@code true} iff this attribute requires documentation. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002258 public boolean isDocumented() {
2259 return !getPropertyFlag(PropertyFlag.UNDOCUMENTED);
2260 }
2261
2262 /**
messa4fc24bc2021-05-20 01:42:18 -07002263 * Returns {@code true} iff this attribute should be published to the rule's tag set. Note that
2264 * not all Type classes support tag conversion.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002265 */
2266 public boolean isTaggable() {
2267 return getPropertyFlag(PropertyFlag.TAGGABLE);
2268 }
2269
2270 public boolean isStrictLabelCheckingEnabled() {
2271 return getPropertyFlag(PropertyFlag.STRICT_LABEL_CHECKING);
2272 }
2273
messa4fc24bc2021-05-20 01:42:18 -07002274 /** Returns true if the value of this attribute should be a part of a given set. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002275 public boolean checkAllowedValues() {
2276 return getPropertyFlag(PropertyFlag.CHECK_ALLOWED_VALUES);
2277 }
2278
Greg Estren875c7a72015-09-24 19:57:54 +00002279 public boolean performPrereqValidatorCheck() {
2280 return !getPropertyFlag(PropertyFlag.SKIP_PREREQ_VALIDATOR_CHECKS);
Ulf Adams0b638972015-09-08 13:25:35 +00002281 }
2282
Greg Estren4a102512015-10-28 20:49:22 +00002283 public boolean checkConstraintsOverride() {
Greg Estren9d837842016-12-01 21:36:59 +00002284 return getPropertyFlag(PropertyFlag.CHECK_CONSTRAINTS_OVERRIDE);
2285 }
2286
2287 public boolean skipConstraintsOverride() {
2288 return getPropertyFlag(PropertyFlag.SKIP_CONSTRAINTS_OVERRIDE);
Greg Estren4a102512015-10-28 20:49:22 +00002289 }
2290
messa4fc24bc2021-05-20 01:42:18 -07002291 /** Returns true if this attribute's value can be influenced by the build configuration. */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002292 public boolean isConfigurable() {
Michael Staiba751f922017-02-14 15:50:04 +00002293 // Output types are excluded because of Rule#populateExplicitOutputFiles.
2294 return !(type.getLabelClass() == LabelClass.OUTPUT
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002295 || getPropertyFlag(PropertyFlag.NONCONFIGURABLE));
2296 }
2297
2298 /**
jcater024deb52021-05-24 14:33:12 -07002299 * Returns true if this attribute is used as a tool dependency, either because the attribute
2300 * declares it directly (with {@link Attribute$Builder.tool}), or because the value's {@link
2301 * TransitionFactory} declares it.
2302 *
2303 * <p>Non-dependency attributes will always return {@code false}.
2304 */
2305 public boolean isToolDependency() {
2306 if (getType().getLabelClass() != LabelClass.DEPENDENCY) {
2307 return false;
2308 }
2309 if (getPropertyFlag(PropertyFlag.IS_TOOL_DEPENDENCY)) {
2310 return true;
2311 }
2312 return getTransitionFactory().isTool();
2313 }
2314 /**
Googler72f3a102017-12-01 16:28:28 -08002315 * Returns a predicate that evaluates to true for rule classes that are allowed labels in this
2316 * attribute. If this is not a label or label-list attribute, the returned predicate always
2317 * evaluates to true.
2318 *
2319 * <p>NOTE: This may return Predicates.<RuleClass>alwaysTrue() as a sentinel meaning "do the right
2320 * thing", rather than actually allowing all rule classes in that attribute. Others parts of bazel
2321 * code check for that specific instance.
2322 */
2323 public Predicate<RuleClass> getAllowedRuleClassesPredicate() {
2324 return allowedRuleClassesForLabels.asPredicateOfRuleClass();
2325 }
2326
2327 /**
messa4fc24bc2021-05-20 01:42:18 -07002328 * Returns a predicate that evaluates to true for rule classes that are allowed labels in this
2329 * attribute with warning. If this is not a label or label-list attribute, the returned predicate
2330 * always evaluates to true.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002331 */
2332 public Predicate<RuleClass> getAllowedRuleClassesWarningPredicate() {
Googler72f3a102017-12-01 16:28:28 -08002333 return allowedRuleClassesForLabelsWarning.asPredicateOfRuleClass();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002334 }
2335
dslomovc13bb392017-08-02 23:29:54 +02002336 public RequiredProviders getRequiredProviders() {
2337 return requiredProviders;
Liam Miller-Cushonbbae4d92016-05-03 18:23:03 +00002338 }
2339
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002340 public FileTypeSet getAllowedFileTypesPredicate() {
2341 return allowedFileTypesForLabels;
2342 }
2343
2344 public ValidityPredicate getValidityPredicate() {
2345 return validityPredicate;
2346 }
2347
2348 public Predicate<AttributeMap> getCondition() {
2349 return condition == null ? Predicates.<AttributeMap>alwaysTrue() : condition;
2350 }
2351
2352 public PredicateWithMessage<Object> getAllowedValues() {
2353 return allowedValues;
2354 }
2355
ulfjack5756b352020-01-23 04:53:22 -08002356 public boolean hasAspects() {
2357 return !aspects.isEmpty();
2358 }
2359
messa4fc24bc2021-05-20 01:42:18 -07002360 /** Returns the list of aspects required for dependencies through this attribute. */
Dmitry Lomovb487ac62015-11-09 13:09:12 +00002361 public ImmutableList<Aspect> getAspects(Rule rule) {
ulfjack5756b352020-01-23 04:53:22 -08002362 if (aspects.isEmpty()) {
2363 return ImmutableList.of();
2364 }
shreyax6b9b6072018-02-26 18:22:13 -08002365 ImmutableList.Builder<Aspect> builder = null;
Googler3e1bf5c2019-11-04 12:41:49 -08002366 for (RuleAspect<?> aspect : aspects) {
Googler459f1302017-04-05 19:40:35 +00002367 Aspect a = aspect.getAspect(rule);
2368 if (a != null) {
shreyax6b9b6072018-02-26 18:22:13 -08002369 if (builder == null) {
2370 builder = ImmutableList.builder();
2371 }
Googler459f1302017-04-05 19:40:35 +00002372 builder.add(a);
2373 }
Marian Lobur702cad72015-09-02 09:53:58 +00002374 }
shreyax6b9b6072018-02-26 18:22:13 -08002375 return builder == null ? ImmutableList.of() : builder.build();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002376 }
2377
Carmi Grushkodf9e5e12016-11-08 23:07:57 +00002378 public ImmutableList<AspectClass> getAspectClasses() {
2379 ImmutableList.Builder<AspectClass> result = ImmutableList.builder();
2380 for (RuleAspect<?> aspect : aspects) {
2381 result.add(aspect.getAspectClass());
2382 }
2383 return result.build();
2384 }
2385
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002386 /**
messa4fc24bc2021-05-20 01:42:18 -07002387 * Returns the default value of this attribute in the context of the specified Rule. For
2388 * attributes with a computed default, i.e. {@code hasComputedDefault()}, {@code rule} must be
2389 * non-null since the result may depend on the values of its other attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002390 *
messa4fc24bc2021-05-20 01:42:18 -07002391 * <p>The result may be null (although this is not a value in the build language).
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002392 *
messa4fc24bc2021-05-20 01:42:18 -07002393 * <p>During population of the rule's attribute dictionary, all non-computed defaults must be set
2394 * before all computed ones.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002395 *
messa4fc24bc2021-05-20 01:42:18 -07002396 * @param rule the rule to which this attribute belongs; non-null if {@code hasComputedDefault()};
2397 * ignored otherwise.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002398 */
2399 public Object getDefaultValue(Rule rule) {
2400 if (!getCondition().apply(rule == null ? null : NonconfigurableAttributeMapper.of(rule))) {
2401 return null;
mstaib807a9b22017-09-19 17:06:32 +02002402 } else if (defaultValue instanceof LateBoundDefault<?, ?>) {
2403 return ((LateBoundDefault<?, ?>) defaultValue).getDefault();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002404 } else {
2405 return defaultValue;
2406 }
2407 }
2408
2409 /**
2410 * Returns the default value of this attribute, even if it has a condition, is a computed default,
2411 * or a late-bound default.
2412 */
2413 @VisibleForTesting
juliexxia84d1a662018-12-26 14:07:04 -08002414 public Object getDefaultValueUnchecked() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002415 return defaultValue;
2416 }
2417
mstaib807a9b22017-09-19 17:06:32 +02002418 public LateBoundDefault<?, ?> getLateBoundDefault() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002419 Preconditions.checkState(isLateBound());
mstaib807a9b22017-09-19 17:06:32 +02002420 return (LateBoundDefault<?, ?>) defaultValue;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002421 }
2422
2423 /**
2424 * Returns true iff this attribute has a computed default or a condition.
2425 *
2426 * @see #getDefaultValue(Rule)
2427 */
2428 boolean hasComputedDefault() {
Florian Weikertea6c82d2016-09-05 12:15:31 +00002429 return (defaultValue instanceof ComputedDefault)
gregce18694cd2020-05-12 15:40:05 -07002430 || (defaultValue instanceof StarlarkComputedDefaultTemplate)
Florian Weikertea6c82d2016-09-05 12:15:31 +00002431 || (condition != null);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002432 }
2433
2434 /**
2435 * Returns if this attribute is an implicit dependency according to the naming policy that
2436 * designates implicit attributes.
2437 */
2438 public boolean isImplicit() {
2439 return isImplicit(getName());
2440 }
2441
2442 /**
messa4fc24bc2021-05-20 01:42:18 -07002443 * Returns if an attribute with the given name is an implicit dependency according to the naming
2444 * policy that designates implicit attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002445 */
2446 public static boolean isImplicit(String name) {
2447 return name.startsWith("$");
2448 }
2449
2450 /**
2451 * Returns if this attribute is late-bound according to the naming policy that designates
2452 * late-bound attributes.
2453 */
2454 public boolean isLateBound() {
2455 return isLateBound(getName());
2456 }
2457
2458 /**
messa4fc24bc2021-05-20 01:42:18 -07002459 * Returns if an attribute with the given name is late-bound according to the naming policy that
2460 * designates late-bound attributes.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002461 */
2462 public static boolean isLateBound(String name) {
2463 return name.startsWith(":");
2464 }
2465
gregce3377c112020-04-13 09:29:59 -07002466 /** Returns whether this attribute is considered private in Starlark. */
Florian Weikertba405252017-01-30 14:42:50 +00002467 private static boolean isPrivateAttribute(String nativeAttrName) {
2468 return isLateBound(nativeAttrName) || isImplicit(nativeAttrName);
2469 }
2470
2471 /**
gregce3377c112020-04-13 09:29:59 -07002472 * Returns the Starlark-usable name of this attribute.
Florian Weikertba405252017-01-30 14:42:50 +00002473 *
gregce3377c112020-04-13 09:29:59 -07002474 * <p>Implicit and late-bound attributes start with '_' (instead of '$' or ':').
Florian Weikertba405252017-01-30 14:42:50 +00002475 */
gregced7c1cef2020-05-12 07:51:48 -07002476 public static String getStarlarkName(String nativeAttrName) {
Florian Weikertba405252017-01-30 14:42:50 +00002477 if (isPrivateAttribute(nativeAttrName)) {
2478 return "_" + nativeAttrName.substring(1);
2479 }
2480 return nativeAttrName;
2481 }
2482
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002483 @Override
2484 public String toString() {
2485 return "Attribute(" + name + ", " + type + ")";
2486 }
2487
2488 @Override
2489 public int compareTo(Attribute other) {
2490 return name.compareTo(other.name);
2491 }
2492
janakr9ba46f82018-03-13 13:07:52 -07002493 @Override
2494 public boolean equals(Object o) {
2495 if (this == o) {
2496 return true;
2497 }
2498 if (o == null || getClass() != o.getClass()) {
2499 return false;
2500 }
2501 Attribute attribute = (Attribute) o;
arostovtsev22f558f2021-02-25 21:44:27 +01002502 return hashCode == attribute.hashCode
nharmata977c8802018-03-21 12:18:21 -07002503 && Objects.equals(name, attribute.name)
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002504 && Objects.equals(doc, attribute.doc)
janakr9ba46f82018-03-13 13:07:52 -07002505 && Objects.equals(type, attribute.type)
2506 && Objects.equals(propertyFlags, attribute.propertyFlags)
2507 && Objects.equals(defaultValue, attribute.defaultValue)
John Cater5adcd3e2019-03-28 10:14:32 -07002508 && Objects.equals(transitionFactory, attribute.transitionFactory)
janakr9ba46f82018-03-13 13:07:52 -07002509 && Objects.equals(allowedRuleClassesForLabels, attribute.allowedRuleClassesForLabels)
2510 && Objects.equals(
2511 allowedRuleClassesForLabelsWarning, attribute.allowedRuleClassesForLabelsWarning)
2512 && Objects.equals(allowedFileTypesForLabels, attribute.allowedFileTypesForLabels)
2513 && Objects.equals(validityPredicate, attribute.validityPredicate)
2514 && Objects.equals(condition, attribute.condition)
2515 && Objects.equals(allowedValues, attribute.allowedValues)
2516 && Objects.equals(requiredProviders, attribute.requiredProviders)
2517 && Objects.equals(aspects, attribute.aspects);
2518 }
2519
2520 @Override
2521 public int hashCode() {
nharmata977c8802018-03-21 12:18:21 -07002522 return hashCode;
janakr9ba46f82018-03-13 13:07:52 -07002523 }
2524
messa4fc24bc2021-05-20 01:42:18 -07002525 /** Returns a replica builder of this Attribute. */
Googler74558fc2016-05-06 21:47:42 +00002526 public <TYPE> Attribute.Builder<TYPE> cloneBuilder(Type<TYPE> tp) {
2527 Preconditions.checkArgument(tp == this.type);
Michajlo Matijkiw69d9b412016-10-06 20:06:59 +00002528 Builder<TYPE> builder = new Builder<>(name, tp);
Klaus Aehlig04952fc2019-03-01 11:36:16 -08002529 builder.doc = doc;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002530 builder.allowedFileTypesForLabels = allowedFileTypesForLabels;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002531 builder.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
2532 builder.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
dslomovc13bb392017-08-02 23:29:54 +02002533 builder.requiredProvidersBuilder = requiredProviders.copyAsBuilder();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002534 builder.validityPredicate = validityPredicate;
2535 builder.condition = condition;
John Cater5adcd3e2019-03-28 10:14:32 -07002536 builder.transitionFactory = transitionFactory;
Greg Estren4ccabd32017-03-14 17:12:45 +00002537 builder.propertyFlags = newEnumSet(propertyFlags, PropertyFlag.class);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002538 builder.value = defaultValue;
2539 builder.valueSet = false;
2540 builder.allowedValues = allowedValues;
Dmitry Lomovf188dc22016-07-19 09:00:55 +00002541 builder.aspects = new LinkedHashMap<>();
2542 for (RuleAspect<?> aspect : aspects) {
2543 builder.aspects.put(aspect.getName(), aspect);
2544 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002545
2546 return builder;
2547 }
Googler74558fc2016-05-06 21:47:42 +00002548
2549 public Attribute.Builder<?> cloneBuilder() {
2550 return cloneBuilder(this.type);
2551 }
adonovanb74f1602020-11-02 17:33:49 -08002552
2553 /**
2554 * Converts a rule attribute value from internal form to Starlark form. Internal form may use any
2555 * subtype of {@link List} or {@link Map} for {@code list} and {@code dict} attributes, whereas
2556 * Starlark uses only immutable {@link StarlarkList} and {@link Dict}.
2557 *
2558 * <p>The conversion is similar to {@link Starlark#fromJava} for all types except {@code
2559 * attr.string_list_dict} ({@code Map<String, List<String>>}), for which fromJava does not
2560 * recursively convert elements. (Doing so is expensive.)
2561 *
2562 * <p>It is tempting to require that attributes are stored internally in Starlark form. However, a
2563 * number of obstacles would need to be overcome:
2564 *
2565 * <ol>
2566 * <li>Some obscure attribute types such as TRISTATE and DISTRIBUTION are not currently legal
2567 * Starlark values.
2568 * <li>ImmutableList is significantly more compact than StarlarkList for small lists (n &lt; 2).
2569 * StarlarkList would need multiple representations and a builder to achieve parity.
2570 * <li>The types used by the Type mechanism would need changing; this has extensive
2571 * ramifications.
2572 * </ol>
2573 */
2574 public static Object valueToStarlark(Object x) {
2575 // Is x a non-empty string_list_dict?
2576 if (x instanceof Map) {
2577 Map<?, ?> map = (Map) x;
2578 if (!map.isEmpty() && map.values().iterator().next() instanceof List) {
2579 // Recursively convert subelements.
2580 Dict.Builder<Object, Object> dict = Dict.builder();
2581 for (Map.Entry<?, ?> e : map.entrySet()) {
2582 dict.put((String) e.getKey(), Starlark.fromJava(e.getValue(), null));
2583 }
2584 return dict.buildImmutable();
2585 }
2586 }
2587
2588 // For all other attribute values, shallow conversion is safe.
2589 return Starlark.fromJava(x, null);
2590 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002591}