blob: 28e71cc24f79b49cb5e224ed831d028a776b696e [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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 Lesinskice5e56e2016-10-21 17:56:45 -070017#include "link/ReferenceLinker.h"
18
19#include "android-base/logging.h"
20#include "androidfw/ResourceTypes.h"
21
Adam Lesinskicacb28f2016-10-19 12:18:14 -070022#include "Diagnostics.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070023#include "ResourceTable.h"
24#include "ResourceUtils.h"
25#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070026#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027#include "link/Linkers.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070028#include "process/IResourceTableConsumer.h"
29#include "process/SymbolTable.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080030#include "util/Util.h"
31#include "xml/XmlUtil.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070032
Adam Lesinski2eed52e2018-02-21 15:55:58 -080033using ::aapt::ResourceUtils::StringBuilder;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070034using ::android::StringPiece;
Adam Lesinskid5083f62017-01-16 15:07:21 -080035
Adam Lesinski1ab598f2015-08-14 14:26:04 -070036namespace aapt {
37
38namespace {
39
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070040// 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 Lesinskid3ffa8442017-09-28 13:34:35 -070046class ReferenceLinkerVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070047 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070048 using DescendingValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070049
Adam Lesinskif34b6f42017-03-03 16:33:26 -080050 ReferenceLinkerVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
51 StringPool* string_pool, xml::IPackageDeclStack* decl)
52 : callsite_(callsite),
53 context_(context),
Adam Lesinskice5e56e2016-10-21 17:56:45 -070054 symbols_(symbols),
55 package_decls_(decl),
Adam Lesinskif34b6f42017-03-03 16:33:26 -080056 string_pool_(string_pool) {}
Adam Lesinskicacb28f2016-10-19 12:18:14 -070057
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 void Visit(Reference* ref) override {
Adam Lesinskif34b6f42017-03-03 16:33:26 -080059 if (!ReferenceLinker::LinkReference(callsite_, ref, context_, symbols_, package_decls_)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070060 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070061 }
62 }
63
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070064 // 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 Lesinskice5e56e2016-10-21 17:56:45 -070067 void Visit(Style* style) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070068 if (style->parent) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070069 Visit(&style->parent.value());
Adam Lesinski1ab598f2015-08-14 14:26:04 -070070 }
71
Adam Lesinskicacb28f2016-10-19 12:18:14 -070072 for (Style::Entry& entry : style->entries) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070073 std::string err_str;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070074
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070075 // 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 Lesinskice5e56e2016-10-21 17:56:45 -070078 Reference transformed_reference = entry.key;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070079 ResolvePackage(package_decls_, &transformed_reference);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070080
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070081 // Find the attribute in the symbol table and check if it is visible from this callsite.
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080082 const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
Chris Warrington481f0272018-02-06 14:03:39 +000083 transformed_reference, callsite_, symbols_, context_->IsAutoNamespace(), &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070084 if (symbol) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070085 // Assign our style key the correct ID. The ID may not exist.
Adam Lesinskicacb28f2016-10-19 12:18:14 -070086 entry.key.id = symbol->id;
87
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070088 // Try to convert the value to a more specific, typed value based on the attribute it is
89 // set to.
Adam Lesinskif34b6f42017-03-03 16:33:26 -080090 entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get());
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091
92 // Link/resolve the final value (mostly if it's a reference).
Adam Lesinskice5e56e2016-10-21 17:56:45 -070093 entry.value->Accept(this);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094
95 // Now verify that the type of this item is compatible with the
Adam Lesinski3124e7c2017-06-13 16:03:55 -070096 // 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 Lesinskicacb28f2016-10-19 12:18:14 -070099 // The actual type of this item is incompatible with the attribute.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 DiagMessage msg(entry.key.GetSource());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700101
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700102 // Call the matches method again, this time with a DiagMessage so we fill in the actual
103 // error message.
Adam Lesinski3124e7c2017-06-13 16:03:55 -0700104 symbol->attribute->Matches(*entry.value, &msg);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700105 context_->GetDiagnostics()->Error(msg);
106 error_ = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700107 }
108
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700109 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 DiagMessage msg(entry.key.GetSource());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700111 msg << "style attribute '";
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700112 ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700113 msg << "' " << err_str;
114 context_->GetDiagnostics()->Error(msg);
115 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700116 }
117 }
118 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800119
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700120 bool HasError() {
121 return error_;
122 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800123
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700124 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700125 DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700126
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700127 // 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 Lesinskice5e56e2016-10-21 17:56:45 -0700129 std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700130 const Attribute* attr) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700131 if (RawString* raw_string = ValueCast<RawString>(value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700132 std::unique_ptr<Item> transformed =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700133 ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700134
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700135 // If we could not parse as any specific type, try a basic STRING.
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800136 if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) {
Adam Lesinski2eed52e2018-02-21 15:55:58 -0800137 StringBuilder string_builder;
138 string_builder.AppendText(*raw_string->value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 if (string_builder) {
Adam Lesinski2eed52e2018-02-21 15:55:58 -0800140 transformed =
141 util::make_unique<String>(string_pool_->MakeRef(string_builder.to_string()));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700142 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700144
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700145 if (transformed) {
146 return transformed;
147 }
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800148 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700149 return value;
150 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700151
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800152 const CallSite& callsite_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700153 IAaptContext* context_;
154 SymbolTable* symbols_;
155 xml::IPackageDeclStack* package_decls_;
156 StringPool* string_pool_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700157 bool error_ = false;
158};
159
160class EmptyDeclStack : public xml::IPackageDeclStack {
161 public:
162 EmptyDeclStack() = default;
163
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700164 Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700165 if (alias.empty()) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700166 return xml::ExtractedPackage{{}, true /*private*/};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700167 }
168 return {};
169 }
170
171 private:
172 DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700173};
174
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700175// 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.
177bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
178 const CallSite& callsite) {
179 if (symbol.is_public || ref.private_reference) {
180 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 }
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700182
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 Lesinski467f1712015-11-16 17:35:44 -0800199}
200
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700201} // namespace
202
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800203const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700204 const CallSite& callsite,
Chris Warrington481f0272018-02-06 14:03:39 +0000205 SymbolTable* symbols,
206 bool auto_namespace) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 if (reference.name) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700208 const ResourceName& name = reference.name.value();
209 if (name.package.empty()) {
210 // Use the callsite's package name if no package name was defined.
Chris Warrington481f0272018-02-06 14:03:39 +0000211 const SymbolTable::Symbol* local_symbol =
212 symbols->FindByName(ResourceName(callsite.package, name.type, name.entry));
213 if (!auto_namespace || local_symbol) {
214 return local_symbol;
215 }
216 return symbols->FindByNameInAnyPackage(name);
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700217 }
218 return symbols->FindByName(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 } else if (reference.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 return symbols->FindById(reference.id.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 } else {
222 return nullptr;
223 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800224}
225
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800226const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference,
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800227 const CallSite& callsite,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800228 SymbolTable* symbols,
Chris Warrington481f0272018-02-06 14:03:39 +0000229 bool auto_namespace,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800230 std::string* out_error) {
Chris Warrington481f0272018-02-06 14:03:39 +0000231 const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, symbols, auto_namespace);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700232 if (!symbol) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700233 if (out_error) *out_error = "not found";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234 return nullptr;
235 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800236
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800237 if (!IsSymbolVisible(*symbol, reference, callsite)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700238 if (out_error) *out_error = "is private";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 return nullptr;
240 }
241 return symbol;
Adam Lesinski467f1712015-11-16 17:35:44 -0800242}
243
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700244const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
Chris Warrington481f0272018-02-06 14:03:39 +0000245 const Reference& reference, const CallSite& callsite, SymbolTable* symbols, bool auto_namespace,
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800246 std::string* out_error) {
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800247 const SymbolTable::Symbol* symbol =
Chris Warrington481f0272018-02-06 14:03:39 +0000248 ResolveSymbolCheckVisibility(reference, callsite, symbols, auto_namespace, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700249 if (!symbol) {
250 return nullptr;
251 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800252
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700253 if (!symbol->attribute) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700254 if (out_error) *out_error = "is not an attribute";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700255 return nullptr;
256 }
257 return symbol;
Adam Lesinski467f1712015-11-16 17:35:44 -0800258}
259
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800260Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800261 const CallSite& callsite,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800262 SymbolTable* symbols,
Chris Warrington481f0272018-02-06 14:03:39 +0000263 bool auto_namespace,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800264 std::string* out_error) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800265 const SymbolTable::Symbol* symbol =
Chris Warrington481f0272018-02-06 14:03:39 +0000266 ResolveAttributeCheckVisibility(reference, callsite, symbols, auto_namespace, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700267 if (!symbol) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700268 return {};
269 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800270
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700271 if (!symbol->attribute) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700272 if (out_error) *out_error = "is not an attribute";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700273 return {};
274 }
Adam Lesinskic744ae82017-05-17 19:28:38 -0700275 return xml::AaptAttribute(*symbol->attribute, symbol->id);
Adam Lesinski467f1712015-11-16 17:35:44 -0800276}
277
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700278void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite,
279 const xml::IPackageDeclStack* decls, DiagMessage* out_msg) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700280 CHECK(out_msg != nullptr);
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700281 if (!ref.name) {
282 *out_msg << ref.id.value();
283 return;
284 }
Adam Lesinski28cacf02015-11-23 14:22:47 -0800285
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700286 *out_msg << ref.name.value();
287
288 Reference fully_qualified = ref;
289 xml::ResolvePackage(decls, &fully_qualified);
290
291 ResourceName& full_name = fully_qualified.name.value();
292 if (full_name.package.empty()) {
293 full_name.package = callsite.package;
294 }
295
296 if (full_name != ref.name.value()) {
297 *out_msg << " (aka " << full_name << ")";
298 }
299}
300
301void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite,
302 const xml::IPackageDeclStack* decls,
303 DiagMessage* out_msg) {
304 CHECK(out_msg != nullptr);
305 if (!ref.name) {
306 *out_msg << ref.id.value();
307 return;
308 }
309
310 const ResourceName& ref_name = ref.name.value();
311 CHECK_EQ(ref_name.type, ResourceType::kAttr);
312
313 if (!ref_name.package.empty()) {
314 *out_msg << ref_name.package << ":";
315 }
316 *out_msg << ref_name.entry;
317
318 Reference fully_qualified = ref;
319 xml::ResolvePackage(decls, &fully_qualified);
320
321 ResourceName& full_name = fully_qualified.name.value();
322 if (full_name.package.empty()) {
323 full_name.package = callsite.package;
324 }
325
326 if (full_name != ref.name.value()) {
327 *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700328 }
Adam Lesinski28cacf02015-11-23 14:22:47 -0800329}
330
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800331bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference,
332 IAaptContext* context, SymbolTable* symbols,
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700333 const xml::IPackageDeclStack* decls) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700334 CHECK(reference != nullptr);
Adam Lesinskibab4ef52017-06-01 15:22:57 -0700335 if (!reference->name && !reference->id) {
336 // This is @null.
337 return true;
338 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800339
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700340 Reference transformed_reference = *reference;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700341 xml::ResolvePackage(decls, &transformed_reference);
Adam Lesinski467f1712015-11-16 17:35:44 -0800342
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700343 std::string err_str;
Chris Warrington481f0272018-02-06 14:03:39 +0000344 const SymbolTable::Symbol* s = ResolveSymbolCheckVisibility(
345 transformed_reference, callsite, symbols, context->IsAutoNamespace(), &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700346 if (s) {
347 // The ID may not exist. This is fine because of the possibility of building
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700348 // against libraries without assigned IDs.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700349 // Ex: Linking against own resources when building a static library.
350 reference->id = s->id;
Todd Kennedy32512992018-04-25 16:45:59 -0700351 reference->is_dynamic = s->is_dynamic;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700352 return true;
353 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800354
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700355 DiagMessage error_msg(reference->GetSource());
356 error_msg << "resource ";
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700357 WriteResourceName(*reference, callsite, decls, &error_msg);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700358 error_msg << " " << err_str;
359 context->GetDiagnostics()->Error(error_msg);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700360 return false;
Adam Lesinski467f1712015-11-16 17:35:44 -0800361}
362
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
364 EmptyDeclStack decl_stack;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700365 bool error = false;
366 for (auto& package : table->packages) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700367 // Since we're linking, each package must have a name.
368 CHECK(!package->name.empty()) << "all packages being linked must have a name";
369
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700370 for (auto& type : package->types) {
371 for (auto& entry : type->entries) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700372 // First, unmangle the name if necessary.
373 ResourceName name(package->name, type->type, entry->name);
374 NameMangler::Unmangle(&name.entry, &name.package);
375
376 // Symbol state information may be lost if there is no value for the resource.
Adam Lesinski71be7052017-12-12 16:48:07 -0800377 if (entry->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) {
378 context->GetDiagnostics()->Error(DiagMessage(entry->visibility.source)
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700379 << "no definition for declared symbol '" << name << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700380 error = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700381 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700382
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700383 // The context of this resource is the package in which it is defined.
384 const CallSite callsite{name.package};
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800385 ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(),
386 &table->string_pool, &decl_stack);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700387
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700388 for (auto& config_value : entry->values) {
389 config_value->value->Accept(&visitor);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700390 }
391
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700392 if (visitor.HasError()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700393 error = true;
394 }
395 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700396 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700397 }
398 return !error;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700399}
400
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700401} // namespace aapt