In SkyQueryEnvironment, rewrite queries using the semantics-preserving transformation 'rdeps(<sky_query_environment_universe_scope>, T, depth)' -> 'allrdeps(T, depth)'.

SkyQueryEnvironment can evaluate such allrdeps queries much more efficiently since it doesn't need to bother filtering out targets outside of universe, meaning it doesn't need to have all targets in the universe in memory at the same time.

--
MOS_MIGRATED_REVID=116075008
diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
index f5ffe54..f5186c8 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java
@@ -47,10 +47,14 @@
 import com.google.devtools.build.lib.profiler.AutoProfiler;
 import com.google.devtools.build.lib.query2.engine.AllRdepsFunction;
 import com.google.devtools.build.lib.query2.engine.Callback;
+import com.google.devtools.build.lib.query2.engine.FunctionExpression;
 import com.google.devtools.build.lib.query2.engine.QueryEvalResult;
 import com.google.devtools.build.lib.query2.engine.QueryException;
 import com.google.devtools.build.lib.query2.engine.QueryExpression;
+import com.google.devtools.build.lib.query2.engine.QueryExpressionMapper;
 import com.google.devtools.build.lib.query2.engine.QueryUtil.AbstractUniquifier;
+import com.google.devtools.build.lib.query2.engine.RdepsFunction;
+import com.google.devtools.build.lib.query2.engine.TargetLiteral;
 import com.google.devtools.build.lib.query2.engine.Uniquifier;
 import com.google.devtools.build.lib.skyframe.FileValue;
 import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider;
@@ -173,6 +177,42 @@
   }
 
   @Override
+  public QueryExpression transformParsedQuery(QueryExpression queryExpression) {
+    // Transform each occurrence of an expressions of the form 'rdeps(<universeScope>, <T>)' to
+    // 'allrdeps(<T>)'. The latter is more efficient.
+    if (universeScope.size() != 1) {
+      return queryExpression;
+    }
+    final TargetPattern.Parser targetPatternParser = new TargetPattern.Parser(parserPrefix);
+    String universeScopePattern = Iterables.getOnlyElement(universeScope);
+    final String absoluteUniverseScopePattern =
+        targetPatternParser.absolutize(universeScopePattern);
+    QueryExpressionMapper rdepsToAllRDepsMapper = new QueryExpressionMapper() {
+      @Override
+      public QueryExpression map(FunctionExpression functionExpression) {
+        if (functionExpression.getFunction().getName().equals(new RdepsFunction().getName())) {
+          List<Argument> args = functionExpression.getArgs();
+          QueryExpression universeExpression = args.get(0).getExpression();
+          if (universeExpression instanceof TargetLiteral) {
+            TargetLiteral literalUniverseExpression = (TargetLiteral) universeExpression;
+            String absolutizedUniverseExpression =
+                targetPatternParser.absolutize(literalUniverseExpression.getPattern());
+            if (absolutizedUniverseExpression.equals(absoluteUniverseScopePattern)) {
+              List<Argument> argsTail = args.subList(1, functionExpression.getArgs().size());
+              return new FunctionExpression(new AllRdepsFunction(), argsTail);
+            }
+          }
+        }
+        return super.map(functionExpression);
+      }
+    };
+    QueryExpression transformedQueryExpression = queryExpression.getMapped(rdepsToAllRDepsMapper);
+    LOG.info(String.format("transformed query [%s] to [%s]", queryExpression,
+        transformedQueryExpression));
+    return transformedQueryExpression;
+  }
+
+  @Override
   public QueryEvalResult evaluateQuery(QueryExpression expr, Callback<Target> callback)
       throws QueryException, InterruptedException {
     // Some errors are reported as QueryExceptions and others as ERROR events (if --keep_going). The