Do not propagate aspect to own attributes when using '*'.
RELNOTES: Do not propagate aspect to its own attributes when using '*'.
--
MOS_MIGRATED_REVID=138194456
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
index a2e9d23..acae678 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
@@ -501,4 +501,48 @@
"rule //a:x");
}
+ /**
+ * Ensures an aspect with attr = '*' doesn't try to propagate to its own implicit attributes.
+ * Doing so leads to a dependency cycle.
+ */
+ @Test
+ public void aspectWithAllAttributesDoesNotPropagateToOwnImplicitAttributes() throws Exception {
+ setRulesAvailableInTests(
+ new TestAspects.BaseRule(),
+ new TestAspects.SimpleRule(),
+ new TestAspects.AllAttributesWithToolAspectRule());
+ pkg(
+ "a",
+ "simple(name='tool')",
+ "simple(name='a')",
+ "all_attributes_with_tool_aspect(name='x', foo=[':a'])");
+
+ ConfiguredTarget a = getConfiguredTarget("//a:x");
+ assertThat(a.getProvider(RuleInfo.class).getData())
+ .containsExactly("aspect //a:a", "rule //a:x");
+ }
+
+ /**
+ * Makes sure the aspect *will* propagate to its implicit attributes if there is a "regular"
+ * dependency path to it (i.e. not through its own implicit attributes).
+ */
+ @Test
+ public void aspectWithAllAttributesPropagatesToItsToolIfThereIsPath() throws Exception {
+ setRulesAvailableInTests(
+ new TestAspects.BaseRule(),
+ new TestAspects.SimpleRule(),
+ new TestAspects.AllAttributesWithToolAspectRule());
+ pkg(
+ "a",
+ "simple(name='tool')",
+ "simple(name='a', foo=[':b'], foo1=':c', txt='some text')",
+ "simple(name='b', foo=[], txt='some text')",
+ "simple(name='c', foo=[':tool'], txt='more text')",
+ "all_attributes_with_tool_aspect(name='x', foo=[':a'])");
+
+ ConfiguredTarget a = getConfiguredTarget("//a:x");
+ assertThat(a.getProvider(RuleInfo.class).getData())
+ .containsExactly(
+ "aspect //a:a", "aspect //a:b", "aspect //a:c", "aspect //a:tool", "rule //a:x");
+ }
}
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 263a795..f6f693e 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
@@ -50,6 +50,7 @@
import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel;
import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList;
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.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
@@ -237,7 +238,25 @@
.allAttributesAspect(ALL_ATTRIBUTES_ASPECT)
.build();
+ /** An aspect that propagates along all attributes and has a tool dependency. */
+ public static class AllAttributesWithToolAspect extends BaseAspect {
+ @Override
+ public AspectDefinition getDefinition(AspectParameters aspectParameters) {
+ return ALL_ATTRIBUTES_WITH_TOOL_ASPECT_DEFINITION;
+ }
+ }
+
+ public static final NativeAspectClass ALL_ATTRIBUTES_WITH_TOOL_ASPECT =
+ new AllAttributesWithToolAspect();
+ private static final AspectDefinition ALL_ATTRIBUTES_WITH_TOOL_ASPECT_DEFINITION =
+ new AspectDefinition.Builder("all_attributes_with_tool_aspect")
+ .allAttributesAspect(ALL_ATTRIBUTES_WITH_TOOL_ASPECT)
+ .add(
+ attr("$tool", BuildType.LABEL)
+ .allowedFileTypes(FileTypeSet.ANY_FILE)
+ .value(Label.parseAbsoluteUnchecked("//a:tool")))
+ .build();
/**
* An aspect that requires aspects on the attributes of rules it attaches to.
@@ -575,6 +594,29 @@
}
}
+ /** A rule that defines an {@link AllAttributesWithToolAspect} on one of its attributes. */
+ public static class AllAttributesWithToolAspectRule implements RuleDefinition {
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .add(
+ attr("foo", LABEL_LIST)
+ .allowedFileTypes(FileTypeSet.ANY_FILE)
+ .aspect(ALL_ATTRIBUTES_WITH_TOOL_ASPECT))
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name("all_attributes_with_tool_aspect")
+ .factoryClass(DummyRuleFactory.class)
+ .ancestors(BaseRule.class)
+ .build();
+ }
+ }
+
/**
* A rule that defines a {@link WarningAspect} on one of its attributes.
*/
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java
index e0eb465..cad9704 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java
@@ -1174,6 +1174,57 @@
})).contains("file.xa");
}
+ @Test
+ public void aspectsPropagatingToAllAttributes() throws Exception {
+ scratch.file(
+ "test/aspect.bzl",
+ "def _impl(target, ctx):",
+ " s = set([target.label])",
+ " if hasattr(ctx.rule.attr, 'runtime_deps'):",
+ " for i in ctx.rule.attr.runtime_deps:",
+ " s += i.target_labels",
+ " return struct(target_labels = s)",
+ "",
+ "MyAspect = aspect(",
+ " implementation=_impl,",
+ " attrs = { '_tool' : attr.label(default = Label('//test:tool')) },",
+ " attr_aspects=['*'],",
+ ")");
+ scratch.file(
+ "test/BUILD",
+ "java_library(",
+ " name = 'tool',",
+ ")",
+ "java_library(",
+ " name = 'bar',",
+ " runtime_deps = [':tool'],",
+ ")",
+ "java_library(",
+ " name = 'foo',",
+ " runtime_deps = [':bar'],",
+ ")");
+ AnalysisResult analysisResult =
+ update(ImmutableList.of("test/aspect.bzl%MyAspect"), "//test:foo");
+ AspectValue aspectValue = analysisResult.getAspects().iterator().next();
+ SkylarkProviders skylarkProviders =
+ aspectValue.getConfiguredAspect().getProvider(SkylarkProviders.class);
+ assertThat(skylarkProviders).isNotNull();
+ Object names = skylarkProviders.getValue("target_labels");
+ assertThat(names).isInstanceOf(SkylarkNestedSet.class);
+ assertThat(
+ transform(
+ (SkylarkNestedSet) names,
+ new Function<Object, String>() {
+ @Nullable
+ @Override
+ public String apply(Object o) {
+ assertThat(o).isInstanceOf(Label.class);
+ return ((Label) o).getName();
+ }
+ }))
+ .containsExactly("foo", "bar", "tool");
+ }
+
@RunWith(JUnit4.class)
public static final class WithKeepGoing extends SkylarkAspectsTest {
@Override