Fix `ConsumedArtifactsTracker` handling of template expansion inputs.

Tree artifacts that are only consumed via action templates were not getting registered as consumed - the children appear as action inputs, but not the parent. Make sure `ConsumedArtifactsTracker` registers the parent tree artifact as consumed if any children are consumed.

PiperOrigin-RevId: 972275451
Change-Id: I8ff550134586efd8705eb4776b166648ce4817fe
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConsumedArtifactsTracker.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConsumedArtifactsTracker.java
index 8501311..c024d4e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConsumedArtifactsTracker.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConsumedArtifactsTracker.java
@@ -35,16 +35,21 @@
   }
 
   void unregisterOutputsAfterExecutionDone(Collection<Artifact> outputs) {
-    consumed.removeAll(outputs);
+    for (Artifact artifact : outputs) {
+      consumed.remove(representative(artifact));
+    }
   }
 
   /** Register the provided artifact as "consumed". */
   void registerConsumedArtifact(Artifact artifact) {
-    // We should only store the consumed status of artifacts that will later on be checked for
-    // orphaned status directly. This is an optimization to keep the set smaller.
-    if (!artifact.isSourceArtifact() // Source artifacts won't be orphaned.
-        && !artifact.hasParent()) { // Will be checked through the parent artifact.
-      consumed.add(artifact);
+    if (artifact.isSourceArtifact()) {
+      return; // Source artifacts are never orphaned, so we don't track them.
     }
+    consumed.add(representative(artifact));
+  }
+
+  private static Artifact representative(Artifact artifact) {
+    // Tree artifact children are checked through the parent artifact.
+    return artifact.hasParent() ? artifact.getParent() : artifact;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/EphemeralCheckIfOutputConsumed.java b/src/main/java/com/google/devtools/build/lib/skyframe/EphemeralCheckIfOutputConsumed.java
index e225ced..90455bd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/EphemeralCheckIfOutputConsumed.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/EphemeralCheckIfOutputConsumed.java
@@ -22,5 +22,12 @@
  * execution of its generating action, and its behavior is undefined afterwards.
  */
 public interface EphemeralCheckIfOutputConsumed {
+
+  /**
+   * Tests whether a generated artifact is known to be consumed.
+   *
+   * <p>Should not be called for {@linkplain Artifact#isSourceArtifact source artifacts}. Children
+   * of tree artifacts should be tested by passing their {@linkplain Artifact#getParent parent}.
+   */
   boolean test(Artifact artifact);
 }
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/rewinding/RewindingTestsHelper.java b/src/test/java/com/google/devtools/build/lib/skyframe/rewinding/RewindingTestsHelper.java
index a651265..4e6a14d 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/rewinding/RewindingTestsHelper.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/rewinding/RewindingTestsHelper.java
@@ -246,7 +246,7 @@
   }
 
   public final ExecResult createLostInputsExecException(
-      ActionExecutionContext context, ImmutableList<ActionInput> lostInputs) throws IOException {
+      ActionExecutionContext context, List<ActionInput> lostInputs) throws IOException {
     ImmutableSetMultimap.Builder<String, ActionInput> builder = ImmutableSetMultimap.builder();
     for (ActionInput lostInput : lostInputs) {
       builder.put(getHexDigest(lostInput, context), lostInput);