Update from Google.

--
MOE_MIGRATED_REVID=85702957
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java
new file mode 100644
index 0000000..417cfca
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TransitiveTargetFunction.java
@@ -0,0 +1,234 @@
+// Copyright 2014 Google Inc. 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.skyframe;
+
+import com.google.common.collect.Lists;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.InputFile;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.OutputFile;
+import com.google.devtools.build.lib.packages.PackageGroup;
+import com.google.devtools.build.lib.packages.PackageIdentifier;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.packages.TargetUtils;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.skyframe.SkyFunction;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+import com.google.devtools.build.skyframe.ValueOrException;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This class builds transitive Target values such that evaluating a Target value is similar to
+ * running it through the LabelVisitor.
+ */
+public class TransitiveTargetFunction implements SkyFunction {
+
+  @Override
+  public SkyValue compute(SkyKey key, Environment env) throws TransitiveTargetFunctionException {
+    Label label = (Label) key.argument();
+    SkyKey packageKey = PackageValue.key(label.getPackageIdentifier());
+    SkyKey targetKey = TargetMarkerValue.key(label);
+    Target target;
+    boolean packageLoadedSuccessfully;
+    boolean successfulTransitiveLoading = true;
+    NestedSetBuilder<Label> transitiveRootCauses = NestedSetBuilder.stableOrder();
+    NoSuchTargetException errorLoadingTarget = null;
+    try {
+      TargetMarkerValue targetValue = (TargetMarkerValue) env.getValueOrThrow(targetKey,
+          NoSuchThingException.class);
+      if (targetValue == null) {
+        return null;
+      }
+      PackageValue packageValue = (PackageValue) env.getValueOrThrow(packageKey,
+          NoSuchThingException.class);
+      if (packageValue == null) {
+        return null;
+      }
+
+      packageLoadedSuccessfully = true;
+      target = packageValue.getPackage().getTarget(label.getName());
+    } catch (NoSuchTargetException e) {
+      target = e.getTarget();
+      if (target == null) {
+        throw new TransitiveTargetFunctionException(e);
+      }
+      successfulTransitiveLoading = false;
+      transitiveRootCauses.add(label);
+      errorLoadingTarget = e;
+      packageLoadedSuccessfully = e.getPackageLoadedSuccessfully();
+    } catch (NoSuchPackageException e) {
+      throw new TransitiveTargetFunctionException(e);
+    } catch (NoSuchThingException e) {
+      throw new IllegalStateException(e
+          + " not NoSuchTargetException or NoSuchPackageException");
+    }
+
+    NestedSetBuilder<PackageIdentifier> transitiveSuccessfulPkgs = NestedSetBuilder.stableOrder();
+    NestedSetBuilder<PackageIdentifier> transitiveUnsuccessfulPkgs = NestedSetBuilder.stableOrder();
+    NestedSetBuilder<Label> transitiveTargets = NestedSetBuilder.stableOrder();
+
+    PackageIdentifier packageId = target.getPackage().getPackageIdentifier();
+    if (packageLoadedSuccessfully) {
+      transitiveSuccessfulPkgs.add(packageId);
+    } else {
+      transitiveUnsuccessfulPkgs.add(packageId);
+    }
+    transitiveTargets.add(target.getLabel());
+    for (Map.Entry<SkyKey, ValueOrException<NoSuchThingException>> entry :
+        env.getValuesOrThrow(getLabelDepKeys(target), NoSuchThingException.class).entrySet()) {
+      Label depLabel = (Label) entry.getKey().argument();
+      TransitiveTargetValue transitiveTargetValue;
+      try {
+        transitiveTargetValue = (TransitiveTargetValue) entry.getValue().get();
+        if (transitiveTargetValue == null) {
+          continue;
+        }
+      } catch (NoSuchPackageException | NoSuchTargetException e) {
+        successfulTransitiveLoading = false;
+        transitiveRootCauses.add(depLabel);
+        maybeReportErrorAboutMissingEdge(target, depLabel, e, env.getListener());
+        continue;
+      } catch (NoSuchThingException e) {
+        throw new IllegalStateException("Unexpected Exception type from TransitiveTargetValue.", e);
+      }
+      transitiveSuccessfulPkgs.addTransitive(
+          transitiveTargetValue.getTransitiveSuccessfulPackages());
+      transitiveUnsuccessfulPkgs.addTransitive(
+          transitiveTargetValue.getTransitiveUnsuccessfulPackages());
+      transitiveTargets.addTransitive(transitiveTargetValue.getTransitiveTargets());
+      NestedSet<Label> rootCauses = transitiveTargetValue.getTransitiveRootCauses();
+      if (rootCauses != null) {
+        successfulTransitiveLoading = false;
+        transitiveRootCauses.addTransitive(rootCauses);
+        if (transitiveTargetValue.getErrorLoadingTarget() != null) {
+          maybeReportErrorAboutMissingEdge(target, depLabel,
+              transitiveTargetValue.getErrorLoadingTarget(), env.getListener());
+        }
+      }
+    }
+
+    if (env.valuesMissing()) {
+      return null;
+    }
+
+    NestedSet<PackageIdentifier> successfullyLoadedPackages = transitiveSuccessfulPkgs.build();
+    NestedSet<PackageIdentifier> unsuccessfullyLoadedPackages = transitiveUnsuccessfulPkgs.build();
+    NestedSet<Label> loadedTargets = transitiveTargets.build();
+    if (successfulTransitiveLoading) {
+      return TransitiveTargetValue.successfulTransitiveLoading(successfullyLoadedPackages,
+          unsuccessfullyLoadedPackages, loadedTargets);
+    } else {
+      NestedSet<Label> rootCauses = transitiveRootCauses.build();
+      return TransitiveTargetValue.unsuccessfulTransitiveLoading(successfullyLoadedPackages,
+          unsuccessfullyLoadedPackages, loadedTargets, rootCauses, errorLoadingTarget);
+    }
+  }
+
+  @Override
+  public String extractTag(SkyKey skyKey) {
+    return Label.print(((Label) skyKey.argument()));
+  }
+
+  private static void maybeReportErrorAboutMissingEdge(Target target, Label depLabel,
+      NoSuchThingException e, EventHandler eventHandler) {
+    if (e instanceof NoSuchTargetException) {
+      NoSuchTargetException nste = (NoSuchTargetException) e;
+      if (depLabel.equals(nste.getLabel())) {
+        eventHandler.handle(Event.error(TargetUtils.getLocationMaybe(target),
+            TargetUtils.formatMissingEdge(target, depLabel, e)));
+      }
+    } else if (e instanceof NoSuchPackageException) {
+      NoSuchPackageException nspe = (NoSuchPackageException) e;
+      if (nspe.getPackageName().equals(depLabel.getPackageName())) {
+        eventHandler.handle(Event.error(TargetUtils.getLocationMaybe(target),
+            TargetUtils.formatMissingEdge(target, depLabel, e)));
+      }
+    }
+  }
+
+  private static Iterable<SkyKey> getLabelDepKeys(Target target) {
+    List<SkyKey> depKeys = Lists.newArrayList();
+    for (Label depLabel : getLabelDeps(target)) {
+      depKeys.add(TransitiveTargetValue.key(depLabel));
+    }
+    return depKeys;
+  }
+
+  // TODO(bazel-team): Unify this logic with that in LabelVisitor, and possibly DependencyResolver.
+  private static Iterable<Label> getLabelDeps(Target target) {
+    final Set<Label> labels = new HashSet<>();
+    if (target instanceof OutputFile) {
+      Rule rule = ((OutputFile) target).getGeneratingRule();
+      labels.add(rule.getLabel());
+      visitTargetVisibility(target, labels);
+    } else if (target instanceof InputFile) {
+      visitTargetVisibility(target, labels);
+    } else if (target instanceof Rule) {
+      visitTargetVisibility(target, labels);
+      labels.addAll(((Rule) target).getLabels(Rule.NO_NODEP_ATTRIBUTES));
+    } else if (target instanceof PackageGroup) {
+      visitPackageGroup((PackageGroup) target, labels);
+    }
+    return labels;
+  }
+
+  private static void visitTargetVisibility(Target target, Set<Label> labels) {
+    for (Label label : target.getVisibility().getDependencyLabels()) {
+      labels.add(label);
+    }
+  }
+
+  private static void visitPackageGroup(PackageGroup packageGroup, Set<Label> labels) {
+    for (final Label include : packageGroup.getIncludes()) {
+      labels.add(include);
+    }
+  }
+
+  /**
+   * Used to declare all the exception types that can be wrapped in the exception thrown by
+   * {@link TransitiveTargetFunction#compute}.
+   */
+  private static class TransitiveTargetFunctionException extends SkyFunctionException {
+    /**
+     * Used to propagate an error from a direct target dependency to the
+     * target that depended on it.
+     */
+    public TransitiveTargetFunctionException(NoSuchPackageException e) {
+      super(e, Transience.PERSISTENT);
+    }
+
+    /**
+     * In nokeep_going mode, used to propagate an error from a direct target dependency to the
+     * target that depended on it.
+     *
+     * In keep_going mode, used the same way, but only for targets that could not be loaded at all
+     * (we proceed with transitive loading on targets that contain errors).
+     */
+    public TransitiveTargetFunctionException(NoSuchTargetException e) {
+      super(e, Transience.PERSISTENT);
+    }
+  }
+}