Allow aspects to specify multiple sets of required providers to match against rules. Aspects can attach to a rule if at least one set of required providers are present on the rule.

--
MOS_MIGRATED_REVID=140605023
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java
index eb6b8f8..6edae5e 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectDefinitionTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.fail;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.AspectDefinition;
 import com.google.devtools.build.lib.packages.AspectParameters;
@@ -150,15 +151,36 @@
   @Test
   public void testRequireProvider_AddsToSetOfRequiredProvidersAndNames() throws Exception {
     AspectDefinition requiresProviders = new AspectDefinition.Builder(TEST_ASPECT_CLASS)
-        .requireProvider(String.class)
-        .requireProvider(Integer.class)
+        .requireProviders(String.class, Integer.class)
         .build();
-    assertThat(requiresProviders.getRequiredProviders())
+    assertThat(requiresProviders.getRequiredProviders()).hasSize(1);
+    assertThat(requiresProviders.getRequiredProviders().get(0))
         .containsExactly(String.class, Integer.class);
-    assertThat(requiresProviders.getRequiredProviderNames())
+    assertThat(requiresProviders.getRequiredProviderNames()).hasSize(1);
+    assertThat(requiresProviders.getRequiredProviderNames().get(0))
         .containsExactly("java.lang.String", "java.lang.Integer");
   }
 
+ @Test
+  public void testRequireProvider_AddsTwoSetsOfRequiredProvidersAndNames() throws Exception {
+    AspectDefinition requiresProviders = new AspectDefinition.Builder(TEST_ASPECT_CLASS)
+        .requireProviderSets(
+            ImmutableList.of(
+                ImmutableSet.<Class<?>>of(String.class, Integer.class),
+                ImmutableSet.<Class<?>>of(Boolean.class)))
+        .build();
+    assertThat(requiresProviders.getRequiredProviders()).hasSize(2);
+    assertThat(requiresProviders.getRequiredProviders().get(0))
+        .containsExactly(String.class, Integer.class);
+    assertThat(requiresProviders.getRequiredProviders().get(1))
+        .containsExactly(Boolean.class);
+    assertThat(requiresProviders.getRequiredProviderNames()).hasSize(2);
+    assertThat(requiresProviders.getRequiredProviderNames().get(0))
+        .containsExactly("java.lang.String", "java.lang.Integer");
+    assertThat(requiresProviders.getRequiredProviderNames().get(1))
+        .containsExactly("java.lang.Boolean");
+  }
+
   @Test
   public void testNoConfigurationFragmentPolicySetup_HasNonNullPolicy() throws Exception {
     AspectDefinition noPolicy = new AspectDefinition.Builder(TEST_ASPECT_CLASS)
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 37abaaf..ae4f533 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
@@ -163,6 +163,21 @@
   }
 
   @Test
+  public void aspectCreatedIfAtLeastOneSetOfAdvertisedProvidersArePresent() throws Exception {
+    setRulesAvailableInTests(new TestAspects.BaseRule(), new TestAspects.HonestRule(),
+        new TestAspects.HonestRule2(), new TestAspects.AspectRequiringProviderSetsRule());
+
+    pkg("a",
+        "aspect_requiring_provider_sets(name='a', foo=[':b', ':c'])",
+        "honest(name='b', foo=[])",
+        "honest2(name='c', foo=[])");
+
+    ConfiguredTarget a = getConfiguredTarget("//a:a");
+    assertThat(a.getProvider(RuleInfo.class).getData())
+        .containsExactly("rule //a:a", "aspect //a:b", "aspect //a:c");
+  }
+
+  @Test
   public void aspectWithParametrizedDefinition() throws Exception {
     setRulesAvailableInTests(
         new TestAspects.BaseRule(),
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 55b0fe8..22a9412 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
@@ -24,6 +24,8 @@
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.ConfiguredAspect;
@@ -117,6 +119,14 @@
   public static final class RequiredProvider implements TransitiveInfoProvider {
   }
 
+  /**
+   * Another very simple provider used in tests that check whether the logic that attaches aspects
+   * depending on whether a configured target has a provider works or not.
+   */
+  @Immutable
+  public static final class RequiredProvider2 implements TransitiveInfoProvider {
+  }
+
   private static NestedSet<String> collectAspectData(String me, RuleContext ruleContext) {
     NestedSetBuilder<String> result = new NestedSetBuilder<>(Order.STABLE_ORDER);
     result.add(me);
@@ -160,6 +170,24 @@
   }
 
   /**
+   * A simple rule configured target factory that exports provider {@link RequiredProvider2}.
+   */
+  public static class DummyRuleFactory2 implements RuleConfiguredTargetFactory {
+    @Override
+    public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+      return new RuleConfiguredTargetBuilder(ruleContext)
+              .addProvider(
+                  new RuleInfo(collectAspectData("rule " + ruleContext.getLabel(), ruleContext)))
+              .setFilesToBuild(NestedSetBuilder.<Artifact>create(Order.STABLE_ORDER))
+              .setRunfilesSupport(null, null)
+              .add(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY))
+              .addProvider(new RequiredProvider())
+              .addProvider(new RequiredProvider2())
+              .build();
+    }
+  }
+
+  /**
    * A base class for mock aspects to reduce boilerplate.
    */
   public abstract static class BaseAspect extends NativeAspectClass
@@ -203,7 +231,7 @@
   private static final AspectDefinition EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER_DEFINITION =
       new AspectDefinition.Builder(EXTRA_ATTRIBUTE_ASPECT_REQUIRING_PROVIDER)
           .add(attr("$dep", LABEL).value(Label.parseAbsoluteUnchecked("//extra:extra")))
-          .requireProvider(RequiredProvider.class)
+          .requireProviders(RequiredProvider.class)
           .build();
 
   /**
@@ -286,6 +314,17 @@
   }
 
   /**
+   * An aspect that requires provider sets {{@link RequiredProvider}} and
+   * {{@link RequiredProvider2}}.
+   */
+  public static class AspectRequiringProviderSets extends BaseAspect {
+    @Override
+    public AspectDefinition getDefinition(AspectParameters aspectParameters) {
+      return ASPECT_REQUIRING_PROVIDER_SETS_DEFINITION;
+    }
+  }
+
+  /**
    * An aspect that has a definition depending on parameters provided by originating rule.
    */
   public static class ParametrizedDefinitionAspect extends NativeAspectClass
@@ -334,9 +373,18 @@
 
   private static final AspectRequiringProvider ASPECT_REQUIRING_PROVIDER =
       new AspectRequiringProvider();
+  private static final AspectRequiringProviderSets ASPECT_REQUIRING_PROVIDER_SETS =
+      new AspectRequiringProviderSets();
   private static final AspectDefinition ASPECT_REQUIRING_PROVIDER_DEFINITION =
       new AspectDefinition.Builder(ASPECT_REQUIRING_PROVIDER)
-          .requireProvider(RequiredProvider.class)
+          .requireProviders(RequiredProvider.class)
+          .build();
+  private static final AspectDefinition ASPECT_REQUIRING_PROVIDER_SETS_DEFINITION =
+      new AspectDefinition.Builder(ASPECT_REQUIRING_PROVIDER_SETS)
+          .requireProviderSets(
+              ImmutableList.of(
+                  ImmutableSet.<Class<?>>of(RequiredProvider.class),
+                  ImmutableSet.<Class<?>>of(RequiredProvider2.class)))
           .build();
 
   /**
@@ -486,6 +534,30 @@
   }
 
   /**
+   * A rule that defines an {@link AspectRequiringProviderSets} on one of its attributes.
+   */
+  public static class AspectRequiringProviderSetsRule implements RuleDefinition {
+
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+      return builder
+          .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)
+              .aspect(ASPECT_REQUIRING_PROVIDER_SETS))
+          .add(attr("baz", STRING))
+          .build();
+    }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("aspect_requiring_provider_sets")
+          .factoryClass(DummyRuleFactory.class)
+          .ancestors(BaseRule.class)
+          .build();
+    }
+  }
+
+  /**
    * A rule that defines an {@link ExtraAttributeAspect} on one of its attributes.
    */
   public static class ExtraAttributeAspectRule implements RuleDefinition {
@@ -731,6 +803,29 @@
   }
 
   /**
+   * A rule that advertises another, different provider and implements it.
+   */
+  public static class HonestRule2 implements RuleDefinition {
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+      return builder
+          .add(attr("foo", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
+          .advertiseProvider(RequiredProvider2.class)
+          .build();
+    }
+
+    @Override
+    public Metadata getMetadata() {
+      return RuleDefinition.Metadata.builder()
+          .name("honest2")
+          .factoryClass(DummyRuleFactory2.class)
+          .ancestors(BaseRule.class)
+          .build();
+    }
+  }
+
+
+  /**
    * Rule with an implcit dependency.
    */
   public static class ImplicitDepRule implements RuleDefinition {