| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2015 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 17 | #include "link/ReferenceLinker.h" | 
 | 18 |  | 
 | 19 | #include "android-base/logging.h" | 
 | 20 | #include "androidfw/ResourceTypes.h" | 
 | 21 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 22 | #include "Diagnostics.h" | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 23 | #include "ResourceTable.h" | 
 | 24 | #include "ResourceUtils.h" | 
 | 25 | #include "ResourceValues.h" | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 26 | #include "ValueVisitor.h" | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 27 | #include "link/Linkers.h" | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 28 | #include "process/IResourceTableConsumer.h" | 
 | 29 | #include "process/SymbolTable.h" | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 30 | #include "util/Util.h" | 
 | 31 | #include "xml/XmlUtil.h" | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 32 |  | 
| Adam Lesinski | 2eed52e | 2018-02-21 15:55:58 -0800 | [diff] [blame] | 33 | using ::aapt::ResourceUtils::StringBuilder; | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 34 | using ::android::StringPiece; | 
| Adam Lesinski | d5083f6 | 2017-01-16 15:07:21 -0800 | [diff] [blame] | 35 |  | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 36 | namespace aapt { | 
 | 37 |  | 
 | 38 | namespace { | 
 | 39 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 40 | // The ReferenceLinkerVisitor will follow all references and make sure they point | 
 | 41 | // to resources that actually exist, either in the local resource table, or as external | 
 | 42 | // symbols. Once the target resource has been found, the ID of the resource will be assigned | 
 | 43 | // to the reference object. | 
 | 44 | // | 
 | 45 | // NOTE: All of the entries in the ResourceTable must be assigned IDs. | 
| Adam Lesinski | d3ffa844 | 2017-09-28 13:34:35 -0700 | [diff] [blame] | 46 | class ReferenceLinkerVisitor : public DescendingValueVisitor { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 47 |  public: | 
| Adam Lesinski | d3ffa844 | 2017-09-28 13:34:35 -0700 | [diff] [blame] | 48 |   using DescendingValueVisitor::Visit; | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 49 |  | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 50 |   ReferenceLinkerVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols, | 
 | 51 |                          StringPool* string_pool, xml::IPackageDeclStack* decl) | 
 | 52 |       : callsite_(callsite), | 
 | 53 |         context_(context), | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 54 |         symbols_(symbols), | 
 | 55 |         package_decls_(decl), | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 56 |         string_pool_(string_pool) {} | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 57 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 58 |   void Visit(Reference* ref) override { | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 59 |     if (!ReferenceLinker::LinkReference(callsite_, ref, context_, symbols_, package_decls_)) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 60 |       error_ = true; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 61 |     } | 
 | 62 |   } | 
 | 63 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 64 |   // We visit the Style specially because during this phase, values of attributes are | 
 | 65 |   // all RawString values. Now that we are expected to resolve all symbols, we can | 
 | 66 |   // lookup the attributes to find out which types are allowed for the attributes' values. | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 67 |   void Visit(Style* style) override { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 68 |     if (style->parent) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 69 |       Visit(&style->parent.value()); | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 70 |     } | 
 | 71 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 72 |     for (Style::Entry& entry : style->entries) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 73 |       std::string err_str; | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 74 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 75 |       // Transform the attribute reference so that it is using the fully qualified package | 
 | 76 |       // name. This will also mark the reference as being able to see private resources if | 
 | 77 |       // there was a '*' in the reference or if the package came from the private namespace. | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 78 |       Reference transformed_reference = entry.key; | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 79 |       ResolvePackage(package_decls_, &transformed_reference); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 80 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 81 |       // Find the attribute in the symbol table and check if it is visible from this callsite. | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 82 |       const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility( | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 83 |           transformed_reference, callsite_, symbols_, &err_str); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 84 |       if (symbol) { | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 85 |         // Assign our style key the correct ID. The ID may not exist. | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 86 |         entry.key.id = symbol->id; | 
 | 87 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 88 |         // Try to convert the value to a more specific, typed value based on the attribute it is | 
 | 89 |         // set to. | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 90 |         entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get()); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 91 |  | 
 | 92 |         // Link/resolve the final value (mostly if it's a reference). | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 93 |         entry.value->Accept(this); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 94 |  | 
 | 95 |         // Now verify that the type of this item is compatible with the | 
| Adam Lesinski | 3124e7c | 2017-06-13 16:03:55 -0700 | [diff] [blame] | 96 |         // attribute it is defined for. We pass `nullptr` as the DiagMessage so that this | 
 | 97 |         // check is fast and we avoid creating a DiagMessage when the match is successful. | 
 | 98 |         if (!symbol->attribute->Matches(*entry.value, nullptr)) { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 99 |           // The actual type of this item is incompatible with the attribute. | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 100 |           DiagMessage msg(entry.key.GetSource()); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 101 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 102 |           // Call the matches method again, this time with a DiagMessage so we fill in the actual | 
 | 103 |           // error message. | 
| Adam Lesinski | 3124e7c | 2017-06-13 16:03:55 -0700 | [diff] [blame] | 104 |           symbol->attribute->Matches(*entry.value, &msg); | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 105 |           context_->GetDiagnostics()->Error(msg); | 
 | 106 |           error_ = true; | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 107 |         } | 
 | 108 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 109 |       } else { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 110 |         DiagMessage msg(entry.key.GetSource()); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 111 |         msg << "style attribute '"; | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 112 |         ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg); | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 113 |         msg << "' " << err_str; | 
 | 114 |         context_->GetDiagnostics()->Error(msg); | 
 | 115 |         error_ = true; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 116 |       } | 
 | 117 |     } | 
 | 118 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 119 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 120 |   bool HasError() { | 
 | 121 |     return error_; | 
 | 122 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 123 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 124 |  private: | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 125 |   DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor); | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 126 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 127 |   // Transform a RawString value into a more specific, appropriate value, based on the | 
 | 128 |   // Attribute. If a non RawString value is passed in, this is an identity transform. | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 129 |   std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value, | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 130 |                                                 const Attribute* attr) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 131 |     if (RawString* raw_string = ValueCast<RawString>(value.get())) { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 132 |       std::unique_ptr<Item> transformed = | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 133 |           ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr); | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 134 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 135 |       // If we could not parse as any specific type, try a basic STRING. | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 136 |       if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) { | 
| Adam Lesinski | 2eed52e | 2018-02-21 15:55:58 -0800 | [diff] [blame] | 137 |         StringBuilder string_builder; | 
 | 138 |         string_builder.AppendText(*raw_string->value); | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 139 |         if (string_builder) { | 
| Adam Lesinski | 2eed52e | 2018-02-21 15:55:58 -0800 | [diff] [blame] | 140 |           transformed = | 
 | 141 |               util::make_unique<String>(string_pool_->MakeRef(string_builder.to_string())); | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 142 |         } | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 143 |       } | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 144 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 145 |       if (transformed) { | 
 | 146 |         return transformed; | 
 | 147 |       } | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 148 |     } | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 149 |     return value; | 
 | 150 |   } | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 151 |  | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 152 |   const CallSite& callsite_; | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 153 |   IAaptContext* context_; | 
 | 154 |   SymbolTable* symbols_; | 
 | 155 |   xml::IPackageDeclStack* package_decls_; | 
 | 156 |   StringPool* string_pool_; | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 157 |   bool error_ = false; | 
 | 158 | }; | 
 | 159 |  | 
 | 160 | class EmptyDeclStack : public xml::IPackageDeclStack { | 
 | 161 |  public: | 
 | 162 |   EmptyDeclStack() = default; | 
 | 163 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 164 |   Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 165 |     if (alias.empty()) { | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 166 |       return xml::ExtractedPackage{{}, true /*private*/}; | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 167 |     } | 
 | 168 |     return {}; | 
 | 169 |   } | 
 | 170 |  | 
 | 171 |  private: | 
 | 172 |   DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack); | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 173 | }; | 
 | 174 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 175 | // The symbol is visible if it is public, or if the reference to it is requesting private access | 
 | 176 | // or if the callsite comes from the same package. | 
 | 177 | bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref, | 
 | 178 |                      const CallSite& callsite) { | 
 | 179 |   if (symbol.is_public || ref.private_reference) { | 
 | 180 |     return true; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 181 |   } | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 182 |  | 
 | 183 |   if (ref.name) { | 
 | 184 |     const ResourceName& name = ref.name.value(); | 
 | 185 |     if (name.package.empty()) { | 
 | 186 |       // If the symbol was found, and the package is empty, that means it was found in the local | 
 | 187 |       // scope, which is always visible (private local). | 
 | 188 |       return true; | 
 | 189 |     } | 
 | 190 |  | 
 | 191 |     // The symbol is visible if the reference is local to the same package it is defined in. | 
 | 192 |     return callsite.package == name.package; | 
 | 193 |   } | 
 | 194 |  | 
 | 195 |   if (ref.id && symbol.id) { | 
 | 196 |     return ref.id.value().package_id() == symbol.id.value().package_id(); | 
 | 197 |   } | 
 | 198 |   return false; | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 199 | } | 
 | 200 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 201 | }  // namespace | 
 | 202 |  | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 203 | const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference, | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 204 |                                                           const CallSite& callsite, | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 205 |                                                           SymbolTable* symbols) { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 206 |   if (reference.name) { | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 207 |     const ResourceName& name = reference.name.value(); | 
 | 208 |     if (name.package.empty()) { | 
 | 209 |       // Use the callsite's package name if no package name was defined. | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 210 |       return symbols->FindByName(ResourceName(callsite.package, name.type, name.entry)); | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 211 |     } | 
 | 212 |     return symbols->FindByName(name); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 213 |   } else if (reference.id) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 214 |     return symbols->FindById(reference.id.value()); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 215 |   } else { | 
 | 216 |     return nullptr; | 
 | 217 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 218 | } | 
 | 219 |  | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 220 | const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference, | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 221 |                                                                          const CallSite& callsite, | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 222 |                                                                          SymbolTable* symbols, | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 223 |                                                                          std::string* out_error) { | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 224 |   const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 225 |   if (!symbol) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 226 |     if (out_error) *out_error = "not found"; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 227 |     return nullptr; | 
 | 228 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 229 |  | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 230 |   if (!IsSymbolVisible(*symbol, reference, callsite)) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 231 |     if (out_error) *out_error = "is private"; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 232 |     return nullptr; | 
 | 233 |   } | 
 | 234 |   return symbol; | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 235 | } | 
 | 236 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 237 | const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility( | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 238 |     const Reference& reference, const CallSite& callsite, SymbolTable* symbols, | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 239 |     std::string* out_error) { | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 240 |   const SymbolTable::Symbol* symbol = | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 241 |       ResolveSymbolCheckVisibility(reference, callsite, symbols, out_error); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 242 |   if (!symbol) { | 
 | 243 |     return nullptr; | 
 | 244 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 245 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 246 |   if (!symbol->attribute) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 247 |     if (out_error) *out_error = "is not an attribute"; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 248 |     return nullptr; | 
 | 249 |   } | 
 | 250 |   return symbol; | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 251 | } | 
 | 252 |  | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 253 | Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference, | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 254 |                                                                const CallSite& callsite, | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 255 |                                                                SymbolTable* symbols, | 
| Adam Lesinski | ceb9b2f | 2017-02-16 12:05:42 -0800 | [diff] [blame] | 256 |                                                                std::string* out_error) { | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 257 |   const SymbolTable::Symbol* symbol = | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 258 |       ResolveAttributeCheckVisibility(reference, callsite, symbols, out_error); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 259 |   if (!symbol) { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 260 |     return {}; | 
 | 261 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 262 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 263 |   if (!symbol->attribute) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 264 |     if (out_error) *out_error = "is not an attribute"; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 265 |     return {}; | 
 | 266 |   } | 
| Adam Lesinski | c744ae8 | 2017-05-17 19:28:38 -0700 | [diff] [blame] | 267 |   return xml::AaptAttribute(*symbol->attribute, symbol->id); | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 268 | } | 
 | 269 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 270 | void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite, | 
 | 271 |                                         const xml::IPackageDeclStack* decls, DiagMessage* out_msg) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 272 |   CHECK(out_msg != nullptr); | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 273 |   if (!ref.name) { | 
 | 274 |     *out_msg << ref.id.value(); | 
 | 275 |     return; | 
 | 276 |   } | 
| Adam Lesinski | 28cacf0 | 2015-11-23 14:22:47 -0800 | [diff] [blame] | 277 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 278 |   *out_msg << ref.name.value(); | 
 | 279 |  | 
 | 280 |   Reference fully_qualified = ref; | 
 | 281 |   xml::ResolvePackage(decls, &fully_qualified); | 
 | 282 |  | 
 | 283 |   ResourceName& full_name = fully_qualified.name.value(); | 
 | 284 |   if (full_name.package.empty()) { | 
 | 285 |     full_name.package = callsite.package; | 
 | 286 |   } | 
 | 287 |  | 
 | 288 |   if (full_name != ref.name.value()) { | 
 | 289 |     *out_msg << " (aka " << full_name << ")"; | 
 | 290 |   } | 
 | 291 | } | 
 | 292 |  | 
 | 293 | void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite, | 
 | 294 |                                          const xml::IPackageDeclStack* decls, | 
 | 295 |                                          DiagMessage* out_msg) { | 
 | 296 |   CHECK(out_msg != nullptr); | 
 | 297 |   if (!ref.name) { | 
 | 298 |     *out_msg << ref.id.value(); | 
 | 299 |     return; | 
 | 300 |   } | 
 | 301 |  | 
 | 302 |   const ResourceName& ref_name = ref.name.value(); | 
 | 303 |   CHECK_EQ(ref_name.type, ResourceType::kAttr); | 
 | 304 |  | 
 | 305 |   if (!ref_name.package.empty()) { | 
 | 306 |     *out_msg << ref_name.package << ":"; | 
 | 307 |   } | 
 | 308 |   *out_msg << ref_name.entry; | 
 | 309 |  | 
 | 310 |   Reference fully_qualified = ref; | 
 | 311 |   xml::ResolvePackage(decls, &fully_qualified); | 
 | 312 |  | 
 | 313 |   ResourceName& full_name = fully_qualified.name.value(); | 
 | 314 |   if (full_name.package.empty()) { | 
 | 315 |     full_name.package = callsite.package; | 
 | 316 |   } | 
 | 317 |  | 
 | 318 |   if (full_name != ref.name.value()) { | 
 | 319 |     *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")"; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 320 |   } | 
| Adam Lesinski | 28cacf0 | 2015-11-23 14:22:47 -0800 | [diff] [blame] | 321 | } | 
 | 322 |  | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 323 | bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference, | 
 | 324 |                                     IAaptContext* context, SymbolTable* symbols, | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 325 |                                     const xml::IPackageDeclStack* decls) { | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 326 |   CHECK(reference != nullptr); | 
| Adam Lesinski | bab4ef5 | 2017-06-01 15:22:57 -0700 | [diff] [blame] | 327 |   if (!reference->name && !reference->id) { | 
 | 328 |     // This is @null. | 
 | 329 |     return true; | 
 | 330 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 331 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 332 |   Reference transformed_reference = *reference; | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 333 |   xml::ResolvePackage(decls, &transformed_reference); | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 334 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 335 |   std::string err_str; | 
| Chris Warrington | 58e2fbf | 2018-07-23 14:12:20 +0000 | [diff] [blame] | 336 |   const SymbolTable::Symbol* s = | 
 | 337 |       ResolveSymbolCheckVisibility(transformed_reference, callsite, symbols, &err_str); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 338 |   if (s) { | 
 | 339 |     // The ID may not exist. This is fine because of the possibility of building | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 340 |     // against libraries without assigned IDs. | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 341 |     // Ex: Linking against own resources when building a static library. | 
 | 342 |     reference->id = s->id; | 
| Todd Kennedy | 3251299 | 2018-04-25 16:45:59 -0700 | [diff] [blame] | 343 |     reference->is_dynamic = s->is_dynamic; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 344 |     return true; | 
 | 345 |   } | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 346 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 347 |   DiagMessage error_msg(reference->GetSource()); | 
 | 348 |   error_msg << "resource "; | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 349 |   WriteResourceName(*reference, callsite, decls, &error_msg); | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 350 |   error_msg << " " << err_str; | 
 | 351 |   context->GetDiagnostics()->Error(error_msg); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 352 |   return false; | 
| Adam Lesinski | 467f171 | 2015-11-16 17:35:44 -0800 | [diff] [blame] | 353 | } | 
 | 354 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 355 | bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) { | 
 | 356 |   EmptyDeclStack decl_stack; | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 357 |   bool error = false; | 
 | 358 |   for (auto& package : table->packages) { | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 359 |     // Since we're linking, each package must have a name. | 
 | 360 |     CHECK(!package->name.empty()) << "all packages being linked must have a name"; | 
 | 361 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 362 |     for (auto& type : package->types) { | 
 | 363 |       for (auto& entry : type->entries) { | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 364 |         // First, unmangle the name if necessary. | 
 | 365 |         ResourceName name(package->name, type->type, entry->name); | 
 | 366 |         NameMangler::Unmangle(&name.entry, &name.package); | 
 | 367 |  | 
 | 368 |         // Symbol state information may be lost if there is no value for the resource. | 
| Adam Lesinski | 71be705 | 2017-12-12 16:48:07 -0800 | [diff] [blame] | 369 |         if (entry->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) { | 
 | 370 |           context->GetDiagnostics()->Error(DiagMessage(entry->visibility.source) | 
| Ryan Mitchell | 75e20dd | 2018-11-06 16:39:36 -0800 | [diff] [blame] | 371 |                                                << "no definition for declared symbol '" << name | 
 | 372 |                                                << "'"); | 
 | 373 |           error = true; | 
 | 374 |         } | 
 | 375 |  | 
 | 376 |         // Ensure that definitions for values declared as overlayable exist | 
| Ryan Mitchell | 54237ff | 2018-12-13 15:44:29 -0800 | [diff] [blame] | 377 |         if (entry->overlayable_item && entry->values.empty()) { | 
 | 378 |           context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_item.value().source) | 
| Ryan Mitchell | 75e20dd | 2018-11-06 16:39:36 -0800 | [diff] [blame] | 379 |                                            << "no definition for overlayable symbol '" | 
 | 380 |                                            << name << "'"); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 381 |           error = true; | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 382 |         } | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 383 |  | 
| Adam Lesinski | 1ef0fa9 | 2017-08-15 21:32:49 -0700 | [diff] [blame] | 384 |         // The context of this resource is the package in which it is defined. | 
 | 385 |         const CallSite callsite{name.package}; | 
| Adam Lesinski | f34b6f4 | 2017-03-03 16:33:26 -0800 | [diff] [blame] | 386 |         ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(), | 
 | 387 |                                        &table->string_pool, &decl_stack); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 388 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 389 |         for (auto& config_value : entry->values) { | 
 | 390 |           config_value->value->Accept(&visitor); | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 391 |         } | 
 | 392 |  | 
| Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 393 |         if (visitor.HasError()) { | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 394 |           error = true; | 
 | 395 |         } | 
 | 396 |       } | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 397 |     } | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 398 |   } | 
 | 399 |   return !error; | 
| Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 400 | } | 
 | 401 |  | 
| Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame] | 402 | }  // namespace aapt |