Move aspect resolution out of ConfiguredTargetFunction.
Part of the effort to simplify ConfiguredTargetFunction.
PiperOrigin-RevId: 169453435
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AspectResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/AspectResolver.java
new file mode 100644
index 0000000..87a942d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AspectResolver.java
@@ -0,0 +1,171 @@
+// Copyright 2017 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.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.Aspect;
+import com.google.devtools.build.lib.packages.AspectDescriptor;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.skyframe.AspectFunction;
+import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue;
+import com.google.devtools.build.lib.util.OrderedSetMultimap;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.ValueOrException2;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/**
+ * Returns the aspects to attach to rule dependencies.
+ */
+public final class AspectResolver {
+ /**
+ * Given a list of {@link Dependency} objects, returns a multimap from the {@link Dependency}s to
+ * the {@link ConfiguredAspect} instances that should be merged with them.
+ *
+ * <p>Returns null if the required aspects are not yet available from Skyframe.
+ */
+ @Nullable
+ public static OrderedSetMultimap<Dependency, ConfiguredAspect> resolveAspectDependencies(
+ SkyFunction.Environment env,
+ Map<SkyKey, ConfiguredTarget> configuredTargetMap,
+ Iterable<Dependency> deps,
+ NestedSetBuilder<Package> transitivePackages)
+ throws AspectFunction.AspectCreationException, InterruptedException {
+ OrderedSetMultimap<Dependency, ConfiguredAspect> result = OrderedSetMultimap.create();
+ Set<SkyKey> allAspectKeys = new HashSet<>();
+ for (Dependency dep : deps) {
+ allAspectKeys.addAll(getAspectKeys(dep).values());
+ }
+
+ Map<SkyKey, ValueOrException2<AspectFunction.AspectCreationException, NoSuchThingException>>
+ depAspects = env.getValuesOrThrow(allAspectKeys,
+ AspectFunction.AspectCreationException.class, NoSuchThingException.class);
+
+ for (Dependency dep : deps) {
+ Map<AspectDescriptor, SkyKey> aspectToKeys = getAspectKeys(dep);
+
+ for (AspectCollection.AspectDeps depAspect : dep.getAspects().getVisibleAspects()) {
+ SkyKey aspectKey = aspectToKeys.get(depAspect.getAspect());
+
+ AspectValue aspectValue;
+ try {
+ // TODO(ulfjack): Catch all thrown AspectCreationException and NoSuchThingException
+ // instances and merge them into a single Exception to get full root cause data.
+ aspectValue = (AspectValue) depAspects.get(aspectKey).get();
+ } catch (NoSuchThingException e) {
+ throw new AspectFunction.AspectCreationException(
+ String.format(
+ "Evaluation of aspect %s on %s failed: %s",
+ depAspect.getAspect().getAspectClass().getName(),
+ dep.getLabel(),
+ e.toString()));
+ }
+
+ if (aspectValue == null) {
+ // Dependent aspect has either not been computed yet or is in error.
+ return null;
+ }
+
+ // Validate that aspect is applicable to "bare" configured target.
+ ConfiguredTarget associatedTarget = configuredTargetMap
+ .get(ConfiguredTargetValue.key(dep.getLabel(), dep.getConfiguration()));
+ if (!aspectMatchesConfiguredTarget(associatedTarget, aspectValue.getAspect())) {
+ continue;
+ }
+
+ result.put(dep, aspectValue.getConfiguredAspect());
+ transitivePackages.addTransitive(aspectValue.getTransitivePackages());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Merges each direct dependency configured target with the aspects associated with it.
+ *
+ * <p>Note that the combination of a configured target and its associated aspects are not
+ * represented by a Skyframe node. This is because there can possibly be many different
+ * combinations of aspects for a particular configured target, so it would result in a
+ * combinatorial explosion of Skyframe nodes.
+ */
+ public static OrderedSetMultimap<Attribute, ConfiguredTarget> mergeAspects(
+ OrderedSetMultimap<Attribute, Dependency> depValueNames,
+ Map<SkyKey, ConfiguredTarget> depConfiguredTargetMap,
+ OrderedSetMultimap<Dependency, ConfiguredAspect> depAspectMap)
+ throws MergedConfiguredTarget.DuplicateException {
+ OrderedSetMultimap<Attribute, ConfiguredTarget> result = OrderedSetMultimap.create();
+
+ for (Map.Entry<Attribute, Dependency> entry : depValueNames.entries()) {
+ Dependency dep = entry.getValue();
+ SkyKey depKey = ConfiguredTargetValue.key(dep.getLabel(), dep.getConfiguration());
+ ConfiguredTarget depConfiguredTarget = depConfiguredTargetMap.get(depKey);
+
+ result.put(entry.getKey(),
+ MergedConfiguredTarget.of(depConfiguredTarget, depAspectMap.get(dep)));
+ }
+
+ return result;
+ }
+
+ private static Map<AspectDescriptor, SkyKey> getAspectKeys(Dependency dep) {
+ HashMap<AspectDescriptor, SkyKey> result = new HashMap<>();
+ AspectCollection aspects = dep.getAspects();
+ for (AspectCollection.AspectDeps aspectDeps : aspects.getVisibleAspects()) {
+ buildAspectKey(aspectDeps, result, dep);
+ }
+ return result;
+ }
+
+ private static AspectValue.AspectKey buildAspectKey(AspectCollection.AspectDeps aspectDeps,
+ HashMap<AspectDescriptor, SkyKey> result, Dependency dep) {
+ if (result.containsKey(aspectDeps.getAspect())) {
+ return (AspectValue.AspectKey) result.get(aspectDeps.getAspect()).argument();
+ }
+
+ ImmutableList.Builder<AspectValue.AspectKey> dependentAspects = ImmutableList.builder();
+ for (AspectCollection.AspectDeps path : aspectDeps.getDependentAspects()) {
+ dependentAspects.add(buildAspectKey(path, result, dep));
+ }
+ AspectValue.AspectKey aspectKey = AspectValue.createAspectKey(
+ dep.getLabel(), dep.getConfiguration(),
+ dependentAspects.build(),
+ aspectDeps.getAspect(),
+ dep.getAspectConfiguration(aspectDeps.getAspect()));
+ result.put(aspectKey.getAspectDescriptor(), aspectKey.getSkyKey());
+ return aspectKey;
+ }
+
+ public static boolean aspectMatchesConfiguredTarget(final ConfiguredTarget dep, Aspect aspect) {
+ if (!aspect.getDefinition().applyToFiles() && !(dep.getTarget() instanceof Rule)) {
+ return false;
+ }
+ if (dep.getTarget().getAssociatedRule() == null) {
+ // even aspects that 'apply to files' cannot apply to input files.
+ return false;
+ }
+ return dep.satisfies(aspect.getDefinition().getRequiredProviders());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 2beb088..f67a4e8 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -21,6 +21,7 @@
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionLookupValue;
import com.google.devtools.build.lib.analysis.AliasProvider;
+import com.google.devtools.build.lib.analysis.AspectResolver;
import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
@@ -466,7 +467,7 @@
}
ConfiguredAspect configuredAspect;
- if (ConfiguredTargetFunction.aspectMatchesConfiguredTarget(associatedTarget, aspect)) {
+ if (AspectResolver.aspectMatchesConfiguredTarget(associatedTarget, aspect)) {
configuredAspect =
view.getConfiguredTargetFactory()
.createAspect(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
index ee23308..8a80192 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
@@ -372,7 +372,7 @@
transitivePackages = null;
}
- NestedSet<Package> getTransitivePackages() {
+ public NestedSet<Package> getTransitivePackages() {
return Preconditions.checkNotNull(transitivePackages);
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index c157351..d1c0eae 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -22,8 +22,7 @@
import com.google.devtools.build.lib.actions.Actions;
import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
-import com.google.devtools.build.lib.analysis.AspectCollection;
-import com.google.devtools.build.lib.analysis.AspectCollection.AspectDeps;
+import com.google.devtools.build.lib.analysis.AspectResolver;
import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -37,7 +36,6 @@
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
-import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget;
import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -46,7 +44,6 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.Aspect;
-import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
@@ -58,7 +55,6 @@
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.skyframe.AspectFunction.AspectCreationException;
-import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException;
import com.google.devtools.build.lib.syntax.EvalException;
@@ -69,11 +65,8 @@
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.devtools.build.skyframe.ValueOrException;
-import com.google.devtools.build.skyframe.ValueOrException2;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@@ -403,15 +396,16 @@
}
// Resolve required aspects.
- OrderedSetMultimap<Dependency, ConfiguredAspect> depAspects = resolveAspectDependencies(
- env, depValues, depValueNames.values(), transitivePackages);
+ OrderedSetMultimap<Dependency, ConfiguredAspect> depAspects =
+ AspectResolver.resolveAspectDependencies(env, depValues, depValueNames.values(),
+ transitivePackages);
if (depAspects == null) {
return null;
}
// Merge the dependent configured targets and aspects into a single map.
try {
- return mergeAspects(depValueNames, depValues, depAspects);
+ return AspectResolver.mergeAspects(depValueNames, depValues, depAspects);
} catch (DuplicateException e) {
env.getListener().handle(
Event.error(ctgValue.getTarget().getLocation(), e.getMessage()));
@@ -422,134 +416,6 @@
}
/**
- * Merges the each direct dependency configured target with the aspects associated with it.
- *
- * <p>Note that the combination of a configured target and its associated aspects are not
- * represented by a Skyframe node. This is because there can possibly be many different
- * combinations of aspects for a particular configured target, so it would result in a
- * combinatiorial explosion of Skyframe nodes.
- */
- private static OrderedSetMultimap<Attribute, ConfiguredTarget> mergeAspects(
- OrderedSetMultimap<Attribute, Dependency> depValueNames,
- Map<SkyKey, ConfiguredTarget> depConfiguredTargetMap,
- OrderedSetMultimap<Dependency, ConfiguredAspect> depAspectMap)
- throws DuplicateException {
- OrderedSetMultimap<Attribute, ConfiguredTarget> result = OrderedSetMultimap.create();
-
- for (Map.Entry<Attribute, Dependency> entry : depValueNames.entries()) {
- Dependency dep = entry.getValue();
- SkyKey depKey = ConfiguredTargetValue.key(dep.getLabel(), dep.getConfiguration());
- ConfiguredTarget depConfiguredTarget = depConfiguredTargetMap.get(depKey);
-
- result.put(entry.getKey(),
- MergedConfiguredTarget.of(depConfiguredTarget, depAspectMap.get(dep)));
- }
-
- return result;
- }
-
- /**
- * Given a list of {@link Dependency} objects, returns a multimap from the
- * {@link Dependency}s too the {@link ConfiguredAspect} instances that should be merged into it.
- *
- * <p>Returns null if the required aspects are not computed yet.
- */
- @Nullable
- private static OrderedSetMultimap<Dependency, ConfiguredAspect> resolveAspectDependencies(
- Environment env,
- Map<SkyKey, ConfiguredTarget> configuredTargetMap,
- Iterable<Dependency> deps,
- NestedSetBuilder<Package> transitivePackages)
- throws AspectCreationException, InterruptedException {
- OrderedSetMultimap<Dependency, ConfiguredAspect> result = OrderedSetMultimap.create();
- Set<SkyKey> allAspectKeys = new HashSet<>();
- for (Dependency dep : deps) {
- allAspectKeys.addAll(getAspectKeys(dep).values());
- }
-
- Map<SkyKey, ValueOrException2<AspectCreationException, NoSuchThingException>> depAspects =
- env.getValuesOrThrow(allAspectKeys,
- AspectCreationException.class, NoSuchThingException.class);
-
- for (Dependency dep : deps) {
- Map<AspectDescriptor, SkyKey> aspectToKeys = getAspectKeys(dep);
-
- for (AspectDeps depAspect : dep.getAspects().getVisibleAspects()) {
- SkyKey aspectKey = aspectToKeys.get(depAspect.getAspect());
-
- AspectValue aspectValue;
- try {
- // TODO(ulfjack): Catch all thrown AspectCreationException and NoSuchThingException
- // instances and merge them into a single Exception to get full root cause data.
- aspectValue = (AspectValue) depAspects.get(aspectKey).get();
- } catch (NoSuchThingException e) {
- throw new AspectCreationException(
- String.format(
- "Evaluation of aspect %s on %s failed: %s",
- depAspect.getAspect().getAspectClass().getName(),
- dep.getLabel(),
- e.toString()));
- }
-
- if (aspectValue == null) {
- // Dependent aspect has either not been computed yet or is in error.
- return null;
- }
-
- // Validate that aspect is applicable to "bare" configured target.
- ConfiguredTarget associatedTarget = configuredTargetMap
- .get(ConfiguredTargetValue.key(dep.getLabel(), dep.getConfiguration()));
- if (!aspectMatchesConfiguredTarget(associatedTarget, aspectValue.getAspect())) {
- continue;
- }
-
- result.put(dep, aspectValue.getConfiguredAspect());
- transitivePackages.addTransitive(aspectValue.getTransitivePackages());
- }
- }
- return result;
- }
-
- private static Map<AspectDescriptor, SkyKey> getAspectKeys(Dependency dep) {
- HashMap<AspectDescriptor, SkyKey> result = new HashMap<>();
- AspectCollection aspects = dep.getAspects();
- for (AspectDeps aspectDeps : aspects.getVisibleAspects()) {
- buildAspectKey(aspectDeps, result, dep);
- }
- return result;
- }
-
- private static AspectKey buildAspectKey(AspectDeps aspectDeps,
- HashMap<AspectDescriptor, SkyKey> result, Dependency dep) {
- if (result.containsKey(aspectDeps.getAspect())) {
- return (AspectKey) result.get(aspectDeps.getAspect()).argument();
- }
-
- ImmutableList.Builder<AspectKey> dependentAspects = ImmutableList.builder();
- for (AspectDeps path : aspectDeps.getDependentAspects()) {
- dependentAspects.add(buildAspectKey(path, result, dep));
- }
- AspectKey aspectKey = AspectValue.createAspectKey(
- dep.getLabel(), dep.getConfiguration(),
- dependentAspects.build(),
- aspectDeps.getAspect(),
- dep.getAspectConfiguration(aspectDeps.getAspect()));
- result.put(aspectKey.getAspectDescriptor(), aspectKey.getSkyKey());
- return aspectKey;
- }
-
- static boolean aspectMatchesConfiguredTarget(final ConfiguredTarget dep, Aspect aspect) {
- if (!aspect.getDefinition().applyToFiles() && !(dep.getTarget() instanceof Rule)) {
- return false;
- }
- if (dep.getTarget().getAssociatedRule() == null) {
- // even aspects that 'apply to files' cannot apply to input files.
- return false;
- }
- return dep.satisfies(aspect.getDefinition().getRequiredProviders());
- }
-
- /**
* Returns the set of {@link ConfigMatchingProvider}s that key the configurable attributes used by
* this rule.
*
@@ -587,7 +453,7 @@
// Collect the corresponding Skyframe configured target values. Abort early if they haven't
// been computed yet.
- Collection<Dependency> configValueNames = null;
+ Collection<Dependency> configValueNames;
try {
configValueNames = resolver.resolveRuleLabels(
ctgValue, configLabelMap, transitiveLoadingRootCauses);