// Copyright 2014 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.packages; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.devtools.build.lib.packages.License.DistributionType; import com.google.devtools.build.lib.packages.License.LicenseParsingException; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.EvalUtils; import com.google.devtools.build.lib.syntax.FilesetEntry; import com.google.devtools.build.lib.syntax.GlobList; import com.google.devtools.build.lib.syntax.Label; import com.google.devtools.build.lib.syntax.Printer; import com.google.devtools.build.lib.syntax.SelectorValue; import com.google.devtools.build.lib.syntax.SkylarkList; import com.google.devtools.build.lib.util.LoggingUtil; import com.google.devtools.build.lib.util.StringCanonicalizer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import javax.annotation.Nullable; /** *

Root of Type symbol hierarchy for values in the build language.

* *

Type symbols are primarily used for their convert method, * which is a kind of cast operator enabling conversion from untyped (Object) * references to values in the build language, to typed references.

* *

For example, this code type-converts a value x returned by * the evaluator, to a list of strings:

* *
 *  Object x = expr.eval(env);
 *  List<String> s = Type.STRING_LIST.convert(x);
 *  
*/ public abstract class Type { private Type() {} /** * Converts untyped Object x resulting from the evaluation of an expression in the build language, * into a typed object of type T. * *

x must be *directly* convertible to this type. This therefore disqualifies "selector * expressions" of the form "{ config1: 'value1_of_orig_type', config2: 'value2_of_orig_type; }" * (which support configurable attributes). To handle those expressions, see * {@link #selectableConvert}. * * @param x the build-interpreter value to convert. * @param what a string description of what x is for; should be included in * any exception thrown. Grammatically, must describe a syntactic * construct, e.g. "attribute 'srcs' of rule foo". * @param currentRule the label of the current BUILD rule; must be non-null if resolution of * package-relative label strings is required * @throws ConversionException if there was a problem performing the type conversion */ public abstract T convert(Object x, String what, @Nullable Label currentRule) throws ConversionException; // TODO(bazel-team): Check external calls (e.g. in PackageFactory), verify they always want // this over selectableConvert. /** * Equivalent to {@link #convert(Object, String, Label)} where the label is {@code null}. * Useful for converting values to types that do not involve the type {@code LABEL} * and hence do not require the label of the current package. */ public final T convert(Object x, String what) throws ConversionException { return convert(x, what, null); } /** * Like {@link #convert(Object, String, Label)}, but converts skylark {@code None} * to given {@code defaultValue}. */ @Nullable public final T convertOptional(Object x, String what, @Nullable Label currentRule, T defaultValue) throws ConversionException { if (EvalUtils.isNullOrNone(x)) { return defaultValue; } return convert(x, what, currentRule); } /** * Like {@link #convert(Object, String, Label)}, but converts skylark {@code None} * to java {@code null}. */ @Nullable public final T convertOptional(Object x, String what, @Nullable Label currentRule) throws ConversionException { return convertOptional(x, what, currentRule, null); } /** * Like {@link #convert(Object, String)}, but converts skylark {@code NONE} to java {@code null}. */ @Nullable public final T convertOptional(Object x, String what) throws ConversionException { return convertOptional(x, what, null); } /** * Variation of {@link #convert} that supports selector expressions for configurable attributes * (i.e. "{ config1: 'value1_of_orig_type', config2: 'value2_of_orig_type; }"). If x is a * selector expression, returns a {@link Selector} instance that contains key-mapped entries * of the native type. Else, returns the native type directly. * *

The caller is responsible for casting the returned value appropriately. */ public Object selectableConvert(Object x, String what, @Nullable Label currentRule) throws ConversionException { if (x instanceof com.google.devtools.build.lib.syntax.SelectorList) { return new SelectorList( ((com.google.devtools.build.lib.syntax.SelectorList) x).getElements(), what, currentRule, this); } else { return convert(x, what, currentRule); } } public abstract T cast(Object value); @Override public abstract String toString(); /** * Returns the default value for this type; may return null iff no default is defined for this * type. */ public abstract T getDefaultValue(); /** * If this type contains labels (e.g. it *is* a label or it's a collection of labels), * returns a list of those labels for a value of that type. If this type doesn't * contain labels, returns an empty list. * *

This is used to support reliable label visitation in * {@link AbstractAttributeMapper#visitLabels}. To preserve that reliability, every * type should faithfully define its own instance of this method. In other words, * be careful about defining default instances in base types that get auto-inherited * by their children. Keep all definitions as explicit as possible. */ public abstract Collection