Add example test for requiring native aspect from a starlark defined aspect.
Starlark native aspects need to override the newly added `getDefaultParametersExtractor` from StarlarkAspect to be able to extract their parameters values from the base rule of the attribute in which they are required.
PiperOrigin-RevId: 381826763
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 9758e22..a3bd3fb 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
@@ -1191,7 +1191,7 @@
}
public Builder<TYPE> aspect(
- NativeAspectClass nativeAspect,
+ StarlarkNativeAspect nativeAspect,
String baseAspectName,
ImmutableList<ImmutableSet<StarlarkProviderIdentifier>> inheritedRequiredProviders,
ImmutableList<String> inheritedAttributeAspects)
@@ -1206,7 +1206,7 @@
NativeRuleAspect nativeRuleAspect =
new NativeRuleAspect(
nativeAspect,
- EMPTY_FUNCTION,
+ nativeAspect.getDefaultParametersExtractor(),
baseAspectName,
inheritedRequiredProviders,
inheritedAttributeAspects);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspect.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspect.java
index f3efc0a..d8f6fd1 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspect.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.packages;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.starlarkbuildapi.StarlarkAspectApi;
@@ -56,4 +57,7 @@
/** Returns the name of this aspect. */
String getName();
+
+ /** Returns a function to extract the aspect parameters values from its base rule. */
+ Function<Rule, AspectParameters> getDefaultParametersExtractor();
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkDefinedAspect.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkDefinedAspect.java
index 3b4397b..4562a99 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkDefinedAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkDefinedAspect.java
@@ -217,6 +217,7 @@
return aspectClass != null;
}
+ @Override
public Function<Rule, AspectParameters> getDefaultParametersExtractor() {
return rule -> {
AttributeMap ruleAttrs = RawAttributeMapper.of(rule);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeAspect.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeAspect.java
index 14cf33e..f1b2f1b 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkNativeAspect.java
@@ -14,13 +14,18 @@
package com.google.devtools.build.lib.packages;
+import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.Printer;
/** A natively-defined aspect that is may be referenced by Starlark attribute definitions. */
public abstract class StarlarkNativeAspect extends NativeAspectClass implements StarlarkAspect {
+ @AutoCodec @AutoCodec.VisibleForSerialization
+ static final Function<Rule, AspectParameters> EMPTY_FUNCTION = input -> AspectParameters.EMPTY;
+
@Override
public void repr(Printer printer) {
printer.append("<native aspect>");
@@ -45,4 +50,9 @@
public ImmutableSet<String> getParamAttributes() {
return ImmutableSet.of();
}
+
+ @Override
+ public Function<Rule, AspectParameters> getDefaultParametersExtractor() {
+ return EMPTY_FUNCTION;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 4add5da..b6c77cf 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -201,7 +201,12 @@
if (key.getAspectClass() instanceof NativeAspectClass) {
NativeAspectClass nativeAspectClass = (NativeAspectClass) key.getAspectClass();
aspectFactory = (ConfiguredAspectFactory) nativeAspectClass;
- aspect = Aspect.forNative(nativeAspectClass, key.getParameters());
+ aspect =
+ Aspect.forNative(
+ nativeAspectClass,
+ key.getParameters(),
+ key.getInheritedRequiredProviders(),
+ key.getInheritedAttributeAspects());
} else if (key.getAspectClass() instanceof StarlarkAspectClass) {
StarlarkAspectClass starlarkAspectClass = (StarlarkAspectClass) key.getAspectClass();
StarlarkDefinedAspect starlarkAspect;
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java b/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
index 7c357e3..56d26fc 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
@@ -46,18 +46,23 @@
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.AspectDefinition;
import com.google.devtools.build.lib.packages.AspectParameters;
+import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
import com.google.devtools.build.lib.packages.Attribute.ComputedDefault;
import com.google.devtools.build.lib.packages.Attribute.LabelListLateBoundDefault;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.NativeAspectClass;
+import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.StarlarkNativeAspect;
import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier;
import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
import com.google.devtools.build.lib.util.FileTypeSet;
+import java.io.Serializable;
import java.util.List;
+import javax.annotation.Nullable;
/**
* Various rule and aspect classes that aid in testing the aspect machinery.
@@ -251,14 +256,38 @@
public static final SimpleAspect SIMPLE_ASPECT = new SimpleAspect();
public static final FooProviderAspect FOO_PROVIDER_ASPECT = new FooProviderAspect();
public static final BarProviderAspect BAR_PROVIDER_ASPECT = new BarProviderAspect();
+ public static final SimpleStarlarkNativeAspect SIMPLE_STARLARK_NATIVE_ASPECT =
+ new SimpleStarlarkNativeAspect();
+ public static final ParametrizedAspectWithProvider
+ PARAMETRIZED_STARLARK_NATIVE_ASPECT_WITH_PROVIDER = new ParametrizedAspectWithProvider();
private static final AspectDefinition SIMPLE_ASPECT_DEFINITION =
new AspectDefinition.Builder(SIMPLE_ASPECT).build();
-
private static final AspectDefinition FOO_PROVIDER_ASPECT_DEFINITION =
new AspectDefinition.Builder(FOO_PROVIDER_ASPECT).build();
private static final AspectDefinition BAR_PROVIDER_ASPECT_DEFINITION =
new AspectDefinition.Builder(BAR_PROVIDER_ASPECT).build();
+ private static final AspectDefinition SIMPLE_STARLARK_NATIVE_ASPECT_DEFINITION =
+ new AspectDefinition.Builder(SIMPLE_STARLARK_NATIVE_ASPECT).build();
+
+ /** Simple StarlarkNativeAspect */
+ public static class SimpleStarlarkNativeAspect extends StarlarkNativeAspect
+ implements ConfiguredAspectFactory {
+ @Override
+ public AspectDefinition getDefinition(AspectParameters aspectParameters) {
+ return SIMPLE_STARLARK_NATIVE_ASPECT_DEFINITION;
+ }
+
+ @Override
+ public ConfiguredAspect create(
+ ConfiguredTargetAndData ctadBase,
+ RuleContext ruleContext,
+ AspectParameters parameters,
+ String toolsRepository)
+ throws ActionConflictException, InterruptedException {
+ return new ConfiguredAspect.Builder(ruleContext).addProvider(new FooProvider()).build();
+ }
+ }
/**
* A very simple aspect.
@@ -458,6 +487,49 @@
}
/**
+ * An aspect that has a definition depending on parameters provided by originating rule and
+ * advertises a simple provider.
+ */
+ public static class ParametrizedAspectWithProvider extends StarlarkNativeAspect
+ implements ConfiguredAspectFactory {
+
+ @Override
+ public AspectDefinition getDefinition(AspectParameters aspectParameters) {
+ AspectDefinition.Builder builder =
+ new AspectDefinition.Builder(PARAMETRIZED_STARLARK_NATIVE_ASPECT_WITH_PROVIDER);
+ ImmutableCollection<String> aspectAttr = aspectParameters.getAttribute("aspect_attr");
+ if (aspectAttr != null) {
+ builder.add(
+ attr("aspect_attr", Type.STRING)
+ .allowedValues(new AllowedValueSet("v1", "v2"))
+ .value(aspectAttr.iterator().next()));
+ }
+ return builder.build();
+ }
+
+ @Override
+ public ConfiguredAspect create(
+ ConfiguredTargetAndData ctadBase,
+ RuleContext ruleContext,
+ AspectParameters parameters,
+ String toolsRepository)
+ throws ActionConflictException, InterruptedException {
+ return new ConfiguredAspect.Builder(ruleContext).addProvider(new FooProvider()).build();
+ }
+
+ @Override
+ public Function<Rule, AspectParameters> getDefaultParametersExtractor() {
+ return (Function<Rule, AspectParameters> & Serializable)
+ (@Nullable Rule rule) -> {
+ AttributeMap attributes = RawAttributeMapper.of(rule);
+ return new AspectParameters.Builder()
+ .addAttribute("aspect_attr", attributes.get("aspect_attr", Type.STRING))
+ .build();
+ };
+ }
+ }
+
+ /**
* An aspect that has a definition depending on parameters provided by originating rule.
*/
public static class ParametrizedDefinitionAspect extends NativeAspectClass
diff --git a/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java b/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java
index e83c387..e6e8483 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java
@@ -344,13 +344,13 @@
Attribute attr =
attr("x", LABEL)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_1",
/** inheritedRequiredProviders= */
ImmutableList.of(),
inheritedAttributeAspects1)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_2",
/** inheritedRequiredProviders= */
ImmutableList.of(),
@@ -375,13 +375,13 @@
Attribute attr =
attr("x", LABEL)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_1",
inheritedRequiredProviders1,
/** inheritedAttributeAspects= */
ImmutableList.of())
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_2",
inheritedRequiredProviders2,
/** inheritedAttributeAspects= */
@@ -417,9 +417,9 @@
Attribute attr =
attr("x", LABEL)
- .aspect(TestAspects.SIMPLE_ASPECT)
+ .aspect(TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect",
/** inheritedRequiredProviders = */
ImmutableList.of(),
@@ -441,9 +441,9 @@
Attribute attr =
attr("x", LABEL)
- .aspect(TestAspects.SIMPLE_ASPECT)
+ .aspect(TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect",
inheritedRequiredProviders,
/** inheritedAttributeAspects= */
@@ -480,15 +480,15 @@
Attribute attr =
attr("x", LABEL)
- .aspect(TestAspects.SIMPLE_ASPECT)
+ .aspect(TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_1",
/** inheritedRequiredProviders = */
ImmutableList.of(),
inheritedAttributeAspects1)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_2",
/** inheritedRequiredProviders = */
ImmutableList.of(),
@@ -511,15 +511,15 @@
Attribute attr =
attr("x", LABEL)
- .aspect(TestAspects.SIMPLE_ASPECT)
+ .aspect(TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT)
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_1",
inheritedRequiredProviders1,
/** inheritedAttributeAspects= */
ImmutableList.of())
.aspect(
- TestAspects.SIMPLE_ASPECT,
+ TestAspects.SIMPLE_STARLARK_NATIVE_ASPECT,
"base_aspect_2",
inheritedRequiredProviders2,
/** inheritedAttributeAspects= */
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java
index bcb0381..fa20580 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkRuleClassFunctionsTest.java
@@ -22,12 +22,14 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
import com.google.devtools.build.lib.analysis.starlark.StarlarkAttrModule;
import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleClassFunctions.StarlarkRuleFunction;
import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleContext;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
+import com.google.devtools.build.lib.analysis.util.TestAspects;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.Depset;
import com.google.devtools.build.lib.events.Event;
@@ -57,6 +59,7 @@
import com.google.devtools.build.lib.skyframe.BzlLoadFunction;
import com.google.devtools.build.lib.starlark.util.BazelEvaluationTestCase;
import com.google.devtools.build.lib.testutil.MoreAsserts;
+import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
import com.google.devtools.build.lib.util.FileTypeSet;
import java.util.Arrays;
import java.util.List;
@@ -95,6 +98,16 @@
ev.setSemantics(options); // for StarlarkThread
}
+ @Override
+ protected ConfiguredRuleClassProvider createRuleClassProvider() {
+ ConfiguredRuleClassProvider.Builder builder = new ConfiguredRuleClassProvider.Builder();
+ TestRuleClassProvider.addStandardRules(builder);
+ builder.addStarlarkAccessibleTopLevels(
+ "parametrized_native_aspect",
+ TestAspects.PARAMETRIZED_STARLARK_NATIVE_ASPECT_WITH_PROVIDER);
+ return builder.build();
+ }
+
@org.junit.Rule public ExpectedException thrown = ExpectedException.none();
@Before
@@ -3025,4 +3038,109 @@
ev.assertContainsError(
"Error in unexported rule: Invalid rule class hasn't been exported by a bzl file");
}
+
+ @Test
+ public void testAttrWithAspectRequiringAspects_requiredNativeAspect_getsParamsFromFromBaseRules()
+ throws Exception {
+ setBuildLanguageOptions("--experimental_required_aspects=true");
+ scratch.file(
+ "lib.bzl",
+ "rule_prov = provider()",
+ "def _impl(target, ctx):",
+ " pass",
+ "aspect_a = aspect(implementation = _impl,",
+ " requires = [parametrized_native_aspect],",
+ " attr_aspects = ['deps'],",
+ " required_providers = [rule_prov])",
+ "def impl(ctx):",
+ " return None",
+ "my_rule = rule(impl,",
+ " attrs={'deps': attr.label_list(aspects = [aspect_a]),",
+ " 'aspect_attr': attr.string()})");
+ scratch.file(
+ "BUILD", "load(':lib.bzl', 'my_rule')", "my_rule(name = 'main', aspect_attr = 'v1')");
+
+ RuleContext ruleContext = createRuleContext("//:main").getRuleContext();
+
+ Rule rule = ruleContext.getRule();
+ Attribute attr = rule.getRuleClassObject().getAttributeByName("deps");
+ ImmutableList<Aspect> aspects = attr.getAspects(rule);
+ Aspect requiredNativeAspect = aspects.get(0);
+ assertThat(requiredNativeAspect.getAspectClass().getName())
+ .isEqualTo("ParametrizedAspectWithProvider");
+ assertThat(
+ requiredNativeAspect
+ .getDefinition()
+ .getAttributes()
+ .get("aspect_attr")
+ .getDefaultValueUnchecked())
+ .isEqualTo("v1");
+ }
+
+ @Test
+ public void testAttrWithAspectRequiringAspects_requiredNativeAspect_inheritsAttrAspects()
+ throws Exception {
+ setBuildLanguageOptions("--experimental_required_aspects=true");
+ scratch.file(
+ "lib.bzl",
+ "rule_prov = provider()",
+ "def _impl(target, ctx):",
+ " pass",
+ "aspect_a = aspect(implementation = _impl,",
+ " requires = [parametrized_native_aspect],",
+ " attr_aspects = ['deps'],",
+ " required_providers = [rule_prov])",
+ "def impl(ctx):",
+ " return None",
+ "my_rule = rule(impl,",
+ " attrs={'deps': attr.label_list(aspects = [aspect_a]),",
+ " 'aspect_attr': attr.string()})");
+ scratch.file(
+ "BUILD", "load(':lib.bzl', 'my_rule')", "my_rule(name = 'main', aspect_attr = 'v1')");
+
+ RuleContext ruleContext = createRuleContext("//:main").getRuleContext();
+
+ Rule rule = ruleContext.getRule();
+ Attribute attr = rule.getRuleClassObject().getAttributeByName("deps");
+ ImmutableList<Aspect> aspects = attr.getAspects(rule);
+ Aspect requiredNativeAspect = aspects.get(0);
+ assertThat(requiredNativeAspect.getAspectClass().getName())
+ .isEqualTo("ParametrizedAspectWithProvider");
+ assertThat(requiredNativeAspect.getDescriptor().getInheritedAttributeAspects())
+ .containsExactly("deps");
+ }
+
+ @Test
+ public void testAttrWithAspectRequiringAspects_requiredNativeAspect_inheritsRequiredProviders()
+ throws Exception {
+ setBuildLanguageOptions("--experimental_required_aspects=true");
+ scratch.file(
+ "lib.bzl",
+ "rule_prov = provider()",
+ "def _impl(target, ctx):",
+ " pass",
+ "aspect_a = aspect(implementation = _impl,",
+ " requires = [parametrized_native_aspect],",
+ " attr_aspects = ['deps'],",
+ " required_providers = [rule_prov])",
+ "def impl(ctx):",
+ " return None",
+ "my_rule = rule(impl,",
+ " attrs={'deps': attr.label_list(aspects = [aspect_a]),",
+ " 'aspect_attr': attr.string()})");
+ scratch.file(
+ "BUILD", "load(':lib.bzl', 'my_rule')", "my_rule(name = 'main', aspect_attr = 'v1')");
+
+ RuleContext ruleContext = createRuleContext("//:main").getRuleContext();
+
+ Rule rule = ruleContext.getRule();
+ Attribute attr = rule.getRuleClassObject().getAttributeByName("deps");
+ ImmutableList<Aspect> aspects = attr.getAspects(rule);
+ Aspect requiredNativeAspect = aspects.get(0);
+ assertThat(requiredNativeAspect.getAspectClass().getName())
+ .isEqualTo("ParametrizedAspectWithProvider");
+ assertThat(
+ requiredNativeAspect.getDescriptor().getInheritedRequiredProviders().getDescription())
+ .isEqualTo("'rule_prov'");
+ }
}