| // Copyright 2014 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.devtools.build.lib.query2.query.output; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.Lists; |
| import com.google.devtools.build.lib.packages.AggregatingAttributeMapper; |
| import com.google.devtools.build.lib.packages.Attribute; |
| import com.google.devtools.build.lib.packages.BuildType; |
| import com.google.devtools.build.lib.packages.Rule; |
| |
| /** Logic for retrieving possible values for an attribute. */ |
| public class PossibleAttributeValues { |
| |
| private PossibleAttributeValues() {} |
| |
| /** |
| * Returns the possible values of the specified attribute in the specified rule. For simple |
| * attributes, this is a single value. For configurable and computed attributes, this may be a |
| * list of values. See {@link AggregatingAttributeMapper#visitAttribute} for how the values are |
| * determined. |
| * |
| * <p>This applies an important optimization for label lists: instead of returning all possible |
| * values, it only returns possible <i>labels</i>. For example, given: |
| * |
| * <pre> |
| * select({ |
| * ":c": ["//a:one", "//a:two"], |
| * ":d": ["//a:two"] |
| * })</pre> |
| * |
| * it returns: |
| * |
| * <pre>["//a:one", "//a:two"]</pre> |
| * |
| * which loses track of which label appears in which branch. |
| * |
| * <p>This avoids the memory overruns that can happen be iterating over every possible value for |
| * an <code>attr = select(...) + select(...) + select(...) + ...</code> expression. Query |
| * operations generally don't care about specific attribute values - they just care which labels |
| * are possible. |
| * |
| * @param mayTreatMultipleAsNone signals if attribute-value computation <b>may</b> be aborted if |
| * more than one possible value is encountered. Useful when the caller needs a single value or |
| * none at all, as is the use case of this method for many attribute types. This parameter is |
| * respected on a best-effort basis - multiple values may still be returned if an unoptimized |
| * code path is visited. |
| */ |
| public static Iterable<Object> forRuleAndAttribute( |
| Rule rule, Attribute attr, boolean mayTreatMultipleAsNone) { |
| AggregatingAttributeMapper attributeMap = AggregatingAttributeMapper.of(rule); |
| if (attr.getType().equals(BuildType.LABEL_LIST) |
| && attributeMap.isConfigurable(attr.getName())) { |
| // TODO(gregce): Expand this to all collection types (we don't do this for scalars because |
| // there's currently no syntax for expressing multiple scalar values). This unfortunately |
| // isn't trivial because Bazel's label visitation logic includes special methods built |
| // directly into Type. |
| return ImmutableList.of( |
| attributeMap.getReachableLabels(attr.getName(), /* includeSelectKeys= */ false)); |
| } |
| |
| Iterable<?> concatenatedSelectsValue = |
| attributeMap.getConcatenatedSelectorListsOfListType(attr.getName(), attr.getType()); |
| if (concatenatedSelectsValue != null) { |
| return Lists.newArrayList(concatenatedSelectsValue); |
| } |
| |
| // The call to visitAttributes below is especially slow with selector lists. |
| @SuppressWarnings("unchecked") // Casting Iterable<T> -> Iterable<Object> |
| Iterable<Object> possibleValues = |
| (Iterable<Object>) |
| attributeMap.visitAttribute(attr.getName(), attr.getType(), mayTreatMultipleAsNone); |
| return possibleValues; |
| } |
| } |