diff options
Diffstat (limited to 'tools/aapt2/link/ReferenceLinker.cpp')
-rw-r--r-- | tools/aapt2/link/ReferenceLinker.cpp | 214 |
1 files changed, 123 insertions, 91 deletions
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp index 414e56eb5dcc..71e828b039e1 100644 --- a/tools/aapt2/link/ReferenceLinker.cpp +++ b/tools/aapt2/link/ReferenceLinker.cpp @@ -30,23 +30,18 @@ #include "util/Util.h" #include "xml/XmlUtil.h" -using android::StringPiece; +using ::android::StringPiece; namespace aapt { namespace { -/** - * The ReferenceLinkerVisitor will follow all references and make sure they - * point - * to resources that actually exist, either in the local resource table, or as - * external - * symbols. Once the target resource has been found, the ID of the resource will - * be assigned - * to the reference object. - * - * NOTE: All of the entries in the ResourceTable must be assigned IDs. - */ +// The ReferenceLinkerVisitor will follow all references and make sure they point +// to resources that actually exist, either in the local resource table, or as external +// symbols. Once the target resource has been found, the ID of the resource will be assigned +// to the reference object. +// +// NOTE: All of the entries in the ResourceTable must be assigned IDs. class ReferenceLinkerVisitor : public ValueVisitor { public: using ValueVisitor::Visit; @@ -65,14 +60,9 @@ class ReferenceLinkerVisitor : public ValueVisitor { } } - /** - * We visit the Style specially because during this phase, values of - * attributes are - * all RawString values. Now that we are expected to resolve all symbols, we - * can - * lookup the attributes to find out which types are allowed for the - * attributes' values. - */ + // We visit the Style specially because during this phase, values of attributes are + // all RawString values. Now that we are expected to resolve all symbols, we can + // lookup the attributes to find out which types are allowed for the attributes' values. void Visit(Style* style) override { if (style->parent) { Visit(&style->parent.value()); @@ -81,28 +71,21 @@ class ReferenceLinkerVisitor : public ValueVisitor { for (Style::Entry& entry : style->entries) { std::string err_str; - // Transform the attribute reference so that it is using the fully - // qualified package - // name. This will also mark the reference as being able to see private - // resources if - // there was a '*' in the reference or if the package came from the - // private namespace. + // Transform the attribute reference so that it is using the fully qualified package + // name. This will also mark the reference as being able to see private resources if + // there was a '*' in the reference or if the package came from the private namespace. Reference transformed_reference = entry.key; - TransformReferenceFromNamespace(package_decls_, - context_->GetCompilationPackage(), - &transformed_reference); + ResolvePackage(package_decls_, &transformed_reference); - // Find the attribute in the symbol table and check if it is visible from - // this callsite. + // 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); if (symbol) { - // Assign our style key the correct ID. - // The ID may not exist. + // Assign our style key the correct ID. The ID may not exist. entry.key.id = symbol->id; - // Try to convert the value to a more specific, typed value based on the - // attribute it is set to. + // Try to convert the value to a more specific, typed value based on the attribute it is + // set to. entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get()); // Link/resolve the final value (mostly if it's a reference). @@ -115,8 +98,8 @@ class ReferenceLinkerVisitor : public ValueVisitor { // The actual type of this item is incompatible with the attribute. DiagMessage msg(entry.key.GetSource()); - // Call the matches method again, this time with a DiagMessage so we - // fill in the actual error message. + // Call the matches method again, this time with a DiagMessage so we fill in the actual + // error message. symbol->attribute->Matches(*entry.value, &msg); context_->GetDiagnostics()->Error(msg); error_ = true; @@ -125,7 +108,7 @@ class ReferenceLinkerVisitor : public ValueVisitor { } else { DiagMessage msg(entry.key.GetSource()); msg << "style attribute '"; - ReferenceLinker::WriteResourceName(&msg, entry.key, transformed_reference); + ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg); msg << "' " << err_str; context_->GetDiagnostics()->Error(msg); error_ = true; @@ -133,17 +116,15 @@ class ReferenceLinkerVisitor : public ValueVisitor { } } - bool HasError() { return error_; } + bool HasError() { + return error_; + } private: DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor); - /** - * Transform a RawString value into a more specific, appropriate value, based - * on the - * Attribute. If a non RawString value is passed in, this is an identity - * transform. - */ + // Transform a RawString value into a more specific, appropriate value, based on the + // Attribute. If a non RawString value is passed in, this is an identity transform. std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value, const Attribute* attr) { if (RawString* raw_string = ValueCast<RawString>(value.get())) { @@ -178,11 +159,9 @@ class EmptyDeclStack : public xml::IPackageDeclStack { public: EmptyDeclStack() = default; - Maybe<xml::ExtractedPackage> TransformPackageAlias( - const StringPiece& alias, - const StringPiece& local_package) const override { + Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override { if (alias.empty()) { - return xml::ExtractedPackage{local_package.to_string(), true /* private */}; + return xml::ExtractedPackage{{}, true /*private*/}; } return {}; } @@ -191,32 +170,44 @@ class EmptyDeclStack : public xml::IPackageDeclStack { DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack); }; -} // namespace +// The symbol is visible if it is public, or if the reference to it is requesting private access +// or if the callsite comes from the same package. +bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref, + const CallSite& callsite) { + if (symbol.is_public || ref.private_reference) { + return true; + } -/** - * The symbol is visible if it is public, or if the reference to it is - * requesting private access - * or if the callsite comes from the same package. - */ -bool ReferenceLinker::IsSymbolVisible(const SymbolTable::Symbol& symbol, - const Reference& ref, - const CallSite& callsite) { - if (!symbol.is_public && !ref.private_reference) { - if (ref.name) { - return callsite.resource.package == ref.name.value().package; - } else if (ref.id && symbol.id) { - return ref.id.value().package_id() == symbol.id.value().package_id(); - } else { - return false; + if (ref.name) { + const ResourceName& name = ref.name.value(); + if (name.package.empty()) { + // If the symbol was found, and the package is empty, that means it was found in the local + // scope, which is always visible (private local). + return true; } + + // The symbol is visible if the reference is local to the same package it is defined in. + return callsite.package == name.package; } - return true; + + if (ref.id && symbol.id) { + return ref.id.value().package_id() == symbol.id.value().package_id(); + } + return false; } +} // namespace + const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference, + const CallSite& callsite, SymbolTable* symbols) { if (reference.name) { - return symbols->FindByName(reference.name.value()); + 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)); + } + return symbols->FindByName(name); } else if (reference.id) { return symbols->FindById(reference.id.value()); } else { @@ -228,7 +219,7 @@ const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const R const CallSite& callsite, SymbolTable* symbols, std::string* out_error) { - const SymbolTable::Symbol* symbol = ResolveSymbol(reference, symbols); + const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols); if (!symbol) { if (out_error) *out_error = "not found"; return nullptr; @@ -274,24 +265,62 @@ Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& return xml::AaptAttribute(*symbol->attribute, symbol->id); } -void ReferenceLinker::WriteResourceName(DiagMessage* out_msg, - const Reference& orig, - const Reference& transformed) { +void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite, + const xml::IPackageDeclStack* decls, DiagMessage* out_msg) { CHECK(out_msg != nullptr); + if (!ref.name) { + *out_msg << ref.id.value(); + return; + } - if (orig.name) { - *out_msg << orig.name.value(); - if (transformed.name.value() != orig.name.value()) { - *out_msg << " (aka " << transformed.name.value() << ")"; - } - } else { - *out_msg << orig.id.value(); + *out_msg << ref.name.value(); + + Reference fully_qualified = ref; + xml::ResolvePackage(decls, &fully_qualified); + + ResourceName& full_name = fully_qualified.name.value(); + if (full_name.package.empty()) { + full_name.package = callsite.package; + } + + if (full_name != ref.name.value()) { + *out_msg << " (aka " << full_name << ")"; + } +} + +void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite, + const xml::IPackageDeclStack* decls, + DiagMessage* out_msg) { + CHECK(out_msg != nullptr); + if (!ref.name) { + *out_msg << ref.id.value(); + return; + } + + const ResourceName& ref_name = ref.name.value(); + CHECK_EQ(ref_name.type, ResourceType::kAttr); + + if (!ref_name.package.empty()) { + *out_msg << ref_name.package << ":"; + } + *out_msg << ref_name.entry; + + Reference fully_qualified = ref; + xml::ResolvePackage(decls, &fully_qualified); + + ResourceName& full_name = fully_qualified.name.value(); + if (full_name.package.empty()) { + full_name.package = callsite.package; + } + + if (full_name != ref.name.value()) { + *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")"; } } bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference, IAaptContext* context, SymbolTable* symbols, - xml::IPackageDeclStack* decls) { + const xml::IPackageDeclStack* decls) { CHECK(reference != nullptr); if (!reference->name && !reference->id) { // This is @null. @@ -299,7 +328,7 @@ bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* referen } Reference transformed_reference = *reference; - TransformReferenceFromNamespace(decls, context->GetCompilationPackage(), &transformed_reference); + xml::ResolvePackage(decls, &transformed_reference); std::string err_str; const SymbolTable::Symbol* s = @@ -314,7 +343,7 @@ bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* referen DiagMessage error_msg(reference->GetSource()); error_msg << "resource "; - WriteResourceName(&error_msg, *reference, transformed_reference); + WriteResourceName(*reference, callsite, decls, &error_msg); error_msg << " " << err_str; context->GetDiagnostics()->Error(error_msg); return false; @@ -324,21 +353,24 @@ bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) { EmptyDeclStack decl_stack; bool error = false; for (auto& package : table->packages) { + // Since we're linking, each package must have a name. + CHECK(!package->name.empty()) << "all packages being linked must have a name"; + for (auto& type : package->types) { for (auto& entry : type->entries) { - // Symbol state information may be lost if there is no value for the - // resource. - if (entry->symbol_status.state != SymbolState::kUndefined && - entry->values.empty()) { - context->GetDiagnostics()->Error( - DiagMessage(entry->symbol_status.source) - << "no definition for declared symbol '" - << ResourceNameRef(package->name, type->type, entry->name) - << "'"); + // First, unmangle the name if necessary. + ResourceName name(package->name, type->type, entry->name); + NameMangler::Unmangle(&name.entry, &name.package); + + // Symbol state information may be lost if there is no value for the resource. + if (entry->symbol_status.state != SymbolState::kUndefined && entry->values.empty()) { + context->GetDiagnostics()->Error(DiagMessage(entry->symbol_status.source) + << "no definition for declared symbol '" << name << "'"); error = true; } - CallSite callsite = {ResourceNameRef(package->name, type->type, entry->name)}; + // The context of this resource is the package in which it is defined. + const CallSite callsite{name.package}; ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(), &table->string_pool, &decl_stack); |