RELNOTES[NEW]: The "args" attribute of *_binary and *_test rules now support expanding $(location //some/deps)

*_binary and *_test rules were supporting make variables substitution but not location expansion like genrule() does. Now the $(location //some/label) where //some/label is the label of a dependency of the rule will be replaced at runtime by the actual location of that dependency. In the same manner $(locations //some/label) will be replaced by the space separated list of files of the //some/label dependency. A longer usage explanation is provided in the build encyclopedia.

--
MOS_MIGRATED_REVID=87927345
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index eef371b..0de3117 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -593,14 +593,27 @@
   }
 
   /**
-   * Gets an attribute of type STRING_LIST expanding Make variables and
-   * tokenizes the result.
+   * Gets an attribute of type STRING_LIST expanding Make variables and tokenizes
+   * the result.
    *
    * @param attributeName the name of the attribute to process
-   * @return a list of strings containing the expanded and tokenized values for the
-   *         attribute
+   * @return a list of strings containing the expanded and tokenized values for the attribute
    */
   public List<String> getTokenizedStringListAttr(String attributeName) {
+    return getTokenizedStringListAttr(attributeName, null);
+  }
+
+  /**
+   * Gets an attribute of type STRING_LIST expanding Make variables, $(location) tags into the
+   * dependency location (see {@link LocationExpander} for details) and tokenizes the result.
+   *
+   * @param attributeName the name of the attribute to process
+   * @param ruleContext the rule context to look for $(location) tag replacement, or null if
+   *        location should not be expanded
+   * @return a list of strings containing the expanded and tokenized values for the attribute
+   */
+  public List<String> getTokenizedStringListAttr(String attributeName,
+      @Nullable RuleContext ruleContext) {
     if (!getRule().isAttrDefined(attributeName, Type.STRING_LIST)) {
       // TODO(bazel-team): This should be an error.
       return ImmutableList.of();
@@ -610,8 +623,12 @@
       return ImmutableList.of();
     }
     List<String> tokens = new ArrayList<>();
+    LocationExpander locationExpander =
+        ruleContext != null ? new LocationExpander(ruleContext, LocationExpander.Options.ALLOW_DATA)
+            : null;
+
     for (String token : original) {
-      tokenizeAndExpandMakeVars(tokens, attributeName, token);
+      tokenizeAndExpandMakeVars(tokens, attributeName, token, locationExpander);
     }
     return ImmutableList.copyOf(tokens);
   }
@@ -621,10 +638,23 @@
    *
    * <p>This methods should be called only during initialization.
    */
+  public void tokenizeAndExpandMakeVars(List<String> tokens, String attributeName, String value) {
+    tokenizeAndExpandMakeVars(tokens, attributeName, value, null);
+  }
+
+  /**
+   * Expands make variables and $(location) tag in value and tokenizes the result into tokens.
+   *
+   * <p>This methods should be called only during initialization.
+   */
   public void tokenizeAndExpandMakeVars(List<String> tokens, String attributeName,
-                                        String value) {
+                                        String value, @Nullable LocationExpander locationExpander) {
     try {
-      ShellUtils.tokenize(tokens, expandMakeVariables(attributeName, value));
+      if (locationExpander != null) {
+        value = locationExpander.expand(attributeName, value);
+      }
+      value = expandMakeVariables(attributeName, value);
+      ShellUtils.tokenize(tokens, value);
     } catch (ShellUtils.TokenizationException e) {
       attributeError(attributeName, e.getMessage());
     }