blob: 8e49fabe6a5ccb1200a36957eef9ff957a45637e [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"
Udam Sainib228df32019-06-18 16:50:34 -070020#include "android-base/stringprintf.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070021#include "androidfw/ResourceTypes.h"
22
Adam Lesinskicacb28f2016-10-19 12:18:14 -070023#include "Diagnostics.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070024#include "ResourceTable.h"
25#include "ResourceUtils.h"
26#include "ResourceValues.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027#include "ValueVisitor.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070028#include "link/Linkers.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070029#include "process/IResourceTableConsumer.h"
30#include "process/SymbolTable.h"
Fabien Sanglard2d34e762019-02-21 15:13:29 -080031#include "trace/TraceBuffer.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080032#include "util/Util.h"
33#include "xml/XmlUtil.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070034
Adam Lesinski2eed52e2018-02-21 15:55:58 -080035using ::aapt::ResourceUtils::StringBuilder;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070036using ::android::StringPiece;
Udam Sainib228df32019-06-18 16:50:34 -070037using ::android::base::StringPrintf;
Adam Lesinskid5083f62017-01-16 15:07:21 -080038
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039namespace aapt {
40
41namespace {
42
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070043// The ReferenceLinkerVisitor will follow all references and make sure they point
44// to resources that actually exist, either in the local resource table, or as external
45// symbols. Once the target resource has been found, the ID of the resource will be assigned
46// to the reference object.
47//
48// NOTE: All of the entries in the ResourceTable must be assigned IDs.
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070049class ReferenceLinkerVisitor : public DescendingValueVisitor {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050 public:
Adam Lesinskid3ffa8442017-09-28 13:34:35 -070051 using DescendingValueVisitor::Visit;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070052
Adam Lesinskif34b6f42017-03-03 16:33:26 -080053 ReferenceLinkerVisitor(const CallSite& callsite, IAaptContext* context, SymbolTable* symbols,
54 StringPool* string_pool, xml::IPackageDeclStack* decl)
55 : callsite_(callsite),
56 context_(context),
Adam Lesinskice5e56e2016-10-21 17:56:45 -070057 symbols_(symbols),
58 package_decls_(decl),
Adam Lesinskif34b6f42017-03-03 16:33:26 -080059 string_pool_(string_pool) {}
Adam Lesinskicacb28f2016-10-19 12:18:14 -070060
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 void Visit(Reference* ref) override {
Adam Lesinskif34b6f42017-03-03 16:33:26 -080062 if (!ReferenceLinker::LinkReference(callsite_, ref, context_, symbols_, package_decls_)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070063 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 }
65 }
66
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070067 // We visit the Style specially because during this phase, values of attributes are
68 // all RawString values. Now that we are expected to resolve all symbols, we can
69 // lookup the attributes to find out which types are allowed for the attributes' values.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070070 void Visit(Style* style) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070071 if (style->parent) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070072 Visit(&style->parent.value());
Adam Lesinski1ab598f2015-08-14 14:26:04 -070073 }
74
Adam Lesinskicacb28f2016-10-19 12:18:14 -070075 for (Style::Entry& entry : style->entries) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070076 std::string err_str;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070077
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070078 // Transform the attribute reference so that it is using the fully qualified package
79 // name. This will also mark the reference as being able to see private resources if
80 // there was a '*' in the reference or if the package came from the private namespace.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070081 Reference transformed_reference = entry.key;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070082 ResolvePackage(package_decls_, &transformed_reference);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070084 // Find the attribute in the symbol table and check if it is visible from this callsite.
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -080085 const SymbolTable::Symbol* symbol = ReferenceLinker::ResolveAttributeCheckVisibility(
Udam Sainib228df32019-06-18 16:50:34 -070086 transformed_reference, callsite_, context_, symbols_, &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070087 if (symbol) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070088 // Assign our style key the correct ID. The ID may not exist.
Adam Lesinskicacb28f2016-10-19 12:18:14 -070089 entry.key.id = symbol->id;
90
Adam Lesinski1ef0fa92017-08-15 21:32:49 -070091 // Try to convert the value to a more specific, typed value based on the attribute it is
92 // set to.
Adam Lesinskif34b6f42017-03-03 16:33:26 -080093 entry.value = ParseValueWithAttribute(std::move(entry.value), symbol->attribute.get());
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094
95 // Link/resolve the final value (mostly if it's a reference).
Adam Lesinskice5e56e2016-10-21 17:56:45 -070096 entry.value->Accept(this);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097
98 // Now verify that the type of this item is compatible with the
Adam Lesinski3124e7c2017-06-13 16:03:55 -070099 // attribute it is defined for. We pass `nullptr` as the DiagMessage so that this
100 // check is fast and we avoid creating a DiagMessage when the match is successful.
101 if (!symbol->attribute->Matches(*entry.value, nullptr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700102 // The actual type of this item is incompatible with the attribute.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700103 DiagMessage msg(entry.key.GetSource());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700104
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700105 // Call the matches method again, this time with a DiagMessage so we fill in the actual
106 // error message.
Adam Lesinski3124e7c2017-06-13 16:03:55 -0700107 symbol->attribute->Matches(*entry.value, &msg);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700108 context_->GetDiagnostics()->Error(msg);
109 error_ = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700110 }
111
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700112 } else {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700113 DiagMessage msg(entry.key.GetSource());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700114 msg << "style attribute '";
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700115 ReferenceLinker::WriteResourceName(entry.key, callsite_, package_decls_, &msg);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700116 msg << "' " << err_str;
117 context_->GetDiagnostics()->Error(msg);
118 error_ = true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700119 }
120 }
121 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800122
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700123 bool HasError() {
124 return error_;
125 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800126
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700127 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 DISALLOW_COPY_AND_ASSIGN(ReferenceLinkerVisitor);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700129
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700130 // Transform a RawString value into a more specific, appropriate value, based on the
131 // Attribute. If a non RawString value is passed in, this is an identity transform.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700132 std::unique_ptr<Item> ParseValueWithAttribute(std::unique_ptr<Item> value,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700133 const Attribute* attr) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700134 if (RawString* raw_string = ValueCast<RawString>(value.get())) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700135 std::unique_ptr<Item> transformed =
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700136 ResourceUtils::TryParseItemForAttribute(*raw_string->value, attr);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700137
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138 // If we could not parse as any specific type, try a basic STRING.
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800139 if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) {
Adam Lesinski2eed52e2018-02-21 15:55:58 -0800140 StringBuilder string_builder;
141 string_builder.AppendText(*raw_string->value);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 if (string_builder) {
Adam Lesinski2eed52e2018-02-21 15:55:58 -0800143 transformed =
144 util::make_unique<String>(string_pool_->MakeRef(string_builder.to_string()));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700145 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700146 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700147
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148 if (transformed) {
149 return transformed;
150 }
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800151 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700152 return value;
153 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800155 const CallSite& callsite_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 IAaptContext* context_;
157 SymbolTable* symbols_;
158 xml::IPackageDeclStack* package_decls_;
159 StringPool* string_pool_;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700160 bool error_ = false;
161};
162
163class EmptyDeclStack : public xml::IPackageDeclStack {
164 public:
165 EmptyDeclStack() = default;
166
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700167 Maybe<xml::ExtractedPackage> TransformPackageAlias(const StringPiece& alias) const override {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700168 if (alias.empty()) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700169 return xml::ExtractedPackage{{}, true /*private*/};
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700170 }
171 return {};
172 }
173
174 private:
175 DISALLOW_COPY_AND_ASSIGN(EmptyDeclStack);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700176};
177
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700178// The symbol is visible if it is public, or if the reference to it is requesting private access
179// or if the callsite comes from the same package.
180bool IsSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
181 const CallSite& callsite) {
182 if (symbol.is_public || ref.private_reference) {
183 return true;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700184 }
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700185
186 if (ref.name) {
187 const ResourceName& name = ref.name.value();
188 if (name.package.empty()) {
189 // If the symbol was found, and the package is empty, that means it was found in the local
190 // scope, which is always visible (private local).
191 return true;
192 }
193
194 // The symbol is visible if the reference is local to the same package it is defined in.
195 return callsite.package == name.package;
196 }
197
198 if (ref.id && symbol.id) {
199 return ref.id.value().package_id() == symbol.id.value().package_id();
200 }
201 return false;
Adam Lesinski467f1712015-11-16 17:35:44 -0800202}
203
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700204} // namespace
205
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800206const SymbolTable::Symbol* ReferenceLinker::ResolveSymbol(const Reference& reference,
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700207 const CallSite& callsite,
Udam Sainib228df32019-06-18 16:50:34 -0700208 IAaptContext* context,
Chris Warrington58e2fbf2018-07-23 14:12:20 +0000209 SymbolTable* symbols) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700210 if (reference.name) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700211 const ResourceName& name = reference.name.value();
212 if (name.package.empty()) {
213 // Use the callsite's package name if no package name was defined.
Udam Sainib228df32019-06-18 16:50:34 -0700214 const SymbolTable::Symbol* symbol = symbols->FindByName(
215 ResourceName(callsite.package, name.type, name.entry));
216 if (symbol) {
217 return symbol;
218 }
219
220 // If the callsite package is the same as the current compilation package,
221 // check the feature split dependencies as well. Feature split resources
222 // can be referenced without a namespace, just like the base package.
223 // TODO: modify the package name of included splits instead of having the
224 // symbol table look up the resource in in every package. b/136105066
225 if (callsite.package == context->GetCompilationPackage()) {
226 const auto& split_name_dependencies = context->GetSplitNameDependencies();
227 for (const std::string& split_name : split_name_dependencies) {
228 std::string split_package =
229 StringPrintf("%s.%s", callsite.package.c_str(), split_name.c_str());
230 symbol = symbols->FindByName(ResourceName(split_package, name.type, name.entry));
231 if (symbol) {
232 return symbol;
233 }
234 }
235 }
236 return nullptr;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700237 }
238 return symbols->FindByName(name);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700239 } else if (reference.id) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700240 return symbols->FindById(reference.id.value());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700241 } else {
242 return nullptr;
243 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800244}
245
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800246const SymbolTable::Symbol* ReferenceLinker::ResolveSymbolCheckVisibility(const Reference& reference,
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800247 const CallSite& callsite,
Udam Sainib228df32019-06-18 16:50:34 -0700248 IAaptContext* context,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800249 SymbolTable* symbols,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800250 std::string* out_error) {
Udam Sainib228df32019-06-18 16:50:34 -0700251 const SymbolTable::Symbol* symbol = ResolveSymbol(reference, callsite, context, symbols);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700252 if (!symbol) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700253 if (out_error) *out_error = "not found";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700254 return nullptr;
255 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800256
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800257 if (!IsSymbolVisible(*symbol, reference, callsite)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700258 if (out_error) *out_error = "is private";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700259 return nullptr;
260 }
261 return symbol;
Adam Lesinski467f1712015-11-16 17:35:44 -0800262}
263
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700264const SymbolTable::Symbol* ReferenceLinker::ResolveAttributeCheckVisibility(
Udam Sainib228df32019-06-18 16:50:34 -0700265 const Reference& reference, const CallSite& callsite, IAaptContext* context,
266 SymbolTable* symbols, std::string* out_error) {
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800267 const SymbolTable::Symbol* symbol =
Udam Sainib228df32019-06-18 16:50:34 -0700268 ResolveSymbolCheckVisibility(reference, callsite, context, symbols, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700269 if (!symbol) {
270 return nullptr;
271 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800272
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700273 if (!symbol->attribute) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700274 if (out_error) *out_error = "is not an attribute";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700275 return nullptr;
276 }
277 return symbol;
Adam Lesinski467f1712015-11-16 17:35:44 -0800278}
279
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800280Maybe<xml::AaptAttribute> ReferenceLinker::CompileXmlAttribute(const Reference& reference,
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800281 const CallSite& callsite,
Udam Sainib228df32019-06-18 16:50:34 -0700282 IAaptContext* context,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800283 SymbolTable* symbols,
Adam Lesinskiceb9b2f2017-02-16 12:05:42 -0800284 std::string* out_error) {
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800285 const SymbolTable::Symbol* symbol =
Udam Sainib228df32019-06-18 16:50:34 -0700286 ResolveAttributeCheckVisibility(reference, callsite, context, symbols, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700287 if (!symbol) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700288 return {};
289 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800290
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700291 if (!symbol->attribute) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700292 if (out_error) *out_error = "is not an attribute";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700293 return {};
294 }
Adam Lesinskic744ae82017-05-17 19:28:38 -0700295 return xml::AaptAttribute(*symbol->attribute, symbol->id);
Adam Lesinski467f1712015-11-16 17:35:44 -0800296}
297
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700298void ReferenceLinker::WriteResourceName(const Reference& ref, const CallSite& callsite,
299 const xml::IPackageDeclStack* decls, DiagMessage* out_msg) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700300 CHECK(out_msg != nullptr);
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700301 if (!ref.name) {
302 *out_msg << ref.id.value();
303 return;
304 }
Adam Lesinski28cacf02015-11-23 14:22:47 -0800305
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700306 *out_msg << ref.name.value();
307
308 Reference fully_qualified = ref;
309 xml::ResolvePackage(decls, &fully_qualified);
310
311 ResourceName& full_name = fully_qualified.name.value();
312 if (full_name.package.empty()) {
313 full_name.package = callsite.package;
314 }
315
316 if (full_name != ref.name.value()) {
317 *out_msg << " (aka " << full_name << ")";
318 }
319}
320
321void ReferenceLinker::WriteAttributeName(const Reference& ref, const CallSite& callsite,
322 const xml::IPackageDeclStack* decls,
323 DiagMessage* out_msg) {
324 CHECK(out_msg != nullptr);
325 if (!ref.name) {
326 *out_msg << ref.id.value();
327 return;
328 }
329
330 const ResourceName& ref_name = ref.name.value();
331 CHECK_EQ(ref_name.type, ResourceType::kAttr);
332
333 if (!ref_name.package.empty()) {
334 *out_msg << ref_name.package << ":";
335 }
336 *out_msg << ref_name.entry;
337
338 Reference fully_qualified = ref;
339 xml::ResolvePackage(decls, &fully_qualified);
340
341 ResourceName& full_name = fully_qualified.name.value();
342 if (full_name.package.empty()) {
343 full_name.package = callsite.package;
344 }
345
346 if (full_name != ref.name.value()) {
347 *out_msg << " (aka " << full_name.package << ":" << full_name.entry << ")";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700348 }
Adam Lesinski28cacf02015-11-23 14:22:47 -0800349}
350
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800351bool ReferenceLinker::LinkReference(const CallSite& callsite, Reference* reference,
352 IAaptContext* context, SymbolTable* symbols,
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700353 const xml::IPackageDeclStack* decls) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700354 CHECK(reference != nullptr);
Adam Lesinskibab4ef52017-06-01 15:22:57 -0700355 if (!reference->name && !reference->id) {
356 // This is @null.
357 return true;
358 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800359
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700360 Reference transformed_reference = *reference;
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700361 xml::ResolvePackage(decls, &transformed_reference);
Adam Lesinski467f1712015-11-16 17:35:44 -0800362
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700363 std::string err_str;
Chris Warrington58e2fbf2018-07-23 14:12:20 +0000364 const SymbolTable::Symbol* s =
Udam Sainib228df32019-06-18 16:50:34 -0700365 ResolveSymbolCheckVisibility(transformed_reference, callsite, context, symbols, &err_str);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700366 if (s) {
367 // The ID may not exist. This is fine because of the possibility of building
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700368 // against libraries without assigned IDs.
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700369 // Ex: Linking against own resources when building a static library.
370 reference->id = s->id;
Todd Kennedy32512992018-04-25 16:45:59 -0700371 reference->is_dynamic = s->is_dynamic;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700372 return true;
373 }
Adam Lesinski467f1712015-11-16 17:35:44 -0800374
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700375 DiagMessage error_msg(reference->GetSource());
376 error_msg << "resource ";
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700377 WriteResourceName(*reference, callsite, decls, &error_msg);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700378 error_msg << " " << err_str;
379 context->GetDiagnostics()->Error(error_msg);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700380 return false;
Adam Lesinski467f1712015-11-16 17:35:44 -0800381}
382
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700383bool ReferenceLinker::Consume(IAaptContext* context, ResourceTable* table) {
Fabien Sanglard2d34e762019-02-21 15:13:29 -0800384 TRACE_NAME("ReferenceLinker::Consume");
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700385 EmptyDeclStack decl_stack;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700386 bool error = false;
387 for (auto& package : table->packages) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700388 // Since we're linking, each package must have a name.
389 CHECK(!package->name.empty()) << "all packages being linked must have a name";
390
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700391 for (auto& type : package->types) {
392 for (auto& entry : type->entries) {
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700393 // First, unmangle the name if necessary.
394 ResourceName name(package->name, type->type, entry->name);
395 NameMangler::Unmangle(&name.entry, &name.package);
396
397 // Symbol state information may be lost if there is no value for the resource.
Adam Lesinski71be7052017-12-12 16:48:07 -0800398 if (entry->visibility.level != Visibility::Level::kUndefined && entry->values.empty()) {
399 context->GetDiagnostics()->Error(DiagMessage(entry->visibility.source)
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800400 << "no definition for declared symbol '" << name
401 << "'");
402 error = true;
403 }
404
405 // Ensure that definitions for values declared as overlayable exist
Ryan Mitchell54237ff2018-12-13 15:44:29 -0800406 if (entry->overlayable_item && entry->values.empty()) {
407 context->GetDiagnostics()->Error(DiagMessage(entry->overlayable_item.value().source)
Ryan Mitchell75e20dd2018-11-06 16:39:36 -0800408 << "no definition for overlayable symbol '"
409 << name << "'");
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700410 error = true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700411 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700412
Adam Lesinski1ef0fa92017-08-15 21:32:49 -0700413 // The context of this resource is the package in which it is defined.
414 const CallSite callsite{name.package};
Adam Lesinskif34b6f42017-03-03 16:33:26 -0800415 ReferenceLinkerVisitor visitor(callsite, context, context->GetExternalSymbols(),
416 &table->string_pool, &decl_stack);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700417
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700418 for (auto& config_value : entry->values) {
419 config_value->value->Accept(&visitor);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700420 }
421
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700422 if (visitor.HasError()) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700423 error = true;
424 }
425 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700426 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700427 }
428 return !error;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700429}
430
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700431} // namespace aapt