// Copyright 2016 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.analysis; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.AttributeMap; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.syntax.Type; import java.util.Collection; /** * An {@link AttributeMap} that supports attribute type queries on both a rule and its aspects and * attribute value queries on the rule. * *

An attribute type query is anything accessible from {@link Attribute} (i.e. anything about how * the attribute is integrated into the {@link RuleClass}). An attribute value query is anything * related to the actual value an attribute takes. * *

For example, given {@code deps = [":adep"]}, checking that {@code deps} exists or that it's * type is {@link com.google.devtools.build.lib.packages.BuildType#LABEL_LIST} are type queries. * Checking that its value is explicitly set in the BUILD File or that its value {@code [":adep"]} * are value queries.. * *

Value queries on aspect attributes trigger {@link UnsupportedOperationException}. */ class AspectAwareAttributeMapper implements AttributeMap { private final AttributeMap ruleAttributes; private final ImmutableMap aspectAttributes; public AspectAwareAttributeMapper(AttributeMap ruleAttributes, ImmutableMap aspectAttributes) { this.ruleAttributes = ruleAttributes; this.aspectAttributes = aspectAttributes; } /** * Don't use this except where absolutely necessary. This exposes internal implementation details. */ ImmutableMap getAspectAttributes() { return aspectAttributes; } @Override public String getName() { return ruleAttributes.getName(); } @Override public String getRuleClassName() { return ruleAttributes.getRuleClassName(); } @Override public Label getLabel() { return ruleAttributes.getLabel(); } @Override public T get(String attributeName, Type type) { if (ruleAttributes.has(attributeName, type)) { return ruleAttributes.get(attributeName, type); } else { Attribute attribute = aspectAttributes.get(attributeName); if (attribute == null) { throw new IllegalArgumentException(String.format( "no attribute '%s' in either %s or its aspects", attributeName, ruleAttributes.getLabel())); } else if (attribute.getType() != type) { throw new IllegalArgumentException(String.format( "attribute %s has type %s, not expected type %s", attributeName, attribute.getType(), type)); } else { throw new UnsupportedOperationException( String.format( "Attribute '%s' comes from an aspect. " + "Value retrieval for aspect attributes is not supported.", attributeName)); } } } @Override public boolean isConfigurable(String attributeName) { return ruleAttributes.isConfigurable(attributeName); } @Override public Iterable getAttributeNames() { return ImmutableList.builder() .addAll(ruleAttributes.getAttributeNames()) .addAll(aspectAttributes.keySet()) .build(); } @Override public Type getAttributeType(String attrName) { Type type = ruleAttributes.getAttributeType(attrName); if (type != null) { return type; } else { Attribute attribute = aspectAttributes.get(attrName); return attribute != null ? attribute.getType() : null; } } @Override public Attribute getAttributeDefinition(String attrName) { Attribute attribute = ruleAttributes.getAttributeDefinition(attrName); if (attribute != null) { return attribute; } else { return aspectAttributes.get(attrName); } } @Override public boolean isAttributeValueExplicitlySpecified(String attributeName) { return ruleAttributes.isAttributeValueExplicitlySpecified(attributeName); } @Override public Collection visitLabels() throws InterruptedException { throw new UnsupportedOperationException("rule + aspects label visition is not supported"); } @Override public String getPackageDefaultHdrsCheck() { return ruleAttributes.getPackageDefaultHdrsCheck(); } @Override public Boolean getPackageDefaultTestOnly() { return ruleAttributes.getPackageDefaultTestOnly(); } @Override public String getPackageDefaultDeprecation() { return ruleAttributes.getPackageDefaultDeprecation(); } @Override public ImmutableList getPackageDefaultCopts() { return ruleAttributes.getPackageDefaultCopts(); } @Override public boolean has(String attrName) { if (ruleAttributes.has(attrName)) { return true; } else { return aspectAttributes.containsKey(attrName); } } @Override public boolean has(String attrName, Type type) { if (ruleAttributes.has(attrName, type)) { return true; } else { return aspectAttributes.containsKey(attrName) && aspectAttributes.get(attrName).getType() == type; } } @Override public Location getAttributeLocation(String attrName) { if (ruleAttributes.has(attrName)) { return ruleAttributes.getAttributeLocation(attrName); } else { return Location.BUILTIN; } } }