| // 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); | |
| } | |
| } | |
| } |