AAPT2: Support static lib referencing static lib

When a static library A references static library B,
and app C references both A and B, we get the following symbol merging,
symbols from library B get imported twice.

We must only check that symbol references to library B are valid
when building library A. We should only merge all the symbols
when building final app C.

Change-Id: I23cba33b0901dcbb5328d9c9dfaa6a979c073c36
diff --git a/tools/aapt2/Linker.cpp b/tools/aapt2/Linker.cpp
index a8b7a14..f3f04a5 100644
--- a/tools/aapt2/Linker.cpp
+++ b/tools/aapt2/Linker.cpp
@@ -40,8 +40,9 @@
 Linker::Args::Args(const ResourceNameRef& r, const SourceLine& s) : referrer(r), source(s) {
 }
 
-Linker::Linker(std::shared_ptr<ResourceTable> table, std::shared_ptr<IResolver> resolver) :
-        mTable(table), mResolver(resolver), mError(false) {
+Linker::Linker(const std::shared_ptr<ResourceTable>& table,
+               const std::shared_ptr<IResolver>& resolver, const Options& options) :
+        mResolver(resolver), mTable(table), mOptions(options), mError(false) {
 }
 
 bool Linker::linkAndValidate() {
@@ -49,7 +50,7 @@
     std::array<std::set<uint16_t>, 256> usedIds;
     usedTypeIds.set(0);
 
-    // First build the graph of references.
+    // Collect which resource IDs are already taken.
     for (auto& type : *mTable) {
         if (type->typeId != ResourceTableType::kUnsetTypeId) {
             // The ID for this type has already been set. We
@@ -66,29 +67,10 @@
                 // later.
                 usedIds[type->typeId].insert(entry->entryId);
             }
-
-            if (entry->publicStatus.isPublic && entry->values.empty()) {
-                // A public resource has no values. It will not be encoded
-                // properly without a symbol table. This is a unresolved symbol.
-                addUnresolvedSymbol(ResourceNameRef{
-                        mTable->getPackage(), type->type, entry->name },
-                        entry->publicStatus.source);
-            } else {
-                for (auto& valueConfig : entry->values) {
-                    // Dispatch to the right method of this linker
-                    // based on the value's type.
-                    valueConfig.value->accept(*this, Args{
-                            ResourceNameRef{ mTable->getPackage(), type->type, entry->name },
-                            valueConfig.source
-                    });
-                }
-            }
         }
     }
 
-    /*
-     * Assign resource IDs that are available.
-     */
+    // Assign resource IDs that are available.
     size_t nextTypeIndex = 0;
     for (auto& type : *mTable) {
         if (type->typeId == ResourceTableType::kUnsetTypeId) {
@@ -109,29 +91,32 @@
                     ++nextEntryIter;
                 }
                 entry->entryId = nextIndex++;
-
-                std::u16string unmangledPackage = mTable->getPackage();
-                std::u16string unmangledName = entry->name;
-                NameMangler::unmangle(&unmangledName, &unmangledPackage);
-
-                // Update callers of this resource with the right ID.
-                auto callersIter = mGraph.find(ResourceNameRef{
-                        unmangledPackage,
-                        type->type,
-                        unmangledName
-                });
-
-                if (callersIter != std::end(mGraph)) {
-                    for (Node& caller : callersIter->second) {
-                        caller.reference->id = ResourceId(mTable->getPackageId(),
-                                                          type->typeId,
-                                                          entry->entryId);
-                    }
-                }
             }
         }
     }
 
+    // Now do reference linking.
+    for (auto& type : *mTable) {
+        for (auto& entry : type->entries) {
+            if (entry->publicStatus.isPublic && entry->values.empty()) {
+                // A public resource has no values. It will not be encoded
+                // properly without a symbol table. This is a unresolved symbol.
+                addUnresolvedSymbol(ResourceNameRef{
+                        mTable->getPackage(), type->type, entry->name },
+                        entry->publicStatus.source);
+                continue;
+            }
+
+            for (auto& valueConfig : entry->values) {
+                // Dispatch to the right method of this linker
+                // based on the value's type.
+                valueConfig.value->accept(*this, Args{
+                        ResourceNameRef{ mTable->getPackage(), type->type, entry->name },
+                        valueConfig.source
+                });
+            }
+        }
+    }
     return !mError;
 }
 
@@ -139,12 +124,48 @@
     return mUnresolvedSymbols;
 }
 
+void Linker::doResolveReference(Reference& reference, const SourceLine& source) {
+    Maybe<ResourceId> result = mResolver->findId(reference.name);
+    if (!result) {
+        addUnresolvedSymbol(reference.name, source);
+        return;
+    }
+    assert(result.value().isValid());
+
+    if (mOptions.linkResourceIds) {
+        reference.id = result.value();
+    } else {
+        reference.id = 0;
+    }
+}
+
+const Attribute* Linker::doResolveAttribute(Reference& attribute, const SourceLine& source) {
+    Maybe<IResolver::Entry> result = mResolver->findAttribute(attribute.name);
+    if (!result || !result.value().attr) {
+        addUnresolvedSymbol(attribute.name, source);
+        return nullptr;
+    }
+
+    const IResolver::Entry& entry = result.value();
+    assert(entry.id.isValid());
+
+    if (mOptions.linkResourceIds) {
+        attribute.id = entry.id;
+    } else {
+        attribute.id = 0;
+    }
+    return entry.attr;
+}
+
 void Linker::visit(Reference& reference, ValueVisitorArgs& a) {
     Args& args = static_cast<Args&>(a);
 
     if (!reference.name.isValid()) {
         // We can't have a completely bad reference.
-        assert(reference.id.isValid());
+        if (!reference.id.isValid()) {
+            Logger::error() << "srsly? " << args.referrer << std::endl;
+            assert(reference.id.isValid());
+        }
 
         // This reference has no name but has an ID.
         // It is a really bad error to have no name and have the same
@@ -156,25 +177,7 @@
         return;
     }
 
-    Maybe<ResourceId> result = mResolver->findId(reference.name);
-    if (!result) {
-        addUnresolvedSymbol(reference.name, args.source);
-        return;
-    }
-
-    const ResourceId& id = result.value();
-    if (id.isValid()) {
-        reference.id = id;
-    } else {
-        // We need to update the ID when it is set, so add it
-        // to the graph.
-        mGraph[reference.name].push_back(Node{
-                args.referrer,
-                args.source.path,
-                args.source.line,
-                &reference
-        });
-    }
+    doResolveReference(reference, args.source);
 
     // TODO(adamlesinski): Verify the referencedType is another reference
     // or a compatible primitive.
@@ -192,7 +195,6 @@
             // We should never get here. All references would have been
             // parsed in the parser phase.
             assert(false);
-            //mTable->addResource(name, ConfigDescription{}, source, util::make_unique<Id>());
         };
 
         convertedValue = ResourceParser::parseItemForAttribute(*str.value, attr,
@@ -240,25 +242,10 @@
     }
 
     for (Style::Entry& styleEntry : style.entries) {
-        Maybe<IResolver::Entry> result = mResolver->findAttribute(styleEntry.key.name);
-        if (!result || !result.value().attr) {
-            addUnresolvedSymbol(styleEntry.key.name, args.source);
-            continue;
+        const Attribute* attr = doResolveAttribute(styleEntry.key, args.source);
+        if (attr) {
+            processAttributeValue(args.referrer, args.source, *attr, styleEntry.value);
         }
-
-        const IResolver::Entry& entry = result.value();
-        if (entry.id.isValid()) {
-            styleEntry.key.id = entry.id;
-        } else {
-            // Create a dependency for the style on this attribute.
-            mGraph[styleEntry.key.name].push_back(Node{
-                    args.referrer,
-                    args.source.path,
-                    args.source.line,
-                    &styleEntry.key
-            });
-        }
-        processAttributeValue(args.referrer, args.source, *entry.attr, styleEntry.value);
     }
 }
 
@@ -300,8 +287,4 @@
     mUnresolvedSymbols[name.toResourceName()].push_back(source);
 }
 
-::std::ostream& operator<<(::std::ostream& out, const Linker::Node& node) {
-    return out << node.name << "(" << node.source << ":" << node.line << ")";
-}
-
 } // namespace aapt