Move whitelist checks so they don't crash on user error. As a bonus, these are now only done on attributes of starlark-defined rules instead of all rules attributes.
PiperOrigin-RevId: 226952583
diff --git a/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java b/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java
index 922c331..2d5ea8f 100644
--- a/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java
+++ b/src/main/java/com/google/devtools/build/docgen/RuleDocumentationAttribute.java
@@ -173,7 +173,7 @@
return "";
}
String prefix = "; default is ";
- Object value = attribute.getDefaultValueForTesting();
+ Object value = attribute.getDefaultValueUnchecked();
if (value instanceof Boolean) {
return prefix + ((Boolean) value ? "True" : "False");
} else if (value instanceof Integer) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
index bc9385a..c9931dc8 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
@@ -47,6 +47,7 @@
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.AttributeValueSource;
import com.google.devtools.build.lib.packages.BuildSetting;
+import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.FunctionSplitTransitionWhitelist;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunctionWithCallback;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SkylarkImplicitOutputsFunctionWithMap;
@@ -652,17 +653,63 @@
throw new EvalException(definitionLocation, "Invalid rule class name '" + ruleClassName
+ "', test rule class names must end with '_test' and other rule classes must not");
}
+ boolean hasStarlarkDefinedTransition = false;
+ boolean hasFunctionTransitionWhitelist = false;
for (Pair<String, SkylarkAttr.Descriptor> attribute : attributes) {
String name = attribute.getFirst();
SkylarkAttr.Descriptor descriptor = attribute.getSecond();
- addAttribute(definitionLocation, builder, descriptor.build(name));
+ Attribute attr = descriptor.build(name);
+ hasStarlarkDefinedTransition |= attr.hasStarlarkDefinedTransition();
+ if (attr.hasAnalysisTestTransition() && !builder.isAnalysisTest()) {
+ throw new EvalException(
+ location,
+ "Only rule definitions with analysis_test=True may have attributes with "
+ + "analysis_test_transition transitions");
+ }
// Check for existence of the function transition whitelist attribute.
+ // TODO(b/121385274): remove when we stop whitelisting starlark transitions
if (name.equals(FunctionSplitTransitionWhitelist.WHITELIST_ATTRIBUTE_NAME)) {
+ if (!BuildType.isLabelType(attr.getType())) {
+ throw new EvalException(
+ location, "_whitelist_function_transition attribute must be a label type");
+ }
+ if (attr.getDefaultValueUnchecked() == null) {
+ throw new EvalException(
+ location, "_whitelist_function_transition attribute must have a default value");
+ }
+ if (!attr.getDefaultValueUnchecked()
+ .equals(FunctionSplitTransitionWhitelist.WHITELIST_LABEL)) {
+ throw new EvalException(
+ location,
+ "_whitelist_function_transition attribute does not have the expected value "
+ + FunctionSplitTransitionWhitelist.WHITELIST_LABEL);
+ }
+ hasFunctionTransitionWhitelist = true;
builder.setHasFunctionTransitionWhitelist();
}
+ addAttribute(definitionLocation, builder, attr);
}
+ // TODO(b/121385274): remove when we stop whitelisting starlark transitions
+ if (hasStarlarkDefinedTransition) {
+ if (!hasFunctionTransitionWhitelist) {
+ throw new EvalException(
+ location,
+ String.format(
+ "Use of function-based split transition without whitelist: %s %s",
+ builder.getRuleDefinitionEnvironmentLabel(), builder.getType()));
+ }
+ } else {
+ if (hasFunctionTransitionWhitelist) {
+ throw new EvalException(
+ location,
+ String.format(
+ "Unused function-based split transition whitelist: %s %s",
+ builder.getRuleDefinitionEnvironmentLabel(), builder.getType()));
+ }
+ }
+
try {
this.ruleClass = builder.build(ruleClassName, skylarkLabel + "%" + ruleClassName);
} catch (IllegalArgumentException | IllegalStateException ex) {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index 7f20fa6..0399edc 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -2002,19 +2002,6 @@
"a late bound default value using the host configuration must use the host transition");
}
- if (name.equals(FunctionSplitTransitionWhitelist.WHITELIST_ATTRIBUTE_NAME)) {
- Preconditions.checkArgument(
- BuildType.isLabelType(type),
- "_whitelist_function_transition attribute must be a label");
- Preconditions.checkArgument(
- defaultValue != null,
- "_whitelist_function_transition attribute must have a default value");
- Preconditions.checkArgument(
- ((Label) defaultValue).equals(FunctionSplitTransitionWhitelist.WHITELIST_LABEL),
- "_whitelist_function_transition attribute does not have the expected value "
- + FunctionSplitTransitionWhitelist.WHITELIST_LABEL);
- }
-
this.name = name;
this.type = type;
this.propertyFlags = propertyFlags;
@@ -2339,7 +2326,7 @@
* or a late-bound default.
*/
@VisibleForTesting
- public Object getDefaultValueForTesting() {
+ public Object getDefaultValueUnchecked() {
return defaultValue;
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index 28184d6..71d2e97 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -781,9 +781,6 @@
.nonconfigurable("Used in toolchain resolution")
.value(ImmutableList.of()));
}
- if (skylark) {
- assertRuleClassProperStarlarkDefinedTransitionUsage();
- }
if (buildSetting != null) {
Type<?> type = buildSetting.getType();
Attribute.Builder<?> attrBuilder =
@@ -853,35 +850,6 @@
type);
}
- private void assertRuleClassProperStarlarkDefinedTransitionUsage() {
- boolean hasStarlarkDefinedTransition = false;
- boolean hasAnalysisTestTransitionAttribute = false;
- for (Attribute attribute : attributes.values()) {
- hasStarlarkDefinedTransition |= attribute.hasStarlarkDefinedTransition();
- hasAnalysisTestTransitionAttribute |= attribute.hasAnalysisTestTransition();
- }
-
- if (hasAnalysisTestTransitionAttribute) {
- Preconditions.checkState(
- isAnalysisTest,
- "Only rule definitions with analysis_test=True may have attributes with "
- + "analysis_test_transition transitions");
- }
- if (hasStarlarkDefinedTransition) {
- Preconditions.checkState(
- hasFunctionTransitionWhitelist,
- "Use of function based split transition without whitelist: %s %s",
- ruleDefinitionEnvironmentLabel,
- type);
- } else {
- Preconditions.checkState(
- !hasFunctionTransitionWhitelist,
- "Unused function based split transition whitelist: %s %s",
- ruleDefinitionEnvironmentLabel,
- type);
- }
- }
-
/**
* Declares that the implementation of the associated rule class requires the given
* fragments to be present in this rule's host and target configurations.
@@ -1187,6 +1155,10 @@
return this;
}
+ public Label getRuleDefinitionEnvironmentLabel() {
+ return this.ruleDefinitionEnvironmentLabel;
+ }
+
/**
* Removes an attribute with the same name from this rule class.
*
@@ -1215,6 +1187,10 @@
return this;
}
+ public boolean isAnalysisTest() {
+ return this.isAnalysisTest;
+ }
+
/**
* This rule class has the _whitelist_function_transition attribute. Intended only for Skylark
* rules.
@@ -1224,6 +1200,10 @@
return this;
}
+ public RuleClassType getType() {
+ return this.type;
+ }
+
/**
* Sets the kind of output files this rule creates.
* DO NOT USE! This only exists to support the non-open-sourced {@code fileset} rule.