Allows features to link to other feature splits without namespacing.

Add uses-split dependencies to AppInfo. At link time, this is used
and allows features to reference other features, before
resource namespacing is implemented in Android Studio.

bug:135681292
Test: Link_test, ReferenceLinker_test, and integration tests.
Change-Id: Ifdf0067e7370552b6b9d4d6d4713d4484b6ea154
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index 28f09aa..8e49fab 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -17,6 +17,7 @@
 #include "link/ReferenceLinker.h"
 
 #include "android-base/logging.h"
+#include "android-base/stringprintf.h"
 #include "androidfw/ResourceTypes.h"
 
 #include "Diagnostics.h"
@@ -33,6 +34,7 @@
 
 using ::aapt::ResourceUtils::StringBuilder;
 using ::android::StringPiece;
+using ::android::base::StringPrintf;
 
 namespace aapt {
 
@@ -81,7 +83,7 @@
 
       // Find the attribute in the symbol table and check if it is visible from this callsite.
       const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
-          transformed_reference, callsite_, symbols_, &err_str);
+          transformed_reference, callsite_, context_, symbols_, &err_str);
       if (symbol) {
         // Assign our style key the correct ID. The ID may not exist.
         entry.key.id = symbol->id;
@@ -203,12 +205,35 @@
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
                                                           const CallSite& callsite,
+                                                          IAaptContext* context,
                                                           SymbolTable* symbols) {
   if (reference.name) {
     const ResourceName& name = reference.name.value();
     if (name.package.empty()) {
       // Use the callsite's package name if no package name was defined.
-      return symbols->FindByName(ResourceName(callsite.package, name.type, name.entry));
+      const SymbolTable::Symbol* symbol = symbols->FindByName(
+          ResourceName(callsite.package, name.type, name.entry));
+      if (symbol) {
+        return symbol;
+      }
+
+      // If the callsite package is the same as the current compilation package,
+      // check the feature split dependencies as well. Feature split resources
+      // can be referenced without a namespace, just like the base package.
+      // TODO: modify the package name of included splits instead of having the
+      // symbol table look up the resource in in every package. b/136105066
+      if (callsite.package == context->GetCompilationPackage()) {
+        const auto& split_name_dependencies = context->GetSplitNameDependencies();
+        for (const std::string& split_name : split_name_dependencies) {
+          std::string split_package =
+              StringPrintf("%s.%s", callsite.package.c_str(), split_name.c_str());
+          symbol = symbols->FindByName(ResourceName(split_package, name.type, name.entry));
+          if (symbol) {
+            return symbol;
+          }
+        }
+      }
+      return nullptr;
     }
     return symbols->FindByName(name);
   } else if (reference.id) {
@@ -220,9 +245,10 @@
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference,
                                                                          const CallSite& callsite,
+                                                                         IAaptContext* context,
                                                                          SymbolTable* symbols,
                                                                          std::string* out_error) {
-  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols);
+  const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, context, symbols);
   if (!symbol) {
     if (out_error) *out_error = "not found";
     return nullptr;
@@ -236,10 +262,10 @@
 }
 
 const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
-    const Reference& reference, const CallSite& callsite, SymbolTable* symbols,
-    std::string* out_error) {
+    const Reference& reference, const CallSite& callsite, IAaptContext* context,
+    SymbolTable* symbols, std::string* out_error) {
   const SymbolTable::Symbol* symbol =
-      ResolveSymbolCheckVisibility(reference, callsite, symbols, out_error);
+      ResolveSymbolCheckVisibility(reference, callsite, context, symbols, out_error);
   if (!symbol) {
     return nullptr;
   }
@@ -253,10 +279,11 @@
 
 Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
                                                                const CallSite& callsite,
+                                                               IAaptContext* context,
                                                                SymbolTable* symbols,
                                                                std::string* out_error) {
   const SymbolTable::Symbol* symbol =
-      ResolveAttributeCheckVisibility(reference, callsite, symbols, out_error);
+      ResolveAttributeCheckVisibility(reference, callsite, context, symbols, out_error);
   if (!symbol) {
     return {};
   }
@@ -335,7 +362,7 @@
 
   std::string err_str;
   const SymbolTable::Symbol* s =
-      ResolveSymbolCheckVisibility(transformed_reference, callsite, symbols, &err_str);
+      ResolveSymbolCheckVisibility(transformed_reference, callsite, context, symbols, &err_str);
   if (s) {
     // The ID may not exist. This is fine because of the possibility of building
     // against libraries without assigned IDs.