blob: 4419d0b162cf6ab0aa6d64487e48c76c5f4bee1d [file] [log] [blame]
// 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.
*
* <p>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.
*
* <p>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..
*
* <p>Value queries on aspect attributes trigger {@link UnsupportedOperationException}.
*/
class AspectAwareAttributeMapper implements AttributeMap {
private final AttributeMap ruleAttributes;
private final ImmutableMap<String, Attribute> aspectAttributes;
public AspectAwareAttributeMapper(AttributeMap ruleAttributes,
ImmutableMap<String, Attribute> aspectAttributes) {
this.ruleAttributes = ruleAttributes;
this.aspectAttributes = aspectAttributes;
}
/**
* Don't use this except where absolutely necessary. This exposes internal implementation details.
*/
ImmutableMap<String, Attribute> 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> T get(String attributeName, Type<T> 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<String> getAttributeNames() {
return ImmutableList.<String>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<DepEdge> 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<String> getPackageDefaultCopts() {
return ruleAttributes.getPackageDefaultCopts();
}
@Override
public boolean has(String attrName) {
if (ruleAttributes.has(attrName)) {
return true;
} else {
return aspectAttributes.containsKey(attrName);
}
}
@Override
public <T> boolean has(String attrName, Type<T> 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;
}
}
}