blob: 8d3c21cb985cbb2e02680a87d1fdc530b6dc954c [file] [log] [blame]
// Copyright 2019 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.packages;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.AttributeMap.DepEdge;
import javax.annotation.Nullable;
/**
* Helper functions for visiting the {@link Label}s of the loading-phase deps of a {@link Target}
* that are entailed by the values of the {@link Target}'s attributes. Notably, this does *not*
* include aspect-entailed deps.
*/
public class LabelVisitationUtils {
private LabelVisitationUtils() {}
/** Interface for processing the {@link Label} of dep, one at a time. */
public interface LabelProcessor {
/**
* Processes the {@link Label} of a single dep.
*
* @param from the {@link Target} that has the dep.
* @param attribute if non-{@code null}, the {@link Attribute} whose value entailed the dep.
* @param to the {@link Label} of the dep.
*/
void process(Target from, @Nullable Attribute attribute, Label to);
}
/** Interface for exceptionally processing the {@link Label} of dep, one at a time. */
public interface ExceptionalLabelProcessor<E1 extends Exception, E2 extends Exception> {
/**
* Processes the {@link Label} of a single dep.
*
* @param from the {@link Target} that has the dep.
* @param attribute if non-{@code null}, the {@link Attribute} whose value entailed the dep.
* @param to the {@link Label} of the dep.
*/
void process(Target from, @Nullable Attribute attribute, Label to) throws E1, E2;
}
/**
* Visits the loading-phase deps of {@code target} that satisfy {@code edgeFilter}, feeding each
* one to {@code labelProcessor} in a streaming manner.
*/
public static void visitTarget(
Target target, DependencyFilter edgeFilter, LabelProcessor labelProcessor) {
try {
visitTargetExceptionally(
target, edgeFilter, new ExceptionalLabelProcessorAdaptor(labelProcessor));
} catch (BottomException e) {
throw new IllegalStateException(e);
}
}
/**
* Visits the loading-phase deps of {@code target} that satisfy {@code edgeFilter}, feeding each
* one to {@code labelProcessor} in a streaming manner.
*/
public static <E1 extends Exception, E2 extends Exception> void visitTargetExceptionally(
Target target, DependencyFilter edgeFilter, ExceptionalLabelProcessor<E1, E2> labelProcessor)
throws E1, E2 {
if (target instanceof OutputFile) {
labelProcessor.process(
target, /*attribute=*/ null, ((OutputFile) target).getGeneratingRule().getLabel());
visitTargetVisibility(target, /*attribute=*/ null, labelProcessor);
return;
}
if (target instanceof InputFile) {
visitTargetVisibility(target, /*attribute=*/ null, labelProcessor);
return;
}
if (target instanceof Rule) {
Rule rule = (Rule) target;
visitRuleVisibility(rule, edgeFilter, labelProcessor);
visitRule(rule, edgeFilter, labelProcessor);
return;
}
if (target instanceof PackageGroup) {
visitPackageGroup((PackageGroup) target, labelProcessor);
return;
}
}
private static <E1 extends Exception, E2 extends Exception> void visitTargetVisibility(
Target target,
@Nullable Attribute attribute,
ExceptionalLabelProcessor<E1, E2> labelProcessor)
throws E1, E2 {
for (Label label : target.getVisibility().getDependencyLabels()) {
labelProcessor.process(target, attribute, label);
}
}
private static <E1 extends Exception, E2 extends Exception> void visitRuleVisibility(
Rule rule, DependencyFilter edgeFilter, ExceptionalLabelProcessor<E1, E2> labelProcessor)
throws E1, E2 {
RuleClass ruleClass = rule.getRuleClassObject();
if (!ruleClass.hasAttr("visibility", BuildType.NODEP_LABEL_LIST)) {
return;
}
Attribute visibilityAttribute = ruleClass.getAttributeByName("visibility");
if (edgeFilter.apply(rule, visibilityAttribute)) {
visitTargetVisibility(rule, visibilityAttribute, labelProcessor);
}
}
private static <E1 extends Exception, E2 extends Exception> void visitRule(
Rule rule, DependencyFilter edgeFilter, ExceptionalLabelProcessor<E1, E2> labelProcessor)
throws E1, E2 {
for (DepEdge depEdge : AggregatingAttributeMapper.of(rule).visitLabels()) {
if (edgeFilter.apply(rule, depEdge.getAttribute())) {
labelProcessor.process(rule, depEdge.getAttribute(), depEdge.getLabel());
}
}
}
private static <E1 extends Exception, E2 extends Exception> void visitPackageGroup(
PackageGroup packageGroup, ExceptionalLabelProcessor<E1, E2> labelProcessor) throws E1, E2 {
for (Label label : packageGroup.getIncludes()) {
labelProcessor.process(packageGroup, /*attribute=*/ null, label);
}
}
private static class BottomException extends Exception {}
private static class ExceptionalLabelProcessorAdaptor
implements ExceptionalLabelProcessor<BottomException, BottomException> {
private final LabelProcessor labelProcessor;
private ExceptionalLabelProcessorAdaptor(LabelProcessor labelProcessor) {
this.labelProcessor = labelProcessor;
}
@Override
public void process(Target from, @Nullable Attribute attribute, Label to) {
labelProcessor.process(from, attribute, to);
}
}
}