Use FeatureConfiguration to compute value of CC_FLAGS make variable

This cl introduces new action_config type for Crosstool named 'generic'. This
can be used to set the value of CC_FLAGS make variable using much more
expressive mechanism (action_configs + features) than previous make_variable
Crosstool messages. This has been requested by the C++ LPT.

However, as FeatureConfiguration needs RuleContext, CC_FLAGS cannot be
computed using configuration only anymore. Also, FeatureConfiguration is C++
rules specific class, and Bazel build-base cannot depend on it. Therefore we
cannot use FeatureConfiguration for ExtraActions, for example. Because it cannot
be made perfect, this cl is not updating all the possible places that expand
make variables but limits the scope to:

* genrule (the only widely used rule that often expands make variables)
* *_test (CC_FLAGS is used by Tensorflow in the 'args' attribute)
* cc_rules (people sometimes set 'copts' to something like:
  "-DCC_STRING=\\\"$(CC)\\\" -DCC_FLAGS_STRING=\"$(CC_FLAGS)\""

The long term plan is to use Skylark C++ API to get C++ command lines, so
CC_FLAGS together with this inconsistent solution will be removed.

RELNOTES: CC_FLAGS can be defined using 'generic' action_config in CROSSTOOL
PiperOrigin-RevId: 157202883
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 170d323..2077a887 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
@@ -92,6 +92,7 @@
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -942,17 +943,46 @@
    * @return a list of strings containing the expanded and tokenized values for the attribute
    */
   public ImmutableList<String> getTokenizedStringListAttr(String attributeName) {
-    return getExpandedStringListAttr(attributeName, Tokenize.YES);
+    return getExpandedStringListAttr(attributeName, Tokenize.YES, Collections.EMPTY_LIST);
   }
 
   /**
-   * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags,
-   * and optionally tokenizes the result.
+   * 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 makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   * @return a list of strings containing the expanded and tokenized values for the attribute
+   */
+  public ImmutableList<String> getTokenizedStringListAttr(
+      String attributeName, Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
+    return getExpandedStringListAttr(attributeName, Tokenize.YES, makeVariableSuppliers);
+  }
+
+  /**
+   * Gets an attribute of type STRING_LIST expanding Make variables and $(location) tags, and
+   * optionally tokenizes the result. Doesn't register any {@link MakeVariableSupplier}.
    *
    * @param attributeName the name of the attribute to process
    * @return a list of strings containing the processed values for the attribute
    */
   public ImmutableList<String> getExpandedStringListAttr(String attributeName, Tokenize tokenize) {
+    return getExpandedStringListAttr(
+        attributeName, tokenize, ImmutableList.<MakeVariableSupplier>of());
+  }
+
+  /**
+   * 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
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   * @return a list of strings containing the processed values for the attribute
+   */
+  public ImmutableList<String> getExpandedStringListAttr(
+      String attributeName,
+      Tokenize tokenize,
+      Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
     if (!getRule().isAttrDefined(attributeName, Type.STRING_LIST)) {
       // TODO(bazel-team): This should be an error.
       return ImmutableList.of();
@@ -966,7 +996,7 @@
         new LocationExpander(this, LocationExpander.Options.ALLOW_DATA);
 
     for (String token : original) {
-      expandValue(tokens, attributeName, token, locationExpander, tokenize);
+      expandValue(tokens, attributeName, token, locationExpander, tokenize, makeVariableSuppliers);
     }
     return ImmutableList.copyOf(tokens);
   }
@@ -974,42 +1004,53 @@
   /**
    * Expands make variables 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) {
-    LocationExpander locationExpander =
-        new LocationExpander(this, Options.ALLOW_DATA, Options.EXEC_PATHS);
-    tokenizeAndExpandMakeVars(tokens, attributeName, value, locationExpander);
-  }
-
-  /**
-   * Expands make variables and $(location) tags in value and tokenizes the result into tokens.
-   *
-   * <p>This methods should be called only during initialization.
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   *     <p>This methods should be called only during initialization.
    */
   public void tokenizeAndExpandMakeVars(
       List<String> tokens,
       String attributeName,
       String value,
-      @Nullable LocationExpander locationExpander) {
-    expandValue(tokens, attributeName, value, locationExpander, Tokenize.YES);
+      Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
+    LocationExpander locationExpander =
+        new LocationExpander(this, Options.ALLOW_DATA, Options.EXEC_PATHS);
+    tokenizeAndExpandMakeVars(
+        tokens, attributeName, value, locationExpander, makeVariableSuppliers);
+  }
+
+  /**
+   * Expands make variables and $(location) tags in value and tokenizes the result into tokens.
+   *
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   *     <p>This methods should be called only during initialization.
+   */
+  public void tokenizeAndExpandMakeVars(
+      List<String> tokens,
+      String attributeName,
+      String value,
+      @Nullable LocationExpander locationExpander,
+      Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
+    expandValue(
+        tokens, attributeName, value, locationExpander, Tokenize.YES, makeVariableSuppliers);
   }
 
   /**
    * Expands make variables and $(location) tags in value, and optionally tokenizes the result.
    *
-   * <p>This methods should be called only during initialization.
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   *     <p>This methods should be called only during initialization.
    */
   public void expandValue(
       List<String> tokens,
       String attributeName,
       String value,
       @Nullable LocationExpander locationExpander,
-      Tokenize tokenize) {
+      Tokenize tokenize,
+      Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
     if (locationExpander != null) {
       value = locationExpander.expandAttribute(attributeName, value);
     }
-    value = expandMakeVariables(attributeName, value);
+    value = expandMakeVariables(attributeName, value, makeVariableSuppliers);
     if (tokenize == Tokenize.YES) {
       try {
         ShellUtils.tokenize(tokens, value);
@@ -1046,30 +1087,64 @@
   }
 
   /**
-   * Return a context that maps Make variable names (string) to values (string).
+   * Returns a (cached! read on) context that maps Make variable names (string) to values (string)
+   * without any extra {@link MakeVariableSupplier}.
+   *
+   * <p>Beware!!! {@link ConfigurationMakeVariableContext} instance is cached, so if you call it
+   * first with some list of {@link MakeVariableSupplier} and then with other list, you will always
+   * get the first instance back. TODO(hlopko): Extract Make variable expansion from RuleContext and
+   * fix all the callers
    *
    * @return a ConfigurationMakeVariableContext.
-   **/
+   */
   public ConfigurationMakeVariableContext getConfigurationMakeVariableContext() {
+    return getConfigurationMakeVariableContext(ImmutableList.<MakeVariableSupplier>of());
+  }
+
+  /**
+   * Returns a (cached! read on) context that maps Make variable names (string) to values (string).
+   *
+   * @see #getConfigurationMakeVariableContext() to understand how the instance is cached!
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   * @return a ConfigurationMakeVariableContext.
+   */
+  public ConfigurationMakeVariableContext getConfigurationMakeVariableContext(
+      Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
     if (configurationMakeVariableContext == null) {
       configurationMakeVariableContext =
-          new ConfigurationMakeVariableContext(this, getRule().getPackage(), getConfiguration());
+          new ConfigurationMakeVariableContext(
+              this, getRule().getPackage(), getConfiguration(), makeVariableSuppliers);
     }
     return configurationMakeVariableContext;
   }
 
   /**
-   * Returns the string "expression" after expanding all embedded references to
-   * "Make" variables.  If any errors are encountered, they are reported, and
-   * "expression" is returned unchanged.
+   * Return a context that maps Make variable names (string) to values (string).
    *
-   * @param attributeName the name of the attribute from which "expression" comes;
-   *     used for error reporting.
-   * @param expression the string to expand.
-   * @return the expansion of "expression".
+   * <p>Uses {@NoopExpansionInterceptor}.
+   *
+   * @return a ConfigurationMakeVariableContext.
    */
   public String expandMakeVariables(String attributeName, String expression) {
-    return expandMakeVariables(attributeName, expression, getConfigurationMakeVariableContext());
+    return expandMakeVariables(attributeName, expression, ImmutableList.<MakeVariableSupplier>of());
+  }
+
+  /**
+   * Returns the string "expression" after expanding all embedded references to "Make" variables. If
+   * any errors are encountered, they are reported, and "expression" is returned unchanged.
+   *
+   * @param attributeName the name of the attribute from which "expression" comes; used for error
+   *     reporting.
+   * @param expression the string to expand.
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
+   * @return the expansion of "expression".
+   */
+  public String expandMakeVariables(
+      String attributeName,
+      String expression,
+      Iterable<? extends MakeVariableSupplier> makeVariableSuppliers) {
+    return expandMakeVariables(
+        attributeName, expression, getConfigurationMakeVariableContext(makeVariableSuppliers));
   }
 
   /**
@@ -1100,24 +1175,29 @@
   public List<String> expandedMakeVariablesList(String attrName) {
     List<String> variables = new ArrayList<>();
     for (String variable : attributes().get(attrName, Type.STRING_LIST)) {
-      variables.add(expandMakeVariables(attrName, variable));
+      variables.add(
+          expandMakeVariables(attrName, variable, ImmutableList.<MakeVariableSupplier>of()));
     }
     return variables;
   }
 
   /**
-   * If the string consists of a single variable, returns the expansion of
-   * that variable. Otherwise, returns null. Syntax errors are reported.
+   * If the string consists of a single variable, returns the expansion of that variable. Otherwise,
+   * returns null. Syntax errors are reported.
    *
-   * @param attrName the name of the attribute from which "expression" comes;
-   *     used for error reporting.
+   * @param attrName the name of the attribute from which "expression" comes; used for error
+   *     reporting.
    * @param expression the string to expand.
+   * @param makeVariableSuppliers to be used with {@link ConfigurationMakeVariableContext}
    * @return the expansion of "expression", or null.
    */
-  public String expandSingleMakeVariable(String attrName, String expression) {
+  public String expandSingleMakeVariable(
+      String attrName,
+      String expression,
+      ImmutableList<? extends MakeVariableSupplier> makeVariableSuppliers) {
     try {
       return MakeVariableExpander.expandSingleVariable(
-          expression, getConfigurationMakeVariableContext());
+          expression, getConfigurationMakeVariableContext(makeVariableSuppliers));
     } catch (MakeVariableExpander.ExpansionException e) {
       attributeError(attrName, e.getMessage());
       return expression;