Fix android_library resources handling

RELNOTES: Fix resource handling for exported android_library rules

--
MOS_MIGRATED_REVID=109532253
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index d95e95c..77ad117 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -561,7 +561,12 @@
     return getDerivedArtifact(getUniqueDirectory(uniqueDirectory).getRelative(relative), root);
   }
 
-  private Attribute getAttribute(String attributeName) {
+  /**
+   * Returns the Attribute associated with this name, if it's a valid attribute for this rule,
+   * or is associated with an attached aspect. Otherwise returns null.
+   */
+  @Nullable
+  public Attribute getAttribute(String attributeName) {
     Attribute result = getRule().getAttributeDefinition(attributeName);
     if (result != null) {
       return result;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
index 7c4d3e9..11c9b0b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java
@@ -19,6 +19,7 @@
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ResourceSet;
 import com.google.devtools.build.lib.analysis.AnalysisUtils;
@@ -30,9 +31,11 @@
 import com.google.devtools.build.lib.analysis.Runfiles;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
 import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
 import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
 import com.google.devtools.build.lib.analysis.actions.SpawnAction;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
+import com.google.devtools.build.lib.collect.IterablesChain;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
@@ -69,6 +72,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 import javax.annotation.Nullable;
 
@@ -83,6 +87,22 @@
   public static final InstrumentationSpec ANDROID_COLLECTION_SPEC = JavaCommon.JAVA_COLLECTION_SPEC
       .withDependencyAttributes("deps", "data", "exports", "runtime_deps", "binary_under_test");
 
+  public static final Set<String> TRANSITIVE_ATTRIBUTES = ImmutableSet.of(
+      "deps",
+      "exports"
+  );
+
+  public static final <T extends TransitiveInfoProvider> Iterable<T> getTransitivePrerequisites(
+      RuleContext ruleContext, Mode mode, final Class<T> classType) {
+    IterablesChain.Builder<T> builder = IterablesChain.builder();
+    for (String attr : TRANSITIVE_ATTRIBUTES) {
+      if (ruleContext.getAttribute(attr) != null) {
+        builder.add(ruleContext.getPrerequisites(attr, mode, classType));
+      }
+    }
+    return builder.build();
+  }
+
   private final RuleContext ruleContext;
   private final JavaCommon javaCommon;
   private final boolean asNeverLink;
@@ -642,14 +662,6 @@
     return prerequisite.getProvider(AndroidResourcesProvider.class);
   }
 
-  public static NestedSet<Artifact> getApplicationApks(RuleContext ruleContext) {
-    NestedSetBuilder<Artifact> applicationApksBuilder = NestedSetBuilder.stableOrder();
-    for (ApkProvider dep : ruleContext.getPrerequisites("deps", Mode.TARGET, ApkProvider.class)) {
-      applicationApksBuilder.addTransitive(dep.getTransitiveApks());
-    }
-    return applicationApksBuilder.build();
-  }
-
   /**
    * Collects Java compilation arguments for this target.
    *
@@ -728,7 +740,7 @@
   private NestedSet<Artifact> collectHiddenTopLevelArtifacts(RuleContext ruleContext) {
     NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder();
     for (OutputGroupProvider provider :
-        ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupProvider.class)) {
+        getTransitivePrerequisites(ruleContext, Mode.TARGET, OutputGroupProvider.class)) {
       builder.addTransitive(provider.getOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL));
     }
     return builder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
index 3547eef..dc00cbb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidIdlHelper.java
@@ -313,8 +313,8 @@
       jarsBuilder.add(idlSourceJar);
     }
 
-    for (AndroidIdlProvider dep : ruleContext.getPrerequisites(
-        "deps", Mode.TARGET, AndroidIdlProvider.class)) {
+    for (AndroidIdlProvider dep : AndroidCommon.getTransitivePrerequisites(
+        ruleContext, Mode.TARGET, AndroidIdlProvider.class)) {
       rootsBuilder.addTransitive(dep.getTransitiveIdlImportRoots());
       importsBuilder.addTransitive(dep.getTransitiveIdlImports());
       jarsBuilder.addTransitive(dep.getTransitiveIdlJars());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
index 3474032..f2658c9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
@@ -219,8 +219,8 @@
 
   private NestedSetBuilder<Aar> collectTransitiveAars(RuleContext ruleContext) {
     NestedSetBuilder<Aar> builder = NestedSetBuilder.naiveLinkOrder();
-    for (AndroidLibraryAarProvider library :
-        ruleContext.getPrerequisites("deps", Mode.TARGET, AndroidLibraryAarProvider.class)) {
+    for (AndroidLibraryAarProvider library : AndroidCommon.getTransitivePrerequisites(
+        ruleContext, Mode.TARGET, AndroidLibraryAarProvider.class)) {
       builder.addTransitive(library.getTransitiveAars());
     }
     return builder;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java
index 808490c..dfd4df3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.rules.android;
 
+import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -56,7 +57,8 @@
 
     NestedSetBuilder<ResourceContainer> transitiveDependencies = NestedSetBuilder.naiveLinkOrder();
     NestedSetBuilder<ResourceContainer> directDependencies = NestedSetBuilder.naiveLinkOrder();
-    extractFromAttribute("resources", ruleContext, transitiveDependencies, directDependencies);
+    extractFromAttributes(
+        ImmutableList.of("resources"), ruleContext, transitiveDependencies, directDependencies);
     return new ResourceDependencies(neverlink,
         transitiveDependencies.build(), directDependencies.build());
   }
@@ -64,7 +66,8 @@
   public static ResourceDependencies fromRuleDeps(RuleContext ruleContext, boolean neverlink) {
     NestedSetBuilder<ResourceContainer> transitiveDependencies = NestedSetBuilder.naiveLinkOrder();
     NestedSetBuilder<ResourceContainer> directDependencies = NestedSetBuilder.naiveLinkOrder();
-    extractFromAttribute("deps", ruleContext, transitiveDependencies, directDependencies);
+    extractFromAttributes(AndroidCommon.TRANSITIVE_ATTRIBUTES, ruleContext, transitiveDependencies,
+        directDependencies);
     return new ResourceDependencies(neverlink,
         transitiveDependencies.build(), directDependencies.build());
   }
@@ -74,29 +77,37 @@
     NestedSetBuilder<ResourceContainer> transitiveDependencies = NestedSetBuilder.naiveLinkOrder();
     NestedSetBuilder<ResourceContainer> directDependencies = NestedSetBuilder.naiveLinkOrder();
     if (hasResourceAttribute(ruleContext)) {
-      extractFromAttribute("resources",ruleContext, transitiveDependencies, directDependencies);
+      extractFromAttributes(
+          ImmutableList.of("resources"), ruleContext, transitiveDependencies, directDependencies);
     }
     if (directDependencies.isEmpty()) {
       // There are no resources, so this library will forward the direct and transitive dependencies
       // without changes.
-      extractFromAttribute("deps", ruleContext, transitiveDependencies, directDependencies);
+      extractFromAttributes(AndroidCommon.TRANSITIVE_ATTRIBUTES, ruleContext,
+          transitiveDependencies, directDependencies);
     } else {
       // There are resources, so the direct dependencies and the transitive will be merged into
       // the transitive dependencies. This maintains the relationship of the resources being
       // directly on the rule.
-      extractFromAttribute("deps", ruleContext, transitiveDependencies, transitiveDependencies);
+      extractFromAttributes(AndroidCommon.TRANSITIVE_ATTRIBUTES, ruleContext,
+          transitiveDependencies, transitiveDependencies);
     }
     return new ResourceDependencies(neverlink,
         transitiveDependencies.build(), directDependencies.build());
   }
 
-  private static void extractFromAttribute(String attribute,
+  private static void extractFromAttributes(Iterable<String> attributes,
       RuleContext ruleContext, NestedSetBuilder<ResourceContainer> builderForTransitive,
       NestedSetBuilder<ResourceContainer> builderForDirect) {
-    for (AndroidResourcesProvider resources :
-        ruleContext.getPrerequisites(attribute, Mode.TARGET, AndroidResourcesProvider.class)) {
-      builderForTransitive.addTransitive(resources.getTransitiveAndroidResources());
-      builderForDirect.addTransitive(resources.getDirectAndroidResources());
+    for (String attr : attributes) {
+      if (ruleContext.getAttribute(attr) == null) {
+        continue;
+      }
+      for (AndroidResourcesProvider resources :
+          ruleContext.getPrerequisites(attr, Mode.TARGET, AndroidResourcesProvider.class)) {
+        builderForTransitive.addTransitive(resources.getTransitiveAndroidResources());
+        builderForDirect.addTransitive(resources.getDirectAndroidResources());
+      }
     }
   }