Support $(location) expansion in java_binary.jvm_flags

This makes it simpler to use jvm_flags to configure java agents, or set custom
bootclasspaths.

--
MOS_MIGRATED_REVID=113754498
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 b54e9e0..68b54e8 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
@@ -762,6 +762,12 @@
     return result;
   }
 
+  /** Indicates whether a string list attribute should be tokenized. */
+  public enum Tokenize {
+    YES,
+    NO
+  }
+
   /**
    * 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.
@@ -770,6 +776,17 @@
    * @return a list of strings containing the expanded and tokenized values for the attribute
    */
   public List<String> getTokenizedStringListAttr(String attributeName) {
+    return getExpandedStringListAttr(attributeName, Tokenize.YES);
+  }
+
+  /**
+   * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags,
+   * and optionally tokenizes the result.
+   *
+   * @param attributeName the name of the attribute to process
+   * @return a list of strings containing the processed values for the attribute
+   */
+  public List<String> getExpandedStringListAttr(String attributeName, Tokenize tokenize) {
     if (!getRule().isAttrDefined(attributeName, Type.STRING_LIST)) {
       // TODO(bazel-team): This should be an error.
       return ImmutableList.of();
@@ -783,7 +800,7 @@
         new LocationExpander(this, LocationExpander.Options.ALLOW_DATA);
 
     for (String token : original) {
-      tokenizeAndExpandMakeVars(tokens, attributeName, token, locationExpander);
+      expandValue(tokens, attributeName, token, locationExpander, tokenize);
     }
     return ImmutableList.copyOf(tokens);
   }
@@ -798,20 +815,41 @@
   }
 
   /**
-   * Expands make variables and $(location) tag in value and tokenizes the result into tokens.
+   * Expands make variables and $(location) tags 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, @Nullable LocationExpander locationExpander) {
-    try {
-      if (locationExpander != null) {
-        value = locationExpander.expandAttribute(attributeName, value);
+  public void tokenizeAndExpandMakeVars(
+      List<String> tokens,
+      String attributeName,
+      String value,
+      @Nullable LocationExpander locationExpander) {
+    expandValue(tokens, attributeName, value, locationExpander, Tokenize.YES);
+  }
+
+  /**
+   * Expands make variables and $(location) tags in value, and optionally tokenizes the result.
+   *
+   * <p>This methods should be called only during initialization.
+   */
+  public void expandValue(
+      List<String> tokens,
+      String attributeName,
+      String value,
+      @Nullable LocationExpander locationExpander,
+      Tokenize tokenize) {
+    if (locationExpander != null) {
+      value = locationExpander.expandAttribute(attributeName, value);
+    }
+    value = expandMakeVariables(attributeName, value);
+    if (tokenize == Tokenize.YES) {
+      try {
+        ShellUtils.tokenize(tokens, value);
+      } catch (ShellUtils.TokenizationException e) {
+        attributeError(attributeName, e.getMessage());
       }
-      value = expandMakeVariables(attributeName, value);
-      ShellUtils.tokenize(tokens, value);
-    } catch (ShellUtils.TokenizationException e) {
-      attributeError(attributeName, e.getMessage());
+    } else {
+      tokens.add(value);
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
index 20aad81..f343844 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -282,7 +282,8 @@
           .add(attr("classpath_resources", LABEL_LIST).legacyAllowAnyFileType())
           /* <!-- #BLAZE_RULE($base_java_binary).ATTRIBUTE(jvm_flags) -->
           A list of flags to embed in the wrapper script generated for running this binary.
-          Subject to <a href="make-variables.html">"Make variable"</a> substitution and
+          Subject to <a href="#location">$(location)</a> and
+          <a href="make-variables.html">"Make variable"</a> substitution, and
           <a href="common-definitions.html#sh-tokenization">Bourne shell tokenization</a>.
           <p>
             The wrapper script for a Java binary includes a <code>CLASSPATH</code> definition (to
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
index a93670c..470b8a1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
@@ -458,12 +458,12 @@
 
   /**
    * Gets the value of the "jvm_flags" attribute combining it with the default
-   * options and expanding any make variables.
+   * options and expanding any make variables and $(location) tags.
    */
   public List<String> getJvmFlags() {
     List<String> jvmFlags = new ArrayList<>();
     jvmFlags.addAll(ruleContext.getFragment(JavaConfiguration.class).getDefaultJvmFlags());
-    jvmFlags.addAll(ruleContext.expandedMakeVariablesList("jvm_flags"));
+    jvmFlags.addAll(ruleContext.getExpandedStringListAttr("jvm_flags", RuleContext.Tokenize.NO));
     return jvmFlags;
   }