Introduce the 'same_pkg_direct_rdeps' query function.

RELNOTES[NEW]: There is now a 'same_pkg_direct_rdeps' query function. See the
query documentation for more details.

PiperOrigin-RevId: 214961929
diff --git a/site/docs/query-how-to.html b/site/docs/query-how-to.html
index 7bf0b33..18c38ef 100644
--- a/site/docs/query-how-to.html
+++ b/site/docs/query-how-to.html
@@ -421,7 +421,7 @@
 
 <h4>What targets directly depend on T, in T's package?</h4>
 
-<pre>bazel query 'let t = T in rdeps(siblings($t), $t, 1)'</pre>
+<pre>bazel query 'same_pkg_direct_rdeps(T)'</pre>
 
 <p><a name="How_do_I_break_a_dependency_"></a></p>
 
diff --git a/site/docs/query.html b/site/docs/query.html
index 605c159..9c7ede7 100644
--- a/site/docs/query.html
+++ b/site/docs/query.html
@@ -535,6 +535,7 @@
 <a href="#loadfiles">loadfiles</a><br/>
 <a href="#rdeps">rdeps</a><br/>
 <a href="#allrdeps">allrdeps</a><br/>
+<a href="#same_pkg_direct_rdeps">same_pkg_direct_rdeps</a><br/>
 <a href="#siblings">siblings</a><br/>
 <a href="#some">some</a><br/>
 <a href="#path-operators">somepath</a><br/>
@@ -617,6 +618,13 @@
   equivalent to <code>rdeps(//foo/..., //bar)</code>.
 </p>
 
+<h3 id="same_pkg_direct_rdeps">Direct reverse dependencies in the same package: same_pkg_direct_rdeps</h3>
+<pre>expr ::= same_pkg_direct_rdeps(<var>expr</var>)</pre>
+<p>
+  The <code>same_pkg_direct_rdeps(<var>x</var>)</code> operator evalutes to the full set of targets
+  that are in the same package as a target in the argument set, and which directly depend on it.
+</p>
+
 <h3 id="siblings">Dealing with a target's package: siblings</h3>
 <pre>expr ::= siblings(<var>expr</var>)</pre>
 <p>
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
index b301676..afdbee3 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryEnvironment.java
@@ -590,6 +590,7 @@
           new LabelsFunction(),
           new LoadFilesFunction(),
           new RdepsFunction(),
+          new SamePkgDirectRdepsFunction(),
           new SiblingsFunction(),
           new SomeFunction(),
           new SomePathFunction(),
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/SamePkgDirectRdepsFunction.java b/src/main/java/com/google/devtools/build/lib/query2/engine/SamePkgDirectRdepsFunction.java
new file mode 100644
index 0000000..7b0067d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/SamePkgDirectRdepsFunction.java
@@ -0,0 +1,71 @@
+// Copyright 2018 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.query2.engine;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Argument;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ArgumentType;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryTaskFuture;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ThreadSafeMutableSet;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A "same_pkg_direct_rdeps" query expression, which computes all of the targets in the same package
+ * of the given targets which directly depend on them.
+ *
+ * <pre>expr ::= SAME_PKG_DIRECT_RDEPS '(' expr ')'</pre>
+ */
+public class SamePkgDirectRdepsFunction implements QueryFunction {
+
+  @Override
+  public String getName() {
+    return "same_pkg_direct_rdeps";
+  }
+
+  @Override
+  public int getMandatoryArguments() {
+    return 1;
+  }
+
+  @Override
+  public Iterable<ArgumentType> getArgumentTypes() {
+    return ImmutableList.of(ArgumentType.EXPRESSION);
+  }
+
+  @Override
+  public <T> QueryTaskFuture<Void> eval(
+      QueryEnvironment<T> env,
+      QueryExpressionContext<T> context,
+      final QueryExpression expression,
+      List<Argument> args,
+      final Callback<T> callback) {
+    Uniquifier<T> uniquifier = env.createUniquifier();
+    return env.eval(
+        args.get(0).getExpression(),
+        context,
+        partialResult -> {
+          for (T target : partialResult) {
+            ThreadSafeMutableSet<T> siblings = env.createThreadSafeMutableSet();
+            siblings.addAll(env.getSiblingTargetsInPackage(target));
+            env.buildTransitiveClosure(expression, siblings, /*maxDepth=*/ 1);
+            Iterable<T> rdeps = env.getReverseDeps(Collections.singleton(target), context);
+            callback.process(uniquifier.unique(Iterables.filter(rdeps, siblings::contains)));
+          }
+        });
+  }
+}