Fix config_setting NullPointerException on bad constraint_values reference.

Also clean up ConfigSetting.java a little bit.

Fixes https://github.com/bazelbuild/bazel/issues/7941

PiperOrigin-RevId: 242180529
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformProviderUtils.java b/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformProviderUtils.java
index 68122a4..21ec846 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformProviderUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/platform/PlatformProviderUtils.java
@@ -59,6 +59,11 @@
     return target.get(ConstraintValueInfo.PROVIDER);
   }
 
+  /** Returns if a target provides {@link ConstraintValueInfo}. * */
+  public static boolean hasConstraintValue(ProviderCollection target) {
+    return target.get(ConstraintValueInfo.PROVIDER) != null;
+  }
+
   /** Retrieves and casts {@link ConstraintValueInfo} providers from the given targets. */
   public static Iterable<ConstraintValueInfo> constraintValues(
       Iterable<? extends ProviderCollection> targets) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
index 2963dea..51b44d3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
@@ -46,7 +46,6 @@
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.platform.ConstraintCollection;
 import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
-import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
@@ -61,6 +60,7 @@
 import com.google.devtools.build.lib.vfs.PathFragment;
 import com.google.devtools.common.options.OptionsParser;
 import com.google.devtools.common.options.OptionsParsingException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -79,6 +79,7 @@
   public ConfiguredTarget create(RuleContext ruleContext)
       throws InterruptedException, RuleErrorException, ActionConflictException {
     AttributeMap attributes = NonconfigurableAttributeMapper.of(ruleContext.getRule());
+
     // Get the built-in Blaze flag settings that match this rule.
     ImmutableMultimap<String, String> nativeFlagSettings =
         ImmutableMultimap.<String, String>builder()
@@ -93,28 +94,17 @@
 
     // Get the user-defined flag settings that match this rule.
     Map<Label, String> userDefinedFlagSettings =
-        NonconfigurableAttributeMapper.of(ruleContext.getRule())
-            .get(
-                ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE,
-                BuildType.LABEL_KEYED_STRING_DICT);
+        attributes.get(
+            ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE, BuildType.LABEL_KEYED_STRING_DICT);
 
-    List<? extends TransitiveInfoCollection> flagValues =
-        ruleContext.getPrerequisites(
-            ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE, Mode.TARGET);
-
-    // Get the constraint values that match this rule
-    Iterable<ConstraintValueInfo> constraintValues =
-        PlatformProviderUtils.constraintValues(
-            ruleContext.getPrerequisites(
-                ConfigSettingRule.CONSTRAINT_VALUES_ATTRIBUTE, Mode.DONT_CHECK));
-
-    // Get the target platform
-    PlatformInfo targetPlatform = ruleContext.getToolchainContext().targetPlatform();
+    // Get the platform constraint settings that match this rule.
+    List<Label> constraintValueSettings =
+        attributes.get(ConfigSettingRule.CONSTRAINT_VALUES_ATTRIBUTE, BuildType.LABEL_LIST);
 
     // Check that this config_setting contains at least one of {values, define_values,
     // constraint_values}
-    if (!checkValidConditions(
-        nativeFlagSettings, userDefinedFlagSettings, constraintValues, ruleContext)) {
+    if (!valuesAreSet(
+        nativeFlagSettings, userDefinedFlagSettings, constraintValueSettings, ruleContext)) {
       return null;
     }
 
@@ -126,9 +116,11 @@
 
     ConfigFeatureFlagMatch featureFlags =
         ConfigFeatureFlagMatch.fromAttributeValueAndPrerequisites(
-            userDefinedFlagSettings, flagValues, ruleContext);
+            userDefinedFlagSettings,
+            ruleContext.getPrerequisites(ConfigSettingRule.FLAG_SETTINGS_ATTRIBUTE, Mode.TARGET),
+            ruleContext);
 
-    boolean constraintValuesMatch = targetPlatform.constraints().containsAll(constraintValues);
+    boolean constraintValuesMatch = constraintValuesMatch(ruleContext);
 
     if (ruleContext.hasErrors()) {
       return null;
@@ -150,12 +142,26 @@
         .build();
   }
 
-  private boolean checkValidConditions(
-      ImmutableMultimap<String, String> nativeFlagSettings,
-      Map<Label, String> userDefinedFlagSettings,
-      Iterable<ConstraintValueInfo> constraintValues,
-      RuleErrorConsumer errors) {
-    if (!valuesAreSet(nativeFlagSettings, userDefinedFlagSettings, constraintValues, errors)) {
+  /**
+   * Returns true if all <code>constraint_values</code> settings are valid and match this
+   * configuration, false otherwise.
+   *
+   * <p>May generate rule errors on bad settings (e.g. wrong target types).
+   */
+  boolean constraintValuesMatch(RuleContext ruleContext) {
+    List<ConstraintValueInfo> constraintValues = new ArrayList<>();
+    for (TransitiveInfoCollection dep :
+        ruleContext.getPrerequisites(
+            ConfigSettingRule.CONSTRAINT_VALUES_ATTRIBUTE, Mode.DONT_CHECK)) {
+      if (!PlatformProviderUtils.hasConstraintValue(dep)) {
+        ruleContext.attributeError(
+            ConfigSettingRule.CONSTRAINT_VALUES_ATTRIBUTE,
+            String.format(dep.getLabel() + " is not a constraint_value"));
+      } else {
+        constraintValues.add(PlatformProviderUtils.constraintValue(dep));
+      }
+    }
+    if (ruleContext.hasErrors()) {
       return false;
     }
 
@@ -165,12 +171,16 @@
     try {
       ConstraintCollection.validateConstraints(constraintValues);
     } catch (ConstraintCollection.DuplicateConstraintException e) {
-      errors.ruleError(
+      ruleContext.ruleError(
           ConstraintCollection.DuplicateConstraintException.formatError(e.duplicateConstraints()));
         return false;
     }
 
-    return true;
+    return ruleContext
+        .getToolchainContext()
+        .targetPlatform()
+        .constraints()
+        .containsAll(constraintValues);
   }
 
   private static RepositoryName getToolsRepository(RuleContext ruleContext) {
@@ -212,7 +222,7 @@
   private boolean valuesAreSet(
       ImmutableMultimap<String, String> nativeFlagSettings,
       Map<Label, String> userDefinedFlagSettings,
-      Iterable<ConstraintValueInfo> constraintValues,
+      Iterable<Label> constraintValues,
       RuleErrorConsumer errors) {
     if (nativeFlagSettings.isEmpty()
         && userDefinedFlagSettings.isEmpty()
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java
index 3c2c31d..b7e3ddc 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigSettingTest.java
@@ -1429,6 +1429,23 @@
         ");");
   }
 
+  @Test
+  public void notAConstraintValue() throws Exception {
+    checkError(
+        "test",
+        "match",
+        "//test:what_am_i is not a constraint_value",
+        "genrule(",
+        "    name = 'what_am_i',",
+        "    srcs = [],",
+        "    outs = ['the_answer'],",
+        "    cmd = 'echo an eternal enigma > $@')",
+        "config_setting(",
+        "    name = 'match',",
+        "    constraint_values = [':what_am_i'],",
+        ")");
+  }
+
   private Set<LicenseType> getLicenses(String label) throws Exception {
     return getTarget(label).getLicense().getLicenseTypes();
   }