Simplify the Action interface by asking it a set of allowed inputs instead of to resolve exec paths found in the action cache.

The resolution algorithm was the same in all cases where it was implemented.

--
PiperOrigin-RevId: 146344672
MOS_MIGRATED_REVID=146344672
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java b/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
index b97d323..4f2a33c 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionCacheChecker.java
@@ -300,16 +300,57 @@
     for (Artifact output : action.getOutputs()) {
       outputs.add(output.getExecPath());
     }
-    List<PathFragment> inputs = new ArrayList<>();
+    List<PathFragment> inputExecPaths = new ArrayList<>();
     for (String path : entry.getPaths()) {
       PathFragment execPath = new PathFragment(path);
       // Code assumes that action has only 1-2 outputs and ArrayList.contains() will be
       // most efficient.
       if (!outputs.contains(execPath)) {
-        inputs.add(execPath);
+        inputExecPaths.add(execPath);
       }
     }
-    return action.resolveInputsFromCache(artifactResolver, resolver, inputs);
+
+    // Note that this method may trigger a violation of the desirable invariant that getInputs()
+    // is a superset of getMandatoryInputs(). See bug about an "action not in canonical form"
+    // error message and the integration test test_crosstool_change_and_failure().
+    Map<PathFragment, Artifact> allowedDerivedInputsMap = new HashMap<>();
+    for (Artifact derivedInput : action.getAllowedDerivedInputs()) {
+      if (!derivedInput.isSourceArtifact()) {
+        allowedDerivedInputsMap.put(derivedInput.getExecPath(), derivedInput);
+      }
+    }
+
+    List<Artifact> inputArtifacts = new ArrayList<>();
+    List<PathFragment> unresolvedPaths = new ArrayList<>();
+    for (PathFragment execPath : inputExecPaths) {
+      Artifact artifact = allowedDerivedInputsMap.get(execPath);
+      if (artifact != null) {
+        inputArtifacts.add(artifact);
+      } else {
+        // Remember this execPath, we will try to resolve it as a source artifact.
+        unresolvedPaths.add(execPath);
+      }
+    }
+
+    Map<PathFragment, Artifact> resolvedArtifacts =
+        artifactResolver.resolveSourceArtifacts(unresolvedPaths, resolver);
+    if (resolvedArtifacts == null) {
+      // We are missing some dependencies. We need to rerun this update later.
+      return null;
+    }
+
+    for (PathFragment execPath : unresolvedPaths) {
+      Artifact artifact = resolvedArtifacts.get(execPath);
+      // If PathFragment cannot be resolved into the artifact, ignore it. This could happen if the
+      // rule has changed and the action no longer depends on, e.g., an additional source file in a
+      // separate package and that package is no longer referenced anywhere else. It is safe to
+      // ignore such paths because dependency checker would identify changes in inputs (ignored path
+      // was used before) and will force action execution.
+      if (artifact != null) {
+        inputArtifacts.add(artifact);
+      }
+    }
+    return inputArtifacts;
   }
 
   /**